;license:MIT ;(c) 2018-9 by 4am ; ; Search Mode - main UI ; ; Public functions ; - SearchMode ; !zone { ;------------------------------------------------------------------------------ ; 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) ;------------------------------------------------------------------------------ SearchMode ldx #$FF txs stx SelectedIndex ; $FF = no game selected inx stx OffscreenPage ; $00 = currently showing HGR page 2 jsr Home ; clear screen (switches to text mode) jsr .OnInputChanged ; draw UI on HGR page 1 jsr HGRMode ; show HGR screen bit CLEARKBD .SearchModeInputLoop jsr WaitForKeyFor30Seconds ; 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. cmp #$8B ; up arrow switches to browse mode beq @arrow cmp #$95 ; also right arrow beq @arrow cmp #$8A ; also down arrow bne @notArrow @arrow ldx #kInputBrowse bne @InputDispatch ; always branches @notArrow bit CLEARKBD ldy #kNumBrowseKeys - dey bmi @noKeyMatch cmp .InputKeys,y bne - ldx .InputKeyDispatch,y bne @InputDispatch ; always branches @noKeyMatch jsr IsSearchKey beq @foundSearchKey ldx #kInputError +HIDE_NEXT_2_BYTES @foundSearchKey ldx #kInputSearch ; execution falls through here @InputDispatch ldy .InputDispatchTableLo,x sty @j+1 ldy .InputDispatchTableHi,x sty @j+2 @j jsr $FDFD ; SMC bcc .SearchModeInputLoop ; if carry is clear, we're done bcs SearchMode ; if carry is set, force full redraw .OnError jmp SoftBell ; Beep on invalid input and start over. .OnClear ldx InputLength bne + jsr CoverFade ; Esc with no input switches to jmp MegaAttractMode ; mega-attract mode + ldx #0 ; Esc with input clears the input stx InputLength beq .OnInputChanged ; always branches .OnBack ldx InputLength beq .OnError dec InputLength jmp .OnInputChanged .OnTab ldx SelectedIndex cpx #$FF beq .OnError jsr MiniAttractMode cmp #$8D ; if we exited mini attract mode beq .OnLaunch ; by pressing Enter, launch the game sec ; tell caller to redraw UI rts .OnLaunch ldx SelectedIndex cpx #$FF beq .OnError jsr PlayGameFromSearch sec ; tell caller to redraw UI rts .OnCheat dec SelectedIndex ; force reload (will be reset to correct value in .OnInputChanged) jsr ToggleCheat beq .OnInputChanged ; always branches because Z=1 on exit from ToggleCheat .OnSearch ldx InputLength cpx #MaxInputLength beq .OnError sta InputBuffer,x inc InputLength ; execution falls through here .OnInputChanged lda InputLength bne @findMatchingTitle ; no input, reset params and UI lda #$FF sta SelectedIndex ; no game selected ldx #39 ; copy instructions to line 2 - lda Instructions,x sta UILine2,x dex bpl - jsr LoadTitleOffscreen ldx #$FF ; no game selected jsr BuildUILine1WithNoDots; build UI line 1 with bars and other shapes ldx #$FF ; no game selected jsr DrawSearchBarOffscreen; draw everything at once (offscreen) jsr ShowOtherPage ; show it all at once clc rts @findMatchingTitle jsr ResetTextRank 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 lda MatchCount ; any matches at all? bne + ; no matches for this input buffer dec InputLength ; ignore the last key typed jmp .OnError ; beep and return + ldx BestMatchIndex ; check if the new best match is the same cpx SelectedIndex ; as the current best match php ; (we'll use this later to skip reloading) stx SelectedIndex +LDADDR gGamesListStore jsr okvs_nth ; get the name of the new best match +STAY @key +STAY @key2 plp bne + jsr ToggleOffscreenPage ; Since we're not loading a new screenshot ; we fake switching the 'offscreen' page ; 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) jsr LoadFile !word kHGRTitleDirectory @key !word $FDFD ; SMC !byte $00 + !byte $FD ; SMC @skipload jsr okvs_get !word gGamesListStore @key2 !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 beq @printCursor lda #" " +HIDE_NEXT_2_BYTES @printCursor lda #$7F +HIDE_NEXT_2_BYTES @printTitleChar lda (SRC),y ; copy game title to search UI sta UILine2,y cpy #MaxInputLength+1 bcc - ldx #8 - lda ReturnToPlay,x ; replace games count with 'to play' label sta UI_ToPlay,x dex bpl - ldx SelectedIndex jsr BuildUILine1WithNoDots; build UI line 1 with bars and other shapes ; now add dots to UI line 1 to highlight matched characters ldx #0 ldy #0 @dotloop iny lda (SRC),y +LOW_ASCII_TO_LOWER cmp InputBuffer,x bne + lda #$11 ; dot character sta UILine1,y inx cpx InputLength ; if input buffer is exhausted, we're done beq @doneHighlight + inc HTAB cpy SAVE ; if game name is exhausted, we're done bne @dotloop @doneHighlight ldx SelectedIndex jsr DrawSearchBarOffscreen; actually draw the search UI (offscreen) jmp ShowOtherPage ; now show everything at once ;------------------------------------------------------------------------------ ; indices into InputDispatchTable kInputSearch = 0 kInputClear = 1 kInputBack = 2 kInputBrowse = 3 kInputTab = 4 kInputLaunch = 5 kInputCredits = 6 kInputCheat = 7 kInputError = 8 .InputDispatchTableLo !byte <.OnSearch !byte <.OnClear !byte <.OnBack !byte .OnSearch !byte >.OnClear !byte >.OnBack !byte >BrowseMode !byte >.OnTab !byte >.OnLaunch !byte >Credits !byte >.OnCheat !byte >.OnError kNumInputKeys = 9 ; number of entries in next 2 tables (each) .InputKeys !byte $83 ; Ctrl-C = toggle cheat mode !byte $AF ; '/' = credits !byte $BF ; '?' = credits !byte $A0 ; Space = mini attract mode !byte $89 ; TAB = mini attract mode !byte $88 ; left arrow = delete (may as well, since ; popular emulators remap this anyway) !byte $FF ; backspace = delete !byte $8D ; ENTER = launch current game (if any) !byte $9B ; Esc = clear input buffer (if any) ; or switch to mega attract mode .InputKeyDispatch !byte kInputCheat !byte kInputCredits !byte kInputCredits !byte kInputTab !byte kInputTab !byte kInputBack !byte kInputBack !byte kInputLaunch !byte kInputClear }