;license:MIT ;(c) 2018-2021 by 4am & qkumba ; ; Attract Mode - cycle through slideshows and self-running demos ; ; Public functions ; - MegaAttractMode ; - MiniAttractMode ; - RunAttractModule kAttractModeFilters !byte ATTRACT_DEMO !byte ATTRACT_HGR_TITLE !byte ATTRACT_HGR_ACTION !byte ATTRACT_DHGR_TITLE !byte ATTRACT_DHGR_ACTION !byte ATTRACT_SHR !byte ATTRACT_GR !byte ATTRACT_DGR ;------------------------------------------------------------------------------ ; MegaAttractMode ; main entry point for Mega Attract Mode, which endlessly cycles through ; modules listed in ATTRACT.CONF to display title pages, action screenshots, ; super hi-res box art (on supporting platforms), and self-running game demos ; ; in: gGlobalPrefsStore must be initialized ; out: never returns to caller (may JMP to other major modes) ;------------------------------------------------------------------------------ MegaAttractMode jsr SwitchToBank1 ldx #$FF txs jsr BlankHGR ; switch to HGR page 1 (once cleared) jsr LoadIndexedFile ; load pre-parsed attract mode configuration data into $6000 - !word $6000 !word kAttractModeIndexRecord @next jsr pref_get ; get attract mode module from prefs !word kNextAttract !word - +ST16 @mname ; A/Y = module name ; $WINDEX = index of module in attract store +LDADDR - jsr okvs_next ; get module after this one +ST16 + jsr pref_set ; update prefs store and save to disk !word kNextAttract + !word $FDFD ; SMC jsr okvs_get ; sets PTR !word - @mname !word $FDFD ; SMC ldy #1 lda (PTR),y tax ; X = module type as ASCII digit and #$0F ; do we want to display this module type tay lda gMegaAttractModeFilter and kAttractModeFilters, y beq @next +LD16 @mname ; A/Y = address of module name jsr RunAttractModule lda KBD bpl MegaAttractMode cmp #$8D ; Enter plays the game shown on screen. bne + ; Any other key switches to Search Mode. jsr ReloadSearchIndexOnly +LD16 gLastMegaAttractGame +ST16 @game jsr okvs_find !word SearchIndexHandle @game !word $FDFD ; SMC jsr PlayGameInAY ; (might return if user hits Ctrl-Reset) + jmp SearchMode ;------------------------------------------------------------------------------ ; MiniAttractMode ; run attract modules related to one game ; ; in: gGameToLaunch = index in gSearchStore (word) ; gSearchStore populated ; out: all flags and registers clobbered ; assume all of main memory has been clobbered (including gSearchStore) ;------------------------------------------------------------------------------ MiniAttractMode jsr GetGameToLaunch +ST16 @GameToLaunch ; We want to load the mini attract index into $800 so we can get the ; index record for this game, but we now have so many games that the ; entire index is larger than $1800 bytes and loading it all at once ; would visibly overwrite bytes in HGR page 1. So the index is now ; split into 2 halves based on the first letter of the game's ; directory name, and we figure out which half we want and load it. +ST16 PTR ldy #1 lda (PTR), y sec sbc #$41 ; A in [0..25] lsr ; A in [0..15] lsr ; A in [0..7] lsr ; A in [0..3] lsr ; A in [0..1] tax lda kMiniAttractIndexLo, x sta @MiniAttractIndexRecord lda kMiniAttractIndexHi, x sta @MiniAttractIndexRecord+1 jsr LoadIndexedFile - !word $0800 @MiniAttractIndexRecord !word $FDFD ; SMC ; Find the index record for this game and copy it into LC RAM so we ; can reuse it without reloading the mini attract index over and over ; during attract mode. jsr okvs_find !word - @GameToLaunch !word $FDFD ; SMC jsr okvs_next_field jsr SwitchToBank2 sty OKVS_CACHE ldy #4 ; length of index record (-1) - lda (PTR), y sta OKVS_CACHE + 1, y dey bpl - ; Now, finally, start the mini attract mode jsr BlankHGR ; X = 0 stx @MiniAttractIndex+1 stx @MiniAttractIndex+3 @loop jsr LoadIndexedFile - !word $6000 !word OKVS_CACHE +LDADDR - jsr okvs_len lda WCOUNT cmp @MiniAttractIndex+1 bne + lda WCOUNT+1 cmp @MiniAttractIndex+3 beq ATTRTS ; we've run through all modules, so exit to caller + @MiniAttractIndex +LDADDR 0 ; SMC +ST16 WINDEX +LDADDR - jsr okvs_nth ; get the next module on the list +ST16 SAVE jsr okvs_next_field ; get module type ; Y = 0 iny lda (PTR),y tax ; X = module type +LD16 SAVE ; A/Y = address of module name jsr RunAttractModule ; execute the module inc @MiniAttractIndex+1 bne + inc @MiniAttractIndex+3 + lda KBD bpl @loop ATTRTS rts ;------------------------------------------------------------------------------ ; RunAttractModule ; run a single attract module of any type and return to caller ; ; in: X = module type as ASCII char (1-6,A-C, see attract.conf) ; A/Y = address of module name ; for demos, this is the filename of an executable in /demo/ ; for slideshows, this is the filename of a .conf file in /ss/ ; for singles, this is a pathname of the graphic to load ; gGlobalPrefsStore must be initialized (if we load a transition effect ; of any kind, we will update the global prefs with the next one) ; out: all flags and registers clobbered ; assume all of main memory has been clobbered ;------------------------------------------------------------------------------ RunAttractModule +ST16 @key cpx #$30 bne @NotDemo ; Self-running demos are loaded into main memory and executed. ; Each demo has been patched to check joystick and memory requirements, ; so a demo won't run if the actual game wouldn't be playable. ; Demos are also patched to jump back to the |Reenter| entry point ; on any key, or at the natural end of the demo cycle. ; All demos are strictly 48K / main memory. No demo uses the ; language card or auxiliary memory. +ST16 PTR ldy #0 lda (PTR), y tay - lda (PTR), y sta DemoFilename, y dey bpl - +LDADDR DemoFilename +ST16 gLastMegaAttractGame ; save game filename in LC in case user hits Return to launch +ST16 xfile jsr ClearScreens ; avoid seeing code load into the HGR page ; (clobbers $106, must do now before loading prelaunch code) jsr LoadStandardPrelaunch ; load standard prelaunch code (|Launch| will call it) jsr LoadIndexedFile ; load demo index file - !word gSearchCache !word kDemoIndexRecord jsr LoadXFile ; load self-running demo into its default address (varies) jmp Launch ; will return to caller via |Reenter| ; not a demo, so maybe a slideshow or single screenshot @NotDemo txa cmp #$41 ; numbers are slideshow modules, bcs @dispatchSingle ; letters are single files ; it's a slideshow, so load slideshow configuration file pha ; save module type jsr LoadIndexedFile ; load slideshow configuration file into $4000 - !word $4000 !word kAttractModeSlideshowIndexRecord jsr okvs_find !word - @key !word $FDFD ; SMC +ST16 + jsr LoadIndexedFile !word $800 + !word $FDFD ; SMC pla ; restore module type +HIDE_NEXT_2_BYTES @dispatchSingle adc #(@singleslo-@slideshowslo)-1 - and #$0F ; convert ASCII digit to int tax lda @slideshowslo-1,x sta @jmp+1 lda @slideshowshi-1,x sta @jmp+2 +LD16 @key ; pass in module name @jmp jmp $FDFD ; SMC @slideshowslo !byte HGRTitleSlideshow !byte >HGRActionSlideshow !byte >DHGRTitleSlideshow !byte >DHGRActionSlideshow !byte >SHRSlideshow !byte >GRActionSlideshow !byte >DGRActionSlideshow @singleshi !byte >HGRSingle !byte >DHGRSingle !byte >SHRSingle !byte >GRSingle !byte >DGRSingle DemoFilename !byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15