mirror of
https://github.com/a2-4am/4cade.git
synced 2024-09-27 12:57:21 +00:00
397 lines
11 KiB
Plaintext
397 lines
11 KiB
Plaintext
;license:MIT
|
|
;(c) 2018 by 4am
|
|
;
|
|
; Search Mode - incrementally search game catalog
|
|
;
|
|
; Public functions
|
|
; - SearchMode
|
|
;
|
|
|
|
; indices into InputDispatchTable
|
|
kInputSearch = 0
|
|
kInputClear = 1
|
|
kInputBack = 2
|
|
kInputLaunch = 3
|
|
|
|
InputDispatchTable
|
|
!word OnSearch
|
|
!word OnClear
|
|
!word OnBack
|
|
!word OnLaunch
|
|
|
|
SearchMode
|
|
jsr Home
|
|
|
|
lda #0
|
|
sta OffscreenPage
|
|
sta InputLength
|
|
jsr _UpdateGameCount
|
|
|
|
jsr OnInputChanged ; draw default UI on HGR page 1
|
|
bit $C052
|
|
bit $C057
|
|
bit $C050
|
|
bit $C010
|
|
jsr _ResetInputTimeout
|
|
|
|
_SearchModeInputLoop
|
|
- lda $C000
|
|
bmi @gotKey
|
|
|
|
inc $4F ; these are only ever incremented, never
|
|
bne + ; reset (used as a pseudorandom seed)
|
|
inc $4E
|
|
+
|
|
dec $50 ; these are a 3-byte timeout counter
|
|
bne - ; that counts down from a number set
|
|
dec $51 ; in _ResetInputTimeout and reset
|
|
bne - ; on every keypress (whether or not
|
|
dec $52 ; the key leads to an action)
|
|
bne -
|
|
lda #kAttractMode ; no input for ~30 seconds
|
|
sta Mode ; switch to attract mode
|
|
jmp _CoverFade
|
|
|
|
@gotKey
|
|
jsr _ResetInputTimeout
|
|
|
|
cmp #$9B ; Esc clears the input buffer (if any)
|
|
bne + ; or switches to attract mode
|
|
ldx #kInputClear
|
|
bne InputDispatch ; always branches
|
|
+
|
|
cmp #$8D ; ENTER launches the current game (if any)
|
|
bne +
|
|
ldx #kInputLaunch
|
|
bne InputDispatch ; always branches
|
|
+
|
|
bit $C010
|
|
and #$7F
|
|
|
|
cmp #$7F ; delete key
|
|
bne +
|
|
- ldx #kInputBack
|
|
bne InputDispatch ; always branches
|
|
|
|
+ cmp #$08 ; left arrow = delete
|
|
beq -
|
|
|
|
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
|
|
; execution falls through here
|
|
@badkey
|
|
jsr SoftBell ; beep on invalid input
|
|
jmp _SearchModeInputLoop ; and start over
|
|
|
|
@goodkey
|
|
ldx #kInputSearch
|
|
; execution falls through here
|
|
InputDispatch
|
|
pha ; save key pressed
|
|
txa
|
|
asl
|
|
tax
|
|
lda InputDispatchTable,x
|
|
sta @j+1
|
|
lda InputDispatchTable+1,x
|
|
sta @j+2
|
|
pla ; restore key pressed
|
|
@j jsr $FDFD ; SMC
|
|
jmp _SearchModeInputLoop
|
|
|
|
OnClear
|
|
ldx InputLength
|
|
bne +
|
|
jsr _CoverFade
|
|
pla ; Esc with no input exits search mode
|
|
pla ; and switches to attract mode
|
|
rts
|
|
+ ldx #0
|
|
stx InputLength
|
|
bit $C010
|
|
jmp OnInputChanged
|
|
|
|
OnBack
|
|
ldx InputLength
|
|
bne +
|
|
jsr SoftBell
|
|
rts
|
|
+ dec InputLength
|
|
bit $C010
|
|
jmp OnInputChanged
|
|
|
|
OnLaunch
|
|
ldx SelectedIndex
|
|
cpx #$FF
|
|
beq +
|
|
pla ; Return exits search mode
|
|
pla ; and launches game
|
|
+ rts
|
|
|
|
OnSearch
|
|
ldx InputLength
|
|
cpx #MaxInputLength
|
|
bne +
|
|
jsr SoftBell
|
|
rts
|
|
+ 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 #40 ; reset visible line
|
|
lda #0
|
|
- sta UILine1-1,x
|
|
dex
|
|
bne -
|
|
ldy #MaxInputLength ; clear visible search bar
|
|
lda #" "
|
|
- sta UILine2+1,y
|
|
dey
|
|
bne -
|
|
lda #$7F
|
|
sta UILine2+1
|
|
|
|
jsr _LoadCoverOffscreen
|
|
jsr _DrawSearchBarOffscreen
|
|
jmp _ShowOtherPage
|
|
|
|
@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 +
|
|
jsr SoftBell ; no matches for this input buffer, beep
|
|
dec InputLength ; and ignore the last key typed
|
|
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
|
|
jsr okvs_nth
|
|
!word gGamesListStore
|
|
@index !byte $FD
|
|
+STAY @key
|
|
|
|
plp
|
|
bne +
|
|
lda OffscreenPage
|
|
eor #$01
|
|
sta OffscreenPage
|
|
jmp @skipload
|
|
+
|
|
lda OffscreenPage ; we have a new best match, so load the
|
|
beq + ; new title screenshot (offscreen)
|
|
lda #$40
|
|
+HIDE_NEXT_2_BYTES
|
|
+ lda #$20
|
|
sta @titleaddress+1
|
|
+LDADDR kHGRTitleDirectory
|
|
jsr SetPath
|
|
+LDADDR kPathSeparator
|
|
jsr AddToPath
|
|
+LDAY @key
|
|
jsr AddToPath
|
|
jsr LoadFileAt
|
|
@titleaddress
|
|
!word $FD00
|
|
|
|
@skipload
|
|
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
|
|
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 #40
|
|
lda #0
|
|
- sta UILine1-1,x ; reset search bar
|
|
dex
|
|
bne -
|
|
tay
|
|
- lda (SRC),y
|
|
+LOW_ASCII_TO_LOWER
|
|
cmp InputBuffer,x
|
|
bne +
|
|
lda #$0B ; add dots to highlight matched characters
|
|
sta UILine1,y
|
|
inx
|
|
cpx InputLength
|
|
beq @doneHighlight
|
|
+ inc HTAB
|
|
iny
|
|
cpy #40
|
|
bne -
|
|
@doneHighlight
|
|
jsr _DrawSearchBarOffscreen; actually draw the search UI (offscreen)
|
|
jmp _ShowOtherPage ; now show everything at once
|
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
_LoadCoverOffscreen
|
|
lda OffscreenPage
|
|
beq +
|
|
lda #$40
|
|
+HIDE_NEXT_2_BYTES
|
|
+ lda #$20
|
|
sta @coveraddress+1
|
|
+LDADDR Cover
|
|
jsr SetPath
|
|
jsr LoadFileAt ; load default background
|
|
@coveraddress
|
|
!word $FD00 ; SMC
|
|
rts
|
|
|
|
_DrawSearchBarOffscreen
|
|
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
|
|
lda OffscreenPage
|
|
eor #$01
|
|
sta OffscreenPage
|
|
bne +
|
|
bit $C055 ; show page 2
|
|
rts
|
|
+ bit $C054 ; show page 1
|
|
rts
|
|
|
|
_UpdateGameCount
|
|
jsr okvs_len
|
|
!word gGamesListStore
|
|
sta SAVE
|
|
ldy #0
|
|
@outer
|
|
lda #0
|
|
pha
|
|
@inner
|
|
lda SAVE
|
|
cmp @powersOfTen,y
|
|
bcc @digitDone
|
|
sbc @powersOfTen,y
|
|
sta SAVE
|
|
lda SAVE+1
|
|
sbc #0
|
|
sta SAVE+1
|
|
pla
|
|
adc #0
|
|
pha
|
|
jmp @inner
|
|
@digitDone
|
|
pla
|
|
ora #$30
|
|
sta UILine2_GameCount,y
|
|
iny
|
|
cpy #$03
|
|
bcc @outer
|
|
rts
|
|
|
|
@powersOfTen
|
|
!byte 100
|
|
!byte 10
|
|
!byte 1
|
|
|
|
_ResetInputTimeout
|
|
; clobbers X, preserves A/Y
|
|
ldx #$16
|
|
stx $50 ; timeout counter
|
|
stx $51
|
|
stx $52
|
|
rts
|
|
|
|
_CoverFade
|
|
jsr _LoadCoverOffscreen
|
|
jsr _ShowOtherPage
|
|
lda OffscreenPage
|
|
bne +
|
|
jsr _LoadCoverOffscreen
|
|
jsr _ShowOtherPage
|
|
+
|
|
; load transition effect code at $6000
|
|
+LDADDR kFXDirectory
|
|
jsr SetPath
|
|
+LDADDR kPathSeparator
|
|
jsr AddToPath
|
|
+LDADDR kFXCoverFade
|
|
jsr AddToPath
|
|
jsr LoadFile
|
|
|
|
jmp $6000
|
|
|
|
kFXCoverFade
|
|
!byte 9
|
|
!text "COVERFADE"
|
|
|
|
Cover !byte 5
|
|
!text "COVER"
|
|
|
|
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 "] "
|
|
UILine2_GameCount
|
|
!text "000 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)
|