Browse Mode

This commit is contained in:
4am 2019-07-03 18:31:50 -04:00
parent 045fe1cfef
commit a37dd59b4f
6 changed files with 355 additions and 109 deletions

View File

@ -65,6 +65,7 @@ RestoreStackNextTime
; these routines will only be called after relocating to language card ; these routines will only be called after relocating to language card
!source "src/ui.search.mode.a" !source "src/ui.search.mode.a"
!source "src/ui.browse.mode.a"
!source "src/ui.attract.mode.a" !source "src/ui.attract.mode.a"
!source "src/ui.attract.hgr.a" !source "src/ui.attract.hgr.a"
!source "src/ui.attract.dhgr.a" !source "src/ui.attract.dhgr.a"
@ -81,6 +82,8 @@ RestoreStackNextTime
!source "src/ui.common.a" !source "src/ui.common.a"
MachineStatus MachineStatus
!byte 0 !byte 0
GameCount
!byte 0
gAttractModeStore gAttractModeStore
gFXStore gFXStore
gDFXStore gDFXStore

View File

@ -117,6 +117,7 @@ OneTimeSetup
jsr okvs_len jsr okvs_len
!word gGamesListStore !word gGamesListStore
sta GameCount
sta SAVE sta SAVE
; calculate and update visible game count (3-digit decimal number as ASCII string) ; calculate and update visible game count (3-digit decimal number as ASCII string)
ldy #0 ldy #0

View File

@ -5,6 +5,7 @@
; ;
; Public functions ; Public functions
; - PlayGameFromSearch ; - PlayGameFromSearch
; - PlayGameFromBrowse
; - PlayGameFromAttract ; - PlayGameFromAttract
; - Prelaunch ; - Prelaunch
; - Launch ; - Launch
@ -17,6 +18,7 @@
!zone { !zone {
PlayGameFromSearch PlayGameFromSearch
PlayGameFromBrowse
stx @gameIndex stx @gameIndex
jsr okvs_nth jsr okvs_nth
!word gGamesListStore !word gGamesListStore

217
src/ui.browse.mode.a Normal file
View File

@ -0,0 +1,217 @@
;license:MIT
;(c) 2018-9 by 4am
;
; Browse Mode - main UI
;
; Public functions
; - BrowseMode
;
!zone {
;------------------------------------------------------------------------------
; BrowseMode
; main entry point for Browse Mode, which allows the user to browse the game
; catalog in alphabetical order and launch games
;
; in: none
; out: never returns to caller (may JMP to other major modes)
;------------------------------------------------------------------------------
BrowseMode
+READ_RAM1_WRITE_RAM1
ldx #$FF
txs
ldx SelectedIndex
stx BrowseSelectedIndex
.BrowseModeInputLoop
lda KBD
bmi @gotKey
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 .BrowseModeInputLoop ; that counts down from a number set
dec Timeout+1 ; in .ResetInputTimeout and reset
bne .BrowseModeInputLoop ; on every keypress (whether or not
dec Timeout+2 ; the key leads to an action)
bne .BrowseModeInputLoop
; jsr .CoverFade ; no input for ~30 seconds, switch to
jmp MegaAttractMode ; mega-attract mode
@gotKey
bit CLEARKBD
jsr ResetInputTimeout
cmp #$88 ; left arrow = previous
bne +
- ldx #kBrowsePrevious
bne @BrowseDispatch ; always branches
+ cmp #$8B ; up arrow is same as left arrow
beq -
cmp #$95 ; right arrow = next
bne +
- ldx #kBrowseNext
bne @BrowseDispatch ; always branches
+ cmp #$8A ; down arrow is same as right arrow
beq -
cmp #$9B ; Esc switches to search mode
bne +
ldx #kBrowseExitMode
bne @BrowseDispatch ; always branches
+
cmp #$8D ; ENTER launches the current game
bne +
ldx #kBrowseLaunch
bne @BrowseDispatch ; always branches
+
cmp #$89 ; TAB switches to mini attract mode
bne + ; temporarily
ldx #kBrowseTab
bne @BrowseDispatch ; always branches
+
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
jsr SoftBell ; beep on invalid input
jmp .BrowseModeInputLoop ; and start over
@goodkey
ldx #kBrowseSearch
; execution falls through here
@BrowseDispatch
pha ; save key pressed
txa
asl
tax
lda .BrowseDispatchTable,x
sta @j+1
lda .BrowseDispatchTable+1,x
sta @j+2
pla ; restore key pressed
@j jsr $FDFD ; SMC
bcs +
jmp .BrowseModeInputLoop ; if carry is clear, we're done
; TODO
+ jmp BrowseMode ; if carry is set, force full redraw
.OnSearch
sta InputBuffer
lda #$01
sta InputLength
jmp SearchMode
.OnPrevious
dec BrowseSelectedIndex
jmp +
.OnNext
inc BrowseSelectedIndex
+
ldx BrowseSelectedIndex
cpx #$FF
bne @notTooSmall
ldx GameCount
dex
bne @done ; always branches
@notTooSmall
cpx GameCount
bcc @done
ldx #0
@done stx BrowseSelectedIndex
jmp .OnBrowseChanged
.OnTab
ldx BrowseSelectedIndex
jsr MiniAttractMode
cmp #$8D
beq .OnLaunch
; TODO redraw
rts
.OnLaunch
ldx BrowseSelectedIndex
jsr PlayGameFromBrowse
jmp BrowseMode
.OnBrowseChanged
stx @index
jsr okvs_nth ; get the name of the new game
!word gGamesListStore
@index !byte $FD
+STAY @key
jsr GetOffscreenAddress ; load new title screenshot offscreen
sta + ; new title screenshot (offscreen)
+LDADDR kHGRTitleDirectory
jsr SetPath
+LDAY @key
jsr AddToPath
jsr LoadFileAt
!byte $00
+ !byte $FD ; SMC
jsr okvs_get
!word gGamesListStore
@key !word $FDFD
+STAY SRC ; A/Y points to game title (in OKVS)
ldy #0 ; copy game title into search bar buffer
lda (SRC),y
sta SAVE ; game title length
inc SAVE
- iny
cpy SAVE
bcc @printTitleChar
lda #" "
+HIDE_NEXT_2_BYTES
@printTitleChar
lda (SRC),y ; copy game title to UI line 2
sta UILine2,y
cpy #MaxInputLength+1
bcc -
ldx #40
lda #0
- sta UILine1-1,x ; reset UI line 1
dex
bne -
jsr DrawSearchBarOffscreen ; actually draw the search UI (offscreen)
jmp ShowOtherPage ; now show everything at once
;------------------------------------------------------------------------------
; indices into BrowseDispatchTable
kBrowseSearch = 0
kBrowsePrevious = 1
kBrowseNext = 2
kBrowseExitMode = 3
kBrowseTab = 4
kBrowseLaunch = 5
.BrowseDispatchTable
!word .OnSearch
!word .OnPrevious
!word .OnNext
!word SearchMode
!word .OnTab
!word .OnLaunch
BrowseSelectedIndex
!byte $FF
}

View File

@ -4,13 +4,96 @@
; common UI functions ; common UI functions
; ;
; Public functions ; Public functions
; - GetOffscreenAddress
; - DrawSearchBarOffscreen
; - ShowOtherPage
; - ToggleOffscreenPage
; - ResetInputTimeout
; - SoftBell ; - SoftBell
; - Home ; - Home
; - BlankHGR ; - BlankHGR
; - BlankDHGR ; - BlankDHGR
; Public variables
; - OffscreenPage
; - UILine1
; - UILine2
; - VisibleGameCount (set during init)
; ;
!zone { !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
!text "["
!byte $7F
!text " "
!text "] "
VisibleGameCount
!text "000"
!text " games"
GetOffscreenAddress
; in: none
; out: A = high byte of offscreen HGR page (#$20 or #$40)
; preserves X/Y
lda OffscreenPage
beq +
lda #$40
rts
+ lda #$20
rts
DrawSearchBarOffscreen
; clobbers all
LDA #22 ; draw visible search bar
sta VTAB
lda OffscreenPage
ror ; draw on offscreen page
+LDADDR UILine1
jsr Draw40Chars
lda OffscreenPage
ror ; draw on offscreen page
+LDADDR UILine2
jmp Draw40Chars
ShowOtherPage
; in: none
; out: A = new value of OffscreenPage
; preserves X/Y
jsr ToggleOffscreenPage
bne +
bit PAGE2 ; show page 2
rts
+ bit PAGE1 ; show page 1
rts
ToggleOffscreenPage
; in: none
; out: A = new value of OffscreenPage
; preserves X/Y
lda OffscreenPage
eor #$01
sta OffscreenPage
rts
ResetInputTimeout
; clobbers X, preserves A/Y
ldx #$16
stx Timeout
stx Timeout+1
stx Timeout+2
rts
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
; SoftBell ; SoftBell

View File

@ -6,8 +6,6 @@
; Public functions ; Public functions
; - SearchMode ; - SearchMode
; ;
; Public addresses
; - VisibleGameCount (set during init)
!zone { !zone {
@ -25,12 +23,12 @@ SearchMode
txs txs
stx SelectedIndex ; no game selected stx SelectedIndex ; no game selected
inx inx
stx .OffscreenPage stx OffscreenPage
jsr Home ; clear screen jsr Home ; clear screen
jsr .OnInputChanged ; draw UI on HGR page 1 jsr .OnInputChanged ; draw UI on HGR page 1
+HGR_MODE ; show HGR +HGR_MODE ; show HGR
bit CLEARKBD bit CLEARKBD
jsr .ResetInputTimeout jsr ResetInputTimeout
.SearchModeInputLoop .SearchModeInputLoop
lda KBD lda KBD
@ -42,7 +40,7 @@ SearchMode
+ +
dec Timeout ; these are a 3-byte timeout counter dec Timeout ; these are a 3-byte timeout counter
bne .SearchModeInputLoop ; that counts down from a number set bne .SearchModeInputLoop ; that counts down from a number set
dec Timeout+1 ; in .ResetInputTimeout and reset dec Timeout+1 ; in ResetInputTimeout and reset
bne .SearchModeInputLoop ; on every keypress (whether or not bne .SearchModeInputLoop ; on every keypress (whether or not
dec Timeout+2 ; the key leads to an action) dec Timeout+2 ; the key leads to an action)
bne .SearchModeInputLoop bne .SearchModeInputLoop
@ -50,8 +48,19 @@ SearchMode
jmp MegaAttractMode ; mega-attract mode jmp MegaAttractMode ; mega-attract mode
@gotKey @gotKey
cmp #$88 ; left arrow switches to browse mode
beq @arrow
cmp #$8B ; also right arrow
beq @arrow
cmp #$95 ; also up arrow
beq @arrow
cmp #$8A ; also down arrow
bne @notArrow
@arrow ldx #kInputBrowse
bne @InputDispatch ; always branches
@notArrow
bit CLEARKBD bit CLEARKBD
jsr .ResetInputTimeout jsr ResetInputTimeout
cmp #$9B ; Esc clears the input buffer (if any) cmp #$9B ; Esc clears the input buffer (if any)
bne + ; or switches to mega attract mode bne + ; or switches to mega attract mode
@ -65,12 +74,9 @@ SearchMode
+ +
cmp #$FF ; delete key cmp #$FF ; delete key
bne + bne +
- ldx #kInputBack ldx #kInputBack
bne @InputDispatch ; always branches bne @InputDispatch ; always branches
+
+ cmp #$88 ; left arrow = delete
beq -
cmp #$89 ; TAB switches to mini attract mode cmp #$89 ; TAB switches to mini attract mode
bne + ; if there is a game selected bne + ; if there is a game selected
ldx #kInputTab ldx #kInputTab
@ -171,19 +177,19 @@ SearchMode
sta SelectedIndex ; no game selected sta SelectedIndex ; no game selected
ldx #40 ; reset visible line ldx #40 ; reset visible line
lda #0 lda #0
- sta .UILine1-1,x - sta UILine1-1,x
dex dex
bne - bne -
ldy #MaxInputLength ; clear visible search bar ldy #MaxInputLength ; clear visible search bar
lda #" " lda #" "
- sta .UILine2+1,y - sta UILine2+1,y
dey dey
bne - bne -
lda #$7F lda #$7F
sta .UILine2+1 sta UILine2+1
jsr .LoadTitleOffscreen jsr .LoadTitleOffscreen
jsr .DrawSearchBarOffscreen jsr DrawSearchBarOffscreen
jsr .ShowOtherPage jsr ShowOtherPage
clc clc
rts rts
@findMatchingTitle @findMatchingTitle
@ -211,12 +217,12 @@ SearchMode
+STAY @key +STAY @key
plp plp
bne + bne +
lda .OffscreenPage ; since we're not loading a new screenshot jsr ToggleOffscreenPage ; Since we're not loading a new screenshot
eor #$01 ; we fake switching the 'offscreen' page ; we fake switching the 'offscreen' page
sta .OffscreenPage ; in order to draw on the visible page ; in order to draw on the visible page.
bpl @skipload ; always branches bpl @skipload ; always branches
+ +
jsr .GetOffscreenAddress ; we have a new best match, so load the jsr GetOffscreenAddress ; we have a new best match, so load the
sta + ; new title screenshot (offscreen) sta + ; new title screenshot (offscreen)
+LDADDR kHGRTitleDirectory +LDADDR kHGRTitleDirectory
jsr SetPath jsr SetPath
@ -246,12 +252,12 @@ SearchMode
+HIDE_NEXT_2_BYTES +HIDE_NEXT_2_BYTES
@printTitleChar @printTitleChar
lda (SRC),y ; copy game title to search UI lda (SRC),y ; copy game title to search UI
sta .UILine2,y sta UILine2,y
cpy #MaxInputLength+1 cpy #MaxInputLength+1
bcc - bcc -
ldx #40 ldx #40
lda #0 lda #0
- sta .UILine1-1,x ; reset search bar - sta UILine1-1,x ; reset search bar
dex dex
bne - bne -
tay tay
@ -260,7 +266,7 @@ SearchMode
cmp InputBuffer,x cmp InputBuffer,x
bne + bne +
lda #$0B ; add dots to highlight matched characters lda #$0B ; add dots to highlight matched characters
sta .UILine1,y sta UILine1,y
inx inx
cpx InputLength cpx InputLength
beq @doneHighlight beq @doneHighlight
@ -269,28 +275,24 @@ SearchMode
cpy #40 cpy #40
bne - bne -
@doneHighlight @doneHighlight
jsr .DrawSearchBarOffscreen; actually draw the search UI (offscreen) jsr DrawSearchBarOffscreen; actually draw the search UI (offscreen)
jmp .ShowOtherPage ; now show everything at once jmp ShowOtherPage ; now show everything at once
;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------
.GetOffscreenAddress
; in: none
; out: A = high byte of offscreen HGR page (#$20 or #$40)
; preserves X/Y
lda .OffscreenPage
beq +
lda #$40
rts
+ lda #$20
rts
.LoadTitleOffscreen .LoadTitleOffscreen
; clobbers all ; [private] clobbers all
jsr .GetOffscreenAddress
sta +
+LDADDR @TitleFile +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
; [private] clobbers all
+LDADDR @CoverFile
+
jsr SetPath jsr SetPath
jsr GetOffscreenAddress
sta +
jsr LoadFileAt jsr LoadFileAt
!byte $00 !byte $00
+ !byte $FD ; SMC + !byte $FD ; SMC
@ -298,61 +300,18 @@ SearchMode
@TitleFile @TitleFile
!byte 5 !byte 5
!text "TITLE" !text "TITLE"
.LoadCoverOffscreen
; clobbers all
jsr .GetOffscreenAddress
sta +
+LDADDR @CoverFile
jsr SetPath
jsr LoadFileAt
!byte $00
+ !byte $FD ; SMC
rts
@CoverFile @CoverFile
!byte 5 !byte 5
!text "COVER" !text "COVER"
.DrawSearchBarOffscreen
; clobbers all
LDA #22 ; draw visible search bar
sta VTAB
lda .OffscreenPage
ror ; draw on offscreen page
+LDADDR .UILine1
jsr Draw40Chars
lda .OffscreenPage
ror ; draw on offscreen page
+LDADDR .UILine2
jmp Draw40Chars
.ShowOtherPage
; clobbers A, preserves X/Y
lda .OffscreenPage
eor #$01
sta .OffscreenPage
bne +
bit PAGE2 ; show page 2
rts
+ bit PAGE1 ; show page 1
rts
.ResetInputTimeout
; clobbers X, preserves A/Y
ldx #$16
stx Timeout
stx Timeout+1
stx Timeout+2
rts
.CoverFade .CoverFade
; clobbers all ; [private] clobbers all
jsr .LoadCoverOffscreen jsr .LoadCoverOffscreen
jsr .ShowOtherPage jsr ShowOtherPage
lda .OffscreenPage lda OffscreenPage
bne + bne +
jsr .LoadCoverOffscreen jsr .LoadCoverOffscreen
jsr .ShowOtherPage jsr ShowOtherPage
+ +
; load transition effect code at $6000 ; load transition effect code at $6000
+LDADDR kFXDirectory +LDADDR kFXDirectory
@ -365,38 +324,19 @@ SearchMode
!byte 9 !byte 9
!text "COVERFADE" !text "COVERFADE"
.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
!text "["
!byte $7F
!text " "
!text "] "
VisibleGameCount
!text "000"
!text " games"
.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)
; indices into InputDispatchTable ; indices into InputDispatchTable
kInputSearch = 0 kInputSearch = 0
kInputClear = 1 kInputClear = 1
kInputBack = 2 kInputBack = 2
kInputTab = 3 kInputBrowse = 3
kInputLaunch = 4 kInputTab = 4
kInputLaunch = 5
.InputDispatchTable .InputDispatchTable
!word .OnSearch !word .OnSearch
!word .OnClear !word .OnClear
!word .OnBack !word .OnBack
!word BrowseMode
!word .OnTab !word .OnTab
!word .OnLaunch !word .OnLaunch