2018-12-23 16:13:47 +00:00
|
|
|
;license:MIT
|
2019-06-24 02:32:18 +00:00
|
|
|
;(c) 2018-9 by 4am
|
2018-12-23 16:13:47 +00:00
|
|
|
;
|
2019-06-24 02:32:18 +00:00
|
|
|
; Search Mode - main UI
|
2018-12-23 16:13:47 +00:00
|
|
|
;
|
|
|
|
; Public functions
|
|
|
|
; - SearchMode
|
2019-07-04 02:27:46 +00:00
|
|
|
; - IsSearchKey
|
2018-12-23 16:13:47 +00:00
|
|
|
;
|
2019-06-27 15:37:23 +00:00
|
|
|
|
|
|
|
!zone {
|
2018-12-23 16:13:47 +00:00
|
|
|
|
2019-06-24 02:32:18 +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
|
2019-06-24 02:32:18 +00:00
|
|
|
ldx #$FF
|
2019-06-23 18:24:09 +00:00
|
|
|
txs
|
2019-06-24 02:32:18 +00:00
|
|
|
stx SelectedIndex ; no game selected
|
|
|
|
inx
|
2019-07-03 22:31:50 +00:00
|
|
|
stx OffscreenPage
|
2019-06-23 18:24:09 +00:00
|
|
|
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-07-03 22:31:50 +00:00
|
|
|
jsr ResetInputTimeout
|
2019-06-21 17:10:29 +00:00
|
|
|
|
2019-06-27 15:37:23 +00:00
|
|
|
.SearchModeInputLoop
|
2019-07-04 02:27:46 +00:00
|
|
|
jsr WaitForKeyFor30Seconds
|
2019-06-21 17:10:29 +00:00
|
|
|
|
2019-07-04 02:27:46 +00:00
|
|
|
; Don't clear keyboard strobe yet. If the user pressed an arrow key,
|
|
|
|
; we want to switch to Browse Mode with the keyboard still hot so
|
|
|
|
; that mode finds and dispatches the arrow key.
|
2019-06-21 17:17:57 +00:00
|
|
|
|
2019-07-08 18:10:11 +00:00
|
|
|
cmp #$8B ; right arrow switches to browse mode
|
2019-07-03 22:31:50 +00:00
|
|
|
beq @arrow
|
|
|
|
cmp #$95 ; also up arrow
|
|
|
|
beq @arrow
|
|
|
|
cmp #$8A ; also down arrow
|
|
|
|
bne @notArrow
|
|
|
|
@arrow ldx #kInputBrowse
|
|
|
|
bne @InputDispatch ; always branches
|
|
|
|
@notArrow
|
2019-06-27 14:55:07 +00:00
|
|
|
bit CLEARKBD
|
2019-07-03 22:31:50 +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
|
2019-06-20 17:56:31 +00:00
|
|
|
+
|
2019-06-24 02:32:18 +00:00
|
|
|
cmp #$FF ; delete key
|
2019-06-18 18:56:05 +00:00
|
|
|
bne +
|
2019-07-08 18:10:11 +00:00
|
|
|
- ldx #kInputBack
|
2019-06-27 15:37:23 +00:00
|
|
|
bne @InputDispatch ; always branches
|
2019-07-03 22:31:50 +00:00
|
|
|
+
|
2019-07-08 18:10:11 +00:00
|
|
|
cmp #$88 ; left arrow = delete (may as well, since
|
|
|
|
; popular emulators remap this anyway)
|
|
|
|
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
|
|
|
+
|
2019-07-10 17:37:59 +00:00
|
|
|
|
|
|
|
cmp #$BF ; '?' display scredits
|
|
|
|
bne +
|
|
|
|
- ldx #kInputCredits
|
|
|
|
bne @InputDispatch ; always branches
|
|
|
|
+
|
|
|
|
cmp #$AF ; '/' also displays credits
|
|
|
|
beq -
|
|
|
|
|
2019-06-24 02:32:18 +00:00
|
|
|
and #$7F ; strip high bit for search characters
|
2019-07-04 02:27:46 +00:00
|
|
|
jsr IsSearchKey
|
|
|
|
beq +
|
|
|
|
jsr SoftBell ; Beep on invalid input and start over.
|
|
|
|
bne .SearchModeInputLoop ; This always branches because SoftBell
|
|
|
|
; preserves all flags and we got here
|
|
|
|
; because the BEQ didn't branch.
|
|
|
|
+
|
2019-06-20 02:13:49 +00:00
|
|
|
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
|
2019-06-20 02:13:49 +00:00
|
|
|
ldx InputLength
|
|
|
|
bne +
|
2019-07-04 02:27:46 +00:00
|
|
|
jsr CoverFade ; Esc with no input switches to
|
2019-06-23 18:24:09 +00:00
|
|
|
jmp MegaAttractMode ; mega-attract mode
|
|
|
|
+ ldx #0 ; Esc with input clears the input
|
2019-06-20 02:13:49 +00:00
|
|
|
stx InputLength
|
2019-06-27 15:37:23 +00:00
|
|
|
jmp .OnInputChanged
|
2019-06-20 02:13:49 +00:00
|
|
|
|
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 +
|
2019-06-23 18:24:09 +00:00
|
|
|
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-07-04 02:27:46 +00:00
|
|
|
|
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
|
2019-06-20 02:13:49 +00:00
|
|
|
sta SelectedIndex ; no game selected
|
2019-07-08 18:10:11 +00:00
|
|
|
ldx #39 ; reset visible line
|
|
|
|
- lda #0
|
|
|
|
sta UILine1,x
|
|
|
|
lda Instructions,x
|
|
|
|
sta UILine2,x
|
2019-06-18 21:07:14 +00:00
|
|
|
dex
|
2019-07-08 18:10:11 +00:00
|
|
|
bpl -
|
2019-07-04 02:27:46 +00:00
|
|
|
jsr LoadTitleOffscreen
|
2019-07-03 22:31:50 +00:00
|
|
|
jsr DrawSearchBarOffscreen
|
|
|
|
jsr ShowOtherPage
|
2019-06-23 18:24:09 +00:00
|
|
|
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
|
|
|
|
2019-06-20 02:13:49 +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
|
2019-06-20 02:13:49 +00:00
|
|
|
+
|
|
|
|
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
|
2019-06-20 02:13:49 +00:00
|
|
|
plp
|
|
|
|
bne +
|
2019-07-03 22:31:50 +00:00
|
|
|
jsr ToggleOffscreenPage ; Since we're not loading a new screenshot
|
|
|
|
; we fake switching the 'offscreen' page
|
|
|
|
; in order to draw on the visible page.
|
2019-06-27 15:37:23 +00:00
|
|
|
bpl @skipload ; always branches
|
|
|
|
+
|
2019-07-03 22:31:50 +00:00
|
|
|
jsr GetOffscreenAddress ; we have a new best match, so load the
|
2019-06-27 15:37:23 +00:00
|
|
|
sta + ; new title screenshot (offscreen)
|
2019-06-20 02:13:49 +00:00
|
|
|
+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
|
|
|
|
2019-06-20 02:13:49 +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-07-03 22:31:50 +00:00
|
|
|
sta UILine2,y
|
2019-06-18 18:56:05 +00:00
|
|
|
cpy #MaxInputLength+1
|
|
|
|
bcc -
|
2019-07-08 18:10:11 +00:00
|
|
|
ldx #8
|
|
|
|
- lda ReturnToPlay,x ; replace games count with 'to play' label
|
|
|
|
sta UI_ToPlay,x
|
|
|
|
dex
|
|
|
|
bpl -
|
2019-06-18 21:07:14 +00:00
|
|
|
ldx #40
|
|
|
|
lda #0
|
2019-07-03 22:31:50 +00:00
|
|
|
- sta UILine1-1,x ; reset search bar
|
2019-06-18 21:07:14 +00:00
|
|
|
dex
|
|
|
|
bne -
|
|
|
|
tay
|
2019-07-04 20:23:29 +00:00
|
|
|
@dotloop
|
|
|
|
iny
|
|
|
|
lda (SRC),y
|
2019-06-18 20:54:15 +00:00
|
|
|
+LOW_ASCII_TO_LOWER
|
|
|
|
cmp InputBuffer,x
|
|
|
|
bne +
|
2019-07-08 18:10:11 +00:00
|
|
|
lda #$11 ; add dots to highlight matched characters
|
2019-07-03 22:31:50 +00:00
|
|
|
sta UILine1,y
|
2019-06-18 20:54:15 +00:00
|
|
|
inx
|
2019-07-04 20:23:29 +00:00
|
|
|
cpx InputLength ; if input buffer is exhausted, we're done
|
2019-06-18 20:54:15 +00:00
|
|
|
beq @doneHighlight
|
|
|
|
+ inc HTAB
|
2019-07-04 20:23:29 +00:00
|
|
|
cpy SAVE ; if game name is exhausted, we're done
|
|
|
|
bne @dotloop
|
2019-06-18 20:54:15 +00:00
|
|
|
@doneHighlight
|
2019-07-03 22:31:50 +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-07-04 02:27:46 +00:00
|
|
|
IsSearchKey
|
|
|
|
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
|
2019-06-21 17:10:29 +00:00
|
|
|
|
2019-07-04 02:27:46 +00:00
|
|
|
+ cmp #$61 ; more punctuation (also ignored)
|
|
|
|
bcc @badkey
|
|
|
|
cmp #$7B ; lowercase letters are good input
|
|
|
|
bcc @goodkey
|
|
|
|
@badkey
|
|
|
|
ldx #1
|
|
|
|
rts
|
|
|
|
@goodkey
|
|
|
|
ldx #0
|
2019-06-24 23:03:59 +00:00
|
|
|
rts
|
2019-06-21 17:10:29 +00:00
|
|
|
|
2019-07-04 02:27:46 +00:00
|
|
|
;------------------------------------------------------------------------------
|
2018-12-23 16:13:47 +00:00
|
|
|
|
2019-06-24 02:32:18 +00:00
|
|
|
; indices into InputDispatchTable
|
|
|
|
kInputSearch = 0
|
|
|
|
kInputClear = 1
|
|
|
|
kInputBack = 2
|
2019-07-03 22:31:50 +00:00
|
|
|
kInputBrowse = 3
|
|
|
|
kInputTab = 4
|
|
|
|
kInputLaunch = 5
|
2019-07-10 17:37:59 +00:00
|
|
|
kInputCredits = 6
|
2019-06-24 02:32:18 +00:00
|
|
|
|
2019-06-27 15:37:23 +00:00
|
|
|
.InputDispatchTable
|
|
|
|
!word .OnSearch
|
|
|
|
!word .OnClear
|
|
|
|
!word .OnBack
|
2019-07-03 22:31:50 +00:00
|
|
|
!word BrowseMode
|
2019-06-27 15:37:23 +00:00
|
|
|
!word .OnTab
|
|
|
|
!word .OnLaunch
|
2019-07-10 17:37:59 +00:00
|
|
|
!word Credits
|
2019-06-27 15:37:23 +00:00
|
|
|
|
|
|
|
}
|