mirror of
https://github.com/a2-4am/million-perfect-letters.git
synced 2025-01-13 16:29:45 +00:00
track completion progress and save to disk
This commit is contained in:
parent
8bbb20fd6d
commit
dabfccdba2
3
Makefile
3
Makefile
@ -26,6 +26,7 @@ asm:
|
||||
$(ACME) -r build/million.lst src/million.a 2>build/log
|
||||
cp res/work.po "$(BUILDDISK)".po >>build/log
|
||||
cp res/_FileInformation.txt build/ >>build/log
|
||||
$(CADIUS) ADDFILE "${BUILDDISK}".po "/MILLION/" "res/PROGRESS" >>build/log
|
||||
$(CADIUS) ADDFILE "${BUILDDISK}".po "/MILLION/" "build/MILLION.SYSTEM" >>build/log
|
||||
for f in res/levels/*; do $(CADIUS) ADDFILE "${BUILDDISK}".po "/MILLION/" "$$f" >>build/log; done
|
||||
|
||||
@ -36,3 +37,5 @@ mount:
|
||||
open "$(BUILDDISK)".po
|
||||
|
||||
all: clean asm mount
|
||||
|
||||
al: all
|
||||
|
BIN
res/PROGRESS
Normal file
BIN
res/PROGRESS
Normal file
Binary file not shown.
@ -1 +1,2 @@
|
||||
MILLION.SYSTEM=Type(FF),AuxType(2000),Access(C3)
|
||||
PROGRESS=Type(06),AuxType(8E10),Access(C3)
|
||||
|
@ -2,6 +2,24 @@
|
||||
;(c) 2020 by 4am
|
||||
;
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; YE OLDE GRAND UNIFIED MEMORY MAP
|
||||
;
|
||||
; MAIN MEMORY
|
||||
; 0300..03CF - data structures for current puzzle
|
||||
; 0400..07FF - text page (kept black for switching)
|
||||
; 0800..19FF - scroll routines (generated at startup)
|
||||
; 1A00..1BFF - HGR lookup tables
|
||||
; 1C00..1FFF - ProDOS file buffer for puzzle files
|
||||
; 2000..3FFF - hi-res page
|
||||
; 4000+ - program code (relocated to here at startup)
|
||||
; ...unused...
|
||||
; 8A00..8DFF - ProDOS file buffer for PROGRESS file
|
||||
; 8E10..8F37 - progress of puzzles in current world
|
||||
; 8F38..8FFF - address lookup table for puzzles within following world data
|
||||
; 9000..BEFF - world data (read from disk)
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
; soft switches
|
||||
KBD = $C000 ; last key pressed (if any)
|
||||
STOREOFF = $C000 ; STA then use the following 4 flags:
|
||||
@ -37,23 +55,25 @@ ROM_IN0 = $FE89 ; SETKBD
|
||||
ROM_PR0 = $FE93 ; SETVID
|
||||
|
||||
; zero page
|
||||
PARAM = $00 ; word (used by PARAMS_ON_STACK macro, so basically everywhere)
|
||||
;PTR = $02 ; word
|
||||
;SRC = $04 ; word
|
||||
;DEST = $06 ; word
|
||||
;SAVE = $08 ; word
|
||||
PARAM = $00 ; word (used by PARAMS_ON_STACK macro)
|
||||
HTAB = $24 ; byte
|
||||
VTAB = $25 ; byte
|
||||
;RNDSEED = $4E ; word
|
||||
|
||||
; application constants
|
||||
; zero page
|
||||
original_char = $ED ; byte
|
||||
char = $EE ; byte
|
||||
charrow = $EF ; byte
|
||||
|
||||
GENSCROLLDOWN = $0800 ; 0x0900 bytes
|
||||
GENSCROLLUP = $1100 ; 0x0900 bytes
|
||||
HGRLO = $1A00 ; 0xC0 bytes
|
||||
HGRHI = $1B00 ; 0xC0 bytes
|
||||
PRODOSFILEBUFFER = $1C00 ; 0x0400 bytes
|
||||
LEVELLO = $8F38 ; 0x64 bytes
|
||||
LEVELHI = $8F9C ; 0x64 bytes
|
||||
HGRLO = $1A00 ; 0x00C0 bytes
|
||||
HGRHI = $1B00 ; 0x00C0 bytes
|
||||
WORLDFILEBUFFER = $1C00 ; 0x0400 bytes
|
||||
|
||||
PROGRESSFILEBUFFER = $8A00; 0x0400 bytes
|
||||
PACKEDPROGRESS = $8E10 ; 0x00C0 bytes
|
||||
PROGRESS = $8ED0 ; 0x0068 bytes
|
||||
PUZZLELO = $8F38 ; 0x0064 bytes
|
||||
PUZZLEHI = $8F9C ; 0x0064 bytes
|
||||
WORLDDATA = $9000 ; 0x2F00 bytes max
|
||||
|
@ -21,6 +21,7 @@ CMD_NEWLINE = $03C9 ; set line-by-line read mode
|
||||
CMD_READ = $04CA ; read an open file
|
||||
CMD_WRITE = $04CB ; write to an open file
|
||||
CMD_CLOSE = $01CC ; close an open file
|
||||
CMD_FLUSH = $01CD ; flush an open, written file to disk
|
||||
CMD_SETMARK = $02CE ; change position in an open file
|
||||
CMD_SETEOF = $02D0 ; set file size
|
||||
|
||||
@ -28,14 +29,16 @@ CMD_SETEOF = $02D0 ; set file size
|
||||
; OpenFile
|
||||
; open file via ProDOS MLI
|
||||
;
|
||||
; in: A/Y address of pathname
|
||||
; in: stack contains 4 bytes of parameters:
|
||||
; +1 [word] address of filename
|
||||
; +3 [word] ProDOS file reference number
|
||||
; out: if C set, open failed and A contains error code
|
||||
; if C clear, open succeeded and A contains file reference number
|
||||
;------------------------------------------------------------------------------
|
||||
OpenFile
|
||||
+ST16 mliparam+1
|
||||
+LDADDR PRODOSFILEBUFFER
|
||||
+ST16 mliparam+3
|
||||
+PARAMS_ON_STACK 4
|
||||
+LDPARAMPTR 1, mliparam+1 ; store filename
|
||||
+LDPARAMPTR 3, mliparam+3 ; store address of ProDOS file buffer
|
||||
+LDADDR CMD_OPEN
|
||||
jsr mli
|
||||
bcs +
|
||||
@ -55,6 +58,7 @@ OpenFile
|
||||
; out: if C set, read failed and A contains error code
|
||||
; if C clear, read succeeded and A contains the same
|
||||
; file reference number that was passed in
|
||||
; stack set to next instruction after parameters
|
||||
;------------------------------------------------------------------------------
|
||||
ReadFile
|
||||
+PARAMS_ON_STACK 5
|
||||
@ -69,9 +73,64 @@ ReadFile
|
||||
lda mliparam+1 ; if no error, return file reference number
|
||||
+ rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; WriteFile
|
||||
; write to an open file via ProDOS MLI
|
||||
;
|
||||
; in: A = file reference number
|
||||
; stack contains 4 bytes of parameters:
|
||||
; +1 [word] address of data buffer
|
||||
; +3 [word] length of data buffer
|
||||
; out: if C set, save failed and A contains error code
|
||||
; if C clear, write succeeded and A contains the same file reference
|
||||
; number that was passed in
|
||||
;------------------------------------------------------------------------------
|
||||
WriteFile
|
||||
sta mliparam+1 ; store file reference number
|
||||
+PARAMS_ON_STACK 4
|
||||
+LDPARAMPTR 1, mliparam+2 ; store data buffer address
|
||||
+LDPARAMPTR 3, mliparam+4 ; store data buffer length
|
||||
+LDADDR CMD_WRITE
|
||||
jsr mli
|
||||
bcs + ; error, A contains MLI error code
|
||||
lda mliparam+1 ; no error, return file reference number
|
||||
+ rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; SetMarkTo0
|
||||
; set file position within an open file to the beginning of the file
|
||||
;
|
||||
; in: A = file reference number
|
||||
; out: if C set, save failed and A contains error code
|
||||
; if C clear, write succeeded and A contains the same file reference
|
||||
; number that was passed in
|
||||
;------------------------------------------------------------------------------
|
||||
SetMarkTo0
|
||||
sta mliparam+1 ; store file reference number
|
||||
lda #0
|
||||
sta mliparam+2
|
||||
sta mliparam+3
|
||||
sta mliparam+4
|
||||
+LDADDR CMD_SETMARK
|
||||
bne mli ; always branches
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; FlushFile
|
||||
; flush an open file (actually writes it to disk, but without closing it)
|
||||
;
|
||||
; in: A = file reference number
|
||||
; out: if error, C set and A contains error code
|
||||
; if success, C clear
|
||||
;------------------------------------------------------------------------------
|
||||
FlushFile
|
||||
sta mliparam+1 ; store file reference number
|
||||
+LDADDR CMD_FLUSH
|
||||
bne mli ; always branches
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CloseFile
|
||||
; close an open file
|
||||
;
|
||||
; in: A = file reference number
|
||||
; out: if error, C set and A contains error code
|
||||
; if success, C clear
|
||||
@ -88,6 +147,8 @@ CloseFile
|
||||
; out: does not return
|
||||
;------------------------------------------------------------------------------
|
||||
Quit
|
||||
lda #0
|
||||
jsr CloseFile
|
||||
+LDADDR CMD_QUIT
|
||||
; /!\ execution falls through here
|
||||
;------------------------------------------------------------------------------
|
||||
@ -106,12 +167,12 @@ mli sta mlicmd ; store command code
|
||||
mlicmd !byte 00 ; command number
|
||||
!word mliparam ; address of parameter table
|
||||
rts
|
||||
mliparam !byte $FE,$FE,$FE,$FE
|
||||
filetype !byte $FE ; file type (set by MLI get_file_info)
|
||||
mliparam !byte $FD,$FD,$FD,$FD
|
||||
filetype !byte $FD ; file type (set by MLI get_file_info)
|
||||
auxtype ; auxiliary file type (2 bytes, set by MLI get_file_info)
|
||||
refnum !byte $FE ; file refnum (set by MLI open)
|
||||
mlilen !byte $FE,$FE ; file length (set by MLI read)
|
||||
blocks !byte $FE,$FE ; blocks used (set by getvolumeinfo)
|
||||
refnum !byte $FD ; file refnum (set by MLI open)
|
||||
mlilen !byte $FD,$FD ; file length (set by MLI read)
|
||||
blocks !byte $FD,$FD ; blocks used (set by getvolumeinfo)
|
||||
; member is also used by createfile
|
||||
!byte $FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE
|
||||
!byte $FD,$FD,$FD,$FD,$FD,$FD,$FD,$FD
|
||||
; used by get_file_info
|
||||
|
355
src/hw.storage.a
355
src/hw.storage.a
@ -1,39 +1,72 @@
|
||||
;license:MIT
|
||||
;(c) 2020 by 4am
|
||||
;
|
||||
; disk functions to load puzzles, and load & save puzzle completion status
|
||||
;
|
||||
; Public functions:
|
||||
; - MaybeLoadWorldFromDisk
|
||||
; - LoadProgressFromDisk
|
||||
; - LoadProgressFromMemory
|
||||
; - LoadPuzzleFromMemory
|
||||
; - HasPuzzleBeenCompleted
|
||||
; - MarkPuzzleCompleted
|
||||
; - FindPackedProgressAddr
|
||||
;
|
||||
; Public variables:
|
||||
; - gWorldID
|
||||
; - gPuzzleID
|
||||
;
|
||||
; Public constants:
|
||||
; - kPuzzleWidths
|
||||
;
|
||||
|
||||
gLevelID
|
||||
gWorldID ; a world is a group of 100 similar puzzles (12 worlds in total, 0-based)
|
||||
!byte $FD ; 0x00..0x0B
|
||||
gPuzzleID
|
||||
gPuzzleID ; ID of current puzzle within the current world (100 puzzles per world, 0-based)
|
||||
!byte $FD ; 0x00..0x63
|
||||
|
||||
kLevelWidths
|
||||
!byte 4,5,6,7
|
||||
kPuzzleWidths ; width in letters of the puzzles in each world
|
||||
!byte 4,5,6,7 ; (every puzzle in a world is the same width)
|
||||
!byte 4,5,6,7
|
||||
!byte 4,5,6,7
|
||||
|
||||
MaybeLoadLevelsFromDisk
|
||||
; in: A = level ID
|
||||
progressRefNum ; [byte][private]
|
||||
!byte $FF ; 0xFF means 'no progress file open'
|
||||
checksum = $FB
|
||||
packedvalue = $FC
|
||||
bitcount = $FD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; MaybeLoadWorldFromDisk
|
||||
; load a world (100 puzzles) from a file on disk
|
||||
; caches the last world loaded to reduce unnecessary disk access
|
||||
;
|
||||
; in: A = world ID
|
||||
; out: C clear if file loaded and parsed successfully (or it was already in memory)
|
||||
; C set if file could not be loaded and/or parsed
|
||||
; other registers/flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
MaybeLoadWorldFromDisk
|
||||
clc
|
||||
adc #$41
|
||||
cmp @fileLoaded
|
||||
beq @exit
|
||||
sta @filename+1
|
||||
+LDADDR @filename
|
||||
bne +
|
||||
clc
|
||||
rts
|
||||
+ sta @filename+1
|
||||
jsr OpenFile
|
||||
!word @filename
|
||||
!word WORLDFILEBUFFER
|
||||
bcs @exit
|
||||
sta @refnum
|
||||
jsr ReadFile
|
||||
@refnum !byte $FD ; SMC
|
||||
!word $9000 ; load address
|
||||
!word WORLDDATA ; load address
|
||||
!word $2F00 ; maximum length to read
|
||||
php
|
||||
bcs @closeAndPopStatus
|
||||
plp
|
||||
jsr ParseLevelData
|
||||
jsr @PreParseWorldData
|
||||
cpx #100
|
||||
bne +
|
||||
clc
|
||||
@ -53,9 +86,9 @@ MaybeLoadLevelsFromDisk
|
||||
!byte 1 ; length
|
||||
!raw $FD ; SMC
|
||||
|
||||
ParseLevelData
|
||||
; find the starting address of each of the 100 puzzles in this file
|
||||
; in: $9000+ contains raw level data from disk
|
||||
@PreParseWorldData
|
||||
; find the starting address of each of the 100 puzzles in this world
|
||||
; in: $9000+ contains raw world data from disk
|
||||
lda #$FF
|
||||
sta $FE
|
||||
lda #$8F
|
||||
@ -76,54 +109,294 @@ ParseLevelData
|
||||
cmp #$5B ; '[' ends the parsing
|
||||
beq @exit
|
||||
lda $FE
|
||||
sta LEVELLO, x
|
||||
sta PUZZLELO, x
|
||||
lda $FF
|
||||
sta LEVELHI, x
|
||||
sta PUZZLEHI, x
|
||||
inx
|
||||
bne @skipLine ; always branches
|
||||
|
||||
@IncAndGetChar
|
||||
inc $FE
|
||||
bne +
|
||||
inc $FF
|
||||
+ lda ($FE),y
|
||||
; in: Y = 0
|
||||
+INCADDR $FE
|
||||
lda ($FE),y
|
||||
cmp #$0D ; CR - hide it
|
||||
beq @IncAndGetChar
|
||||
@exit rts
|
||||
rts
|
||||
|
||||
ParseOnePuzzle
|
||||
ldx gPuzzleID
|
||||
lda LEVELLO, x
|
||||
;------------------------------------------------------------------------------
|
||||
; LoadProgressFromDisk
|
||||
;
|
||||
; see comments in MarkPuzzleCompleted for file format
|
||||
;
|
||||
; in: none
|
||||
; out: C clear if file was read successfully, and
|
||||
; progressRefNum contains ProDOS file reference number (file is left
|
||||
; open)
|
||||
; C set if error occurred, and
|
||||
; progressRefNum = 0xFF
|
||||
;------------------------------------------------------------------------------
|
||||
LoadProgressFromDisk
|
||||
jsr OpenFile
|
||||
!word @progressFile
|
||||
!word PROGRESSFILEBUFFER
|
||||
bcs +
|
||||
sta @refnum
|
||||
sta progressRefNum
|
||||
jsr ReadFile
|
||||
@refnum !byte $FD ; SMC
|
||||
!word PACKEDPROGRESS ; data address
|
||||
!word $00C0 ; data length
|
||||
+ rts
|
||||
@progressFile
|
||||
!byte 8
|
||||
!raw "PROGRESS"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; LoadProgressFromMemory
|
||||
; unpacks one world's progress into a 1-byte-per-puzzle array for easier access
|
||||
;
|
||||
; in: progress file must be in memory (call MaybeLoadProgressFromDisk and
|
||||
; check C)
|
||||
; out: A = next puzzle ID
|
||||
;------------------------------------------------------------------------------
|
||||
LoadProgressFromMemory
|
||||
lda gWorldID
|
||||
jsr FindPackedProgressAddr
|
||||
; ($FE) -> start of the 16-byte structure for this world
|
||||
; zero destination array
|
||||
ldx #103
|
||||
lda #0
|
||||
- sta PROGRESS, x
|
||||
dex
|
||||
bpl -
|
||||
; unpack values
|
||||
ldy #0 ; index into ($FE) (source data)
|
||||
ldx #0 ; index into PROGRESS (destination data)
|
||||
-- lda #8
|
||||
sta bitcount
|
||||
lda ($FE), y
|
||||
- lsr
|
||||
rol PROGRESS, x ; note: PROGRESS structure is 104 bytes (a multiple of 8),
|
||||
inx ; even though only the first 100 bytes are used
|
||||
dec bitcount
|
||||
bne -
|
||||
iny
|
||||
cpy #$0D
|
||||
bne --
|
||||
lda ($FE), y ; A = next puzzle ID
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; LoadPuzzleFromMemory
|
||||
; loads one puzzle from the in-memory cache of the world file, into the
|
||||
; 'now playing this puzzle' data structures
|
||||
;
|
||||
; in: X = puzzle ID
|
||||
; world file must be in memory (call MaybeLoadWorldFromDisk and check C)
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
LoadPuzzleFromMemory
|
||||
lda PUZZLELO, x
|
||||
sta $FE
|
||||
lda LEVELHI, x
|
||||
lda PUZZLEHI, x
|
||||
sta $FF
|
||||
bne @addLine ; always branches
|
||||
@lineLoop
|
||||
jsr @inc
|
||||
+INCADDR $FE
|
||||
@addLine
|
||||
jsr AddLineToPuzzle
|
||||
ldx gLevelID
|
||||
ldy kLevelWidths, x
|
||||
- jsr @inc
|
||||
dey
|
||||
bne -
|
||||
ldx gWorldID
|
||||
lda kPuzzleWidths, x
|
||||
clc
|
||||
adc $FE
|
||||
sta $FE
|
||||
bcc +
|
||||
inc $FF
|
||||
+
|
||||
ldy #0
|
||||
lda ($FE), y
|
||||
cmp #$2C ; ,
|
||||
beq @lineLoop
|
||||
@targetWordLoop
|
||||
jsr @inc
|
||||
+INCADDR $FE
|
||||
jsr AddTargetWordToPuzzle
|
||||
ldx gLevelID
|
||||
ldy kLevelWidths, x
|
||||
- jsr @inc
|
||||
dey
|
||||
bne -
|
||||
ldx gWorldID
|
||||
lda kPuzzleWidths, x
|
||||
clc
|
||||
adc $FE
|
||||
sta $FE
|
||||
bcc +
|
||||
inc $FF
|
||||
+
|
||||
ldy #0
|
||||
lda ($FE), y
|
||||
cmp #$2C ; ,
|
||||
beq @targetWordLoop
|
||||
rts
|
||||
@inc
|
||||
inc $FE
|
||||
bne +
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; HasPuzzleBeenCompleted
|
||||
;
|
||||
; in: X = puzzle ID
|
||||
; out: C clear if puzzle had previously been marked as completed
|
||||
; C set if puzzle has never been marked as completed
|
||||
; X/Y preserved
|
||||
; A clobbered
|
||||
; other flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
HasPuzzleBeenCompleted
|
||||
lda PROGRESS, x
|
||||
beq +
|
||||
clc
|
||||
rts
|
||||
+ sec
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; MarkPuzzleCompleted
|
||||
;
|
||||
; in: X = puzzle ID
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
MarkPuzzleCompleted
|
||||
; Completion status for the current world (100 puzzles) is stored unpacked in
|
||||
; memory for easy access
|
||||
; Mark this puzzle as completed in the unpacked table
|
||||
lda #1
|
||||
sta PROGRESS, x
|
||||
; Find the next uncompleted puzzle
|
||||
clc
|
||||
+HIDE_NEXT_BYTE
|
||||
-- sec
|
||||
- lda PROGRESS, x
|
||||
beq +
|
||||
inx
|
||||
cpx #100
|
||||
bne -
|
||||
ldx #0 ; start over at the puzzle 0
|
||||
bcc --
|
||||
; If we fall through here, it means all puzzles in this world
|
||||
; have been completed (yay!), and we'll leave X at 0.
|
||||
; If we branch here, we found the next uncompleted puzzle
|
||||
; and X contains that puzzle ID.
|
||||
+ txa
|
||||
pha ; push next puzzle ID
|
||||
;
|
||||
; Completion status for all puzzles across all worlds is stored in packed
|
||||
; bitfields, 1 bit per puzzle, so that the file on disk fits in a single
|
||||
; block (actually a single sector).
|
||||
;
|
||||
; This is the file format (0xC0 bytes):
|
||||
; +0x00 bit 0 - completion status for world 0x00, puzzle 0x00
|
||||
; bit 1 - completion status for world 0x00, puzzle 0x01
|
||||
; bit 2 - completion status for world 0x00, puzzle 0x02
|
||||
; bit 3 - completion status for world 0x00, puzzle 0x03
|
||||
; bit 4 - completion status for world 0x00, puzzle 0x04
|
||||
; bit 5 - completion status for world 0x00, puzzle 0x05
|
||||
; bit 6 - completion status for world 0x00, puzzle 0x06
|
||||
; bit 7 - completion status for world 0x00, puzzle 0x07
|
||||
; ...
|
||||
; +0x0C bit 0 - completion status for world 0x00, puzzle 0x60
|
||||
; bit 1 - completion status for world 0x00, puzzle 0x61
|
||||
; bit 2 - completion status for world 0x00, puzzle 0x62
|
||||
; bit 3 - completion status for world 0x00, puzzle 0x63
|
||||
; bit 4-7 always 0
|
||||
; +0x0D next puzzle to play in world 0x00 (0x00..0x63)
|
||||
; +0x0E percent complete (0x00..0x64)
|
||||
; +0x0F XOR of bytes +0x00..+0x0E
|
||||
; +0x10..+0x1F same format but for world 0x01
|
||||
; +0x20..+0x2F same format but for world 0x02
|
||||
; +0x30..+0x3F same format but for world 0x03
|
||||
; +0x40..+0x4F same format but for world 0x04
|
||||
; +0x50..+0x5F same format but for world 0x05
|
||||
; +0x60..+0x6F same format but for world 0x06
|
||||
; +0x70..+0x7F same format but for world 0x07
|
||||
; +0x80..+0x8F same format but for world 0x08
|
||||
; +0x90..+0x9F same format but for world 0x09
|
||||
; +0xA0..+0xAF same format but for world 0x0A
|
||||
; +0xB0..+0xBF same format but for world 0x0B
|
||||
;
|
||||
; Among other things, this means that a file filled with zeroes is valid
|
||||
; and means that no puzzles have been completed in any world and you should
|
||||
; start at the beginning. So that's nice.
|
||||
;
|
||||
lda gWorldID
|
||||
jsr FindPackedProgressAddr
|
||||
; ($FE) -> start of the 16-byte structure for this world
|
||||
; zero out all 16 bytes
|
||||
ldy #$0F
|
||||
lda #$00
|
||||
- sta ($FE), y
|
||||
dey
|
||||
bpl -
|
||||
sta checksum
|
||||
; build packed values
|
||||
ldy #0
|
||||
ldx #0
|
||||
-- lda #8
|
||||
sta bitcount
|
||||
lda #0
|
||||
sta packedvalue
|
||||
- lda PROGRESS, x
|
||||
ror
|
||||
ror packedvalue
|
||||
inx
|
||||
dec bitcount
|
||||
bne -
|
||||
lda packedvalue
|
||||
sta ($FE), y
|
||||
eor checksum
|
||||
sta checksum
|
||||
iny
|
||||
cpy #$0D
|
||||
bne --
|
||||
pla ; A = next puzzle ID (pushed earlier)
|
||||
sta ($FE), y
|
||||
eor checksum
|
||||
sta checksum
|
||||
; count number of completed puzzles
|
||||
ldy #0
|
||||
ldx #99
|
||||
- lda PROGRESS, x
|
||||
beq +
|
||||
iny
|
||||
+ dex
|
||||
bpl -
|
||||
tya ; A = number of puzzles completed (out of 100, so also the percent complete)
|
||||
ldy #$0E
|
||||
sta ($FE), y
|
||||
eor checksum
|
||||
iny
|
||||
sta ($FE), y
|
||||
lda progressRefNum
|
||||
jsr SetMarkTo0
|
||||
lda progressRefNum
|
||||
jsr WriteFile
|
||||
!word PACKEDPROGRESS
|
||||
!word $00C0
|
||||
lda progressRefNum
|
||||
jsr FlushFile
|
||||
ldy #$0D
|
||||
lda ($FE), y
|
||||
rts
|
||||
|
||||
FindPackedProgressAddr
|
||||
; in: A = world ID
|
||||
; out: ($FE) points to first byte of this world's packed progress (16-byte structure)
|
||||
; A/Y clobbered
|
||||
; X preserved
|
||||
; all flags clobbered
|
||||
pha
|
||||
+LDADDR PACKEDPROGRESS
|
||||
+ST16 $FE
|
||||
pla
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc $FE
|
||||
sta $FE
|
||||
bcc +
|
||||
inc $FF
|
||||
+ rts
|
||||
rts
|
||||
|
@ -112,6 +112,14 @@
|
||||
+
|
||||
}
|
||||
|
||||
; increment a 16-bit value stored at an address
|
||||
!macro INCADDR .addr {
|
||||
inc .addr
|
||||
bne +
|
||||
inc .addr+1
|
||||
+
|
||||
}
|
||||
|
||||
; compare a 16-bit value in A (low) and Y (high) to an absolute address
|
||||
!macro CMP16ADDR .addr {
|
||||
cmp .addr
|
||||
|
@ -10,40 +10,57 @@ row = $FD
|
||||
|
||||
!source "src/constants.a" ; no code
|
||||
!source "src/macros.a" ; no code
|
||||
!source "src/million.init.a" ; one-time initialization code
|
||||
!source "src/hw.vbl.init.a"
|
||||
!source "src/million.init.a" ; one-time initialization code, exits via Start
|
||||
!source "src/hw.vbl.init.a" ; TODO hook this up
|
||||
|
||||
FirstMover
|
||||
!pseudopc $4000 {
|
||||
Start
|
||||
jsr LoadProgressFromDisk
|
||||
jsr TitlePage
|
||||
; C set if title sequence ended prematurely (i.e. main menu requires full redraw)
|
||||
- jsr MainMenu
|
||||
; C set if main menu requires full redraw (e.g. title sequence ended prematurely)
|
||||
@GoToMainMenu
|
||||
jsr MainMenu
|
||||
bcc +
|
||||
jmp Quit
|
||||
+ sta gLevelID
|
||||
jsr MaybeLoadLevelsFromDisk ; A = level ID from 'select level' page
|
||||
bcc +
|
||||
+ sta gWorldID
|
||||
jsr MaybeLoadWorldFromDisk ; A = world ID from selection page
|
||||
bcc @PlayNext
|
||||
jmp $FF59 ; TODO
|
||||
+ ldx gLevelID
|
||||
lda kLevelLeftMargins, x
|
||||
sta GlobalLeftMargin
|
||||
lda kLevelWidths, x
|
||||
jsr InitPuzzleStorage
|
||||
lda #0
|
||||
@PlayNext
|
||||
jsr LoadProgressFromMemory
|
||||
; A = next puzzle ID
|
||||
@Play
|
||||
sta gPuzzleID
|
||||
;jsr FindNextUnsolvedPuzzle ; TODO
|
||||
|
||||
jsr ParseOnePuzzle
|
||||
|
||||
ldx gWorldID
|
||||
lda kWorldLeftMargins, x
|
||||
sta GlobalLeftMargin
|
||||
lda kPuzzleWidths, x
|
||||
jsr InitPuzzleStorage
|
||||
ldx gPuzzleID
|
||||
jsr LoadPuzzleFromMemory
|
||||
lda #0
|
||||
sta selected_logical_column
|
||||
jsr RedrawPuzzle
|
||||
sta gSelectedLogicalColumn
|
||||
jsr DrawPuzzleChrome
|
||||
jsr ClearAndDrawPuzzle
|
||||
jsr AnimatePuzzleIntoPlace
|
||||
jsr DrawColumnSelectionIndicator
|
||||
jsr PlayEventLoop
|
||||
cmp #kCompletedPuzzle
|
||||
bne +
|
||||
jsr AnimatePuzzleCompleted
|
||||
ldx gPuzzleID
|
||||
jsr MarkPuzzleCompleted
|
||||
; A - next puzzle ID
|
||||
jmp @Play
|
||||
+ cmp #kRequestedRestart
|
||||
bne +
|
||||
jsr Home
|
||||
lda gPuzzleID
|
||||
jmp @Play
|
||||
+
|
||||
sec
|
||||
bcs - ; always branches
|
||||
bcs @GoToMainMenu
|
||||
|
||||
!source "src/puzzle.a"
|
||||
!source "src/hw.vbl.a"
|
||||
|
52
src/puzzle.a
52
src/puzzle.a
@ -3,11 +3,28 @@
|
||||
;
|
||||
; data storage routines for puzzles
|
||||
;
|
||||
; Public functions:
|
||||
; - InitPuzzleStorage
|
||||
; - AddLineToPuzzle
|
||||
; - AddTargetWordToPuzzle
|
||||
; - CheckForTargetWord
|
||||
; - FindLetterInColumn
|
||||
; - ScrollPuzzleDown
|
||||
; - ScrollPuzzleUp
|
||||
; - IsPuzzleComplete
|
||||
|
||||
|
||||
puzzle_logical_width = $0300 ; [0x01 byte ] number of letters per word (4..7)
|
||||
puzzle_logical_height = $0301 ; [0x01 byte ] number of rows with letters (1..5)
|
||||
puzzle_offsets = $0302 ; [0x08 bytes] how far each column has been scrolled down from top of grid
|
||||
puzzle_data = $030A ; [0x08 bytes] character data
|
||||
|
||||
; 9 rows of data for current puzzle
|
||||
; each byte is one of
|
||||
; - letter with high bit off (unmatched letter)
|
||||
; - letter with high bit on (matched letter, displayed in grey)
|
||||
; - 0x00 (unused space)
|
||||
; if letters per word is less than 7, extra bytes at end of each row are guaranteed to be 0x00
|
||||
puzzle_data0 = $030A ; [0x08 bytes] character data
|
||||
puzzle_data1 = $0312 ; [0x08 bytes]
|
||||
puzzle_data2 = $031A ; [0x08 bytes]
|
||||
puzzle_data3 = $0322 ; [0x08 bytes]
|
||||
@ -24,17 +41,11 @@ puzzle_words = $0353 ; [0x80 bytes]
|
||||
InitPuzzleStorage
|
||||
; in: A = logical puzzle width (number of letters in each word, 4..7)
|
||||
sta puzzle_logical_width
|
||||
ldx #$CF
|
||||
lda #0
|
||||
sta puzzle_logical_height
|
||||
sta puzzle_word_count
|
||||
ldx #8
|
||||
- sta puzzle_offsets-1, x
|
||||
- sta puzzle_logical_width, x
|
||||
dex
|
||||
bne -
|
||||
ldx #$7F
|
||||
- sta puzzle_words, x
|
||||
dex
|
||||
bpl -
|
||||
rts
|
||||
|
||||
AddLineToPuzzle
|
||||
@ -47,7 +58,7 @@ AddLineToPuzzle
|
||||
tax
|
||||
ldy #0
|
||||
- lda ($FE), y
|
||||
sta puzzle_data, x
|
||||
sta puzzle_data0, x
|
||||
inx
|
||||
iny
|
||||
cpy puzzle_logical_width
|
||||
@ -152,11 +163,11 @@ ScrollPuzzleDown
|
||||
lda puzzle_data1, y
|
||||
sta puzzle_data2, y
|
||||
|
||||
lda puzzle_data, y
|
||||
lda puzzle_data0, y
|
||||
sta puzzle_data1, y
|
||||
|
||||
lda #0
|
||||
sta puzzle_data, y
|
||||
sta puzzle_data0, y
|
||||
|
||||
lda puzzle_offsets, y
|
||||
clc
|
||||
@ -179,7 +190,7 @@ ScrollPuzzleUp
|
||||
beq @fail
|
||||
|
||||
lda puzzle_data1, y
|
||||
sta puzzle_data, y
|
||||
sta puzzle_data0, y
|
||||
|
||||
lda puzzle_data2, y
|
||||
sta puzzle_data1, y
|
||||
@ -213,3 +224,18 @@ ScrollPuzzleUp
|
||||
rts
|
||||
@fail sec
|
||||
rts
|
||||
|
||||
IsPuzzleComplete
|
||||
; out: C clear if puzzle is complete (all letters have been matched)
|
||||
; C set if puzzle is not yet complete
|
||||
ldx #$47
|
||||
- lda puzzle_data0, x
|
||||
beq @keepChecking
|
||||
bmi @keepChecking
|
||||
sec
|
||||
rts
|
||||
@keepChecking
|
||||
dex
|
||||
bpl -
|
||||
clc
|
||||
rts
|
||||
|
@ -113,3 +113,56 @@ SoftBell
|
||||
dex
|
||||
bne -
|
||||
rts
|
||||
|
||||
nonZeroDigits = $EE
|
||||
paddingCharacter = $EF
|
||||
ToASCIIString
|
||||
; convert byte value to length-prefixed 3-digit decimal number as ASCII string with given padding character
|
||||
; in: X = any number (0..255 obviously)
|
||||
; A = padding character (e.g. '0' or ' ')
|
||||
; out: $F1 = 0x03
|
||||
; $F2..$F4 = ASCII digits of decimal representation
|
||||
; clobbers $EE,$EF,$F0
|
||||
; all flags & registers clobbered
|
||||
sta paddingCharacter
|
||||
stx $F0
|
||||
ldx #0
|
||||
stx nonZeroDigits
|
||||
stx $F1
|
||||
@outer lda #0
|
||||
pha
|
||||
@inner lda $F0
|
||||
cmp @kPowersOfTen, x
|
||||
bcc @digitDone
|
||||
sbc @kPowersOfTen, x
|
||||
sta $F0
|
||||
lda $F1
|
||||
sbc #0
|
||||
sta $F1
|
||||
pla
|
||||
adc #0
|
||||
pha
|
||||
jmp @inner
|
||||
@digitDone
|
||||
pla
|
||||
beq @maybeUsePaddingChar
|
||||
inc nonZeroDigits
|
||||
- ora #$30
|
||||
bne + ; always branches
|
||||
@maybeUsePaddingChar
|
||||
cpx #2
|
||||
beq -
|
||||
ldy nonZeroDigits
|
||||
bne -
|
||||
lda paddingCharacter
|
||||
+ sta $F2, x
|
||||
inx
|
||||
cpx #$03
|
||||
bcc @outer
|
||||
lda #3 ; length byte
|
||||
sta $F1
|
||||
rts
|
||||
@kPowersOfTen
|
||||
!byte 100
|
||||
!byte 10
|
||||
!byte 1
|
||||
|
@ -13,8 +13,8 @@ MainMenu
|
||||
; C set if full screen clear & redraw is required
|
||||
; (will happen if key is pressed during title screen, or
|
||||
; if user returns to main menu from play or any other screen)
|
||||
; out: C clear if user selected a level to play, and
|
||||
; A = level ID
|
||||
; out: C clear if user selected a world to play, and
|
||||
; A = world ID
|
||||
; C set if user selected quit
|
||||
bcc @noredraw
|
||||
jsr Home
|
||||
@ -22,13 +22,13 @@ MainMenu
|
||||
sta GlobalLeftMargin
|
||||
ldy #3
|
||||
- ldx #1
|
||||
lda titleline1-2, y
|
||||
lda kTitleLine1-2, y
|
||||
jsr DrawLargeCharacter
|
||||
inx
|
||||
lda titleline2-2, y
|
||||
lda kTitleLine2-2, y
|
||||
jsr DrawLargeCharacter
|
||||
inx
|
||||
lda titleline3-2, y
|
||||
lda kTitleLine3-2, y
|
||||
jsr DrawLargeCharacter
|
||||
iny
|
||||
cpy #$0A
|
||||
@ -53,9 +53,9 @@ MainMenu
|
||||
jsr SoftBell
|
||||
jmp -
|
||||
@eventReturn
|
||||
jsr SelectLevel
|
||||
jsr SelectWorld
|
||||
bcs @noselection
|
||||
rts ; return to caller with A = level ID
|
||||
rts ; return to caller with A = world ID
|
||||
@noselection
|
||||
jmp MainMenu ; C is already set so this will do a full redraw
|
||||
@eventEsc
|
||||
@ -63,27 +63,27 @@ MainMenu
|
||||
rts
|
||||
|
||||
counter = $F2
|
||||
selectedlevel = $F3
|
||||
selectedworld = $F3
|
||||
|
||||
SelectLevel
|
||||
SelectWorld
|
||||
; in: none
|
||||
; out: C clear if level was selected, and
|
||||
; A = 0-based level ID
|
||||
; C set if no level was selected and A is undefined
|
||||
; out: C clear if world was selected, and
|
||||
; A = 0-based world ID
|
||||
; C set if no world was selected and A is undefined
|
||||
jsr Home
|
||||
|
||||
+LDADDR leveldescriptions ; TODO update level descriptions with % complete
|
||||
jsr UpdateWorldPercents
|
||||
+LDADDR worlddescriptions
|
||||
+ST16 $FE
|
||||
lda #0
|
||||
sta counter
|
||||
sta selectedlevel ; TODO set selected level from prefs
|
||||
sta selectedworld ; TODO set selected world from prefs
|
||||
lda #6
|
||||
sta VTAB
|
||||
- lda #10
|
||||
sta HTAB
|
||||
+LD16 $FE
|
||||
ldx counter
|
||||
cpx selectedlevel
|
||||
cpx selectedworld
|
||||
beq +
|
||||
ldx #20
|
||||
jsr DrawHeavySilkBuffer
|
||||
@ -102,12 +102,12 @@ SelectLevel
|
||||
cmp #12
|
||||
bcc -
|
||||
|
||||
+PRINT_AT levelhelp, 23, 0
|
||||
+PRINT_AT worldhelp, 23, 0
|
||||
|
||||
bit CLEARKBD
|
||||
@selectLevelLoop
|
||||
@selectWorldLoop
|
||||
lda KBD
|
||||
bpl @selectLevelLoop
|
||||
bpl @selectWorldLoop
|
||||
bit CLEARKBD
|
||||
and #$7F
|
||||
cmp #$0B ; up arrow
|
||||
@ -125,7 +125,7 @@ SelectLevel
|
||||
rts
|
||||
@eventReturn
|
||||
jsr Home
|
||||
lda selectedlevel
|
||||
lda selectedworld
|
||||
clc
|
||||
rts
|
||||
@eventEsc
|
||||
@ -133,56 +133,56 @@ SelectLevel
|
||||
rts
|
||||
@eventLeftArrow
|
||||
@eventUpArrow
|
||||
jsr RedrawPreviouslySelectedLevel
|
||||
ldx selectedlevel
|
||||
jsr RedrawPreviouslySelectedWorld
|
||||
ldx selectedworld
|
||||
bne +
|
||||
ldx #12
|
||||
+ dex
|
||||
stx selectedlevel
|
||||
jsr DrawNewlySelectedLevel
|
||||
jmp @selectLevelLoop
|
||||
stx selectedworld
|
||||
jsr DrawNewlySelectedWorld
|
||||
jmp @selectWorldLoop
|
||||
@eventRightArrow
|
||||
@eventDownArrow
|
||||
jsr RedrawPreviouslySelectedLevel
|
||||
ldx selectedlevel
|
||||
jsr RedrawPreviouslySelectedWorld
|
||||
ldx selectedworld
|
||||
cpx #11
|
||||
bne +
|
||||
ldx #$FF
|
||||
+ inx
|
||||
stx selectedlevel
|
||||
jsr DrawNewlySelectedLevel
|
||||
jmp @selectLevelLoop
|
||||
stx selectedworld
|
||||
jsr DrawNewlySelectedWorld
|
||||
jmp @selectWorldLoop
|
||||
|
||||
RedrawPreviouslySelectedLevel
|
||||
lda selectedlevel
|
||||
RedrawPreviouslySelectedWorld
|
||||
lda selectedworld
|
||||
tax
|
||||
clc
|
||||
adc #6
|
||||
sta VTAB
|
||||
lda #10
|
||||
sta HTAB
|
||||
jsr GetLevelDescription
|
||||
jsr GetWorldDescription
|
||||
+LD16 $FE
|
||||
ldx #20
|
||||
jmp DrawHeavySilkBuffer
|
||||
|
||||
DrawNewlySelectedLevel
|
||||
lda selectedlevel
|
||||
DrawNewlySelectedWorld
|
||||
lda selectedworld
|
||||
tax
|
||||
clc
|
||||
adc #6
|
||||
sta VTAB
|
||||
lda #10
|
||||
sta HTAB
|
||||
jsr GetLevelDescription
|
||||
jsr GetWorldDescription
|
||||
+LD16 $FE
|
||||
ldx #20
|
||||
jmp DrawHeavySilkBufferInverse
|
||||
|
||||
GetLevelDescription
|
||||
; in: X = 0-based level ID
|
||||
; out: $FE/$FF points to level description buffer
|
||||
+LDADDR leveldescriptions
|
||||
GetWorldDescription
|
||||
; in: X = 0-based world ID
|
||||
; out: $FE/$FF points to world description buffer
|
||||
+LDADDR worlddescriptions
|
||||
+ST16 $FE
|
||||
jmp +
|
||||
- lda $FE
|
||||
@ -195,6 +195,37 @@ GetLevelDescription
|
||||
bpl -
|
||||
rts
|
||||
|
||||
worldindex=$FB
|
||||
UpdateWorldPercents
|
||||
+LDADDR worlddescriptions
|
||||
+ST16 $FC
|
||||
lda #0
|
||||
sta worldindex
|
||||
-- jsr FindPackedProgressAddr
|
||||
ldy #$0E
|
||||
lda ($FE), y
|
||||
tax
|
||||
lda #$20
|
||||
jsr ToASCIIString
|
||||
ldx #2
|
||||
ldy #17
|
||||
- lda $F2, x
|
||||
sta ($FC), y
|
||||
dey
|
||||
dex
|
||||
bpl -
|
||||
lda $FC
|
||||
clc
|
||||
adc #20
|
||||
sta $FC
|
||||
bcc +
|
||||
inc $FD
|
||||
+ inc worldindex
|
||||
lda worldindex
|
||||
cmp #12
|
||||
bne --
|
||||
rts
|
||||
|
||||
asterisk
|
||||
!byte 1
|
||||
!byte "*"
|
||||
@ -214,7 +245,7 @@ disclaimer
|
||||
!byte 40
|
||||
!raw "* NOT GUARANTEED, ACTUAL COUNT MAY VARY."
|
||||
|
||||
leveldescriptions
|
||||
worlddescriptions
|
||||
!raw " 4X3, EASY 0% "
|
||||
!raw " 5X3, BASIC 0% "
|
||||
!raw " 6X3, SIMPLE 0% "
|
||||
@ -228,6 +259,36 @@ leveldescriptions
|
||||
!raw " 6X5, TRICKY 0% "
|
||||
!raw " 7X5, COMPLEX 0% "
|
||||
|
||||
levelhelp
|
||||
kWorldShortNames
|
||||
!byte 3
|
||||
!raw "4X3"
|
||||
!byte 3
|
||||
!raw "5X3"
|
||||
!byte 3
|
||||
!raw "6X3"
|
||||
!byte 3
|
||||
!raw "7X3"
|
||||
!byte 3
|
||||
!raw "4X4"
|
||||
!byte 3
|
||||
!raw "5X4"
|
||||
!byte 3
|
||||
!raw "6X4"
|
||||
!byte 3
|
||||
!raw "7X4"
|
||||
!byte 3
|
||||
!raw "4X5"
|
||||
!byte 3
|
||||
!raw "5X5"
|
||||
!byte 3
|
||||
!raw "6X5"
|
||||
!byte 3
|
||||
!raw "7X5"
|
||||
|
||||
kDash
|
||||
!byte 1
|
||||
!raw "-"
|
||||
|
||||
worldhelp
|
||||
!byte 40
|
||||
!raw "ARROWS TO SELECT, RETURN TO PLAY, OR ESC"
|
||||
|
336
src/ui.play.a
336
src/ui.play.a
@ -5,17 +5,26 @@
|
||||
;
|
||||
; Public functions:
|
||||
; - PlayEventLoop
|
||||
; - ClearAndDrawPuzzle
|
||||
; - DrawPuzzleChrome
|
||||
; - AnimatePuzzleIntoPlace
|
||||
; - AnimatePuzzleCompleted
|
||||
;
|
||||
|
||||
selected_logical_column
|
||||
; codes returned from PlayEventLoop to explain why the event loop ended
|
||||
kCompletedPuzzle = 1
|
||||
kRequestedRestart = 2
|
||||
kPressedEsc = 3
|
||||
|
||||
gSelectedLogicalColumn
|
||||
!byte 0
|
||||
|
||||
kLevelLeftMargins
|
||||
kWorldLeftMargins
|
||||
!byte 15,13,12,10
|
||||
!byte 15,13,12,10
|
||||
!byte 15,13,12,10
|
||||
|
||||
kLevelRightMargins
|
||||
kWorldRightMargins
|
||||
!byte 27,28,30,31
|
||||
!byte 27,28,30,31
|
||||
!byte 27,28,30,31
|
||||
@ -23,6 +32,15 @@ kLevelRightMargins
|
||||
kStartingColor
|
||||
!byte $D5,$AA
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; PlayEventLoop
|
||||
; main event loop for playing a puzzle
|
||||
;
|
||||
; in: puzzle has been loaded into memory, drawn on screen, animated, &c.
|
||||
; and is ready to play
|
||||
; out: A = reason why event loop ended (see list above)
|
||||
; all other registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
PlayEventLoop
|
||||
bit CLEARKBD
|
||||
- lda KBD
|
||||
@ -39,6 +57,8 @@ PlayEventLoop
|
||||
beq @eventRightArrow
|
||||
cmp #$1B ; Esc
|
||||
beq @eventEsc
|
||||
cmp #$12 ; Ctrl-R
|
||||
beq @eventCtrlR
|
||||
cmp #$61
|
||||
bcc +
|
||||
and #$DF
|
||||
@ -46,54 +66,65 @@ PlayEventLoop
|
||||
bcc +
|
||||
cmp #$5B
|
||||
bcs +
|
||||
jsr @eventLetter
|
||||
jmp @eventLetter
|
||||
+ jmp PlayEventLoop
|
||||
|
||||
@eventLeftArrow
|
||||
ldy selected_logical_column
|
||||
ldy gSelectedLogicalColumn
|
||||
jsr EraseColumnSelectionIndicator
|
||||
bne +
|
||||
ldy puzzle_logical_width
|
||||
+ dey
|
||||
sty selected_logical_column
|
||||
sty gSelectedLogicalColumn
|
||||
jsr DrawColumnSelectionIndicator
|
||||
jmp @done
|
||||
jmp PlayEventLoop
|
||||
|
||||
@eventRightArrow
|
||||
ldy selected_logical_column
|
||||
ldy gSelectedLogicalColumn
|
||||
jsr EraseColumnSelectionIndicator
|
||||
iny
|
||||
cpy puzzle_logical_width
|
||||
bcc +
|
||||
ldy #0
|
||||
+ sty selected_logical_column
|
||||
+ sty gSelectedLogicalColumn
|
||||
jsr DrawColumnSelectionIndicator
|
||||
jmp @done
|
||||
jmp PlayEventLoop
|
||||
|
||||
@eventLetter
|
||||
ldy selected_logical_column
|
||||
ldy gSelectedLogicalColumn
|
||||
jsr FindLetterInColumn
|
||||
bcs +
|
||||
; TODO
|
||||
jmp PlayEventLoop
|
||||
|
||||
@eventEsc
|
||||
+ rts
|
||||
lda #kPressedEsc
|
||||
rts
|
||||
|
||||
@eventCtrlR
|
||||
lda #kRequestedRestart
|
||||
rts
|
||||
|
||||
@eventUpArrow
|
||||
ldy selected_logical_column
|
||||
ldy gSelectedLogicalColumn
|
||||
jsr ScrollPuzzleUp
|
||||
bcs @fail
|
||||
jsr ScrollUp
|
||||
jsr CheckForTargetWord
|
||||
bcc FoundTargetWord
|
||||
bcc @foundTargetWord
|
||||
bcs @done
|
||||
@fail jsr SoftBell
|
||||
@done jmp PlayEventLoop
|
||||
|
||||
@eventDownArrow
|
||||
ldy selected_logical_column
|
||||
ldy gSelectedLogicalColumn
|
||||
jsr ScrollPuzzleDown
|
||||
bcs @fail
|
||||
jsr ScrollDown
|
||||
jsr CheckForTargetWord
|
||||
bcc FoundTargetWord
|
||||
bcs @done ; always branches
|
||||
bcc @foundTargetWord
|
||||
bcs @done
|
||||
|
||||
FoundTargetWord
|
||||
@foundTargetWord
|
||||
ldx #4
|
||||
ldy #0
|
||||
- lda puzzle_data4, y
|
||||
@ -101,90 +132,24 @@ FoundTargetWord
|
||||
iny
|
||||
cpy puzzle_logical_width
|
||||
bne -
|
||||
; TODO check whether puzzle is complete
|
||||
jmp PlayEventLoop
|
||||
|
||||
DrawThinLines
|
||||
ldx #$55
|
||||
jsr DrawThinLine
|
||||
ldx #$6B
|
||||
; /!\ execution falls through here
|
||||
DrawThinLine
|
||||
; in: X = HGR row (0x00..0xBF)
|
||||
ldy HGRLO, x
|
||||
sty $FE
|
||||
ldy HGRHI, x
|
||||
sty $FF
|
||||
ldx gLevelID
|
||||
ldy kLevelRightMargins, x
|
||||
sty @right+1
|
||||
ldy GlobalLeftMargin
|
||||
dey
|
||||
tya
|
||||
and #1
|
||||
tax
|
||||
lda kStartingColor, x
|
||||
- sta ($FE), y
|
||||
eor #$7F
|
||||
iny
|
||||
@right cpy #$FD ; SMC
|
||||
bcc -
|
||||
jsr IsPuzzleComplete
|
||||
bcs @done
|
||||
lda #kCompletedPuzzle
|
||||
rts
|
||||
|
||||
EraseColumnSelectionIndicator
|
||||
; out: preserves X/Y
|
||||
stx @x+1
|
||||
sty @y+1
|
||||
;------------------------------------------------------------------------------
|
||||
; ClearAndDrawPuzzle
|
||||
; clears screen and draws current puzzle (but not column selection indicator or
|
||||
; other UI elements)
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
ClearAndDrawPuzzle
|
||||
; jsr Home
|
||||
; bit TEXTMODE
|
||||
jsr DrawThinLines
|
||||
@x ldx #$FD ; SMC
|
||||
@y ldy #$FD ; SMC
|
||||
rts
|
||||
|
||||
DrawColumnSelectionIndicator
|
||||
; out: preserves X/Y
|
||||
stx @x+1
|
||||
sty @y+1
|
||||
ldx #$55
|
||||
jsr DrawOneSelectionIndicator
|
||||
ldx #$6B
|
||||
jsr DrawOneSelectionIndicator
|
||||
@x ldx #$FD ; SMC
|
||||
@y ldy #$FD ; SMC
|
||||
rts
|
||||
|
||||
DrawOneSelectionIndicator
|
||||
lda HGRLO, x
|
||||
sta $FE
|
||||
lda HGRHI, x
|
||||
sta $FF
|
||||
ldy GlobalLeftMargin
|
||||
dey
|
||||
tya
|
||||
and #1
|
||||
eor #1
|
||||
tax
|
||||
lda kStartingColor, x
|
||||
ldx selected_logical_column
|
||||
beq +
|
||||
- iny
|
||||
iny
|
||||
iny
|
||||
eor #$7F
|
||||
dex
|
||||
bne -
|
||||
+ ldx #4
|
||||
- sta ($FE), y
|
||||
eor #$7F
|
||||
iny
|
||||
dex
|
||||
bne -
|
||||
rts
|
||||
|
||||
RedrawPuzzle
|
||||
jsr Home
|
||||
bit TEXTMODE
|
||||
jsr DrawThinLines
|
||||
+LDADDR puzzle_data
|
||||
+LDADDR puzzle_data0
|
||||
+ST16 $FE
|
||||
ldx #0 ; logical row
|
||||
-- ldy #0 ; logical column
|
||||
@ -206,9 +171,15 @@ RedrawPuzzle
|
||||
bit GFXMODE
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; AnimatePuzzleIntoPlace
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
AnimatePuzzleIntoPlace
|
||||
ldx gLevelID
|
||||
ldy kLevelWidths, x
|
||||
ldx gWorldID
|
||||
ldy kPuzzleWidths, x
|
||||
sty @max+1
|
||||
ldy #0
|
||||
-- ldx #4
|
||||
@ -220,3 +191,164 @@ AnimatePuzzleIntoPlace
|
||||
@max cpy #$FD ; SMC
|
||||
bne --
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; DrawPuzzleChrome
|
||||
; draw all elements on puzzle screen that are not the actual puzzle
|
||||
; (e.g. column selection indicator, game title, help text)
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
DrawPuzzleChrome
|
||||
+PRINT_AT kTitleLine1, 0, 0
|
||||
+PRINT_AT kTitleLine2, 1, 0
|
||||
+PRINT_AT kTitleLine3, 2, 0
|
||||
+LDADDR kWorldShortNames
|
||||
+ST16 $FE
|
||||
lda gWorldID
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc $FE
|
||||
sta $FE
|
||||
bcc +
|
||||
inc $FF
|
||||
+
|
||||
lda #4
|
||||
sta VTAB
|
||||
lda #0
|
||||
sta HTAB
|
||||
+LD16 $FE
|
||||
jsr DrawHeavySilkString
|
||||
+LDADDR kDash
|
||||
jsr DrawHeavySilkString
|
||||
ldx gPuzzleID
|
||||
inx ; visible puzzle number is 1-based
|
||||
lda #$30 ; padding character ('0')
|
||||
jsr ToASCIIString
|
||||
+LDADDR $00F1
|
||||
jsr DrawHeavySilkString
|
||||
jmp DrawColumnSelectionIndicator
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; AnimatePuzzleCompleted
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
AnimatePuzzleCompleted
|
||||
jsr DrawThinLines
|
||||
ldx gWorldID
|
||||
lda kPuzzleWidths, x
|
||||
sta @max+1
|
||||
ldy #0
|
||||
ldx #0
|
||||
- jsr ScrollDown
|
||||
inc puzzle_offsets, x
|
||||
lda puzzle_offsets, x
|
||||
cmp #9
|
||||
bne -
|
||||
inx
|
||||
iny
|
||||
@max cpy #$FD ; SMC
|
||||
bne -
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; DrawThinLines [private]
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
DrawThinLines
|
||||
ldx #$55
|
||||
jsr DrawThinLine
|
||||
ldx #$6B
|
||||
; /!\ execution falls through here
|
||||
DrawThinLine
|
||||
; in: X = HGR row (0x00..0xBF)
|
||||
ldy HGRLO, x
|
||||
sty $FE
|
||||
ldy HGRHI, x
|
||||
sty $FF
|
||||
ldx gWorldID
|
||||
ldy kWorldRightMargins, x
|
||||
sty @right+1
|
||||
ldy GlobalLeftMargin
|
||||
dey
|
||||
tya
|
||||
and #1
|
||||
tax
|
||||
lda kStartingColor, x
|
||||
- sta ($FE), y
|
||||
eor #$7F
|
||||
iny
|
||||
@right cpy #$FD ; SMC
|
||||
bcc -
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; EraseColumnSelectionIndicator [private]
|
||||
;
|
||||
; in: none
|
||||
; out: preserves X/Y
|
||||
;------------------------------------------------------------------------------
|
||||
EraseColumnSelectionIndicator
|
||||
stx @x+1
|
||||
sty @y+1
|
||||
jsr DrawThinLines
|
||||
@x ldx #$FD ; SMC
|
||||
@y ldy #$FD ; SMC
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; DrawColumnSelectionIndicator [private]
|
||||
;
|
||||
; in: none
|
||||
; out: preserves X/Y
|
||||
;------------------------------------------------------------------------------
|
||||
DrawColumnSelectionIndicator
|
||||
stx @x+1
|
||||
sty @y+1
|
||||
ldx #$55
|
||||
jsr DrawOneSelectionIndicator
|
||||
ldx #$6B
|
||||
jsr DrawOneSelectionIndicator
|
||||
@x ldx #$FD ; SMC
|
||||
@y ldy #$FD ; SMC
|
||||
rts
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; DrawOneSelectionIndicator [private]
|
||||
;
|
||||
; in: none
|
||||
; out: all registers and flags clobbered
|
||||
;------------------------------------------------------------------------------
|
||||
DrawOneSelectionIndicator
|
||||
lda HGRLO, x
|
||||
sta $FE
|
||||
lda HGRHI, x
|
||||
sta $FF
|
||||
ldy GlobalLeftMargin
|
||||
dey
|
||||
tya
|
||||
and #1
|
||||
eor #1
|
||||
tax
|
||||
lda kStartingColor, x
|
||||
ldx gSelectedLogicalColumn
|
||||
beq +
|
||||
- iny
|
||||
iny
|
||||
iny
|
||||
eor #$7F
|
||||
dex
|
||||
bne -
|
||||
+ ldx #4
|
||||
- sta ($FE), y
|
||||
eor #$7F
|
||||
iny
|
||||
dex
|
||||
bne -
|
||||
rts
|
||||
|
@ -7,19 +7,19 @@
|
||||
; Public functions:
|
||||
; - TitlePage
|
||||
;
|
||||
; Public variables:
|
||||
; - titleline1
|
||||
; - titleline2
|
||||
; - titleline3
|
||||
; Public constants:
|
||||
; - kTitleLine1
|
||||
; - kTitleLine2
|
||||
; - kTitleLine3
|
||||
|
||||
titlechar = $FD
|
||||
titleline1
|
||||
kTitleLine1
|
||||
!byte 7
|
||||
!raw "MILLION"
|
||||
titleline2
|
||||
kTitleLine2
|
||||
!byte 7
|
||||
!raw "PERFECT"
|
||||
titleline3
|
||||
kTitleLine3
|
||||
!byte 7
|
||||
!raw "LETTERS"
|
||||
|
||||
@ -79,11 +79,11 @@ TitlePage
|
||||
beq @line3
|
||||
@random lda titlechar
|
||||
jmp + ; can't use a BNE because <titlechar> will actually be 0 the third time around
|
||||
@line1 lda titleline1-2, y
|
||||
@line1 lda kTitleLine1-2, y
|
||||
bne +
|
||||
@line2 lda titleline2-2, y
|
||||
@line2 lda kTitleLine2-2, y
|
||||
bne +
|
||||
@line3 lda titleline3-2, y
|
||||
@line3 lda kTitleLine3-2, y
|
||||
+ jsr DrawLargeCharacter
|
||||
lda titlechar
|
||||
beq +
|
||||
|
Loading…
x
Reference in New Issue
Block a user