2019-01-15 00:06:58 +00:00
|
|
|
;license:MIT
|
2019-06-24 02:32:18 +00:00
|
|
|
;(c) 2018-9 by 4am
|
2019-01-15 00:06:58 +00:00
|
|
|
;
|
|
|
|
; Functions to launch games and self-running demos
|
|
|
|
;
|
|
|
|
; Public functions
|
2019-10-08 18:43:41 +00:00
|
|
|
; - GetGameToLaunch
|
2020-03-18 16:08:39 +00:00
|
|
|
; - FindGame
|
|
|
|
; - FindGameInActionSlideshow
|
|
|
|
; - GetGameDisplayName
|
2019-09-21 03:26:32 +00:00
|
|
|
; - PlayGame
|
2019-06-26 02:44:39 +00:00
|
|
|
; - Launch
|
2019-01-15 00:06:58 +00:00
|
|
|
;
|
2019-09-24 22:40:43 +00:00
|
|
|
; Public variables:
|
2020-03-24 20:30:14 +00:00
|
|
|
; - gGameToLaunch - 0-based index into gGamesListStore (word)
|
2019-09-24 22:40:43 +00:00
|
|
|
;
|
2019-01-15 00:06:58 +00:00
|
|
|
|
2020-03-24 20:30:14 +00:00
|
|
|
gGameToLaunch
|
2020-05-30 14:53:29 +00:00
|
|
|
!word $FFFF
|
2020-03-24 20:30:14 +00:00
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; AnyGameSelected
|
|
|
|
; get index of game that is currently selected in the UI (if any)
|
|
|
|
;
|
2020-03-24 20:30:14 +00:00
|
|
|
; in: none
|
|
|
|
; out: A/Y = gGameToLaunch (word)
|
|
|
|
; C clear if gGameToLaunch is not #$FFFF
|
|
|
|
; C set if gGameToLaunch is #$FFFF
|
|
|
|
; X preserved
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
AnyGameSelected
|
2020-03-24 20:30:14 +00:00
|
|
|
+LD16 gGameToLaunch
|
2021-10-13 22:58:26 +00:00
|
|
|
+CMP16_NE $FFFF, ForceGoodResult
|
2020-05-30 15:14:04 +00:00
|
|
|
rts ; CMP sets carry when equal
|
2020-03-24 20:30:14 +00:00
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; GetGameToLaunch
|
|
|
|
; get filename of game that is currently selected in the UI (if any)
|
|
|
|
;
|
2020-03-24 20:30:14 +00:00
|
|
|
; in: gGameToLaunch = index into gGamesListStore (word) or #$FFFF if no game selected
|
|
|
|
; out: C clear if a game is selected, and
|
|
|
|
; A/Y points to game filename
|
|
|
|
; C set if no game is selected
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
GetGameToLaunch
|
2020-03-24 20:30:14 +00:00
|
|
|
jsr AnyGameSelected
|
2020-05-30 15:14:04 +00:00
|
|
|
bcs _gameToLaunchExit
|
2020-03-24 20:30:14 +00:00
|
|
|
+ST16 WINDEX
|
2019-10-08 18:43:41 +00:00
|
|
|
+LDADDR gGamesListStore
|
2020-03-24 20:30:14 +00:00
|
|
|
jsr okvs_nth
|
2020-05-30 15:14:04 +00:00
|
|
|
ForceGoodResult
|
2020-03-24 20:30:14 +00:00
|
|
|
clc
|
2020-05-30 15:14:04 +00:00
|
|
|
_gameToLaunchExit
|
|
|
|
rts
|
2019-10-08 18:43:41 +00:00
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; FindGame
|
|
|
|
; check if an arbitrary game exists, for some definition of 'exists'
|
|
|
|
;
|
2019-07-08 19:03:25 +00:00
|
|
|
; in: A/Y points to game filename
|
|
|
|
; out: C clear if game exists in gGamesListStore, and
|
2020-03-24 20:30:14 +00:00
|
|
|
; $WINDEX = game index, or #$FFFF if the game doesn't really
|
|
|
|
; exist but we want to return a successful result anyway
|
|
|
|
; C set if game does not exist (this can happen because slideshows
|
|
|
|
; list games that require a joystick, but the games list parser
|
|
|
|
; filters them out if the machine doesn't have a joystick)
|
|
|
|
; all registers clobbered
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
FindGame
|
2020-03-24 20:30:14 +00:00
|
|
|
+ST16 @key
|
2020-03-18 16:08:39 +00:00
|
|
|
jsr okvs_find
|
2019-07-08 19:03:25 +00:00
|
|
|
!word gGamesListStore
|
|
|
|
@key !word $FDFD ; SMC
|
2020-05-30 15:14:04 +00:00
|
|
|
bcc GlueLaunchRTS
|
2019-09-08 18:50:50 +00:00
|
|
|
; Hack to allow self-running demos that don't correspond to a game
|
|
|
|
; filename. If the name ends in a '.', accept it unconditionally.
|
2020-03-18 16:08:39 +00:00
|
|
|
ldx #$FF
|
2020-03-24 20:30:14 +00:00
|
|
|
stx WINDEX
|
|
|
|
stx WINDEX+1
|
|
|
|
+LD16 @key
|
|
|
|
+ST16 PARAM
|
2019-07-08 19:03:25 +00:00
|
|
|
ldy #0
|
|
|
|
lda (PARAM),y
|
|
|
|
tay
|
|
|
|
lda (PARAM),y
|
|
|
|
cmp #"."
|
2020-05-30 15:14:04 +00:00
|
|
|
beq ForceGoodResult
|
2019-07-08 19:03:25 +00:00
|
|
|
sec
|
2020-05-30 15:14:04 +00:00
|
|
|
GlueLaunchRTS
|
2019-07-08 19:03:25 +00:00
|
|
|
rts
|
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; FindGameInActionSlideshow
|
|
|
|
; check if an arbitrary game exists, for some definition of 'exists', while
|
|
|
|
; in the middle of a slideshow
|
|
|
|
;
|
|
|
|
; /!\ This function assumes that gSlideshowStore exists and is populated,
|
|
|
|
; which is generally only true during the callback function of a slideshow
|
|
|
|
;
|
2020-03-18 16:08:39 +00:00
|
|
|
; in: A/Y points to game filename
|
|
|
|
; out: C clear if game exists, and
|
2020-03-24 20:30:14 +00:00
|
|
|
; $WINDEX = game index, and
|
2020-03-18 16:08:39 +00:00
|
|
|
; A/Y points to game display name + game info bitfield
|
|
|
|
; C set if game can't be found by any means
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
FindGameInActionSlideshow
|
2020-03-24 20:30:14 +00:00
|
|
|
+ST16 @sskey
|
2020-03-18 16:08:39 +00:00
|
|
|
jsr FindGame
|
2020-05-30 15:14:04 +00:00
|
|
|
bcc GetGameDisplayName
|
2020-03-18 16:08:39 +00:00
|
|
|
; if the game was not found, try getting the value of the current record from
|
|
|
|
; gSlideshowStore (some games have multiple action screenshots, in which case
|
|
|
|
; the key is only the screenshot filename, and the value is the actual game
|
|
|
|
; filename)
|
|
|
|
jsr okvs_get
|
|
|
|
!word gSlideshowStore
|
|
|
|
@sskey !word $FDFD ; SMC
|
|
|
|
jsr FindGame
|
2020-05-30 15:14:04 +00:00
|
|
|
bcs GlueLaunchRTS
|
|
|
|
; /!\ execution falls through here to GetGameDisplayName
|
2020-03-18 16:08:39 +00:00
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; GetGameDisplayName
|
|
|
|
; lookup or construct the display name for a specific game
|
|
|
|
;
|
2020-03-18 16:08:39 +00:00
|
|
|
; in: A/Y contains address of a key in gGamesListStore
|
|
|
|
; out: A/Y contains address of game display name + game info bitfield
|
|
|
|
; (this might be just the corresponding value in gGamesListStore,
|
|
|
|
; or it might be a temporary buffer in main memory that we constructed
|
|
|
|
; out of thin air)
|
|
|
|
; gValLen possibly clobbered (up to gValLen+MaxInputLength)
|
|
|
|
; X preserved
|
2020-05-30 15:14:04 +00:00
|
|
|
; C clear
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
GetGameDisplayName
|
2020-03-24 20:30:14 +00:00
|
|
|
+ST16 SAVE
|
2020-03-18 16:08:39 +00:00
|
|
|
jsr okvs_get_current ; get value for this key
|
|
|
|
; (PTR) -> truncated game display name + info bitfield
|
2021-10-13 22:58:26 +00:00
|
|
|
; Y = 0
|
2020-03-18 16:08:39 +00:00
|
|
|
lda (PTR), y ; A = length of truncated game display name + info bitfield
|
2021-10-13 22:58:26 +00:00
|
|
|
lsr ;;cmp #1 ; 1 means there's no title, just info bitfield (1 byte)
|
2020-03-18 16:08:39 +00:00
|
|
|
beq +
|
2020-03-24 20:30:14 +00:00
|
|
|
+LD16 PTR
|
2020-05-30 15:14:04 +00:00
|
|
|
clc
|
2020-03-18 16:08:39 +00:00
|
|
|
rts
|
|
|
|
+ ; game display name is truncated, we must expand it
|
|
|
|
iny ; Y = 1
|
|
|
|
lda (PTR), y ; A = game info bitfield
|
|
|
|
pha ; save on stack
|
|
|
|
dey
|
|
|
|
lda (SAVE), y ; A = length of key
|
|
|
|
tay
|
|
|
|
iny
|
|
|
|
sty @len
|
|
|
|
sty gValLen
|
|
|
|
lda #$24 ; BIT opcode
|
2020-03-18 17:31:40 +00:00
|
|
|
sta @or ; first character remains capitalized
|
2020-03-18 16:08:39 +00:00
|
|
|
ldy #1
|
|
|
|
- lda (SAVE), y
|
2020-05-29 21:39:04 +00:00
|
|
|
cmp #$49 ; 'I'
|
|
|
|
bne +
|
|
|
|
cmp gValLen-1,y
|
|
|
|
beq ++ ; preserve 'II' casing
|
|
|
|
+ cmp #$2E
|
2020-03-18 17:31:40 +00:00
|
|
|
bne @or
|
|
|
|
lda #$20 ; convert '.' to ' '
|
2020-03-18 16:08:39 +00:00
|
|
|
@or ora #$20 ; SMC (opcode)
|
2020-05-29 21:39:04 +00:00
|
|
|
++ sta gValLen, y
|
2020-03-18 17:31:40 +00:00
|
|
|
cmp #$20
|
|
|
|
bne +
|
|
|
|
lda #$24 ; first character after ' ' remains capitalized
|
|
|
|
+HIDE_NEXT_2_BYTES
|
|
|
|
+ lda #$09 ; OR opcode
|
2020-03-18 16:08:39 +00:00
|
|
|
sta @or
|
|
|
|
@next iny
|
|
|
|
@len=*+1
|
|
|
|
cpy #$FD ; SMC
|
|
|
|
bne -
|
|
|
|
pla
|
|
|
|
sta gValLen, y
|
|
|
|
+LDADDR gValLen
|
2020-05-30 15:14:04 +00:00
|
|
|
clc
|
2020-03-18 16:08:39 +00:00
|
|
|
rts
|
|
|
|
|
2020-03-31 23:19:45 +00:00
|
|
|
;------------------------------------------------------------------------------
|
|
|
|
; PlayGame
|
|
|
|
;
|
|
|
|
; in: gGameToLaunch != #$FFFF
|
|
|
|
; out: exits via the game, but also backs up the stack, which may get
|
|
|
|
; restored in |Reenter|... what I'm saying is that we might actually
|
|
|
|
; 'return' from this after the user is done playing the game, which is
|
|
|
|
; a neat trick
|
|
|
|
;------------------------------------------------------------------------------
|
2019-09-21 03:26:32 +00:00
|
|
|
PlayGame
|
2019-10-08 18:43:41 +00:00
|
|
|
jsr GetGameToLaunch
|
2019-09-16 01:35:34 +00:00
|
|
|
; A/Y = address of game filename
|
2020-03-24 20:30:14 +00:00
|
|
|
+ST16 SAVE
|
|
|
|
+ST16 @pfile
|
2019-09-18 18:04:41 +00:00
|
|
|
|
2019-10-10 01:02:46 +00:00
|
|
|
jsr ClearScreens ; avoid seeing code load into the HGR page
|
|
|
|
; (clobbers $106, must do now before loading prelaunch code)
|
2019-09-15 02:57:52 +00:00
|
|
|
|
2021-10-13 22:58:45 +00:00
|
|
|
jsr LoadFile ; load prelaunch index file into $6000
|
|
|
|
!word kRootDirectory
|
|
|
|
!word kPrelaunchIndexFile
|
|
|
|
- !word $6000
|
|
|
|
|
|
|
|
jsr okvs_find
|
|
|
|
!word -
|
|
|
|
@pfile !word $FDFD ; SMC
|
|
|
|
+ST16 @indexRecordPtr
|
|
|
|
|
|
|
|
jsr LoadIndexedFile
|
|
|
|
!word kPrelaunchFulFile
|
2019-09-15 21:55:16 +00:00
|
|
|
!word $0106
|
2021-10-13 22:58:45 +00:00
|
|
|
@indexRecordPtr
|
|
|
|
!word $FDFD ; SMC
|
2019-09-15 02:57:52 +00:00
|
|
|
|
2019-10-09 04:25:10 +00:00
|
|
|
; we start by placing the subdirectory name at gPathname+kGameDirectoryLen
|
|
|
|
; to leave room for the GameDirectory name as the parent
|
|
|
|
|
|
|
|
lda #kGameDirectoryLen
|
|
|
|
sta gPathname
|
2020-03-24 20:30:14 +00:00
|
|
|
+LD16 SAVE
|
2019-10-09 04:25:10 +00:00
|
|
|
jsr AddToPath
|
|
|
|
|
|
|
|
; attach the separator
|
|
|
|
|
|
|
|
inc gPathname
|
|
|
|
lda #'/'
|
|
|
|
sta gPathname+1,x
|
2019-01-15 00:06:58 +00:00
|
|
|
|
2019-10-09 17:00:33 +00:00
|
|
|
; then we save the length of the resulting string without the count byte
|
|
|
|
|
|
|
|
dex
|
|
|
|
txa
|
|
|
|
pha
|
|
|
|
|
2019-10-09 04:25:10 +00:00
|
|
|
; then attach the game name
|
|
|
|
|
2020-03-24 20:30:14 +00:00
|
|
|
+LD16 SAVE
|
2019-10-09 04:25:10 +00:00
|
|
|
jsr AddToPath
|
|
|
|
|
|
|
|
; don't look while I do this
|
|
|
|
; we "place" a string at gPathname+kGameDirectoryLen
|
|
|
|
; whose length is the subdirectory name and game name
|
|
|
|
; then we load it
|
|
|
|
; the load sets the path to the GameDirectory
|
|
|
|
; and then finds the subdirectory name and game name right after it
|
|
|
|
; and attaches it to the path by overwriting the count byte
|
|
|
|
|
2019-11-27 21:51:43 +00:00
|
|
|
;;sec ; carry set by AddToPath
|
2019-10-09 04:25:10 +00:00
|
|
|
lda gPathname
|
|
|
|
sbc #kGameDirectoryLen
|
|
|
|
sta gPathname+kGameDirectoryLen
|
2019-06-26 02:44:39 +00:00
|
|
|
jsr LoadFile ; load the game startup file
|
2019-10-09 04:25:10 +00:00
|
|
|
!word kGameDirectory
|
|
|
|
!word gPathname+kGameDirectoryLen
|
2019-09-10 02:38:17 +00:00
|
|
|
!word 0 ; use file's default address
|
2019-01-15 00:06:58 +00:00
|
|
|
|
2019-06-21 23:47:05 +00:00
|
|
|
pla
|
2019-06-26 02:44:39 +00:00
|
|
|
sta ProDOS_prefix ; set 'root' directory to the path part
|
|
|
|
; of the game startup file we just loaded
|
2019-09-10 02:38:17 +00:00
|
|
|
; so games can load other files without
|
2019-06-26 02:44:39 +00:00
|
|
|
; knowing which directory they're in
|
2019-01-15 00:06:58 +00:00
|
|
|
|
2019-06-26 02:44:39 +00:00
|
|
|
; execution falls through here
|
|
|
|
Launch
|
2019-09-20 13:33:23 +00:00
|
|
|
jsr SwitchToBank2
|
2020-05-23 22:47:16 +00:00
|
|
|
lda #$BD
|
|
|
|
sta launchpatch
|
|
|
|
jsr saveslot ; set proper slot information
|
|
|
|
lda #$9D
|
|
|
|
sta launchpatch
|
2019-09-24 22:40:43 +00:00
|
|
|
jmp LaunchInternal
|
2020-06-15 16:44:46 +00:00
|
|
|
|
|
|
|
Joystick
|
2021-10-13 22:58:45 +00:00
|
|
|
jsr LoadStandardPrelaunch
|
2020-06-15 16:44:46 +00:00
|
|
|
|
|
|
|
jsr LoadFile
|
|
|
|
!word kRootDirectory
|
|
|
|
!word kJoystickFile
|
|
|
|
!word 0
|
|
|
|
|
|
|
|
jmp Launch
|
2021-10-13 22:58:45 +00:00
|
|
|
|
|
|
|
LoadStandardPrelaunch
|
|
|
|
jsr LoadIndexedFile ; load standard prelaunch code at $0106
|
|
|
|
!word kPrelaunchFulFile
|
|
|
|
!word $0106
|
|
|
|
!word +
|
|
|
|
rts
|
|
|
|
+ !byte 0
|
|
|
|
!be24 0
|
2021-10-21 17:04:01 +00:00
|
|
|
!le16 68
|