Compare commits

..

No commits in common. "master" and "compression" have entirely different histories.

30 changed files with 3024 additions and 2476 deletions

View File

@ -1,36 +1,19 @@
.POSIX:
ASM=$(wildcard src/*.asm)
RES=res.bin/amour2.sid res.bin/levels.bin res.bin/unlzg.bin
RES=res.bin/amour.sid res.bin/levels.bin res.bin/unlzg.bin
.PHONY: debug env clean all
.PHONY: debug env clean
all: bin/snake6502.bin bin/snake6502.d64
bin/snake6502.bin: bin/snake.pack.lz
dasm src/cart.asm -Isrc/ -f3 -T1 -sbuild/cart.symbols.txt -obin/snake6502.bin
bin/snake6502.d64: bin/loader.prg
c1541 -format "snake6502,01" d64 bin/snake6502.d64
c1541 -attach bin/snake6502.d64 -write bin/loader.prg loader
c1541 -attach bin/snake6502.d64 -write bin/snake.pack.lz.prg packlz
bin/loader.prg: bin/snake.pack.lz.prg
dasm src/loader.asm -Isrc/ -f1 -sbuild/loader.sybols.txt -obin/loader.prg
bin/snake.prg: bin/snake.pack
dasm src/prg.asm -Isrc/ -f1 -T1 -sbuild/prg.symbols.txt -obin/snake.prg
bin/snake.bin: bin/snake.pack.lz
dasm src/cart.asm -Isrc/ -DVERBOSE=$(VERBOSE) -f3 -sbuild/cart.symbols.txt -obin/snake.bin
bin/snake.pack: env $(ASM) $(RES) bin/explodefont
dasm src/main.asm -Isrc/ -DSYSTEM=64 -DDEBUG=$(DEBUG) -f3 -T1 -sbuild/pack.symbols.txt -obin/snake.pack
dasm src/main.asm -Isrc/ -DSYSTEM=64 -DDEBUG=$(DEBUG) -DVERBOSE=$(VERBOSE) -DCARTRIDGE=$(CARTRIDGE) -f3 -sbuild/pack.symbols.txt -obin/snake.pack
bin/snake.pack.lz: bin/snake.pack liblzg/src/tools/lzg
liblzg/src/tools/lzg bin/snake.pack > bin/snake.pack.lz
bin/snake.pack.lz.prg: bin/snake.pack.lz
echo -n -e "\x00\x80" > bin/snake.pack.lz.prg
cat bin/snake.pack.lz >> bin/snake.pack.lz.prg
liblzg/src/tools/lzg:
cd liblzg/src && make
@ -43,8 +26,8 @@ env:
bin/explodefont: util/explodefont.cpp
g++ -o bin/explodefont util/explodefont.cpp
res.bin/amour2.sid:
cp res.org/amour2.sid res.bin/amour2.sid
res.bin/amour.sid:
cp res.org/amour.sid res.bin/amour.sid
res.bin/levels.bin: bin/level res.org/levels.txt
bin/level < res.org/levels.txt > res.bin/levels.bin

View File

@ -1,35 +1,23 @@
# snake6502
![Intro screenshot](scrot/intro.png)
![Gameplay screenshot](scrot/gameplay.png)
*snake6502* is a snake-like game clone for Commodore home computers, written for fun because «I always wanted to code something for a computer of my retrocomputers collection actually, this is the main reason I collect them: to write programs».
Current development status [here](https://git.giomba.it/giomba/snake6502).
Download the [binary .prg](dist/snake.prg).
## Download
* [.d64](dist/snake6502.d64) for floppy disks
* [.bin](dist/snake6502.bin) for 8KiB cartridges
Current development status [here](https://git.giomba.it/giomba/snake6502).
## Compile
You need the GNU compiler collection and the [dasm](https://dasm-assembler.github.io/) macro assembler, then:
```
$ git submodule init
$ git submodule update
$ make
```
Interesting targets:
* ```make bin/snake6502.bin``` produces .bin, ready to be burnt on an 8K EEPROM for making a cartridge
* ```make bin/snake6502.d64``` produces .d64, ready to be used for floppy disks
You can also define the following environment variables:
```$ DEBUG=1 make``` build with debugging artifacts
## Tape
Copy ```loader.prg``` and ```packlz``` from disk to tape.
On a physical machine, you can use [disk2tape](https://git.giomba.it/giomba/cbmutil).
```$ VERBOSE=1 make``` output useful info during compilation
## Developer docs
### Package
@ -46,55 +34,30 @@ Address | PRG | Description
```$0000 - $0001``` | no | hardware
```$0002 - $00FF``` | no | zero page pointers
```$0100 - $01FF``` | no | stack page
```$0200 - $03FF``` | no | operating system variables
```$0400 - $07FF``` | no | video memory
```$1000 - $1FFF``` | yes | SID tune, may overlap charset
```$2000 - $23FF``` | yes | custom char, unused, allow SID overlap
```$2400 - $27FF``` | yes | custom char (actual 0x80+)
```$0200 - $07FF``` | no | *free ram*
```$1000 - $1FFF``` | yes | SID tune
```$2000 - $27FF``` | yes | custom char
```$2800 - $xxxx``` | yes | Program segment (only needed part used)
```$xxxx - $CCFF``` | no | *free ram*
```$CD00 - $CFFF``` | no | data segment (not-initialized vars)
```$CD00 - $CDFF``` | no | data segment (not-initialized vars)
```$CE00 - $CEFF``` | no | list X
```$CF00 - $CFFF``` | no | list Y
```$D000 - $DFFF``` | no | I/O
```$E000 - $FFFF``` | no | Kernal
### Compression
```snake.pack``` is compressed into ```snake.pack.lz``` using [liblzg](https://github.com/mbitsnbites/liblzg), to save space, mainly in order to fit the game in a *PROM.
Decompression occurs with one of the following loaders.
```snake.pack``` is compressed into ```snake.pack.lz``` using [liblzg](https://github.com/mbitsnbites/liblzg), to save space in order to fit the game in a *PROM.
### Loader
#### Cartridge
### Decompression
```cart.asm``` is located at ```$8000``` (standard org address for C64 cartridges), and contains the decompression routine and the ```snake.pack.lz```. It decompresses ```snake.pack.lz``` back to ```$1000```, and jumps to its entry point at ```$2800```.
#### Disk
```loader.asm``` loads at ```$801```, like any other BASIC automatic runner, and contains the decompression routine.
```snake.pack.lz``` is loaded at ```$8000``` from disk drive, then decompressed back to ```$1000```, and finally the loader jumps to the program entry point at ```$2800```.
### Miscellanea
#### Custom charset
Index | Description
----------------|-------------
```$00 - $7F``` | unused (space for SID)
```$80 - $9F``` | A-Z (space first)
```$A0 - $BF``` | A-Z, reversed (space first)
```$C0 - $CF``` | hex digits
```$D0 - $DF``` | hex digits, reversed
```$E0 - $EF``` | game tiles
```$F0 - $FF``` | semigraphic tiles
##### Semigrahic Tiles
Char | Output
----------|--------
```$F0``` | ```◜```
```$F1``` | ```◝```
```$F2``` | ```◟```
```$F3``` | ```◞```
```$F4``` | ```-```
```$F5``` | ```|```
```$F6``` | ```◢```
```$F7``` | ```◣```
```$F8``` | ```◥```
```$F9``` | ```◤```
```$FA``` | ```┴```
```$FB``` | ```┬```
```$FC``` | ```┤```
```$FD``` | ```├```
```$00 - $1F``` | A-Z (space first)
```$20 - $3F``` | A-Z, reversed (space first)
```$40 - $4F``` | hex digits
```$50 - $5F``` | hex digits, reversed
```$60 - ``` | game tiles

BIN
dist/snake.prg vendored Normal file

Binary file not shown.

BIN
dist/snake6502.bin vendored

Binary file not shown.

BIN
dist/snake6502.d64 vendored

Binary file not shown.

BIN
res.org/amour.sid Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,13 +1,12 @@
processor 6502
; SEGMENTS
SEG.U zeropageSegment
org $02
SEG loaderSegment
INCLUDE "zeropage.asm"
SEG cartridgeSegment
org $8000
; LOADER
SEG loaderSegment
cartridge SUBROUTINE
WORD .coldstart
WORD .warmstart
@ -48,9 +47,12 @@ cartridge SUBROUTINE
; decompression util
INCLUDE "lzgmini.asm"
#if VERBOSE = 1
ECHO "8k CARTRIDGE SIZE:",(. - $8000),"=",[(. - $8000)d]
ECHO "SPACE LEFT:",($9fff - .),"=",[($9fff - .)d]
#endif
; force filler for the *PROM
. = $9fff
BYTE #$ff

View File

@ -1,4 +1,9 @@
SEG.U dataSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
; Data section - Not initialized variables ($CD00 - $CDFF)
; ----------------------------------------------------------------------
; Number of interrupt
; Used as counter to be decremented to do some things less frequently
irqn:
@ -49,22 +54,6 @@ delayStatus:
score:
WORD
; vertical scroll intro
introYscroll:
BYTE
; interrupt raster line to draw moustache
moustacheLine:
BYTE
; horizontal intro scroll
XScrollOffset:
BYTE
XScrollDirection:
BYTE
XCharOffset:
BYTE
; Lists for snake head and tail
listX DS 256
listY DS 256
#if VERBOSE = 1
ECHO "data.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,7 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
statusPlay: ; do Game
; Check counter
ldx irqn
@ -332,4 +335,9 @@ checkEndWallHit:
sta (tileMem),y
skipPauseTests:
rts
#if VERBOSE = 1
ECHO "game.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,4 +1,7 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
; Game is over
; ----------------------------------------------------------------------
gameover:
@ -21,3 +24,7 @@ gameover:
lda #ST_DELAY
sta status
rts
#if VERBOSE = 1
ECHO "gameover.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,4 +1,7 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
; Initialized variables
; ----------------------------------------------------------------------
@ -22,20 +25,11 @@ delay:
; Status of the game (costants pre-processor defined, sort of enum)
ST_INTRO0 = 0
ST_INTRO1 = 1
ST_INTRO2 = 2
ST_INTRO3 = 3
ST_INTRO4 = 4
ST_INTRO5 = 5
ST_INTRO6 = 6
ST_INTRO7 = 7
ST_INTRO8 = 8
ST_MENURESET = 64
ST_MENU = 65
ST_LEVEL_TITLE = 128
ST_LEVEL_LOAD = 129
ST_PLAY = 130
ST_DELAY = 131
ST_END = 132
ST_LEVEL_TITLE = 2
ST_LEVEL_LOAD = 3
ST_PLAY = 4
ST_DELAY = 5
ST_END = 6
ST_PAUSE = 255
; Screen features
@ -44,10 +38,10 @@ SCREEN_H = 24
; Tiles
; -----
EMPTY_TILE = $e0
SNAKE_TILE = $e1
FOOD_TILE = $e2
WALL_TILE = $e3
EMPTY_TILE = $60
SNAKE_TILE = $61
FOOD_TILE = $62
WALL_TILE = $63
; Tiles colors
; Note: these colors will be picked by the level select routine
@ -68,6 +62,16 @@ WALL_COLOR:
gameoverString:
BYTE "GAME IS OVER"
BYTE #0
intro0string:
#if SYSTEM = 64
BYTE " SNAKE BY GIOMBA "
#else
BYTE " SNAKE16 BY GIOMBA "
#endif
BYTE #0
intro1string:
BYTE " PRESS SPACE TO PLAY "
BYTE #0
intro2string:
BYTE "RETROFFICINA.GLGPROGRAMS.IT"
BYTE #0
@ -75,38 +79,26 @@ intro3string:
#if DEBUG = 1
BYTE "DBG RELS"
#else
BYTE "2017 (C) 2021"
BYTE "(C) 2018"
#endif
BYTE #0
levelIntroString:
BYTE "NEXT LEVEL"
BYTE #0
colorshade: ; a gradient of dark-bright-dark (40 columns)
HEX 0b 0b 0b 0b 0b 0c 0c 0c 0c 0c 05 05 05 0d 0d 0d 0d 07 07 07 07 07 07 0d 0d 0d 0d 05 05 05 0c 0c 0c 0c 0c 0b 0b 0b 0b 0b
scoreString:
BYTE "SCORE PART"
BYTE #0
noMoreLevelsString:
BYTE "NO MORE LEVELS"
BYTE #0
introStringA1:
BYTE "RETROFFICINA"
BYTE #$0
introStringA2:
BYTE "AND"
BYTE #$0
introStringA3:
BYTE "GIOMBA"
BYTE #$0
introStringA4:
BYTE "PRESENT"
BYTE #$0
introStringA5:
BYTE "A COMMODORE 64"
BYTE #$0
introStringA6:
BYTE "VIDEOGAME"
BYTE #$0
; Levels
; ----------------------------------------------------------------------
levelsList:
INCBIN "../res.bin/levels.bin"
#if VERBOSE = 1
ECHO "initdata.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,656 +1,86 @@
SEG zeropageSegment
introDestPtr WORD
SEG programSegment
introreset SUBROUTINE
jsr multicolorOff
jsr clearScreen
; Set screen colors
lda #0
sta $d020 ; overscan
sta $d021 ; center
lda #14
sta introYscroll
; for "GLGPROGRAMS" at the beginning
ldx #$78
stx introDestPtr
ldy #$04
sty introDestPtr + 1
; GLGPROGRAMS color
ldy #$00
lda #$02
.colorLoop:
sta $d800,y
sta $d900,y
sta $da00,y
sta $db00,y
dey
bne .colorLoop
; first raster interrupt line, for moustaches
lda #68+18
sta moustacheLine
rts
statusIntro0 SUBROUTINE
; arrives raster interrupt, move moustache one line below
inc moustacheLine
lda $d011 ; load current vertical offset from VIC-II
and #$07
cmp #$07
beq .nextline ; if 7, then it is next text line
inc $d011 ; else setup moustache interrupt to trigger next raster line...
jsr setupMoustacheInterrupt
rts ; ...and return: my job here is done
.nextline:
lda $d011 ; reset raster offset to 0...
and #$f8
sta $d011
MOV_WORD_MEM dstPointer, introDestPtr
MEMSET "D", #$80, #40
clc ; ... move introDestPtr to next text line ...
lda introDestPtr
adc #40
sta introDestPtr
lda introDestPtr + 1
adc #0
sta introDestPtr + 1
MOV_WORD_MEM dstPointer, introDestPtr
MEMCPY "D", #GLGProgramsText, #200 ; ... and copy "GLG Programs" text to next text line
dec introYscroll ; remember that we are one line below
beq .next ; if we reached the end of the vertical scroll, advance status
jsr setupMoustacheInterrupt ; else just continue with the moustache
rts
.next:
lda #ST_INTRO1
sta status
rts
setupMoustacheInterrupt SUBROUTINE
; Store in $314 address of our custom interrupt handler
ldx #<.moustacheInterruptH
ldy #>.moustacheInterruptH
stx $314
sty $315
; Set raster beam to trigger interrupt at row
lda moustacheLine
sta $d012
rts
.moustacheInterruptH:
; "higher" moustache interrupt (on the right of the screen)
; +36
dec $d019 ; +42, EOI
lda #$02 ; +44, color
sta $d020 ; +48, color
nop ; +50, timing
nop ; +52, timing
nop ; +54, timing
bit $02 ; +57, timing
lda #$00 ; +59, color
sta $d020 ; +63, color
; second line, +0
inc $0800 ; + 6, timing
inc $0800 ; +12, timing
inc $0800 ; +18, timing
inc $0800 ; +24, timing
inc $0800 ; +30, timing
inc $0800 ; +36, timing
inc $0800 ; +42, timing
lda #$02 ; +44, color
sta $d020 ; +48, color
inc $0800 ; +54, timing
bit $02 ; +57, timing
lda #$00 ; +59, color
sta $d020 ; +63, color
; set raster beam low
ldx #<.moustacheInterruptL
ldy #>.moustacheInterruptL
stx $314
sty $315
clc
lda moustacheLine
adc #23 ; "lower" moustache is 23 raster lines below higher one
sta $d012
jmp $ea31
.moustacheInterruptL:
; "lower" moustache interrupt (on the left of the screen)
; +36
dec $d019 ; +42, EOI
inc $0800 ; +48, timing
inc $0800 ; +54, timing
lda #$02 ; +56, color
bit $0800 ; +60, timing
bit $02 ; +63, timing
; newline
sta $d020 ; + 4, color
lda #$00 ; + 6, timing
inc $0800 ; +12, timing
inc $0800 ; +18, timing
nop ; +20, timing
sta $d020 ; +24, color
lda #$02 ; +26, color
bit $0800 ; +30, timing
inc $0800 ; +36, timing
inc $0800 ; +42, timing
inc $0800 ; +48, timing
inc $0800 ; +54, timing
inc $0800 ; +60, timing
bit $02 ; +63, timing
; newline
sta $d020 ; + 4, color
lda #$00 ; + 6, color
inc $0800 ; +12, timing
inc $0800 ; +18, timing
sta $d020 ; +22, color
ldx #<irq ; restore main raster interrupt handler
ldy #>irq
stx $314
sty $315
lda #$00
sta $d012
jmp $ea31
GLGProgramsText: ; fancy PETSCII-looking brand name
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$80,#$f0,#$f4,#$80,#$80,#$f0,#$f4,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$f5,#$80,#$f5,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f1,#$80,#$80,#$80,#$f0,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f5,#$80,#$f5,#$f5,#$80,#$f5,#$80,#$f5,#$80,#$fd,#$f4,#$f3,#$f0,#$f0,#$f1,#$f0,#$f1,#$f0,#$f0,#$fc,#$f0,#$fb,#$f1,#$f2,#$f1,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f2,#$f4,#$fc,#$f2,#$f4,#$f2,#$f4,#$fc,#$80,#$f5,#$80,#$80,#$f5,#$f2,#$f3,#$f2,#$fc,#$f5,#$f2,#$f3,#$f5,#$f5,#$f5,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
BYTE #$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$f4,#$fa,#$f4,#$f4,#$f4,#$f4,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$f3,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80,#$80
statusIntro1 SUBROUTINE
; continue moving moustaches down, up to 4 raster lines (middle of text)
lda $d011
and #$07
cmp #$04
beq .next ; if interrupt is in the middle, don't move it anymore, and...
inc $d011
inc moustacheLine
jsr setupMoustacheInterrupt
rts
.next:
jsr setupMoustacheInterrupt ; ... always remember to display moustache, anyhow ...
lda counter ; wait for song synchronization up to interrupt $0080
cmp #$80
bne .end
lda counter + 1
cmp #$00
bne .end
ldy #$0
lda #$07
.colorLoop:
sta $d940,y
iny
cpy #200
bne .colorLoop
lda #ST_INTRO2
sta status
.end:
rts
statusIntro2 SUBROUTINE
jsr setupMoustacheInterrupt
; "RETROFFICINA"
lda #<introStringA1
sta srcStringPointer
lda #>introStringA1
sta srcStringPointer + 1
lda #$48
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$01
bne .end
lda #ST_INTRO3
sta status
.end:
rts
statusIntro3 SUBROUTINE
jsr setupMoustacheInterrupt
; "AND"
lda #<introStringA2
sta srcStringPointer
lda #>introStringA2
sta srcStringPointer + 1
lda #$a5
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$86
bne .end
lda counter + 1
cmp #$01
bne .end
lda #ST_INTRO4
sta status
.end:
rts
statusIntro4 SUBROUTINE
jsr setupMoustacheInterrupt
; "GIOMBA"
lda #<introStringA3
sta srcStringPointer
lda #>introStringA3
sta srcStringPointer + 1
lda #$f9
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$02
bne .end
MEMSET #$540, #$80, #200
lda #ST_INTRO5
sta status
.end:
rts
statusIntro5 SUBROUTINE
jsr setupMoustacheInterrupt
; "PRESENT"
lda #<introStringA4
sta srcStringPointer
lda #>introStringA4
sta srcStringPointer + 1
lda #$50
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$80
bne .end
lda counter + 1
cmp #$02
bne .end
lda #ST_INTRO6
sta status
.end:
rts
statusIntro6 SUBROUTINE
jsr setupMoustacheInterrupt
; "A COMMODORE 64"
lda #<introStringA5
sta srcStringPointer
lda #>introStringA5
sta srcStringPointer + 1
lda #$9d
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$08
bne .end
lda counter + 1
cmp #$03
bne .end
lda #ST_INTRO7
sta status
.end:
rts
statusIntro7 SUBROUTINE
jsr setupMoustacheInterrupt
; "VIDEOGAME"
lda #<introStringA6
sta srcStringPointer
lda #>introStringA6
sta srcStringPointer + 1
lda #$ef
sta dstScreenPointer
lda #$05
sta dstScreenPointer + 1
jsr printString
lda counter
cmp #$80
bne .end
lda counter + 1
cmp #$03
bne .end
lda #ST_INTRO8
sta status
.end:
rts
statusIntro8 SUBROUTINE
jsr setupMoustacheInterrupt
; blank wait
lda counter
cmp #$16
bne .end
lda counter + 1
cmp #$04
bne .end
lda #ST_MENURESET
sta status
.end:
rts
statusMenuReset SUBROUTINE
lda #$05
ldy #$0
.lastlineColorLoop:
sta $db98,y
iny
cpy #80
bne .lastlineColorLoop
; Print Game Title: big "SNAKE"
MEMSET #$d800, #$02, #280 ; color
MEMCPY #$400, #SnakeText, #280 ; text
; Print PETSCII GLG Programs
MEMSET #($6a8 + $d800 - $400), #$02, #200 ; color
MEMCPY #$6a8, #GLGProgramsText, #200 ; text
; Print website
lda #<intro2string ; lsb of string address
sta srcStringPointer ; put into lsb of source pointer
lda #>intro2string ; do the same for msb of string address
sta srcStringPointer + 1 ; put into msb of source pointer
lda #$9e ; this is lsb of address of 23th line
sta dstScreenPointer ; put into lsb of dest pointer
lda #$07 ; do the same for msb of adress of 20th line
sta dstScreenPointer + 1 ; put into msb of dest pointer
jsr printString ; print
; Print Copyright
lda #<intro3string ; the assembly is the same as above,
sta srcStringPointer ; just change string to be printed
lda #>intro3string ; and line (24th line)
sta srcStringPointer + 1
lda #$ce
sta dstScreenPointer
lda #$07
sta dstScreenPointer + 1
jsr printString
; boat-shaped horizontal line (rounded edges toward the top)
; this overwrites the "present" word from the intro
lda #$f2 ; 3rd quadrant
sta $540
lda #$f3 ; 4th quadrant
sta $567
lda #$07 ; color for edges
sta $540+$d800-$400
sta $567+$d800-$400
ldy #$1
.boatLineLoop:
lda #$f4 ; horizontal line
sta $540,y
lda #$07
sta $540+$d800-$400,y
iny
cpy #39
bne .boatLineLoop
lda #$05
sta XCharOffset
jsr setupMoustacheInterrupt ; never forget the magic moustaches
lda #ST_MENU
sta status
rts
SnakeText:
HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f7 80 80 f6 80 f6 a0 a0 f7 80 f7 80 80 80 f6 a0 a0 f9 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 f7 80 a0 80 a0 80 80 a0 80 a0 f6 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 a0 80 80 80 80 a0 a0 f7 a0 80 a0 80 80 a0 80 a0 a0 f9 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 f8 a0 a0 f7 80 a0 f8 a0 a0 80 a0 a0 a0 a0 80 a0 f9 80 80 a0 a0 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 f8 a0 80 a0 80 80 a0 80 a0 f7 80 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 80 80 80 a0 80 a0 80 80 a0 80 a0 80 80 a0 80 a0 a0 f7 80 a0 80 80 80 80 80 80 80 80 80 80 80 80
HEX 80 80 80 80 80 80 80 80 f6 a0 a0 f9 80 f8 80 80 f8 80 f9 80 80 f8 80 a0 f8 f9 80 f8 a0 a0 f7 80 80 80 80 80 80 80 80 80
;ParabolicSpaceChars:
; HEX 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
;ParabolicSpaceScroll:
; HEX 00 01 01 01 01 01 01 01 02 02 02 03 03 04 04 05 06 06 07 00 00 01 02 03 04 05 06 07 00 01 02 04 05 06 00 01 02 04 05 07 00 02 04 05 07 00 01 03 04 06 00 01 03 04 06 07 00 02 03 04 06 07 00 01 02 03 04 05 06 07 00 01 02 02 03 04 04 05 05 06 06 06 07 06 07 07 07 07 07 07 07
setupXScrollInterrupt SUBROUTINE
ldx #<XScrollInterruptH
ldy #>XScrollInterruptH
stx $314
sty $315
; Set raster beam to trigger interrupt at row
lda #42
sta $d012
rts
XScrollInterruptH SUBROUTINE
lda $d016
and #$f8
ora XScrollOffset
sta $d016
dec $d019
ldx #<XScrollInterruptL
ldy #>XScrollInterruptL
stx $314
sty $315
lda #110
sta $d012
jmp $ea31
XScrollInterruptL SUBROUTINE
lda $d016
and #$f8
sta $d016
dec $d019
ldx #<XScrollInterruptMoveAll
ldy #>XScrollInterruptMoveAll
stx $314
sty $315
lda #120
sta $d012
jmp $ea31
XScrollInterruptMoveAll SUBROUTINE
dec $d019 ; EOI
tsx
#if VERBOSE = 1
LASTINIT SET .
#endif
; Currently statusIntro0 is the same as statusIntro1
; statusIntro1 has just been reserved for future use
statusIntro0:
statusIntro1:
; Decrement interrupt divider for the intro
ldx introCounter
dex
stx introCounter
cpx #0
beq status1do ; if divider is 0, then do status1do ...
rts ; ... else just do nothing and return
status1do:
; Reset introCounter
ldx #5
stx introCounter
lda XCharOffset
asl
asl
asl
sta $100,x
lda $d016
and #$07
ora $100,x
; I want to print strings at different columns to make them
; bounce across the screen, so take last introX and add introXinc,
; then print string at that point. If introX is too far right, then
; set introXinc as #$ff (equals -1) so next time introX will be
; decremented by 1. And then, if introX is too far left, then
; set introXinc as #$01 so next time will be moved to right again.
lda introX
clc
adc introXinc ; this is #$01 or #$0ff, so actually it is +1 or -1
sta introX
cmp #19 ; am I too far right?
beq status1setSX ; if yes, set SX (left)
cmp #0 ; am I too far left?
beq status1setDX ; if yes, set DX (right)
jmp status1okset ; else do nothing (aka, next time re-use current
; increment value)
status1setDX:
lda #$01 ; set introXinc as +1
sta introXinc
jmp status1okset
status1setSX:
lda #$ff ; set introXinc as -1
sta introXinc
jmp status1okset
inx
txs
status1okset:
; Print "SNAKE BY GIOMBA" (see above for pointer details)
lda #<intro0string
sta srcStringPointer
lda #>intro0string
sta srcStringPointer + 1
; $0428 is 2nd line (previously filled with color shades by reset routine)
lda #$28
clc
adc introX ; just add X, to make it look like it has moved
sta dstScreenPointer
lda #$04
sta dstScreenPointer + 1
jsr printString
cmp #78
bcs .isEdge
cmp #3
bcc .isEdge
cmp #70
bcs .isMiddle
cmp #10
bcc .isMiddle
jmp .enter
; Print "PRESS SPACE TO PLAY"
lda #<intro1string
sta srcStringPointer
lda #>intro1string
sta srcStringPointer + 1
; $0478 is 4th line (previously filled with color shades by reset routine)
; add #19, then sub introX will make it move to other way of 2nd line
lda #$78
clc
adc #19 ; add #19
sec
sbc introX ; sub introX
sta dstScreenPointer
lda #$04
sta dstScreenPointer + 1
jsr printString
.isMiddle:
lda counter
and #$01
beq .enter
jmp .next
.isEdge:
lda counter
and #$03
beq .enter ; ah, some good spaghetti code to accomodate for far branch
jmp .next ; bounce slower
.isCenter:
.enter:
lda XScrollDirection
and #$01
bne .goRight
.goLeft:
dec XScrollOffset
lda XScrollOffset
and #$07
cmp #$07
beq .continue1
jmp .next
.continue1:
lda #$07
sta XScrollOffset
.moveEverythingLeft:
dec XCharOffset
ldy #0
.loop1:
lda $401,y
sta $400,y
lda $429,y
sta $428,y
lda $451,y
sta $450,y
lda $479,y
sta $478,y
lda $4a1,y
sta $4a0,y
lda $4c9,y
sta $4c8,y
lda $4f1,y
sta $4f0,y
iny
cpy #38
bne .loop1
lda XCharOffset
cmp #0
bne .next
lda #$01
sta XScrollDirection
jmp .next
.goRight:
inc XScrollOffset
lda XScrollOffset
and #$07
cmp #$00
bne .next
lda #$00
sta XScrollOffset
.moveEverythingRight:
inc XCharOffset
ldy #38
.loop2:
lda $400,y
sta $401,y
lda $428,y
sta $429,y
lda $450,y
sta $451,y
lda $478,y
sta $479,y
lda $4a0,y
sta $4a1,y
lda $4c8,y
sta $4c9,y
lda $4f0,y
sta $4f1,y
dey
bne .loop2
lda XCharOffset
cmp #10
bne .next
lda #$00
sta XScrollOffset
lda #$00
sta XScrollDirection
.next:
jsr setupMoustacheInterrupt
jmp $ea31
statusMenu SUBROUTINE
jsr setupXScrollInterrupt
; Some considerations on speed:
; yes, maybe I should have put the string chars once in screen text memory
; and then move it left and right. Should re-think about this.
; For now, just return.
rts
#if VERBOSE = 1
ECHO "intro1.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

53
src/introreset.asm Normal file
View File

@ -0,0 +1,53 @@
#if VERBOSE = 1
LASTINIT SET .
#endif
; Intro reset
; ----------------------------------------------------------------------
introreset:
jsr multicolorOff
jsr clearScreen
; Copy shade colors from costant table to color RAM for 2nd and 4th line of text
ldx #39
introresetColorShade
lda colorshade,x
sta $d828,x ; 2nd line
sta $d878,x ; 4th line
dex
cpx #$ff
bne introresetColorShade
; Set screen colors
lda #0
sta $d020 ; overscan
sta $d021 ; center
; Print website
lda #<intro2string ; lsb of string address
sta srcStringPointer ; put into lsb of source pointer
lda #>intro2string ; do the same for msb of string address
sta srcStringPointer + 1 ; put into msb of source pointer
lda #$26 ; this is lsb of address of 20th line
sta dstScreenPointer ; put into lsb of dest pointer
lda #$07 ; do the same for msb of adress of 20th line
sta dstScreenPointer + 1 ; put into msb of dest pointer
jsr printString ; print
; Print Copyright
lda #<intro3string ; the assembly is the same as above,
sta srcStringPointer ; just change string to be printed
lda #>intro3string ; and line (21th line)
sta srcStringPointer + 1
lda #$58
sta dstScreenPointer
lda #$07
sta dstScreenPointer + 1
jsr printString
rts
#if VERBOSE = 1
ECHO "introreset.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,4 +1,7 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
; Reset variables for a new level
; ----------------------------------------------------------------------
levelresetvar:
@ -32,3 +35,7 @@ clearListLoop:
bne clearListLoop
rts
#if VERBOSE = 1
ECHO "levelreset.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,14 +1,9 @@
SEG zeropageSegment
; Pointer to video memory used in the level loading routine
levelVideoPointer WORD
levelColorPointer WORD
; Pointer to level struct
levelPointer WORD
#if VERBOSE = 1
LASTINIT SET .
#endif
SEG programSegment
; load new level on the screen
statusLevelTitle SUBROUTINE
jsr multicolorOff
jsr clearScreen
; Print "Next Level"
@ -62,11 +57,10 @@ statusLevelTitle SUBROUTINE
rts
statusLevelLoad SUBROUTINE
jsr multicolorOn
; Upper bar -- fill with spaces, color yellow
ldx #39
.loop:
lda #$80
lda #$0
sta $400,x
lda #7
sta $d800,x
@ -145,9 +139,9 @@ writeLevelElement:
lda levelT
sta (levelVideoPointer),y
; tiles colors can be found in an array
; position in array = tile value - $e0
; position in array = tile value - $60
sec
sbc #$e0
sbc #$60
tax
lda tilesColors,x
sta (levelColorPointer),y
@ -171,3 +165,7 @@ writeLevelEnd:
lda #ST_PLAY
sta status
rts
#if VERBOSE = 1
ECHO "levels.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,57 +0,0 @@
processor 6502
SEG.U zeropageSegment
org $02
SEG loaderSegment
org $801
autostartRoutine SUBROUTINE
; this is at $801
; and it MUST be exactly at this location in order to autostart
; 10 SYS2060 ($80c) BASIC autostart
BYTE #$0b,#$08,#$0a,#$00,#$9e,#$32,#$30,#$36,#$31,#$00,#$00,#$00
; this is at (2061 dec)=($80d)
; and it MUST be exactly after the above BASIC statement
. = $80d
; load pack from tape
lda #(packFileNameEnd - packFileName) ; filename length
ldx #<packFileName ; filename string address
ldy #>packFileName
jsr $ffbd ; setnam
lda #$01 ; file nr
ldx $ba ; last used device nr
ldy #$01 ; load to address stored in file
jsr $ffba ; setlfs
lda #$0 ; load to memory
jsr $ffd5 ; load
; address of input compressed data
lda #$00
sta srcPointer
lda #$80
sta srcPointer + 1
; address of output decompressed data
lda #$00
sta dstPointer
lda #$10
sta dstPointer + 1
jsr inflate
jmp $2800
; decompression util
INCLUDE "lzgmini.asm"
; DATA
; -------------------------------------
SEG loaderSegment
packFileName:
BYTE "PACKLZ"
packFileNameEnd:

View File

@ -1,48 +1,44 @@
SEG zeropageSegment
srcPointer WORD
dstPointer WORD
inEnd WORD
offset WORD
length BYTE
symbol BYTE
marker1 BYTE
marker2 BYTE
marker3 BYTE
marker4 BYTE
copy WORD
SEG loaderSegment
inflate SUBROUTINE
.inEnd EQU 2
.offset EQU 4
.length EQU 6
.symbol EQU 25
.marker1 EQU 30
.marker2 EQU 31
.marker3 EQU 32
.marker4 EQU 33
.copy EQU 34
clc
ldy #10
lda (srcPointer),y
adc srcPointer
sta inEnd
sta .inEnd
dey
lda (srcPointer),y
adc srcPointer + 1
sta inEnd + 1
sta .inEnd + 1
clc
lda inEnd
lda .inEnd
adc #16
sta inEnd
lda inEnd + 1
sta .inEnd
lda .inEnd + 1
adc #0
sta inEnd + 1
sta .inEnd + 1
; Get the marker symbols
ldy #16
lda (srcPointer),y
sta marker1
sta .marker1
iny
lda (srcPointer),y
sta marker2
sta .marker2
iny
lda (srcPointer),y
sta marker3
sta .marker3
iny
lda (srcPointer),y
sta marker4
sta .marker4
; Skip header + marker symbols (16 + 4 bytes)
clc
@ -57,30 +53,30 @@ inflate SUBROUTINE
ldy #0 ; Make sure that Y is zero
.mainloop:
lda srcPointer ; done?
cmp inEnd
cmp .inEnd
bne .notdone
lda srcPointer + 1
cmp inEnd + 1
cmp .inEnd + 1
bne .notdone
rts
.notdone:
lda (srcPointer),y ; A = symbol
sta symbol
sta .symbol
sta $d020
inc srcPointer
bne .noinc1
inc srcPointer + 1
.noinc1:
cmp marker1 ; Marker1?
cmp .marker1 ; Marker1?
beq .domarker1
cmp marker2 ; Marker2?
cmp .marker2 ; Marker2?
beq .domarker2
cmp marker3 ; Marker3?
cmp .marker3 ; Marker3?
beq .domarker3
cmp marker4 ; Marker4?
cmp .marker4 ; Marker4?
beq .domarker4
.literal:
lda symbol
lda .symbol
sta (dstPointer),y ; Plain copy
inc dstPointer
bne .mainloop
@ -105,15 +101,15 @@ inflate SUBROUTINE
lsr
lsr
lsr
sta offset
inc offset
sta .offset
inc .offset
lda #0
sta offset + 1 ; offset = (b >> 5) + 1
sta .offset + 1 ; offset = (b >> 5) + 1
txa
and #$1f
tax
lda .LZG_LENGTH_DECODE_LUT,x
sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
jmp .docopy
; marker3 - "Short copy"
@ -134,13 +130,13 @@ inflate SUBROUTINE
lsr
clc
adc #3
sta length ; length = (b >> 6) + 3
sta .length ; length = (b >> 6) + 3
txa
and #$3f
adc #8
sta offset
sta .offset
lda #0
sta offset + 1 ; offset = (b & 0x3f) + 8
sta .offset + 1 ; offset = (b & 0x3f) + 8
beq .docopy
; marker2 - "Medium copy"
@ -158,7 +154,7 @@ inflate SUBROUTINE
lsr
lsr
lsr
sta offset + 1
sta .offset + 1
lda (srcPointer),y
inc srcPointer
bne .noinc6
@ -166,15 +162,15 @@ inflate SUBROUTINE
.noinc6:
clc
adc #8
sta offset
sta .offset
bcc .noinc7
inc offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8
inc .offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8
.noinc7:
txa
and #$1f
tax
lda .LZG_LENGTH_DECODE_LUT,x
sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
bne .docopy
.literal2:
@ -192,13 +188,13 @@ inflate SUBROUTINE
and #$1f
tax
lda .LZG_LENGTH_DECODE_LUT,x
sta length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
sta .length ; length = .LZG_LENGTH_DECODE_LUT[b & 0x1f]
lda (srcPointer),y
inc srcPointer
bne .noinc9
inc srcPointer + 1
.noinc9:
sta offset + 1
sta .offset + 1
lda (srcPointer),y
inc srcPointer
bne .noinc10
@ -206,31 +202,31 @@ inflate SUBROUTINE
.noinc10:
clc
adc #$08
sta offset
lda offset + 1
sta .offset
lda .offset + 1
adc #$08
sta offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056
sta .offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056
; Copy corresponding data from history window
.docopy:
sec
lda dstPointer
sbc offset
sta copy
sbc .offset
sta .copy
lda dstPointer + 1
sbc offset + 1
sta copy + 1
sbc .offset + 1
sta .copy + 1
.loop1:
lda (copy),y
lda (.copy),y
sta (dstPointer),y
iny
cpy length
cpy .length
bne .loop1
ldy #0 ; Make sure that Y is zero
clc
lda dstPointer
adc length
adc .length
sta dstPointer
bcc .noinc11
inc dstPointer + 1

View File

@ -1,101 +0,0 @@
SEG zeropageSegment
; Generic src/dst copy pointers
srcPointer WORD
dstPointer WORD
dstPointerEnd WORD
SEG programSegment
MACRO MEMSET
IF {1} != "D"
clc
lda <{1}
sta dstPointer
adc <{3}
sta dstPointerEnd
lda >{1}
sta dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ELSE
clc
lda dstPointer
adc <{3}
sta dstPointerEnd
lda dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ENDIF
lda {2}
ldy #0
.loop:
sta (dstPointer),y
inc dstPointer
bne .skipInc
inc dstPointer + 1
.skipInc:
ldx dstPointer
cpx dstPointerEnd
bne .loop
ldx dstPointer + 1
cpx dstPointerEnd + 1
bne .loop
ENDM
SEG zeroPageSegment
SEG programSegment
MACRO MEMCPY
IF {1} != "D"
clc
lda <{1}
sta dstPointer
adc <{3}
sta dstPointerEnd
lda >{1}
sta dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ELSE
clc
lda dstPointer
adc <{3}
sta dstPointerEnd
lda dstPointer + 1
adc >{3}
sta dstPointerEnd + 1
ENDIF
lda <{2}
sta srcPointer
lda >{2}
sta srcPointer + 1
ldy #$0
.loop:
lda (srcPointer),y
sta (dstPointer),y
inc dstPointer
bne .skipIncDst
inc dstPointer + 1
.skipIncDst:
inc srcPointer
bne .skipIncSrc
inc srcPointer + 1
.skipIncSrc:
ldx dstPointer
cpx dstPointerEnd
bne .loop
ldx dstPointer + 1
cpx dstPointerEnd + 1
bne .loop
ENDM
SEG programSegment
MACRO MOV_WORD_MEM
lda {2}
sta {1}
lda {2} + 1
sta {1} + 1
ENDM

View File

@ -1,50 +1,81 @@
processor 6502
; Platform specific code
; Code yet to be developed, example to use:
; ----------------------------------------------------------------------
#if SYSTEM = 64
; Commodore64 specific code
#else
; Commodore16 specific code
#endif
; Uninitialized zeropage segment
; ----------------------------------------------------------------------
SEG.U zeropageSegment
ORG_ZEROPAGE EQU $02
org ORG_ZEROPAGE
org $02
INCLUDE "zeropage.asm"
#if VERBOSE = 1
; Locations $90-$FF in zeropage are used by kernal
ECHO "End of zeropage variables. Space left: ",($90 - .)
#endif
; SID tune (previously properly cleaned, see HVSC)
; ----------------------------------------------------------------------
SEG sidSegment
ORG_SID EQU $1000
org ORG_SID
ORG_FONT EQU $2400
SEG fontSegment
org ORG_FONT
ORG_PROGRAM EQU $2800
org $1000
sidtune:
INCBIN "../res.bin/amour.sid"
#if VERBOSE = 1
ECHO "End of SIDtune at ",.,"Space left:",($2000 - .)
#endif
; Font Data
; ----------------------------------------------------------------------
SEG tggsSegment
org $2000
; This binary data that defines the font is exactly 2kB long ($800)
tggsFont:
INCLUDE "tggs.asm"
; Program Segment
; ----------------------------------------------------------------------
SEG programSegment
org ORG_PROGRAM
ORG_DATA EQU $cd00
SEG.U dataSegment
org ORG_DATA
; INCLUDE
; -----------------------------------------------------------------------------
LASTINIT SET ORG_SID
INCLUDE "sidtune.asm"
ECHO "sidtune : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
LASTINIT SET ORG_FONT
INCLUDE "font.asm"
ECHO "font : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
LASTINIT SET ORG_PROGRAM
org $2800
INCLUDE "program.asm"
INCLUDE "initdata.asm"
INCLUDE "game.asm"
INCLUDE "gameover.asm"
INCLUDE "introreset.asm"
INCLUDE "subroutines.asm"
INCLUDE "levels.asm"
INCLUDE "intro1.asm"
INCLUDE "multicolor.asm"
INCLUDE "levelreset.asm"
INCLUDE "outro.asm"
#if VERBOSE = 1
ECHO "End of program segment at:",.
ECHO "PACK SIZE:",(. - $1000),"=",[(. - $1000)d]
#endif
; Data variables
; -----------------
SEG.U dataSegment
org $cd00
INCLUDE "data.asm"
INCLUDE "macro.asm"
ECHO "program : start ",LASTINIT," end ",.," size ",(. - LASTINIT)
#if VERBOSE = 1
ECHO "End of Data segment. Space left:",($ce00 - .)
#endif
; Lists
; -----------------
SEG.U listSegment
org $ce00
listX DS 256
listY DS 256
;
; coded 2017, 2018, 2019, 2020, 2021
; coded 2017, 2018, 2019, 2020
; by giomba -- giomba at glgprograms.it
; this software is free software and is distributed
; under the terms of GNU GPL v3 license

View File

@ -1,4 +1,9 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
processor 6502
multicolor SUBROUTINE
; Prepare data struct for MultiColor mode
@ -38,3 +43,7 @@ multicolorOff:
and #$ef
sta $d016
rts
#if VERBOSE = 1
ECHO "multicolor.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,4 +1,7 @@
SEG programSegment
#if VERBOSE = 1
LASTINIT SET .
#endif
; Wait for some delay
statusDelay SUBROUTINE
ldy delay ; load outroDelay and decrement
@ -11,3 +14,7 @@ statusDelay SUBROUTINE
lda delayStatus
sta status
rts
#if VERBOSE = 1
ECHO "outro.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,10 +1,9 @@
SEG zeropageSegment
; Interrupt counter
counter DS 2
#if VERBOSE = 1
LASTINIT SET .
#endif
SEG programSegment
; this is the entry point of the program and must stay at this address
org $2800
; ENTRY OF PROGRAM
; ----------------------------------------------------------------------
start:
; Clear screen, initialize keyboard, restore interrupts
jsr $ff81
@ -58,45 +57,22 @@ zeroFillZeroPage:
lda #ST_INTRO0
sta status
; Reset screen (and other parameters) to play intro
jsr introreset
; Enable interrupts
cli
menu SUBROUTINE
.menu: ; Cycle here until SPACE or `Q` is pressed
; Reset screen (and other parameters) to play intro
jsr introreset
intro0running: ; Cycle here until SPACE or `Q` is pressed
jsr $ffe4 ; GETIN
cmp #$20 ; Is it SPACE?
beq .intro0end ; if yes, go to intro0end and start game (see)
#if DEBUG = 1
cmp #$41 ; Is it A?
beq .printCounter ; if yes, print current counter
#endif
beq intro0end ; if yes, go to intro0end and start game (see)
cmp #$51 ; Is it Q?
bne .menu ; If not, keep looping here,
bne intro0running ; If not, keep looping here,
jmp $fce2 ; else, reset the computer
#if DEBUG = 1
.printCounter
lda counter + 1
ldy #2
jsr printByte
lda counter
ldy #4
jsr printByte
jmp .menu
#endif
; Intro is finished, now it's time to start the proper game
.intro0end:
; Are you sure? Maybe the demo-intro is not finished, yet
; We do not want to actually start unless the demo is finished,
; otherwise vertical raster line offset may be != 0
lda status
cmp #ST_MENU
bne .menu
intro0end:
; Set current level pointer to list start
lda #<levelsList
sta levelPointer
@ -116,21 +92,20 @@ menu SUBROUTINE
lda #ST_LEVEL_TITLE
sta status
.endless:
endless:
; Loop waiting for gameover
lda status
cmp #ST_END ; is status equal to end ?
bne .endless ; if not, just wait looping here, else...
bne endless ; if not, just wait looping here, else...
jsr clearScreen
jsr introreset ; reset variables for intro
lda #ST_INTRO0
sta status ; put machine into play intro status
jmp intro0running ; and go there waiting for keypress
lda #ST_MENURESET
sta status ; put machine into menu status
jmp .menu ; and go there waiting for keypress
; Main Raster Interrupt Handler
; Interrupt Handler
; ----------------------------------------------------------------------
irq SUBROUTINE
irq:
; Things that must be done every interrupt (50Hz)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Acknoweledge IRQ
@ -143,83 +118,23 @@ irq SUBROUTINE
tya
pha
#if DEBUG = 1
; Change background to show how much time does music take for each interrupt
lda #1
sta $d020
#endif
; Play music first -> no audio skew if computations are slow
jsr sidtune + 3
#if DEBUG = 1
; Change background to visually see the ISR timing
lda #2
sta $d020
#endif
inc counter
bne .noIncCounter
inc counter + 1
.noIncCounter
; Check status and call appropriate sub-routine
; Sort of switch-case
lda status
checkStatusIntro0:
cmp #ST_INTRO0
bne checkStatusIntro1
jsr statusIntro0
jmp checkEndStatus
checkStatusIntro1:
cmp #ST_INTRO1
bne checkStatusIntro2
jsr statusIntro1
jmp checkEndStatus
checkStatusIntro2:
cmp #ST_INTRO2
bne checkStatusIntro3
jsr statusIntro2
jmp checkEndStatus
checkStatusIntro3:
cmp #ST_INTRO3
bne checkStatusIntro4
jsr statusIntro3
jmp checkEndStatus
checkStatusIntro4:
cmp #ST_INTRO4
bne checkStatusIntro5
jsr statusIntro4
jmp checkEndStatus
checkStatusIntro5:
cmp #ST_INTRO5
bne checkStatusIntro6
jsr statusIntro5
jmp checkEndStatus
checkStatusIntro6:
cmp #ST_INTRO6
bne checkStatusIntro7
jsr statusIntro6
jmp checkEndStatus
checkStatusIntro7:
cmp #ST_INTRO7
bne checkStatusIntro8
jsr statusIntro7
jmp checkEndStatus
checkStatusIntro8:
cmp #ST_INTRO8
bne checkStatusMenuReset
jsr statusIntro8
jmp checkEndStatus
checkStatusMenuReset:
cmp #ST_MENURESET
bne checkStatusMenu
jsr statusMenuReset
jmp checkEndStatus
checkStatusMenu:
cmp #ST_MENU
bne checkStatusPlay
jsr statusMenu
jsr statusIntro1
jmp checkEndStatus
checkStatusPlay:
cmp #ST_PLAY
@ -243,6 +158,19 @@ checkStatusLevelLoad:
jmp checkEndStatus
checkEndStatus:
#if DEBUG = 1
; Change background to show how much time does music take for each interrupt
lda #1
sta $d020
#endif
; Play music
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
jsr sidtune + 3
; Increase random value
inc random
@ -261,3 +189,7 @@ checkEndStatus:
; Go to original system routine
jmp $ea31
#if VERBOSE = 1
ECHO "program.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,6 +0,0 @@
SEG sidSegment
sidtune:
INCBIN "../res.bin/amour2.sid"
; Note: the SID tune must be properly cleaned (eg. header removed)
; See HVSC for .sid music format

View File

@ -1,14 +1,15 @@
SEG zeropageSegment
; Where is the snake head in video memory? Do math to calculate address
; using pointer at tileMem
tileMem WORD
#if VERBOSE = 1
LASTINIT SET .
#endif
; Subroutines
; ----------------------------------------------------------------------
SEG programSegment
; Clear screen -- easy
clearScreen SUBROUTINE
ldx #$ff
.loop:
lda #$80
lda #$00
sta $400,x
sta $500,x
sta $600,x
@ -80,23 +81,16 @@ printByte SUBROUTINE
lsr
lsr
lsr
ora #$c0 ; add 192 (see font)
ora #$40 ; add 64 (see font)
sta $400,y ; print msb char
txa ; Take least significant nibble (use previous copy)
and #$0f
ora #$c0 ; add 192 (see font)
ora #$40 ; add 64 (see font)
sta $401,y ; print lsb char
rts
SEG zeropageSegment
; Pointer to string
srcStringPointer WORD
; Pointer to screen position where to print intro string
dstScreenPointer DS 2
SEG programSegment
printString SUBROUTINE
; Print string
; Input parameters:
@ -110,22 +104,22 @@ printString SUBROUTINE
beq .end ; if zero, then end (string must be null-terminated)
cmp #$20 ; is space?
bne .checkP1
lda #$80
lda #$0
jmp .print
.checkP1:
cmp #$28 ; is char '(' ?
bne .checkP2
lda #$9b
lda #$1b
jmp .print
.checkP2:
cmp #$29 ; is char ')' ?
bne .checkP3
lda #$9c
lda #$1c
jmp .print
.checkP3
cmp #$2e ; is char '.' ?
bne .checkNumber
lda #$9d
lda #$1d
jmp .print
.checkNumber: ; is char a number?
cmp #$2f
@ -135,14 +129,14 @@ printString SUBROUTINE
sec
sbc #$30
clc
adc #$c0
adc #$40
jmp .print
.nextCheck:
.isLetter:
; defaults to an uppercase letter of ASCII set
clc
adc #$40
sec
sbc #$40
.print:
sta (dstScreenPointer),y ; put screen code to screen
iny ; next char in string
@ -150,11 +144,6 @@ printString SUBROUTINE
.end:
rts
SEG zeropageSegment
; Pointer for Pointer in the NextPointer routine
nextPointerPointer DS 2
SEG programSegment
; Increment a pointer in the zeropage
; Input parameters:
; nextPointerPointer pointer to the pointer in zeropage
@ -175,3 +164,7 @@ nextPointer:
sta (nextPointerPointer),y
rts
#if VERBOSE = 1
ECHO "subroutines.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

2568
src/tggs.asm Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
; Zero page utility pointers
; ----------------------------------------------------------------------
; Where is the snake head in video memory? Do math to calculate address
; using pointer at tileMem,tileMem+1
tileMem DS 2
; Pointer to string
srcStringPointer DS 2
; Pointer to screen position where to print intro string
dstScreenPointer DS 2
; Pointer to level struct
levelPointer DS 2
; Pointer to video memory used in the level loading routine
levelVideoPointer DS 2
levelColorPointer DS 2
; Pointer for Pointer in the NextPointer routine
nextPointerPointer DS 2
; Pointer to string for strlen routine
strlenString DS 2
; Generic src/dst copy pointers
srcPointer DS 2
dstPointer DS 2
; Note: Locations $90-$FF in zeropage are used by kernal

View File

@ -7,11 +7,11 @@ void flush(char last, int count) {
char tile, color;
switch(last) {
case 'x':
tile = (char)0xe3; break;
tile = (char)0x63; break;
case 'f':
tile = (char)0xe2; break;
tile = (char)0x62; break;
default:
tile = (char)0xe0; break;
tile = (char)0x60; break;
}
cout << tile << (char)count;
}