;license:MIT ;(c) 2018-9 by 4am ; ; Search Mode - main UI ; ; Public functions ; - SearchMode ; - SoftBell ; ; indices into InputDispatchTable kInputSearch = 0 kInputClear = 1 kInputBack = 2 kInputBrowse = 3 kInputTab = 4 kInputLaunch = 5 kInputHelp = 6 kInputCredits = 7 kInputCheat = 8 kInputError = 9 InputDispatchTableLo !byte OnSearch !byte >OnClear !byte >OnBack !byte >BrowseMode !byte >OnTab !byte >OnLaunch !byte >Help !byte >Credits !byte >OnCheat !byte >OnError kNumInputKeys = 10 ; number of entries in next 2 tables (each) InputKeys !byte $83 ; Ctrl-C = toggle cheat mode !byte $A6 ; '&' = credits !byte $AF ; '/' = help !byte $BF ; '?' = help !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 kInputHelp !byte kInputHelp !byte kInputTab !byte kInputTab !byte kInputBack !byte kInputBack !byte kInputLaunch !byte kInputClear .noKeyMatch jsr IsSearchKey beq .foundSearchKey ldx #kInputError +HIDE_NEXT_2_BYTES .IsArrow ldx #kInputBrowse !if kInputSearch > 0 { +HIDE_NEXT_2_BYTES .foundSearchKey ldx #kInputSearch } else { .foundSearchKey } ; execution falls through here to .InputDispatch .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 ; fall through to force full redraw ;------------------------------------------------------------------------------ ; 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 gGameToLaunch ; $FF = no game selected jsr Home ; clear screen (switches to text mode) jsr OnInputChanged ; draw UI offscreen jsr HGRMode ; show HGR screen jsr ResyncPage lda KBD jsr IsSearchKey beq .SearchModeInputLoop 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. jsr IsUpDownOrRightArrow beq .IsArrow bit CLEARKBD ldy #kNumBrowseKeys - dey bmi .noKeyMatch cmp InputKeys,y bne - ldx InputKeyDispatch,y bne .InputDispatch ; always branches OnClear ldx InputLength bne + jmp CoverFade ; Esc with no input transitions to ; mega attract mode OnBack ldx InputLength beq OnError +HIDE_NEXT_2_BYTES + ldx #1 ; Esc with input clears the input dex stx InputLength bpl OnInputChanged ; always branches OnTab ldx gGameToLaunch cpx #$FF beq OnError jsr MiniAttractMode cmp #$8D ; if we exited mini attract mode bne .req_redraw ; by pressing Enter, launch the game OnLaunch ldx gGameToLaunch cpx #$FF beq OnError jsr PlayGame .req_redraw sec ; tell caller to redraw UI rts OnCheat dec gGameToLaunch ; 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 to OnInputChanged OnInputChanged lda InputLength bne FindMatchingTitle ; no input, reset params and UI ldx #$FF stx gGameToLaunch ; no game selected jsr LoadTitleOffscreen jsr DrawUIWithoutDots clc rts FindMatchingTitle jsr SwitchToBank2 jsr EnableAcceleratorAndSwitchToBank1 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 OnError jsr SwitchToBank2 jsr DisableAcceleratorAndSwitchToBank1 ; /!\ execution falls through to SoftBell ;------------------------------------------------------------------------------ ; 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 + ldx BestMatchIndex ; check if the new best match is the same cpx gGameToLaunch ; as the current best match stx gGameToLaunch 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 @noload ; (always branches) + jsr LoadGameTitleOffscreen @noload jsr DrawUI jsr SwitchToBank2 jsr DisableAcceleratorAndSwitchToBank1 ; /!\ execution falls through to ui.animation/MaybeAnimateTitle