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: .POSIX:
ASM=$(wildcard src/*.asm) 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/snake.bin: bin/snake.pack.lz
dasm src/cart.asm -Isrc/ -DVERBOSE=$(VERBOSE) -f3 -sbuild/cart.symbols.txt -obin/snake.bin
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.pack: env $(ASM) $(RES) bin/explodefont 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 bin/snake.pack.lz: bin/snake.pack liblzg/src/tools/lzg
liblzg/src/tools/lzg bin/snake.pack > bin/snake.pack.lz 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: liblzg/src/tools/lzg:
cd liblzg/src && make cd liblzg/src && make
@ -43,8 +26,8 @@ env:
bin/explodefont: util/explodefont.cpp bin/explodefont: util/explodefont.cpp
g++ -o bin/explodefont util/explodefont.cpp g++ -o bin/explodefont util/explodefont.cpp
res.bin/amour2.sid: res.bin/amour.sid:
cp res.org/amour2.sid res.bin/amour2.sid cp res.org/amour.sid res.bin/amour.sid
res.bin/levels.bin: bin/level res.org/levels.txt res.bin/levels.bin: bin/level res.org/levels.txt
bin/level < res.org/levels.txt > res.bin/levels.bin bin/level < res.org/levels.txt > res.bin/levels.bin

View File

@ -1,35 +1,23 @@
# snake6502 # snake6502
![Intro screenshot](scrot/intro.png)
![Gameplay screenshot](scrot/gameplay.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». *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 Current development status [here](https://git.giomba.it/giomba/snake6502).
* [.d64](dist/snake6502.d64) for floppy disks
* [.bin](dist/snake6502.bin) for 8KiB cartridges
## Compile ## Compile
You need the GNU compiler collection and the [dasm](https://dasm-assembler.github.io/) macro assembler, then: You need the GNU compiler collection and the [dasm](https://dasm-assembler.github.io/) macro assembler, then:
``` ```
$ git submodule init
$ git submodule update
$ make $ 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: You can also define the following environment variables:
```$ DEBUG=1 make``` build with debugging artifacts ```$ DEBUG=1 make``` build with debugging artifacts
## Tape ```$ VERBOSE=1 make``` output useful info during compilation
Copy ```loader.prg``` and ```packlz``` from disk to tape.
On a physical machine, you can use [disk2tape](https://git.giomba.it/giomba/cbmutil).
## Developer docs ## Developer docs
### Package ### Package
@ -46,55 +34,30 @@ Address | PRG | Description
```$0000 - $0001``` | no | hardware ```$0000 - $0001``` | no | hardware
```$0002 - $00FF``` | no | zero page pointers ```$0002 - $00FF``` | no | zero page pointers
```$0100 - $01FF``` | no | stack page ```$0100 - $01FF``` | no | stack page
```$0200 - $03FF``` | no | operating system variables ```$0200 - $07FF``` | no | *free ram*
```$0400 - $07FF``` | no | video memory ```$1000 - $1FFF``` | yes | SID tune
```$1000 - $1FFF``` | yes | SID tune, may overlap charset ```$2000 - $27FF``` | yes | custom char
```$2000 - $23FF``` | yes | custom char, unused, allow SID overlap
```$2400 - $27FF``` | yes | custom char (actual 0x80+)
```$2800 - $xxxx``` | yes | Program segment (only needed part used) ```$2800 - $xxxx``` | yes | Program segment (only needed part used)
```$xxxx - $CCFF``` | no | *free ram* ```$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 ```$D000 - $DFFF``` | no | I/O
```$E000 - $FFFF``` | no | Kernal ```$E000 - $FFFF``` | no | Kernal
### Compression ### 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. ```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.
Decompression occurs with one of the following loaders.
### Loader ### Decompression
#### Cartridge
```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```. ```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 ### Miscellanea
#### Custom charset #### Custom charset
Index | Description Index | Description
----------------|------------- ----------------|-------------
```$00 - $7F``` | unused (space for SID) ```$00 - $1F``` | A-Z (space first)
```$80 - $9F``` | A-Z (space first) ```$20 - $3F``` | A-Z, reversed (space first)
```$A0 - $BF``` | A-Z, reversed (space first) ```$40 - $4F``` | hex digits
```$C0 - $CF``` | hex digits ```$50 - $5F``` | hex digits, reversed
```$D0 - $DF``` | hex digits, reversed ```$60 - ``` | game tiles
```$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``` | ```├```

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 processor 6502
; SEGMENTS
SEG.U zeropageSegment SEG.U zeropageSegment
org $02 org $02
SEG loaderSegment INCLUDE "zeropage.asm"
SEG cartridgeSegment
org $8000 org $8000
; LOADER
SEG loaderSegment
cartridge SUBROUTINE cartridge SUBROUTINE
WORD .coldstart WORD .coldstart
WORD .warmstart WORD .warmstart
@ -48,9 +47,12 @@ cartridge SUBROUTINE
; decompression util ; decompression util
INCLUDE "lzgmini.asm" INCLUDE "lzgmini.asm"
#if VERBOSE = 1
ECHO "8k CARTRIDGE SIZE:",(. - $8000),"=",[(. - $8000)d] ECHO "8k CARTRIDGE SIZE:",(. - $8000),"=",[(. - $8000)d]
ECHO "SPACE LEFT:",($9fff - .),"=",[($9fff - .)d] ECHO "SPACE LEFT:",($9fff - .),"=",[($9fff - .)d]
#endif
; force filler for the *PROM ; force filler for the *PROM
. = $9fff . = $9fff
BYTE #$ff 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 ; Number of interrupt
; Used as counter to be decremented to do some things less frequently ; Used as counter to be decremented to do some things less frequently
irqn: irqn:
@ -49,22 +54,6 @@ delayStatus:
score: score:
WORD WORD
; vertical scroll intro #if VERBOSE = 1
introYscroll: ECHO "data.asm @ ",LASTINIT,"len:",(. - LASTINIT)
BYTE #endif
; 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

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 statusPlay: ; do Game
; Check counter ; Check counter
ldx irqn ldx irqn
@ -332,4 +335,9 @@ checkEndWallHit:
sta (tileMem),y sta (tileMem),y
skipPauseTests: skipPauseTests:
rts 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 ; Game is over
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
gameover: gameover:
@ -21,3 +24,7 @@ gameover:
lda #ST_DELAY lda #ST_DELAY
sta status sta status
rts 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 ; Initialized variables
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
@ -22,20 +25,11 @@ delay:
; Status of the game (costants pre-processor defined, sort of enum) ; Status of the game (costants pre-processor defined, sort of enum)
ST_INTRO0 = 0 ST_INTRO0 = 0
ST_INTRO1 = 1 ST_INTRO1 = 1
ST_INTRO2 = 2 ST_LEVEL_TITLE = 2
ST_INTRO3 = 3 ST_LEVEL_LOAD = 3
ST_INTRO4 = 4 ST_PLAY = 4
ST_INTRO5 = 5 ST_DELAY = 5
ST_INTRO6 = 6 ST_END = 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_PAUSE = 255 ST_PAUSE = 255
; Screen features ; Screen features
@ -44,10 +38,10 @@ SCREEN_H = 24
; Tiles ; Tiles
; ----- ; -----
EMPTY_TILE = $e0 EMPTY_TILE = $60
SNAKE_TILE = $e1 SNAKE_TILE = $61
FOOD_TILE = $e2 FOOD_TILE = $62
WALL_TILE = $e3 WALL_TILE = $63
; Tiles colors ; Tiles colors
; Note: these colors will be picked by the level select routine ; Note: these colors will be picked by the level select routine
@ -68,6 +62,16 @@ WALL_COLOR:
gameoverString: gameoverString:
BYTE "GAME IS OVER" BYTE "GAME IS OVER"
BYTE #0 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: intro2string:
BYTE "RETROFFICINA.GLGPROGRAMS.IT" BYTE "RETROFFICINA.GLGPROGRAMS.IT"
BYTE #0 BYTE #0
@ -75,38 +79,26 @@ intro3string:
#if DEBUG = 1 #if DEBUG = 1
BYTE "DBG RELS" BYTE "DBG RELS"
#else #else
BYTE "2017 (C) 2021" BYTE "(C) 2018"
#endif #endif
BYTE #0 BYTE #0
levelIntroString: levelIntroString:
BYTE "NEXT LEVEL" BYTE "NEXT LEVEL"
BYTE #0 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: scoreString:
BYTE "SCORE PART" BYTE "SCORE PART"
BYTE #0 BYTE #0
noMoreLevelsString: noMoreLevelsString:
BYTE "NO MORE LEVELS" BYTE "NO MORE LEVELS"
BYTE #0 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 ; Levels
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
levelsList: levelsList:
INCBIN "../res.bin/levels.bin" INCBIN "../res.bin/levels.bin"
#if VERBOSE = 1
ECHO "initdata.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,656 +1,86 @@
SEG zeropageSegment #if VERBOSE = 1
introDestPtr WORD LASTINIT SET .
#endif
SEG programSegment
introreset SUBROUTINE ; Currently statusIntro0 is the same as statusIntro1
jsr multicolorOff ; statusIntro1 has just been reserved for future use
statusIntro0:
jsr clearScreen statusIntro1:
; Decrement interrupt divider for the intro
; Set screen colors ldx introCounter
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
dex 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 ; I want to print strings at different columns to make them
asl ; bounce across the screen, so take last introX and add introXinc,
asl ; then print string at that point. If introX is too far right, then
asl ; set introXinc as #$ff (equals -1) so next time introX will be
sta $100,x ; decremented by 1. And then, if introX is too far left, then
lda $d016 ; set introXinc as #$01 so next time will be moved to right again.
and #$07 lda introX
ora $100,x 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 status1okset:
txs ; 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 ; Print "PRESS SPACE TO PLAY"
bcs .isEdge lda #<intro1string
cmp #3 sta srcStringPointer
bcc .isEdge lda #>intro1string
cmp #70 sta srcStringPointer + 1
bcs .isMiddle ; $0478 is 4th line (previously filled with color shades by reset routine)
cmp #10 ; add #19, then sub introX will make it move to other way of 2nd line
bcc .isMiddle lda #$78
jmp .enter clc
adc #19 ; add #19
sec
sbc introX ; sub introX
sta dstScreenPointer
lda #$04
sta dstScreenPointer + 1
jsr printString
.isMiddle: ; Some considerations on speed:
lda counter ; yes, maybe I should have put the string chars once in screen text memory
and #$01 ; and then move it left and right. Should re-think about this.
beq .enter ; For now, just return.
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
rts 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 ; Reset variables for a new level
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
levelresetvar: levelresetvar:
@ -32,3 +35,7 @@ clearListLoop:
bne clearListLoop bne clearListLoop
rts rts
#if VERBOSE = 1
ECHO "levelreset.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,14 +1,9 @@
SEG zeropageSegment #if VERBOSE = 1
; Pointer to video memory used in the level loading routine LASTINIT SET .
levelVideoPointer WORD #endif
levelColorPointer WORD
; Pointer to level struct
levelPointer WORD
SEG programSegment
; load new level on the screen ; load new level on the screen
statusLevelTitle SUBROUTINE statusLevelTitle SUBROUTINE
jsr multicolorOff
jsr clearScreen jsr clearScreen
; Print "Next Level" ; Print "Next Level"
@ -62,11 +57,10 @@ statusLevelTitle SUBROUTINE
rts rts
statusLevelLoad SUBROUTINE statusLevelLoad SUBROUTINE
jsr multicolorOn
; Upper bar -- fill with spaces, color yellow ; Upper bar -- fill with spaces, color yellow
ldx #39 ldx #39
.loop: .loop:
lda #$80 lda #$0
sta $400,x sta $400,x
lda #7 lda #7
sta $d800,x sta $d800,x
@ -145,9 +139,9 @@ writeLevelElement:
lda levelT lda levelT
sta (levelVideoPointer),y sta (levelVideoPointer),y
; tiles colors can be found in an array ; tiles colors can be found in an array
; position in array = tile value - $e0 ; position in array = tile value - $60
sec sec
sbc #$e0 sbc #$60
tax tax
lda tilesColors,x lda tilesColors,x
sta (levelColorPointer),y sta (levelColorPointer),y
@ -171,3 +165,7 @@ writeLevelEnd:
lda #ST_PLAY lda #ST_PLAY
sta status sta status
rts 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 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 clc
ldy #10 ldy #10
lda (srcPointer),y lda (srcPointer),y
adc srcPointer adc srcPointer
sta inEnd sta .inEnd
dey dey
lda (srcPointer),y lda (srcPointer),y
adc srcPointer + 1 adc srcPointer + 1
sta inEnd + 1 sta .inEnd + 1
clc clc
lda inEnd lda .inEnd
adc #16 adc #16
sta inEnd sta .inEnd
lda inEnd + 1 lda .inEnd + 1
adc #0 adc #0
sta inEnd + 1 sta .inEnd + 1
; Get the marker symbols ; Get the marker symbols
ldy #16 ldy #16
lda (srcPointer),y lda (srcPointer),y
sta marker1 sta .marker1
iny iny
lda (srcPointer),y lda (srcPointer),y
sta marker2 sta .marker2
iny iny
lda (srcPointer),y lda (srcPointer),y
sta marker3 sta .marker3
iny iny
lda (srcPointer),y lda (srcPointer),y
sta marker4 sta .marker4
; Skip header + marker symbols (16 + 4 bytes) ; Skip header + marker symbols (16 + 4 bytes)
clc clc
@ -57,30 +53,30 @@ inflate SUBROUTINE
ldy #0 ; Make sure that Y is zero ldy #0 ; Make sure that Y is zero
.mainloop: .mainloop:
lda srcPointer ; done? lda srcPointer ; done?
cmp inEnd cmp .inEnd
bne .notdone bne .notdone
lda srcPointer + 1 lda srcPointer + 1
cmp inEnd + 1 cmp .inEnd + 1
bne .notdone bne .notdone
rts rts
.notdone: .notdone:
lda (srcPointer),y ; A = symbol lda (srcPointer),y ; A = symbol
sta symbol sta .symbol
sta $d020 sta $d020
inc srcPointer inc srcPointer
bne .noinc1 bne .noinc1
inc srcPointer + 1 inc srcPointer + 1
.noinc1: .noinc1:
cmp marker1 ; Marker1? cmp .marker1 ; Marker1?
beq .domarker1 beq .domarker1
cmp marker2 ; Marker2? cmp .marker2 ; Marker2?
beq .domarker2 beq .domarker2
cmp marker3 ; Marker3? cmp .marker3 ; Marker3?
beq .domarker3 beq .domarker3
cmp marker4 ; Marker4? cmp .marker4 ; Marker4?
beq .domarker4 beq .domarker4
.literal: .literal:
lda symbol lda .symbol
sta (dstPointer),y ; Plain copy sta (dstPointer),y ; Plain copy
inc dstPointer inc dstPointer
bne .mainloop bne .mainloop
@ -105,15 +101,15 @@ inflate SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
sta offset sta .offset
inc offset inc .offset
lda #0 lda #0
sta offset + 1 ; offset = (b >> 5) + 1 sta .offset + 1 ; offset = (b >> 5) + 1
txa txa
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x 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 jmp .docopy
; marker3 - "Short copy" ; marker3 - "Short copy"
@ -134,13 +130,13 @@ inflate SUBROUTINE
lsr lsr
clc clc
adc #3 adc #3
sta length ; length = (b >> 6) + 3 sta .length ; length = (b >> 6) + 3
txa txa
and #$3f and #$3f
adc #8 adc #8
sta offset sta .offset
lda #0 lda #0
sta offset + 1 ; offset = (b & 0x3f) + 8 sta .offset + 1 ; offset = (b & 0x3f) + 8
beq .docopy beq .docopy
; marker2 - "Medium copy" ; marker2 - "Medium copy"
@ -158,7 +154,7 @@ inflate SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
sta offset + 1 sta .offset + 1
lda (srcPointer),y lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc6 bne .noinc6
@ -166,15 +162,15 @@ inflate SUBROUTINE
.noinc6: .noinc6:
clc clc
adc #8 adc #8
sta offset sta .offset
bcc .noinc7 bcc .noinc7
inc offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8 inc .offset + 1 ; offset = (((b & 0xe0) << 3) | b2) + 8
.noinc7: .noinc7:
txa txa
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x 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 bne .docopy
.literal2: .literal2:
@ -192,13 +188,13 @@ inflate SUBROUTINE
and #$1f and #$1f
tax tax
lda .LZG_LENGTH_DECODE_LUT,x 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 lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc9 bne .noinc9
inc srcPointer + 1 inc srcPointer + 1
.noinc9: .noinc9:
sta offset + 1 sta .offset + 1
lda (srcPointer),y lda (srcPointer),y
inc srcPointer inc srcPointer
bne .noinc10 bne .noinc10
@ -206,31 +202,31 @@ inflate SUBROUTINE
.noinc10: .noinc10:
clc clc
adc #$08 adc #$08
sta offset sta .offset
lda offset + 1 lda .offset + 1
adc #$08 adc #$08
sta offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056 sta .offset + 1 ; offset = ((b2 << 8) | (*src++)) + 2056
; Copy corresponding data from history window ; Copy corresponding data from history window
.docopy: .docopy:
sec sec
lda dstPointer lda dstPointer
sbc offset sbc .offset
sta copy sta .copy
lda dstPointer + 1 lda dstPointer + 1
sbc offset + 1 sbc .offset + 1
sta copy + 1 sta .copy + 1
.loop1: .loop1:
lda (copy),y lda (.copy),y
sta (dstPointer),y sta (dstPointer),y
iny iny
cpy length cpy .length
bne .loop1 bne .loop1
ldy #0 ; Make sure that Y is zero ldy #0 ; Make sure that Y is zero
clc clc
lda dstPointer lda dstPointer
adc length adc .length
sta dstPointer sta dstPointer
bcc .noinc11 bcc .noinc11
inc dstPointer + 1 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 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 SEG.U zeropageSegment
ORG_ZEROPAGE EQU $02 org $02
org ORG_ZEROPAGE 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 SEG sidSegment
ORG_SID EQU $1000 org $1000
org ORG_SID sidtune:
ORG_FONT EQU $2400 INCBIN "../res.bin/amour.sid"
SEG fontSegment #if VERBOSE = 1
org ORG_FONT ECHO "End of SIDtune at ",.,"Space left:",($2000 - .)
ORG_PROGRAM EQU $2800 #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 SEG programSegment
org ORG_PROGRAM org $2800
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
INCLUDE "program.asm" INCLUDE "program.asm"
INCLUDE "initdata.asm" INCLUDE "initdata.asm"
INCLUDE "game.asm" INCLUDE "game.asm"
INCLUDE "gameover.asm" INCLUDE "gameover.asm"
INCLUDE "introreset.asm"
INCLUDE "subroutines.asm" INCLUDE "subroutines.asm"
INCLUDE "levels.asm" INCLUDE "levels.asm"
INCLUDE "intro1.asm" INCLUDE "intro1.asm"
INCLUDE "multicolor.asm" INCLUDE "multicolor.asm"
INCLUDE "levelreset.asm" INCLUDE "levelreset.asm"
INCLUDE "outro.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 "data.asm"
INCLUDE "macro.asm" #if VERBOSE = 1
ECHO "program : start ",LASTINIT," end ",.," size ",(. - LASTINIT) 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 ; by giomba -- giomba at glgprograms.it
; this software is free software and is distributed ; this software is free software and is distributed
; under the terms of GNU GPL v3 license ; 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 multicolor SUBROUTINE
; Prepare data struct for MultiColor mode ; Prepare data struct for MultiColor mode
@ -38,3 +43,7 @@ multicolorOff:
and #$ef and #$ef
sta $d016 sta $d016
rts 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 ; Wait for some delay
statusDelay SUBROUTINE statusDelay SUBROUTINE
ldy delay ; load outroDelay and decrement ldy delay ; load outroDelay and decrement
@ -11,3 +14,7 @@ statusDelay SUBROUTINE
lda delayStatus lda delayStatus
sta status sta status
rts rts
#if VERBOSE = 1
ECHO "outro.asm @ ",LASTINIT,"len:",(. - LASTINIT)
#endif

View File

@ -1,10 +1,9 @@
SEG zeropageSegment #if VERBOSE = 1
; Interrupt counter LASTINIT SET .
counter DS 2 #endif
SEG programSegment ; ENTRY OF PROGRAM
; this is the entry point of the program and must stay at this address ; ----------------------------------------------------------------------
org $2800
start: start:
; Clear screen, initialize keyboard, restore interrupts ; Clear screen, initialize keyboard, restore interrupts
jsr $ff81 jsr $ff81
@ -58,45 +57,22 @@ zeroFillZeroPage:
lda #ST_INTRO0 lda #ST_INTRO0
sta status sta status
; Reset screen (and other parameters) to play intro
jsr introreset
; Enable interrupts ; Enable interrupts
cli cli
menu SUBROUTINE ; Reset screen (and other parameters) to play intro
.menu: ; Cycle here until SPACE or `Q` is pressed jsr introreset
intro0running: ; Cycle here until SPACE or `Q` is pressed
jsr $ffe4 ; GETIN jsr $ffe4 ; GETIN
cmp #$20 ; Is it SPACE? cmp #$20 ; Is it SPACE?
beq .intro0end ; if yes, go to intro0end and start game (see) 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
cmp #$51 ; Is it Q? 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 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 ; Intro is finished, now it's time to start the proper game
.intro0end: 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
; Set current level pointer to list start ; Set current level pointer to list start
lda #<levelsList lda #<levelsList
sta levelPointer sta levelPointer
@ -116,21 +92,20 @@ menu SUBROUTINE
lda #ST_LEVEL_TITLE lda #ST_LEVEL_TITLE
sta status sta status
.endless: endless:
; Loop waiting for gameover ; Loop waiting for gameover
lda status lda status
cmp #ST_END ; is status equal to end ? 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 ; Interrupt Handler
sta status ; put machine into menu status
jmp .menu ; and go there waiting for keypress
; Main Raster Interrupt Handler
; ---------------------------------------------------------------------- ; ----------------------------------------------------------------------
irq SUBROUTINE irq:
; Things that must be done every interrupt (50Hz) ; Things that must be done every interrupt (50Hz)
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Acknoweledge IRQ ; Acknoweledge IRQ
@ -143,83 +118,23 @@ irq SUBROUTINE
tya tya
pha 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 #if DEBUG = 1
; Change background to visually see the ISR timing ; Change background to visually see the ISR timing
lda #2 lda #2
sta $d020 sta $d020
#endif #endif
inc counter
bne .noIncCounter
inc counter + 1
.noIncCounter
; Check status and call appropriate sub-routine ; Check status and call appropriate sub-routine
; Sort of switch-case ; Sort of switch-case
lda status lda status
checkStatusIntro0:
cmp #ST_INTRO0 cmp #ST_INTRO0
bne checkStatusIntro1 bne checkStatusIntro1
jsr statusIntro0 jsr statusIntro0
jmp checkEndStatus jmp checkEndStatus
checkStatusIntro1: checkStatusIntro1:
cmp #ST_INTRO1 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 bne checkStatusPlay
jsr statusMenu jsr statusIntro1
jmp checkEndStatus jmp checkEndStatus
checkStatusPlay: checkStatusPlay:
cmp #ST_PLAY cmp #ST_PLAY
@ -243,6 +158,19 @@ checkStatusLevelLoad:
jmp checkEndStatus jmp checkEndStatus
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 ; Increase random value
inc random inc random
@ -261,3 +189,7 @@ checkEndStatus:
; Go to original system routine ; Go to original system routine
jmp $ea31 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 #if VERBOSE = 1
; Where is the snake head in video memory? Do math to calculate address LASTINIT SET .
; using pointer at tileMem #endif
tileMem WORD
; Subroutines
; ----------------------------------------------------------------------
SEG programSegment
; Clear screen -- easy ; Clear screen -- easy
clearScreen SUBROUTINE clearScreen SUBROUTINE
ldx #$ff ldx #$ff
.loop: .loop:
lda #$80 lda #$00
sta $400,x sta $400,x
sta $500,x sta $500,x
sta $600,x sta $600,x
@ -80,23 +81,16 @@ printByte SUBROUTINE
lsr lsr
lsr lsr
lsr lsr
ora #$c0 ; add 192 (see font) ora #$40 ; add 64 (see font)
sta $400,y ; print msb char sta $400,y ; print msb char
txa ; Take least significant nibble (use previous copy) txa ; Take least significant nibble (use previous copy)
and #$0f and #$0f
ora #$c0 ; add 192 (see font) ora #$40 ; add 64 (see font)
sta $401,y ; print lsb char sta $401,y ; print lsb char
rts rts
SEG zeropageSegment
; Pointer to string
srcStringPointer WORD
; Pointer to screen position where to print intro string
dstScreenPointer DS 2
SEG programSegment
printString SUBROUTINE printString SUBROUTINE
; Print string ; Print string
; Input parameters: ; Input parameters:
@ -110,22 +104,22 @@ printString SUBROUTINE
beq .end ; if zero, then end (string must be null-terminated) beq .end ; if zero, then end (string must be null-terminated)
cmp #$20 ; is space? cmp #$20 ; is space?
bne .checkP1 bne .checkP1
lda #$80 lda #$0
jmp .print jmp .print
.checkP1: .checkP1:
cmp #$28 ; is char '(' ? cmp #$28 ; is char '(' ?
bne .checkP2 bne .checkP2
lda #$9b lda #$1b
jmp .print jmp .print
.checkP2: .checkP2:
cmp #$29 ; is char ')' ? cmp #$29 ; is char ')' ?
bne .checkP3 bne .checkP3
lda #$9c lda #$1c
jmp .print jmp .print
.checkP3 .checkP3
cmp #$2e ; is char '.' ? cmp #$2e ; is char '.' ?
bne .checkNumber bne .checkNumber
lda #$9d lda #$1d
jmp .print jmp .print
.checkNumber: ; is char a number? .checkNumber: ; is char a number?
cmp #$2f cmp #$2f
@ -135,14 +129,14 @@ printString SUBROUTINE
sec sec
sbc #$30 sbc #$30
clc clc
adc #$c0 adc #$40
jmp .print jmp .print
.nextCheck: .nextCheck:
.isLetter: .isLetter:
; defaults to an uppercase letter of ASCII set ; defaults to an uppercase letter of ASCII set
clc sec
adc #$40 sbc #$40
.print: .print:
sta (dstScreenPointer),y ; put screen code to screen sta (dstScreenPointer),y ; put screen code to screen
iny ; next char in string iny ; next char in string
@ -150,11 +144,6 @@ printString SUBROUTINE
.end: .end:
rts rts
SEG zeropageSegment
; Pointer for Pointer in the NextPointer routine
nextPointerPointer DS 2
SEG programSegment
; Increment a pointer in the zeropage ; Increment a pointer in the zeropage
; Input parameters: ; Input parameters:
; nextPointerPointer pointer to the pointer in zeropage ; nextPointerPointer pointer to the pointer in zeropage
@ -175,3 +164,7 @@ nextPointer:
sta (nextPointerPointer),y sta (nextPointerPointer),y
rts 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; char tile, color;
switch(last) { switch(last) {
case 'x': case 'x':
tile = (char)0xe3; break; tile = (char)0x63; break;
case 'f': case 'f':
tile = (char)0xe2; break; tile = (char)0x62; break;
default: default:
tile = (char)0xe0; break; tile = (char)0x60; break;
} }
cout << tile << (char)count; cout << tile << (char)count;
} }