4cade/src/ui.search.mode.a

404 lines
12 KiB
Plaintext
Raw Normal View History

2018-12-23 16:13:47 +00:00
;license:MIT
;(c) 2018-9 by 4am
2018-12-23 16:13:47 +00:00
;
; Search Mode - main UI
2018-12-23 16:13:47 +00:00
;
; Public functions
; - SearchMode
;
2019-06-27 15:37:23 +00:00
; Public addresses
; - VisibleGameCount (set during init)
!zone {
2018-12-23 16:13:47 +00:00
;------------------------------------------------------------------------------
; SearchMode
; main entry point for Search Mode, which allows the user to search the game
; catalog and launch games
;
; in: none
; out: never returns to caller (may JMP to other major modes)
;------------------------------------------------------------------------------
2018-12-23 16:13:47 +00:00
SearchMode
2019-06-27 14:55:07 +00:00
+READ_RAM1_WRITE_RAM1
ldx #$FF
txs
stx SelectedIndex ; no game selected
inx
2019-06-27 15:37:23 +00:00
stx .OffscreenPage
jsr Home ; clear screen
2019-06-27 15:37:23 +00:00
jsr .OnInputChanged ; draw UI on HGR page 1
+HGR_MODE ; show HGR
2019-06-27 14:55:07 +00:00
bit CLEARKBD
2019-06-27 15:37:23 +00:00
jsr .ResetInputTimeout
2019-06-21 17:10:29 +00:00
2019-06-27 15:37:23 +00:00
.SearchModeInputLoop
2019-06-27 14:55:07 +00:00
lda KBD
2019-06-21 17:10:29 +00:00
bmi @gotKey
2019-06-27 15:37:23 +00:00
inc RNDSEED+1 ; these are only ever incremented, never
bne + ; reset (may be used as a pseudorandom
2019-06-27 15:37:23 +00:00
inc RNDSEED ; seed)
2019-06-21 17:10:29 +00:00
+
dec Timeout ; these are a 3-byte timeout counter
2019-06-27 15:37:23 +00:00
bne .SearchModeInputLoop ; that counts down from a number set
dec Timeout+1 ; in .ResetInputTimeout and reset
bne .SearchModeInputLoop ; on every keypress (whether or not
dec Timeout+2 ; the key leads to an action)
2019-06-27 15:37:23 +00:00
bne .SearchModeInputLoop
jsr .CoverFade ; no input for ~30 seconds, switch to
jmp MegaAttractMode ; mega-attract mode
2019-06-21 17:17:57 +00:00
2019-06-21 17:10:29 +00:00
@gotKey
2019-06-27 14:55:07 +00:00
bit CLEARKBD
2019-06-27 15:37:23 +00:00
jsr .ResetInputTimeout
2019-06-20 18:18:23 +00:00
2019-06-21 17:10:29 +00:00
cmp #$9B ; Esc clears the input buffer (if any)
2019-06-27 02:51:34 +00:00
bne + ; or switches to mega attract mode
2019-06-20 18:18:23 +00:00
ldx #kInputClear
2019-06-27 15:37:23 +00:00
bne @InputDispatch ; always branches
2019-06-20 18:18:23 +00:00
+
cmp #$8D ; ENTER launches the current game (if any)
bne +
ldx #kInputLaunch
2019-06-27 15:37:23 +00:00
bne @InputDispatch ; always branches
+
cmp #$FF ; delete key
2019-06-18 18:56:05 +00:00
bne +
- ldx #kInputBack
2019-06-27 15:37:23 +00:00
bne @InputDispatch ; always branches
2019-06-18 18:56:05 +00:00
+ cmp #$88 ; left arrow = delete
2019-06-18 18:56:05 +00:00
beq -
2019-06-27 02:51:34 +00:00
cmp #$89 ; TAB switches to mini attract mode
bne + ; if there is a game selected
ldx #kInputTab
2019-06-27 15:37:23 +00:00
bne @InputDispatch ; always branches
2019-06-27 02:51:34 +00:00
+
and #$7F ; strip high bit for search characters
2019-06-18 18:56:05 +00:00
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
2019-06-27 15:37:23 +00:00
jmp .SearchModeInputLoop ; and start over
2019-06-18 18:56:05 +00:00
@goodkey
ldx #kInputSearch
2019-06-18 18:56:05 +00:00
; execution falls through here
2019-06-27 15:37:23 +00:00
@InputDispatch
2019-06-18 18:56:05 +00:00
pha ; save key pressed
txa
asl
tax
2019-06-27 15:37:23 +00:00
lda .InputDispatchTable,x
2019-06-18 18:56:05 +00:00
sta @j+1
2019-06-27 15:37:23 +00:00
lda .InputDispatchTable+1,x
2019-06-18 18:56:05 +00:00
sta @j+2
pla ; restore key pressed
@j jsr $FDFD ; SMC
2019-06-27 02:51:34 +00:00
bcs +
2019-06-27 15:37:23 +00:00
jmp .SearchModeInputLoop ; if carry is clear, we're done
2019-06-27 02:51:34 +00:00
+ jmp SearchMode ; if carry is set, force full redraw
2018-12-23 16:13:47 +00:00
2019-06-27 15:37:23 +00:00
.OnClear
ldx InputLength
bne +
2019-06-27 15:37:23 +00:00
jsr .CoverFade ; Esc with no input switches to
jmp MegaAttractMode ; mega-attract mode
+ ldx #0 ; Esc with input clears the input
stx InputLength
2019-06-27 15:37:23 +00:00
jmp .OnInputChanged
2019-06-27 15:37:23 +00:00
.OnBack
2018-12-23 16:13:47 +00:00
ldx InputLength
2019-06-18 18:56:05 +00:00
bne +
jsr SoftBell
rts
+ dec InputLength
2019-06-27 15:37:23 +00:00
jmp .OnInputChanged
2018-12-23 16:13:47 +00:00
2019-06-27 15:37:23 +00:00
.OnTab
2019-06-27 02:51:34 +00:00
ldx SelectedIndex
cpx #$FF
beq +
jsr MiniAttractMode
2019-06-27 15:37:23 +00:00
cmp #$8D ; if we exited mini attract mode
beq .OnLaunch ; by pressing Enter, launch the game
2019-06-27 02:51:34 +00:00
sec ; tell caller to redraw UI
rts
+ clc
rts
2019-06-27 15:37:23 +00:00
.OnLaunch
2019-06-20 18:18:23 +00:00
ldx SelectedIndex
cpx #$FF
beq +
jsr PlayGameFromSearch
sec ; tell caller to redraw UI
rts
+ clc
rts
2018-12-23 16:13:47 +00:00
2019-06-27 15:37:23 +00:00
.OnSearch
2019-06-18 18:56:05 +00:00
ldx InputLength
cpx #MaxInputLength
bne +
jsr SoftBell
2019-06-24 23:20:00 +00:00
clc
2019-06-18 18:56:05 +00:00
rts
+ sta InputBuffer,x
inc InputLength
; execution falls through here
2019-06-27 15:37:23 +00:00
.OnInputChanged
2019-06-18 18:56:05 +00:00
lda InputLength
bne @findMatchingTitle
; no input, reset params and UI
lda #$FF
sta SelectedIndex ; no game selected
2019-06-18 21:07:14 +00:00
ldx #40 ; reset visible line
lda #0
2019-06-27 15:37:23 +00:00
- sta .UILine1-1,x
2019-06-18 21:07:14 +00:00
dex
bne -
2019-06-18 18:56:05 +00:00
ldy #MaxInputLength ; clear visible search bar
lda #" "
2019-06-27 15:37:23 +00:00
- sta .UILine2+1,y
2019-06-18 18:56:05 +00:00
dey
bne -
lda #$7F
2019-06-27 15:37:23 +00:00
sta .UILine2+1
jsr .LoadTitleOffscreen
jsr .DrawSearchBarOffscreen
jsr .ShowOtherPage
clc
rts
2019-06-18 18:56:05 +00:00
@findMatchingTitle
2019-06-18 21:07:14 +00:00
jsr ResetTextRank
2018-12-23 16:13:47 +00:00
2019-06-18 21:07:14 +00:00
jsr okvs_iter_values ; iterate through all game titles
!word gGamesListStore ; and rank them for the best match
!word TextRankCallback ; to the current input buffer
2018-12-23 16:13:47 +00:00
lda MatchCount ; any matches at all?
bne +
2019-06-18 18:56:05 +00:00
jsr SoftBell ; no matches for this input buffer, beep
dec InputLength ; and ignore the last key typed
2019-06-24 23:20:00 +00:00
clc
2019-06-18 18:56:05 +00:00
rts
+
lda BestMatchIndex ; check if the new best match is the same
cmp SelectedIndex ; as the current best match
php ; (we'll use this later to skip reloading)
sta SelectedIndex
sta @index
2019-06-27 15:37:23 +00:00
jsr okvs_nth ; get the name of the new best match
2018-12-23 16:13:47 +00:00
!word gGamesListStore
@index !byte $FD
+STAY @key
plp
bne +
2019-06-27 15:37:23 +00:00
lda .OffscreenPage ; since we're not loading a new screenshot
eor #$01 ; we fake switching the 'offscreen' page
sta .OffscreenPage ; in order to draw on the visible page
bpl @skipload ; always branches
+
jsr .GetOffscreenAddress ; we have a new best match, so load the
sta + ; new title screenshot (offscreen)
+LDADDR kHGRTitleDirectory
jsr SetPath
+LDAY @key
jsr AddToPath
jsr LoadFileAt
2019-06-27 15:37:23 +00:00
!byte $00
+ !byte $FD ; SMC
2018-12-23 16:13:47 +00:00
@skipload
2018-12-23 16:13:47 +00:00
jsr okvs_get
!word gGamesListStore
@key !word $FDFD
2019-06-18 18:56:05 +00:00
+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
2019-06-20 03:05:48 +00:00
bcc @printTitleChar
beq @printCursor
2019-06-18 18:56:05 +00:00
lda #" "
+HIDE_NEXT_2_BYTES
2019-06-20 03:05:48 +00:00
@printCursor
lda #$7F
+HIDE_NEXT_2_BYTES
@printTitleChar
lda (SRC),y ; copy game title to search UI
2019-06-27 15:37:23 +00:00
sta .UILine2,y
2019-06-18 18:56:05 +00:00
cpy #MaxInputLength+1
bcc -
2019-06-18 21:07:14 +00:00
ldx #40
lda #0
2019-06-27 15:37:23 +00:00
- sta .UILine1-1,x ; reset search bar
2019-06-18 21:07:14 +00:00
dex
bne -
tay
2019-06-18 20:54:15 +00:00
- lda (SRC),y
+LOW_ASCII_TO_LOWER
cmp InputBuffer,x
bne +
lda #$0B ; add dots to highlight matched characters
2019-06-27 15:37:23 +00:00
sta .UILine1,y
2019-06-18 20:54:15 +00:00
inx
cpx InputLength
beq @doneHighlight
+ inc HTAB
iny
2019-06-18 21:07:14 +00:00
cpy #40
2019-06-18 20:54:15 +00:00
bne -
@doneHighlight
2019-06-27 15:37:23 +00:00
jsr .DrawSearchBarOffscreen; actually draw the search UI (offscreen)
jmp .ShowOtherPage ; now show everything at once
2018-12-23 16:13:47 +00:00
2019-06-21 17:10:29 +00:00
;------------------------------------------------------------------------------
2019-06-27 15:37:23 +00:00
.GetOffscreenAddress
; in: none
; out: A = high byte of offscreen HGR page (#$20 or #$40)
; preserves X/Y
lda .OffscreenPage
beq +
lda #$40
2019-06-27 15:37:23 +00:00
rts
+ lda #$20
2019-06-27 15:37:23 +00:00
rts
.LoadTitleOffscreen
; clobbers all
jsr .GetOffscreenAddress
sta +
+LDADDR @TitleFile
jsr SetPath
jsr LoadFileAt
2019-06-27 15:37:23 +00:00
!byte $00
+ !byte $FD ; SMC
rts
2019-06-27 15:37:23 +00:00
@TitleFile
!byte 5
!text "TITLE"
2019-06-27 15:37:23 +00:00
.LoadCoverOffscreen
; clobbers all
2019-06-27 15:37:23 +00:00
jsr .GetOffscreenAddress
sta +
+LDADDR @CoverFile
2019-06-21 17:10:29 +00:00
jsr SetPath
jsr LoadFileAt
2019-06-27 15:37:23 +00:00
!byte $00
+ !byte $FD ; SMC
2019-06-21 17:10:29 +00:00
rts
2019-06-27 15:37:23 +00:00
@CoverFile
!byte 5
!text "COVER"
2019-06-21 17:10:29 +00:00
2019-06-27 15:37:23 +00:00
.DrawSearchBarOffscreen
; clobbers all
LDA #22 ; draw visible search bar
2019-06-18 21:07:14 +00:00
sta VTAB
2019-06-27 15:37:23 +00:00
lda .OffscreenPage
ror ; draw on offscreen page
2019-06-27 15:37:23 +00:00
+LDADDR .UILine1
2019-06-18 21:07:14 +00:00
jsr Draw40Chars
2019-06-27 15:37:23 +00:00
lda .OffscreenPage
ror ; draw on offscreen page
2019-06-27 15:37:23 +00:00
+LDADDR .UILine2
jmp Draw40Chars
2019-06-18 21:07:14 +00:00
2019-06-27 15:37:23 +00:00
.ShowOtherPage
; clobbers A, preserves X/Y
2019-06-27 15:37:23 +00:00
lda .OffscreenPage
eor #$01
2019-06-27 15:37:23 +00:00
sta .OffscreenPage
bne +
2019-06-27 15:37:23 +00:00
bit PAGE2 ; show page 2
rts
2019-06-27 15:37:23 +00:00
+ bit PAGE1 ; show page 1
2019-06-18 18:56:05 +00:00
rts
2019-06-27 15:37:23 +00:00
.ResetInputTimeout
; clobbers X, preserves A/Y
2019-06-21 17:10:29 +00:00
ldx #$16
stx Timeout
stx Timeout+1
stx Timeout+2
rts
2019-06-27 15:37:23 +00:00
.CoverFade
; clobbers all
2019-06-27 15:37:23 +00:00
jsr .LoadCoverOffscreen
jsr .ShowOtherPage
lda .OffscreenPage
2019-06-21 17:10:29 +00:00
bne +
2019-06-27 15:37:23 +00:00
jsr .LoadCoverOffscreen
jsr .ShowOtherPage
2019-06-21 17:10:29 +00:00
+
; load transition effect code at $6000
+LDADDR kFXDirectory
jsr SetPath
2019-06-27 15:37:23 +00:00
+LDADDR @CoverFadeFile
2019-06-21 17:10:29 +00:00
jsr AddToPath
jsr LoadFile
2019-06-27 15:37:23 +00:00
jmp $6000 ; exit via loaded code
@CoverFadeFile
2019-06-21 17:10:29 +00:00
!byte 9
!text "COVERFADE"
2018-12-23 16:13:47 +00:00
2019-06-27 15:37:23 +00:00
.UILine1
2018-12-23 16:13:47 +00:00
!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
2019-06-27 15:37:23 +00:00
.UILine2
2018-12-23 16:13:47 +00:00
!text "["
!byte $7F
!text " "
2019-06-20 03:05:48 +00:00
!text "] "
2019-06-27 15:37:23 +00:00
VisibleGameCount
!text "000"
!text " games"
2019-06-27 15:37:23 +00:00
.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
kInputSearch = 0
kInputClear = 1
kInputBack = 2
2019-06-27 02:51:34 +00:00
kInputTab = 3
kInputLaunch = 4
2019-06-27 15:37:23 +00:00
.InputDispatchTable
!word .OnSearch
!word .OnClear
!word .OnBack
!word .OnTab
!word .OnLaunch
}