ZINFO glue and resume dialog (parses properly, displays without crashing)

This commit is contained in:
4am 2018-04-16 23:48:30 -04:00
parent 993f6cca20
commit 42d4c858de
11 changed files with 343 additions and 120 deletions

View File

@ -37,4 +37,5 @@ MAGICRTS = $FF58 ; used to set overflow bit
PTR = $02
SRC = $04
DEST = $06
ZPTR = $06 ; used by glue.zinfo because it's unused by okvs_append
SAVE = $08

30
src/glue.common.a Normal file
View File

@ -0,0 +1,30 @@
;license:MIT
;(c) 2018 by 4am
;
; Common functions across glue code
;
; Public functions
; - SetStartupPathToCurrentVersionOfCurrentGame
SetStartupPathToCurrentVersionOfCurrentGame
jsr ResetPath ; gPathname = ''
+LDADDR kGameRootDirectory ; gPathname = game root directory + '/'
jsr AddToPath
jsr okvs_get
!word gGlobalPrefsStore
!word kLastPlayed
+STAY + ; A/Y contains address
jsr AddToPath ; gPathname = root + '/' + game shortname
+LDADDR kPathSeparator
jsr AddToPath ; gPathname = root + '/' + game shortname + '/'
jsr okvs_get
!word gGlobalPrefsStore
+ !word $FDFD ; SMC
jsr AddToPath ; gPathname = root + '/' + game shortname + '/' + game filename
+LDADDR gPathname
jmp SetStartupPath ; store gPathname at $2006 to pass it to interpreter

View File

@ -11,11 +11,12 @@
; - LaunchInterpreterWithHints
;
!zone {
kGameRootDirectory ; length-prefixed pathname of game subdirectories
!byte 2
!raw "Z/"
kHintsRootDirectory ; length-prefixed pathname of hint files
!byte 5
!byte 6
!raw "PRIZM/"
kOnBeyondOptionsStruct = $0300
@ -133,26 +134,7 @@ LaunchInterpreterWithGame
jsr SaveGlobalPreferences
jsr LoadInterpreter
bcs .launchError
jsr ResetPath
+LDADDR kGameRootDirectory
jsr AddToPath
jsr okvs_get
!word gGlobalPrefsStore
!word kLastPlayed
+STAY + ; A/Y contains address
jsr AddToPath
jsr SetPrefix ; set ProDOS prefix to game directory
!word gPathname
bcs .launchError
jsr okvs_get
!word gGlobalPrefsStore
+ !word $FDFD ; SMC
jsr SetStartupPath ; store game filename at $2006
jsr SetStartupPathToCurrentVersionOfCurrentGame
jsr ExitWeeGUI ; shut down WeeGUI
jsr SetInterpreterOptions ; set options struct at $300
jmp kSystemAddress ; exit via interpreter
@ -175,6 +157,7 @@ LaunchInterpreterWithHints
bcs .launchError
jsr ResetPath
+LDADDR kHintsRootDirectory
jsr AddToPath
@ -199,19 +182,15 @@ LaunchInterpreterWithHints
; out: C clear if success
; C set if interpreter could not be loaded
; all other registers and flags clobbered
; gPathname clobbered
;------------------------------------------------------------------------------
LoadInterpreter
jsr ResetPath
+LDADDR .interpreterFilename
jsr AddToPath
jsr LoadFile
!word gPathname
!word kInterpreterFilename
!word kSystemAddress
!word kProDOSFileBuffer
rts
.interpreterFilename
kInterpreterFilename
!byte 15
!raw "ONBEYOND.SYSTEM"
}

155
src/glue.zinfo.a Normal file
View File

@ -0,0 +1,155 @@
;license:MIT
;(c) 2018 by 4am
;
; glue code to load and call ZINFO, the Z-Machine saved game parser
;
; Public functions
; - LoadSavedGameInfo
;
; Public variables
; - gSavedGamesStore
;
; TODO move these to a ZINFO_MLI kind of separate file
zinfo_base = $2000
zinfo_recordlen= 64
zinfo_maxslots = 8
name_offset = 0 ;1+37 bytes
time_offset = 42 ;1+8 bytes ("12:01 pm")
score_offset = 51 ;1+6 bytes (-12345)
moves_offset = 58 ;1+5 bytes (12345)
!zone {
gSavedGamesStore
!word $FDFD ; set in LoadGameInfo
gSavedGamesSlotsInUse
!byte $FD ; set in LoadSavedGameInfo
;------------------------------------------------------------------------------
; LoadSavedGameInfo
; load ZINFO, call it with the current game, and parse the results
;
; in: current ProDOS prefix is the same as the PITCH.DARK file
; out: C set if something went wrong
; C clear otherwise
;------------------------------------------------------------------------------
LoadSavedGameInfo
jsr okvs_init
!word gSavedGamesStore
stz gSavedGamesSlotsInUse
jsr LoadFile ; load ZINFO.SYSTEM at $2000
!word kZINFOFilename
!word kSystemAddress
!word kProDOSFileBuffer
bcs .error
jsr SetStartupPathToCurrentVersionOfCurrentGame
jsr kSystemAddress
jsr zparse
clc
rts
.error
jmp SoftBell
zparse
+LDADDR zinfo_base
+STAY ZPTR
ldx #0
.zParseLoop
+LDAY ZPTR
pha
phy
phx
jsr ResetPath
lda (ZPTR)
beq .saveAndMoveToNextSlot; no saved game in this slot
inc gSavedGamesSlotsInUse ; update number of slots in use (separate from length of store)
+LDAY ZPTR
jsr AddToPathWithHighBit ; add location information
lda ZPTR
clc
adc #time_offset
sta ZPTR
bcc +
inc ZPTR+1
+ ; ZPTR -> ZINFO time field (length-prefixed string, may be empty string if no time)
+LDADDR kLeftParen
jsr AddToPathWithHighBit ; add ' ('
lda (ZPTR)
bne .justTime
lda ZPTR
clc
adc #(score_offset-time_offset)
sta ZPTR
bcc +
inc ZPTR+1
+ ; ZPTR -> ZINFO score field (length-prefixed string, guaranteed non-empty if no time)
ldy ZPTR+1
jsr AddToPathWithHighBit ; add score information
+LDADDR kSlash
jsr AddToPathWithHighBit ; add '/'
lda ZPTR
clc
adc #(moves_offset-score_offset)
sta ZPTR
bcc +
inc ZPTR+1
+ ; A/Y -> ZINFO moves field (length-prefixed string, guaranteed non-empty)
; execution falls through here
.justTime
+LDAY ZPTR
jsr AddToPathWithHighBit ; add final piece of information (moves or time, depending on how we got here)
+LDADDR kRightParen
jsr AddToPathWithHighBit ; add ')'
; execution falls through here
.saveAndMoveToNextSlot
plx
phx
lda gPathname
beq +
lda #1
+ sta kSlotName ; set length of key (0 if value is empty, otherwise 8)
jsr okvs_append ; add this key/value to saved games store (used by ResumeDialog)
!word gSavedGamesStore
!word kSlotName ; key = printable short label, or empty string if slot is unused
!word gPathname ; value = printable long label, or empty string if slot is unused
!byte 0
plx
ply
pla
clc
adc #zinfo_recordlen
bcc +
iny
+
+STAY ZPTR ; ZPTR -> start of next ZINFO record
inx
cpx #zinfo_maxslots
bcs +
jmp .zParseLoop
+ rts
kZINFOFilename
!byte 12
!raw "ZINFO.SYSTEM"
kSlotName
!byte 1
!text " "
kLeftParen
!byte 2
!text " ("
kRightParen
!byte 1
!text ")"
kSlash
!byte 1
!text "/"
}

View File

@ -108,6 +108,7 @@ okvs_len
; $00/$01 clobbered
; $02/$03 clobbered
; $04/$05 has the address of the next available byte after the new record
; $08/$09 clobbered
;------------------------------------------------------------------------------
okvs_append
+PARAMS_ON_STACK 7

View File

@ -137,6 +137,10 @@ LoadGameInfo
!word gOptionsStore
!word addrOptions
!byte 0
+LDAY SRC
+STAY gSavedGamesStore ; save pointer to free space for next store
; execution falls through here
CheckForSavedGames
jsr okvs_get ; get shortname of current game

View File

@ -30,17 +30,19 @@
!source "src/prodos.mli.a"
!source "src/prodos.ramdisk.a"
!source "src/prodos.path.a"
!source "src/glue.onbeyond.a"
!source "src/parse.common.a"
!source "src/parse.gamelist.a"
!source "src/parse.gameinfo.a"
!source "src/parse.prefs.a"
!source "src/glue.common.a"
!source "src/glue.onbeyond.a"
!source "src/glue.zinfo.a"
!source "src/ui.common.a"
!source "src/ui.sound.a"
!source "src/ui.main.a"
!source "src/ui.main.keys.a"
!source "src/ui.options.a"
; !source "src/ui.resume.a"
!source "src/ui.resume.a"
!source "src/ui.versions.a"
!source "src/ui.artwork.a"

View File

@ -37,7 +37,12 @@ ResetPath
; gPathname updated with concatenated length-prefixed string
;------------------------------------------------------------------------------
!zone {
AddToPathWithHighBit
ldx #$80
!byte $2C
AddToPath
ldx #0
stx .mask
+STAY $00
ldx gPathname ; current pathname length
lda ($00) ; length of this segment
@ -45,6 +50,8 @@ AddToPath
sta .len
ldy #$01
- lda ($00),y
.mask=*+1
ora #$FD ; SMC
sta gPathname+1,x
inx
iny

View File

@ -210,7 +210,7 @@ callback_next
callback_options = OptionsDialog
callback_play = LaunchInterpreterWithGame
callback_resume = LaunchInterpreterWithGame
callback_resume = ResumeDialog
callback_boxart = DisplayArtwork
callback_hints = LaunchInterpreterWithHints
callback_versions = VersionsDialog

View File

@ -67,10 +67,13 @@ ResumeDialog
ldx #WGResetAll ; reset WeeGUI
jsr WeeGUI
jsr LoadSavedGameInfo
; TODO call ZINFO and calculate proper height
ldy #3
sty kViewResumeFrame+3 ; frame top
iny
sty .resumeVTAB ; top of first radio button
sty kViewResumeOK+2 ; OK top
iny
iny
@ -88,22 +91,21 @@ ResumeDialog
jsr CreateButton
!word kViewResumeCancel
jsr okvs_iter
!word gSavedGamesStore
!word CreateResumeRadioCallback
jsr CreateRadio
!word kViewResumeSlot0
jsr CreateRadio
!word kViewResumeSlot1
jsr CreateRadio
!word kViewResumeSlot2
jsr CreateRadio
!word kViewResumeSlot3
jsr CreateRadio
!word kViewResumeSlot4
jsr CreateRadio
!word kViewResumeSlot5
jsr CreateRadio
!word kViewResumeSlot6
jsr CreateRadio
!word kViewResumeSlot7
!word kViewResumeNewGame
; TODO set proper radio button based on ZINFO
lda #ID_RESUME_NEWGAME
ldx #WGSelectView
jsr WeeGUI
lda #1
sta PARAM0
ldx #WGSetState
jsr WeeGUI
ldx #WGDesktop ; paint background
jsr WeeGUI
@ -113,10 +115,16 @@ ResumeDialog
jsr PaintTitleBar ; paint top title bar
ldx #WGSelectView
ldx #WGSelectView ; select frame (required for print routines that follow)
lda #ID_RESUME_FRAME
jsr WeeGUI
lda #1 ; WeeGUI radio buttons are limited to 15 characters, so we
sta .resumeVTAB ; print the longer labels separately
jsr okvs_iter_values
!word gSavedGamesStore
!word PrintResumeLabelCallback
.runLoop
ldx #WGPendingViewAction
jsr WeeGUI
@ -129,6 +137,48 @@ ResumeDialog
;------------------------------------------------------------------------------
; internal functions
CreateResumeRadioCallback
; X = index (0-based) into gSavedGamesStore, which is also the slot number
; A/Y points to caption (length-prefixed, 0 if slot is unused and should be skipped)
;
+STAY SAVE
lda (SAVE)
sta gResumeViewInUse+1,x ; mark whether this view is in use (hotkeys activate based on this array)
beq .createResumeRadioDone; 0-length key means this slot is unused, so we're done
txa
asl
tax
lda kViewResumeArray,x
ldy kViewResumeArray+1,x
+STAY +
+STAY SRC
ldy #2
lda .resumeVTAB
sta (SRC),y ; radio button top = frame top + 1 + (2 * X)
jsr CreateRadio ; create radio button for this version (will print label later)
+ !word $FDFD ; SMC
inc .resumeVTAB
inc .resumeVTAB
.createResumeRadioDone
rts
PrintResumeLabelCallback
+STAY SAVE
lda (SAVE)
beq .printVersionLabelDone
ldx #44
lda SAVE
jsr CreateNullTerminatedString
jsr PrintAt
!byte 13 ; htab (constant)
.resumeVTAB
!byte $FD ; SMC
!word kNullTerminatedBuffer
inc .resumeVTAB
inc .resumeVTAB
.printVersionLabelDone
rts
HandleResumeKey
ldx #.endkeys-.keys
- cmp .keys,x
@ -174,91 +224,94 @@ kViewResumeCancel
!word callback_resume_cancel ; callback
!word kStringCancel ; caption
kViewResumeArray
!word kViewResumeSlot0
!word kViewResumeSlot1
!word kViewResumeSlot2
!word kViewResumeSlot3
!word kViewResumeSlot4
!word kViewResumeSlot5
!word kViewResumeSlot6
!word kViewResumeSlot7
kViewResumeSlot0
!byte ID_RESUME_SLOT0 ; view ID
!byte 8 ; left
!byte 4 ; top
!word kStringSlot0 ; caption
kStringSlot0
!text " Slot "
!byte $30 ; '0' inverse
!text ":",0
kViewResumeSlot1
!byte ID_RESUME_SLOT1 ; view ID
!byte 8 ; left
!byte 6 ; top
!word kStringSlot1 ; caption
kStringSlot1
!text " Slot "
!byte $31 ; '1' inverse
!text ":",0
kViewResumeSlot2
!byte ID_RESUME_SLOT2 ; view ID
!byte 8 ; left
!byte 8 ; top
!word kStringSlot2 ; caption
kStringSlot2
!text " Slot "
!byte $32 ; '2' inverse
!text ":",0
kViewResumeSlot3
!byte ID_RESUME_SLOT3 ; view ID
!byte 8 ; left
!byte 10 ; top
!word kStringSlot3 ; caption
kStringSlot3
!text " Slot "
!byte $33 ; '3' inverse
!text ":",0
kViewResumeSlot4
!byte ID_RESUME_SLOT4 ; view ID
!byte 8 ; left
!byte 12 ; top
!word kStringSlot4 ; caption
kStringSlot4
!text " Slot "
!byte $34 ; '4' inverse
!text ":",0
kViewResumeSlot5
!byte ID_RESUME_SLOT5 ; view ID
!byte 8 ; left
!byte 14 ; top
!word kStringSlot5 ; caption
kStringSlot5
!text " Slot "
!byte $35 ; '5' inverse
!text ":",0
kViewResumeSlot6
!byte ID_RESUME_SLOT6 ; view ID
!byte 8 ; left
!byte 16 ; top
!word kStringSlot6 ; caption
kStringSlot6
!text " Slot "
!byte $36 ; '6' inverse
!text ":",0
kViewResumeSlot7
!byte ID_RESUME_SLOT7 ; view ID
!byte 8 ; left
!byte 18 ; top
!byte 18 ; top
!word kStringSlot7 ; caption
kViewResumeNewGame
!byte ID_RESUME_NEWGAME ; view ID
!byte 8 ; left
!byte 20 ; top
!word kStringNewGame ; caption
kStringSlot0
!text " Slot ",$30,":",0
kStringSlot1
!text " Slot ",$31,":",0
kStringSlot2
!text " Slot ",$32,":",0
kStringSlot3
!text " Slot ",$33,":",0
kStringSlot4
!text " Slot ",$34,":",0
kStringSlot5
!text " Slot ",$35,":",0
kStringSlot6
!text " Slot ",$36,":",0
kStringSlot7
!text " Slot "
!byte $37 ; '7' inverse
!text ":",0
!text " Slot ",$37,":",0
kStringNewGame
!text " Start ",110,"ew game",0
}

View File

@ -326,87 +326,78 @@ kViewVersions1
!byte 4 ; top
!word kString1 ; caption
kString1
!text " "
!byte $31,0 ; '1' inverse
kViewVersions2
!byte ID_VERSIONS_2 ; view ID
!byte 8 ; left
!byte 6 ; top
!word kString2 ; caption
kString2
!text " "
!byte $32,0 ; '2' inverse
kViewVersions3
!byte ID_VERSIONS_3 ; view ID
!byte 8 ; left
!byte 8 ; top
!word kString3 ; caption
kString3
!text " "
!byte $33,0 ; '3' inverse
kViewVersions4
!byte ID_VERSIONS_4 ; view ID
!byte 8 ; left
!byte 10 ; top
!word kString4 ; caption
kString4
!text " "
!byte $34,0 ; '4' inverse
kViewVersions5
!byte ID_VERSIONS_5 ; view ID
!byte 8 ; left
!byte 12 ; top
!word kString5 ; caption
kString5
!text " "
!byte $35,0 ; '5' inverse
kViewVersions6
!byte ID_VERSIONS_6 ; view ID
!byte 8 ; left
!byte 14 ; top
!word kString6 ; caption
kString6
!text " "
!byte $36,0 ; '6' inverse
kViewVersions7
!byte ID_VERSIONS_7 ; view ID
!byte 8 ; left
!byte 16 ; top
!word kString7 ; caption
kString7
!text " "
!byte $37,0 ; '7' inverse
kViewVersions8
!byte ID_VERSIONS_8 ; view ID
!byte 8 ; left
!byte 18 ; top
!word kString8 ; caption
kString8
!text " "
!byte $38,0 ; '8' inverse
kViewVersions9
!byte ID_VERSIONS_9 ; view ID
!byte 8 ; left
!byte 20 ; top
!word kString9 ; caption
kString1
!text " ",$31,0
kString2
!text " ",$32,0
kString3
!text " ",$33,0
kString4
!text " ",$34,0
kString5
!text " ",$35,0
kString6
!text " ",$36,0
kString7
!text " ",$37,0
kString8
!text " ",$38,0
kString9
!text " "
!byte $39,0 ; '9' inverse
!text " ",$39,0
}