Big memory and repository reorganization
This commit is contained in:
parent
868d1e6253
commit
5d9248e580
6
Makefile
6
Makefile
@ -1,8 +1,8 @@
|
|||||||
64:
|
64:
|
||||||
dasm snake.asm -DSYSTEM=64 -DDEBUG=0 -osnake.prg
|
dasm main.asm -DSYSTEM=64 -DDEBUG=0 -osnake.prg
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
dasm snake.asm -DSYSTEM=64 -DDEBUG=1 -ssymbols.txt -osnake.prg
|
dasm main.asm -DSYSTEM=64 -DDEBUG=1 -ssymbols.txt -osnake.prg
|
||||||
|
|
||||||
16:
|
16:
|
||||||
dasm snake.asm -DSYSTEM=16 -osnake.prg
|
dasm main.asm -DSYSTEM=16 -osnake.prg
|
||||||
|
2
basic.asm
Normal file
2
basic.asm
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
; 10 SYS10240 ($2800) BASIC autostart
|
||||||
|
BYTE #$0b,#$08,#$0a,#$00,#$9e,#$31,#$30,#$32,#$34,#$30,#$00,#$00,#$00
|
53
data.asm
Normal file
53
data.asm
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
; Data section
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
; Number of interrupt
|
||||||
|
; Used as counter to be decremented to do some things less frequently
|
||||||
|
irqn:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Direction of the snake (2,4,6,8 as down,left,right,up)
|
||||||
|
; 5 means `pause`
|
||||||
|
direction:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Snake head coordinates in video memory
|
||||||
|
snakeX:
|
||||||
|
BYTE
|
||||||
|
snakeY:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Parameters for calcTileMem
|
||||||
|
calcTileX:
|
||||||
|
BYTE
|
||||||
|
calcTileY:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; List start and length
|
||||||
|
listStart:
|
||||||
|
BYTE
|
||||||
|
length:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Random value
|
||||||
|
random:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Status
|
||||||
|
status:
|
||||||
|
BYTE
|
||||||
|
|
||||||
|
; Intro counter
|
||||||
|
introCounter:
|
||||||
|
BYTE #$4
|
||||||
|
|
||||||
|
; Intro string x position, and next increment
|
||||||
|
introX:
|
||||||
|
BYTE #$0
|
||||||
|
introXinc:
|
||||||
|
BYTE #$1
|
||||||
|
|
||||||
|
; Outro delay
|
||||||
|
outroDelay
|
||||||
|
BYTE #$ff
|
||||||
|
|
||||||
|
|
314
game.asm
Normal file
314
game.asm
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
statusPlay: ; do Game
|
||||||
|
; Check counter
|
||||||
|
ldx irqn
|
||||||
|
dex
|
||||||
|
stx irqn
|
||||||
|
beq irqsometime ; if counter is 0, then do these "rare" things
|
||||||
|
rts ; else do nothing and simply return
|
||||||
|
; as you can see, game actually runs at 12 Hz
|
||||||
|
|
||||||
|
irqsometime:
|
||||||
|
; Things that must be done only one in four interrupts (12 Hz)
|
||||||
|
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
; If I am here, counter reached 0, so first reset it
|
||||||
|
ldx #4
|
||||||
|
stx irqn
|
||||||
|
|
||||||
|
; Get pressed key and decide snake direction
|
||||||
|
jsr $ffe4 ; Kernal routine GETIN
|
||||||
|
cmp #0
|
||||||
|
beq keybEndCheck ; if no key pressed, just skip this switch-case
|
||||||
|
ldx #$7f ; else, if key pressed, reset random variable
|
||||||
|
stx random
|
||||||
|
keybCheckA: ; check for press of key `A`
|
||||||
|
cmp #$41
|
||||||
|
bne keybCheckS ; if not pressed `A`, just skip to next key to check
|
||||||
|
lda direction ; else check if current direction is right
|
||||||
|
cmp #6
|
||||||
|
beq keybEndCheck ; if yes, you can't turn over yourself, so just skip to next key check
|
||||||
|
lda #4
|
||||||
|
sta direction ; else set direction to left and store new value
|
||||||
|
jmp keybEndCheck ; skip all other key tests
|
||||||
|
keybCheckS: ; simply re-do for S, D, W and other keys...
|
||||||
|
cmp #$53
|
||||||
|
bne keybCheckD
|
||||||
|
lda direction
|
||||||
|
cmp #8
|
||||||
|
beq keybEndCheck
|
||||||
|
lda #2
|
||||||
|
sta direction
|
||||||
|
jmp keybEndCheck
|
||||||
|
keybCheckD:
|
||||||
|
cmp #$44
|
||||||
|
bne keybCheckW
|
||||||
|
lda direction
|
||||||
|
cmp #4
|
||||||
|
beq keybEndCheck
|
||||||
|
lda #6
|
||||||
|
sta direction
|
||||||
|
jmp keybEndCheck
|
||||||
|
keybCheckW:
|
||||||
|
cmp #$57
|
||||||
|
bne keybCheckP
|
||||||
|
lda direction
|
||||||
|
cmp #2
|
||||||
|
beq keybEndCheck
|
||||||
|
lda #8
|
||||||
|
sta direction
|
||||||
|
jmp keybEndCheck
|
||||||
|
keybCheckP:
|
||||||
|
cmp #$50
|
||||||
|
bne keybEndCheck
|
||||||
|
lda #5
|
||||||
|
sta direction
|
||||||
|
jmp keybEndCheck
|
||||||
|
keybEndCheck:
|
||||||
|
|
||||||
|
; Get joystick status and decide snake direction
|
||||||
|
; Joystick register bits 4:0 => Fire,Right,Left,Down,Up
|
||||||
|
; 0 = Pressed; 1 = Idle
|
||||||
|
lda $dc00 ; CIA joystick port 2 register
|
||||||
|
ror ; rotate bit and put bit#0 in CF
|
||||||
|
tax ; store byte value for next key check
|
||||||
|
bcs joyCheckDown ; if CF = 1, then key was not depressed, so skip and check next...
|
||||||
|
; ... else key was depressed!
|
||||||
|
lda direction ; check for not overlapping direction (turn over yourself)
|
||||||
|
cmp #2
|
||||||
|
beq joyEndCheck
|
||||||
|
lda #8
|
||||||
|
sta direction
|
||||||
|
jmp joyEndCheck
|
||||||
|
joyCheckDown:
|
||||||
|
txa
|
||||||
|
ror
|
||||||
|
tax
|
||||||
|
bcs joyCheckLeft
|
||||||
|
lda direction
|
||||||
|
cmp #8
|
||||||
|
beq joyEndCheck
|
||||||
|
lda #2
|
||||||
|
sta direction
|
||||||
|
jmp joyEndCheck
|
||||||
|
joyCheckLeft:
|
||||||
|
txa
|
||||||
|
ror
|
||||||
|
tax
|
||||||
|
bcs joyCheckRight
|
||||||
|
lda direction
|
||||||
|
cmp #6
|
||||||
|
beq joyEndCheck
|
||||||
|
lda #4
|
||||||
|
sta direction
|
||||||
|
jmp joyEndCheck
|
||||||
|
joyCheckRight:
|
||||||
|
txa
|
||||||
|
ror
|
||||||
|
tax
|
||||||
|
bcs joyCheckFire
|
||||||
|
lda direction
|
||||||
|
cmp #4
|
||||||
|
beq joyEndCheck
|
||||||
|
lda #6
|
||||||
|
sta direction
|
||||||
|
jmp joyEndCheck
|
||||||
|
joyCheckFire: ; `Fire` joystick key used to pause game
|
||||||
|
txa
|
||||||
|
ror
|
||||||
|
tax
|
||||||
|
bcs joyEndCheck
|
||||||
|
lda #5
|
||||||
|
sta direction
|
||||||
|
joyEndCheck:
|
||||||
|
|
||||||
|
; Get direction and move head accordingly
|
||||||
|
lda direction
|
||||||
|
dirCheck2: ; check if direction is down...
|
||||||
|
cmp #2
|
||||||
|
bne dirCheck4 ; if not down, then skip and check next direction,
|
||||||
|
ldy snakeY ; else, direction is down, so get snakeY
|
||||||
|
iny ; increment snakeY (keep in mind that screen up/down coordinates are reversed)
|
||||||
|
sty snakeY ; update snakeY
|
||||||
|
dirCheck4: ; simply re-do for other directions...
|
||||||
|
cmp #4
|
||||||
|
bne dirCheck6
|
||||||
|
ldx snakeX
|
||||||
|
dex
|
||||||
|
stx snakeX
|
||||||
|
dirCheck6:
|
||||||
|
cmp #6
|
||||||
|
bne dirCheck8
|
||||||
|
ldx snakeX
|
||||||
|
inx
|
||||||
|
stx snakeX
|
||||||
|
dirCheck8:
|
||||||
|
cmp #8
|
||||||
|
bne dirCheck5
|
||||||
|
ldy snakeY
|
||||||
|
dey
|
||||||
|
sty snakeY
|
||||||
|
dirCheck5:
|
||||||
|
cmp #5
|
||||||
|
bne dirEndCheck
|
||||||
|
jmp skipPauseTests
|
||||||
|
dirEndCheck:
|
||||||
|
|
||||||
|
; Check screen boundaries overflow
|
||||||
|
lda snakeX
|
||||||
|
cmp #40
|
||||||
|
bne overCheckX0 ; if snakeX is not 40, then all ok, skip to next test
|
||||||
|
lda #0 ; else, there is an overflow, so trespass screen border
|
||||||
|
sta snakeX
|
||||||
|
overCheckX0: ; simply re-do for every side of the screen
|
||||||
|
lda snakeX
|
||||||
|
cmp #$ff
|
||||||
|
bne overCheckY1
|
||||||
|
lda #39
|
||||||
|
sta snakeX
|
||||||
|
overCheckY1:
|
||||||
|
lda snakeY
|
||||||
|
cmp #25
|
||||||
|
bne overCheckY0
|
||||||
|
lda #1
|
||||||
|
sta snakeY
|
||||||
|
overCheckY0
|
||||||
|
lda snakeY
|
||||||
|
cmp #0
|
||||||
|
bne overEndCheck
|
||||||
|
lda #24
|
||||||
|
sta snakeY
|
||||||
|
overEndCheck:
|
||||||
|
|
||||||
|
; Put new head coordinates in list
|
||||||
|
ldy listStart
|
||||||
|
lda snakeX
|
||||||
|
sta listX,y
|
||||||
|
lda snakeY
|
||||||
|
sta listY,y
|
||||||
|
iny
|
||||||
|
sty listStart
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
; Check for food eat / wall hit / self-eat
|
||||||
|
; - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
; --- Food eat ---
|
||||||
|
lda snakeX ; calc head location in memory
|
||||||
|
sta calcTileX
|
||||||
|
lda snakeY
|
||||||
|
sta calcTileY
|
||||||
|
jsr calcTileMem
|
||||||
|
lda (tileMem),y ; read content of head memory location
|
||||||
|
cmp #FOOD_TILE
|
||||||
|
beq foodEaten ; if memory does contain food, then perform foodEaten actions,
|
||||||
|
jmp checkSelfEat ; else just loooong jump to test if I ate myself
|
||||||
|
foodEaten:
|
||||||
|
ldx length ; else, increment snake length,
|
||||||
|
inx
|
||||||
|
stx length
|
||||||
|
genFood:
|
||||||
|
ldx random
|
||||||
|
inx
|
||||||
|
stx random
|
||||||
|
|
||||||
|
txa
|
||||||
|
genFoodX: ; calculate `random` modulo SCREEN_W
|
||||||
|
sec
|
||||||
|
sbc #SCREEN_W
|
||||||
|
cmp #SCREEN_W
|
||||||
|
bcs genFoodX
|
||||||
|
sta calcTileX
|
||||||
|
|
||||||
|
txa
|
||||||
|
genFoodY: ; calculate `random` modulo 22 (22 = SCREEN_H - 1)
|
||||||
|
sec
|
||||||
|
sbc #22
|
||||||
|
cmp #22
|
||||||
|
bcs genFoodY
|
||||||
|
clc ; add 1 because 1st line can not be used
|
||||||
|
adc #1
|
||||||
|
sta calcTileY
|
||||||
|
|
||||||
|
; Now I have X and Y coordinate for food stored in calcTileX, calcTileY
|
||||||
|
; and I must check it is not the location that I am going to overwrite
|
||||||
|
; with the head in draw snake head...
|
||||||
|
lda calcTileX
|
||||||
|
cmp snakeX
|
||||||
|
bne foodOK
|
||||||
|
lda calcTileY
|
||||||
|
cmp snakeY
|
||||||
|
beq genFood
|
||||||
|
foodOK:
|
||||||
|
; debug -- print choosen X,Y for food
|
||||||
|
; ldy #$18
|
||||||
|
; lda calcTileX
|
||||||
|
; jsr printByte
|
||||||
|
; ldy #$1b
|
||||||
|
; lda calcTileY
|
||||||
|
; jsr printByte
|
||||||
|
|
||||||
|
ldy #0
|
||||||
|
jsr calcTileMem ; calc food address in memory
|
||||||
|
lda (tileMem),y ; check if memory is empty
|
||||||
|
cmp #$20 ; is there a space?
|
||||||
|
bne genFood ; if not, must generate another number
|
||||||
|
lda #FOOD_TILE ; else, just put that fucking piece of food there
|
||||||
|
sta (tileMem),y
|
||||||
|
|
||||||
|
lda #$d4
|
||||||
|
clc
|
||||||
|
adc tileMem + 1
|
||||||
|
sta tileMem + 1
|
||||||
|
lda #FOOD_COLOR
|
||||||
|
sta (tileMem),y
|
||||||
|
|
||||||
|
; print score at $10th column
|
||||||
|
ldy #$10
|
||||||
|
lda length
|
||||||
|
jsr printByte
|
||||||
|
|
||||||
|
jmp checkEndSelfEat
|
||||||
|
checkEndFood:
|
||||||
|
|
||||||
|
; --- Self eat ---
|
||||||
|
checkSelfEat:
|
||||||
|
cmp #SNAKE_TILE
|
||||||
|
bne checkEndSelfEat
|
||||||
|
jmp gameover
|
||||||
|
checkEndSelfEat:
|
||||||
|
|
||||||
|
; Draw snake head
|
||||||
|
ldy #0
|
||||||
|
lda snakeX ; calc char address in video memory, and put SNAKE_TILE
|
||||||
|
sta calcTileX
|
||||||
|
lda snakeY
|
||||||
|
sta calcTileY
|
||||||
|
jsr calcTileMem
|
||||||
|
lda #SNAKE_TILE
|
||||||
|
sta (tileMem),y
|
||||||
|
|
||||||
|
lda #$d4 ; add #$d400 to previous address (obtain color memory
|
||||||
|
clc ; correspondent), and put SNAKE_COLOR
|
||||||
|
adc tileMem + 1
|
||||||
|
sta tileMem + 1
|
||||||
|
lda #SNAKE_COLOR
|
||||||
|
sta (tileMem),y
|
||||||
|
|
||||||
|
; Erase snake tail
|
||||||
|
lda listStart ; take start of list, and subtract snake length,
|
||||||
|
sec ; to obtain index of end of list
|
||||||
|
sbc length
|
||||||
|
tax ; use previous value as index in list, and calc video memory address
|
||||||
|
lda listX,x
|
||||||
|
sta calcTileX
|
||||||
|
lda listY,x
|
||||||
|
sta calcTileY
|
||||||
|
jsr calcTileMem
|
||||||
|
lda #$20 ; just put a space to erase snake tail tile
|
||||||
|
sta (tileMem),y
|
||||||
|
|
||||||
|
skipPauseTests:
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
17
gameover.asm
Normal file
17
gameover.asm
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
; Game is over
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
gameover:
|
||||||
|
lda #<gameoverString
|
||||||
|
sta printStatusString
|
||||||
|
lda #>gameoverString
|
||||||
|
sta printStatusString + 1
|
||||||
|
jsr printStatus
|
||||||
|
|
||||||
|
; Set gameover and outro status
|
||||||
|
lda #$ff
|
||||||
|
sta outroDelay
|
||||||
|
lda #ST_OUTRO
|
||||||
|
sta status
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
80
intro1.asm
Normal file
80
intro1.asm
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
; 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
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
status1okset:
|
||||||
|
; Print "SNAKE BY GIOMBA" (see above for pointer details)
|
||||||
|
lda #<intro0string
|
||||||
|
sta printIntroString
|
||||||
|
lda #>intro0string
|
||||||
|
sta printIntroString + 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 introScreenStart
|
||||||
|
lda #$04
|
||||||
|
sta introScreenStart + 1
|
||||||
|
jsr printIntro
|
||||||
|
|
||||||
|
; Print "PRESS SPACE TO PLAY"
|
||||||
|
lda #<intro1string
|
||||||
|
sta printIntroString
|
||||||
|
lda #>intro1string
|
||||||
|
sta printIntroString + 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 introScreenStart
|
||||||
|
lda #$04
|
||||||
|
sta introScreenStart + 1
|
||||||
|
jsr printIntro
|
||||||
|
|
||||||
|
; 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
|
||||||
|
|
||||||
|
|
57
introreset.asm
Normal file
57
introreset.asm
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
; Intro reset
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
introreset:
|
||||||
|
jsr multicolorOff
|
||||||
|
|
||||||
|
; Clear screen
|
||||||
|
ldx #$ff
|
||||||
|
lda #$20
|
||||||
|
introresetCLS:
|
||||||
|
sta $400,x
|
||||||
|
sta $500,x
|
||||||
|
sta $600,x
|
||||||
|
sta $700,x
|
||||||
|
dex
|
||||||
|
cpx #$ff
|
||||||
|
bne introresetCLS
|
||||||
|
|
||||||
|
; 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 printIntroString ; put into lsb of source pointer
|
||||||
|
lda #>intro2string ; do the same for msb of string address
|
||||||
|
sta printIntroString + 1 ; put into msb of source pointer
|
||||||
|
lda #$26 ; this is lsb of address of 20th line
|
||||||
|
sta introScreenStart ; put into lsb of dest pointer
|
||||||
|
lda #$07 ; do the same for msb of adress of 20th line
|
||||||
|
sta introScreenStart + 1 ; put into msb of dest pointer
|
||||||
|
jsr printIntro ; print
|
||||||
|
|
||||||
|
; Print Copyright
|
||||||
|
lda #<intro3string ; the assembly is the same as above,
|
||||||
|
sta printIntroString ; just change string to be printed
|
||||||
|
lda #>intro3string ; and line (21th line)
|
||||||
|
sta printIntroString + 1
|
||||||
|
lda #$58
|
||||||
|
sta introScreenStart
|
||||||
|
lda #$07
|
||||||
|
sta introScreenStart + 1
|
||||||
|
jsr printIntro
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
79
main.asm
Normal file
79
main.asm
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
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 $02
|
||||||
|
INCLUDE "zeropage.asm"
|
||||||
|
|
||||||
|
; Initialized segments
|
||||||
|
SEG basicSegment
|
||||||
|
org $801
|
||||||
|
INCLUDE "basic.asm"
|
||||||
|
|
||||||
|
SEG dataSegment
|
||||||
|
org $900
|
||||||
|
INCLUDE "data.asm"
|
||||||
|
INCLUDE "const.asm"
|
||||||
|
|
||||||
|
; List
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
. = $e00
|
||||||
|
listX:
|
||||||
|
. = $f00
|
||||||
|
listY:
|
||||||
|
|
||||||
|
; SID tune (previously properly cleaned, see HVSC)
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
SEG sidSegment
|
||||||
|
org $1000
|
||||||
|
sidtune:
|
||||||
|
INCBIN "amour.sid"
|
||||||
|
#if DEBUG = 1
|
||||||
|
ECHO "End of SIDtune. Space left: ",($2000 - .)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; Font Data
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
SEG tggsSegment
|
||||||
|
org $2000
|
||||||
|
; This binary data that defines the font is exactly 2kB long ($800)
|
||||||
|
tggsFont:
|
||||||
|
INCBIN "tggs.font"
|
||||||
|
|
||||||
|
; Include program
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
SEG programSegment
|
||||||
|
org $2800
|
||||||
|
jmp start
|
||||||
|
|
||||||
|
INCLUDE "game.asm"
|
||||||
|
INCLUDE "gameover.asm"
|
||||||
|
INCLUDE "gamereset.asm"
|
||||||
|
INCLUDE "introreset.asm"
|
||||||
|
INCLUDE "intro1.asm"
|
||||||
|
INCLUDE "multicolor.asm"
|
||||||
|
INCLUDE "outro.asm"
|
||||||
|
INCLUDE "program.asm"
|
||||||
|
INCLUDE "subroutines.asm"
|
||||||
|
|
||||||
|
#if DEBUG = 1
|
||||||
|
ECHO "Program ends at: ",.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
;
|
||||||
|
; coded during december 2017
|
||||||
|
; by giomba -- giomba at glgprograms.it
|
||||||
|
; this software is free software and is distributed
|
||||||
|
; under the terms of GNU GPL v3 license
|
||||||
|
;
|
||||||
|
|
||||||
|
; vim: set expandtab tabstop=4 shiftwidth=4:
|
16
outro.asm
Normal file
16
outro.asm
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
; Decrement outroDelay, just to let player see her/his end screen
|
||||||
|
; with score
|
||||||
|
statusOutro:
|
||||||
|
ldy outroDelay ; load outroDelay and decrement
|
||||||
|
dey
|
||||||
|
sty outroDelay
|
||||||
|
cpy #0
|
||||||
|
beq statusOutroEnd
|
||||||
|
rts
|
||||||
|
statusOutroEnd:
|
||||||
|
; Set status as ST_END: this way, the loop out of this interrupt,
|
||||||
|
; will know that we finished, and will play the intro again
|
||||||
|
lda #ST_END
|
||||||
|
sta status
|
||||||
|
rts
|
||||||
|
|
170
program.asm
Normal file
170
program.asm
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
; ENTRY OF PROGRAM
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
start:
|
||||||
|
; Clear screen, initialize keyboard, restore interrupts
|
||||||
|
jsr $ff81
|
||||||
|
|
||||||
|
; Disable all interrupts
|
||||||
|
sei
|
||||||
|
|
||||||
|
; Turn off CIA interrupts and (eventually) flush the pending queue
|
||||||
|
ldy #$7f
|
||||||
|
sty $dc0d
|
||||||
|
sty $dd0d
|
||||||
|
lda $dc0d
|
||||||
|
lda $dd0d
|
||||||
|
|
||||||
|
; Set Interrupt Request Mask as we want IRQ by raster beam
|
||||||
|
lda #$1
|
||||||
|
sta $d01a
|
||||||
|
|
||||||
|
; Store in $314 address of our custom interrupt handler
|
||||||
|
ldx #<irq ; least significant byte
|
||||||
|
ldy #>irq ; most significant byte
|
||||||
|
stx $314
|
||||||
|
sty $315
|
||||||
|
|
||||||
|
; Set raster beam to trigger interrupt at row zero
|
||||||
|
lda #$00
|
||||||
|
sta $d012
|
||||||
|
|
||||||
|
; Bit#0 of $d011 is used as bit#9 of $d012, and must be zero
|
||||||
|
lda $d011
|
||||||
|
and #$7f
|
||||||
|
sta $d011
|
||||||
|
|
||||||
|
; Initialize player for first song
|
||||||
|
lda #0
|
||||||
|
jsr sidtune
|
||||||
|
|
||||||
|
; Initialize MultiColor mode
|
||||||
|
jsr multicolorInit
|
||||||
|
|
||||||
|
; Zero-fill zeropage variables
|
||||||
|
lda #$0
|
||||||
|
ldx #$90
|
||||||
|
zeroFillZeroPage:
|
||||||
|
dex
|
||||||
|
sta $0,x
|
||||||
|
cpx #$2
|
||||||
|
bne zeroFillZeroPage
|
||||||
|
|
||||||
|
; Set status as first-time intro playing
|
||||||
|
lda #ST_INTRO0
|
||||||
|
sta status
|
||||||
|
|
||||||
|
; Enable interrupts
|
||||||
|
cli
|
||||||
|
|
||||||
|
; 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)
|
||||||
|
cmp #$51 ; Is it Q?
|
||||||
|
bne intro0running ; If not, keep looping here,
|
||||||
|
jmp $fce2 ; else, reset the computer
|
||||||
|
|
||||||
|
; Intro is finished, now it's time to start the proper game
|
||||||
|
intro0end:
|
||||||
|
; Pause everything in interrupt
|
||||||
|
lda #ST_PAUSE
|
||||||
|
sta status
|
||||||
|
; Set init variables of the game
|
||||||
|
jsr gamereset
|
||||||
|
|
||||||
|
; Set status as game playing
|
||||||
|
lda #ST_PLAY
|
||||||
|
sta status
|
||||||
|
|
||||||
|
endless:
|
||||||
|
; Loop waiting for gameover
|
||||||
|
lda status
|
||||||
|
cmp #ST_END ; is status equal to end ?
|
||||||
|
bne endless ; if not, just wait looping here, else...
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
; Interrupt Handler
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
irq:
|
||||||
|
; Things that must be done every interrupt (50Hz)
|
||||||
|
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
; Acknoweledge IRQ
|
||||||
|
dec $d019
|
||||||
|
|
||||||
|
; Save registers in stack
|
||||||
|
pha
|
||||||
|
txa
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
|
||||||
|
#if DEBUG = 1
|
||||||
|
; Change background to visually see the ISR timing
|
||||||
|
lda #2
|
||||||
|
sta $d020
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; Check status and call appropriate sub-routine
|
||||||
|
; Sort of switch-case
|
||||||
|
lda status
|
||||||
|
cmp #ST_INTRO0
|
||||||
|
bne checkStatus1
|
||||||
|
jsr statusIntro0
|
||||||
|
jmp checkEndStatus
|
||||||
|
checkStatus1:
|
||||||
|
cmp #ST_INTRO1
|
||||||
|
bne checkStatus2
|
||||||
|
jsr statusIntro1
|
||||||
|
jmp checkEndStatus
|
||||||
|
checkStatus2
|
||||||
|
cmp #ST_PLAY
|
||||||
|
bne checkStatus3
|
||||||
|
jsr statusPlay
|
||||||
|
jmp checkEndStatus
|
||||||
|
checkStatus3
|
||||||
|
cmp #ST_OUTRO
|
||||||
|
bne checkEndStatus
|
||||||
|
jsr statusOutro
|
||||||
|
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
|
||||||
|
|
||||||
|
#if DEBUG = 1
|
||||||
|
; Change background back again to visally see ISR timing
|
||||||
|
lda #11
|
||||||
|
sta $d020
|
||||||
|
#endif
|
||||||
|
|
||||||
|
; Restore registers from stack
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
|
||||||
|
; Go to original system routine
|
||||||
|
jmp $ea31
|
||||||
|
|
||||||
|
|
917
snake.asm
917
snake.asm
@ -1,917 +0,0 @@
|
|||||||
processor 6502
|
|
||||||
|
|
||||||
; Platform specific code
|
|
||||||
; Code yet to be developed, example to use:
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
#if SYSTEM = 64
|
|
||||||
; Commodore64 specific code
|
|
||||||
#else
|
|
||||||
; Commodore16 specific code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
; Zero page utilities
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
SEG.U zeropage
|
|
||||||
org $02
|
|
||||||
; Where is the snake head in video memory? Do math to calculate address
|
|
||||||
; using pointer at tileMem,tileMem+1
|
|
||||||
tileMem DS 2
|
|
||||||
|
|
||||||
; Pointer to status string
|
|
||||||
printStatusString DS 2
|
|
||||||
|
|
||||||
; Pointer to intro string
|
|
||||||
printIntroString DS 2
|
|
||||||
; Pointer to screen position where to print intro string ($fb-$fc)
|
|
||||||
introScreenStart DS 2
|
|
||||||
|
|
||||||
#if DEBUG = 1
|
|
||||||
; Locations $90-$FF in zeropage are used by kernal
|
|
||||||
ECHO "End of zeropage variables. Space left: ",($90 - .)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SEG program
|
|
||||||
org $801
|
|
||||||
. = $801 ; 10 SYS10240 ($2800) BASIC autostart
|
|
||||||
BYTE #$0b,#$08,#$0a,#$00,#$9e,#$31,#$30,#$32,#$34,#$30,#$00,#$00,#$00
|
|
||||||
|
|
||||||
; Data section
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
; Number of interrupt
|
|
||||||
; Used as counter to be decremented to do some things less frequently
|
|
||||||
irqn:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Direction of the snake (2,4,6,8 as down,left,right,up)
|
|
||||||
; 5 means `pause`
|
|
||||||
direction:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Snake head coordinates in video memory
|
|
||||||
snakeX:
|
|
||||||
BYTE
|
|
||||||
snakeY:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Parameters for calcTileMem
|
|
||||||
calcTileX:
|
|
||||||
BYTE
|
|
||||||
calcTileY:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; List start and length
|
|
||||||
listStart:
|
|
||||||
BYTE
|
|
||||||
length:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Random value
|
|
||||||
random:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Status
|
|
||||||
status:
|
|
||||||
BYTE
|
|
||||||
|
|
||||||
; Intro counter
|
|
||||||
introCounter:
|
|
||||||
BYTE #$4
|
|
||||||
|
|
||||||
; Intro string x position, and next increment
|
|
||||||
introX:
|
|
||||||
BYTE #$0
|
|
||||||
introXinc:
|
|
||||||
BYTE #$1
|
|
||||||
|
|
||||||
; Outro delay
|
|
||||||
outroDelay
|
|
||||||
BYTE #$ff
|
|
||||||
|
|
||||||
INCLUDE "cost.asm"
|
|
||||||
|
|
||||||
#if DEBUG = 1
|
|
||||||
ECHO "End of Data. Space left: ",($e00 - .)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
; List
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
. = $e00
|
|
||||||
listX:
|
|
||||||
. = $f00
|
|
||||||
listY:
|
|
||||||
|
|
||||||
; SID tune (previously properly cleaned, see HVSC)
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
. = $1000
|
|
||||||
sidtune:
|
|
||||||
INCBIN "amour.sid"
|
|
||||||
#if DEBUG = 1
|
|
||||||
ECHO "End of SIDtune. Space left: ",($2000 - .)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
. = $2000
|
|
||||||
; This binary data that defines the font is exactly 2kB long ($800)
|
|
||||||
tggsFont:
|
|
||||||
INCBIN "tggs.font"
|
|
||||||
|
|
||||||
; ENTRY OF PROGRAM
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
. = $2800
|
|
||||||
start:
|
|
||||||
; Clear screen, initialize keyboard, restore interrupts
|
|
||||||
jsr $ff81
|
|
||||||
|
|
||||||
; Disable all interrupts
|
|
||||||
sei
|
|
||||||
|
|
||||||
; Turn off CIA interrupts and (eventually) flush the pending queue
|
|
||||||
ldy #$7f
|
|
||||||
sty $dc0d
|
|
||||||
sty $dd0d
|
|
||||||
lda $dc0d
|
|
||||||
lda $dd0d
|
|
||||||
|
|
||||||
; Set Interrupt Request Mask as we want IRQ by raster beam
|
|
||||||
lda #$1
|
|
||||||
sta $d01a
|
|
||||||
|
|
||||||
; Store in $314 address of our custom interrupt handler
|
|
||||||
ldx #<irq ; least significant byte
|
|
||||||
ldy #>irq ; most significant byte
|
|
||||||
stx $314
|
|
||||||
sty $315
|
|
||||||
|
|
||||||
; Set raster beam to trigger interrupt at row zero
|
|
||||||
lda #$00
|
|
||||||
sta $d012
|
|
||||||
|
|
||||||
; Bit#0 of $d011 is used as bit#9 of $d012, and must be zero
|
|
||||||
lda $d011
|
|
||||||
and #$7f
|
|
||||||
sta $d011
|
|
||||||
|
|
||||||
; Initialize player for first song
|
|
||||||
lda #0
|
|
||||||
jsr sidtune
|
|
||||||
|
|
||||||
; Initialize MultiColor mode
|
|
||||||
jsr multicolorInit
|
|
||||||
|
|
||||||
; Zero-fill zeropage variables
|
|
||||||
lda #$0
|
|
||||||
ldx #$90
|
|
||||||
zeroFillZeroPage:
|
|
||||||
dex
|
|
||||||
sta $0,x
|
|
||||||
cpx #$2
|
|
||||||
bne zeroFillZeroPage
|
|
||||||
|
|
||||||
; Set status as first-time intro playing
|
|
||||||
lda #ST_INTRO0
|
|
||||||
sta status
|
|
||||||
|
|
||||||
; Enable interrupts
|
|
||||||
cli
|
|
||||||
|
|
||||||
; 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)
|
|
||||||
cmp #$51 ; Is it Q?
|
|
||||||
bne intro0running ; If not, keep looping here,
|
|
||||||
jmp $fce2 ; else, reset the computer
|
|
||||||
|
|
||||||
; Intro is finished, now it's time to start the proper game
|
|
||||||
intro0end:
|
|
||||||
; Pause everything in interrupt
|
|
||||||
lda #ST_PAUSE
|
|
||||||
sta status
|
|
||||||
; Set init variables of the game
|
|
||||||
jsr gamereset
|
|
||||||
|
|
||||||
; Set status as game playing
|
|
||||||
lda #ST_PLAY
|
|
||||||
sta status
|
|
||||||
|
|
||||||
endless:
|
|
||||||
; Loop waiting for gameover
|
|
||||||
lda status
|
|
||||||
cmp #ST_END ; is status equal to end ?
|
|
||||||
bne endless ; if not, just wait looping here, else...
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
INCLUDE "gamereset.asm"
|
|
||||||
|
|
||||||
; Intro reset
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
introreset:
|
|
||||||
jsr multicolorOff
|
|
||||||
|
|
||||||
; Clear screen
|
|
||||||
ldx #$ff
|
|
||||||
lda #$20
|
|
||||||
introresetCLS:
|
|
||||||
sta $400,x
|
|
||||||
sta $500,x
|
|
||||||
sta $600,x
|
|
||||||
sta $700,x
|
|
||||||
dex
|
|
||||||
cpx #$ff
|
|
||||||
bne introresetCLS
|
|
||||||
|
|
||||||
; 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 printIntroString ; put into lsb of source pointer
|
|
||||||
lda #>intro2string ; do the same for msb of string address
|
|
||||||
sta printIntroString + 1 ; put into msb of source pointer
|
|
||||||
lda #$26 ; this is lsb of address of 20th line
|
|
||||||
sta introScreenStart ; put into lsb of dest pointer
|
|
||||||
lda #$07 ; do the same for msb of adress of 20th line
|
|
||||||
sta introScreenStart + 1 ; put into msb of dest pointer
|
|
||||||
jsr printIntro ; print
|
|
||||||
|
|
||||||
; Print Copyright
|
|
||||||
lda #<intro3string ; the assembly is the same as above,
|
|
||||||
sta printIntroString ; just change string to be printed
|
|
||||||
lda #>intro3string ; and line (21th line)
|
|
||||||
sta printIntroString + 1
|
|
||||||
lda #$58
|
|
||||||
sta introScreenStart
|
|
||||||
lda #$07
|
|
||||||
sta introScreenStart + 1
|
|
||||||
jsr printIntro
|
|
||||||
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Interrupt Handler
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
irq:
|
|
||||||
; Things that must be done every interrupt (50Hz)
|
|
||||||
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
; Acknoweledge IRQ
|
|
||||||
dec $d019
|
|
||||||
|
|
||||||
; Save registers in stack
|
|
||||||
pha
|
|
||||||
txa
|
|
||||||
pha
|
|
||||||
tya
|
|
||||||
pha
|
|
||||||
|
|
||||||
#if DEBUG = 1
|
|
||||||
; Change background to visually see the ISR timing
|
|
||||||
lda #2
|
|
||||||
sta $d020
|
|
||||||
#endif
|
|
||||||
|
|
||||||
; Check status and call appropriate sub-routine
|
|
||||||
; Sort of switch-case
|
|
||||||
lda status
|
|
||||||
cmp #ST_INTRO0
|
|
||||||
bne checkStatus1
|
|
||||||
jsr statusIntro0
|
|
||||||
jmp checkEndStatus
|
|
||||||
checkStatus1:
|
|
||||||
cmp #ST_INTRO1
|
|
||||||
bne checkStatus2
|
|
||||||
jsr statusIntro1
|
|
||||||
jmp checkEndStatus
|
|
||||||
checkStatus2
|
|
||||||
cmp #ST_PLAY
|
|
||||||
bne checkStatus3
|
|
||||||
jsr statusPlay
|
|
||||||
jmp checkEndStatus
|
|
||||||
checkStatus3
|
|
||||||
cmp #ST_OUTRO
|
|
||||||
bne checkEndStatus
|
|
||||||
jsr statusOutro
|
|
||||||
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
|
|
||||||
|
|
||||||
#if DEBUG = 1
|
|
||||||
; Change background back again to visally see ISR timing
|
|
||||||
lda #11
|
|
||||||
sta $d020
|
|
||||||
#endif
|
|
||||||
|
|
||||||
; Restore registers from stack
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
|
|
||||||
; Go to original system routine
|
|
||||||
jmp $ea31
|
|
||||||
|
|
||||||
; 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
|
|
||||||
|
|
||||||
; 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
|
|
||||||
|
|
||||||
status1okset:
|
|
||||||
; Print "SNAKE BY GIOMBA" (see above for pointer details)
|
|
||||||
lda #<intro0string
|
|
||||||
sta printIntroString
|
|
||||||
lda #>intro0string
|
|
||||||
sta printIntroString + 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 introScreenStart
|
|
||||||
lda #$04
|
|
||||||
sta introScreenStart + 1
|
|
||||||
jsr printIntro
|
|
||||||
|
|
||||||
; Print "PRESS SPACE TO PLAY"
|
|
||||||
lda #<intro1string
|
|
||||||
sta printIntroString
|
|
||||||
lda #>intro1string
|
|
||||||
sta printIntroString + 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 introScreenStart
|
|
||||||
lda #$04
|
|
||||||
sta introScreenStart + 1
|
|
||||||
jsr printIntro
|
|
||||||
|
|
||||||
; 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
|
|
||||||
|
|
||||||
statusPlay: ; do Game
|
|
||||||
; Check counter
|
|
||||||
ldx irqn
|
|
||||||
dex
|
|
||||||
stx irqn
|
|
||||||
beq irqsometime ; if counter is 0, then do these "rare" things
|
|
||||||
rts ; else do nothing and simply return
|
|
||||||
; as you can see, game actually runs at 12 Hz
|
|
||||||
|
|
||||||
irqsometime:
|
|
||||||
; Things that must be done only one in four interrupts (12 Hz)
|
|
||||||
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
|
|
||||||
; If I am here, counter reached 0, so first reset it
|
|
||||||
ldx #4
|
|
||||||
stx irqn
|
|
||||||
|
|
||||||
; Get pressed key and decide snake direction
|
|
||||||
jsr $ffe4 ; Kernal routine GETIN
|
|
||||||
cmp #0
|
|
||||||
beq keybEndCheck ; if no key pressed, just skip this switch-case
|
|
||||||
ldx #$7f ; else, if key pressed, reset random variable
|
|
||||||
stx random
|
|
||||||
keybCheckA: ; check for press of key `A`
|
|
||||||
cmp #$41
|
|
||||||
bne keybCheckS ; if not pressed `A`, just skip to next key to check
|
|
||||||
lda direction ; else check if current direction is right
|
|
||||||
cmp #6
|
|
||||||
beq keybEndCheck ; if yes, you can't turn over yourself, so just skip to next key check
|
|
||||||
lda #4
|
|
||||||
sta direction ; else set direction to left and store new value
|
|
||||||
jmp keybEndCheck ; skip all other key tests
|
|
||||||
keybCheckS: ; simply re-do for S, D, W and other keys...
|
|
||||||
cmp #$53
|
|
||||||
bne keybCheckD
|
|
||||||
lda direction
|
|
||||||
cmp #8
|
|
||||||
beq keybEndCheck
|
|
||||||
lda #2
|
|
||||||
sta direction
|
|
||||||
jmp keybEndCheck
|
|
||||||
keybCheckD:
|
|
||||||
cmp #$44
|
|
||||||
bne keybCheckW
|
|
||||||
lda direction
|
|
||||||
cmp #4
|
|
||||||
beq keybEndCheck
|
|
||||||
lda #6
|
|
||||||
sta direction
|
|
||||||
jmp keybEndCheck
|
|
||||||
keybCheckW:
|
|
||||||
cmp #$57
|
|
||||||
bne keybCheckP
|
|
||||||
lda direction
|
|
||||||
cmp #2
|
|
||||||
beq keybEndCheck
|
|
||||||
lda #8
|
|
||||||
sta direction
|
|
||||||
jmp keybEndCheck
|
|
||||||
keybCheckP:
|
|
||||||
cmp #$50
|
|
||||||
bne keybEndCheck
|
|
||||||
lda #5
|
|
||||||
sta direction
|
|
||||||
jmp keybEndCheck
|
|
||||||
keybEndCheck:
|
|
||||||
|
|
||||||
; Get joystick status and decide snake direction
|
|
||||||
; Joystick register bits 4:0 => Fire,Right,Left,Down,Up
|
|
||||||
; 0 = Pressed; 1 = Idle
|
|
||||||
lda $dc00 ; CIA joystick port 2 register
|
|
||||||
ror ; rotate bit and put bit#0 in CF
|
|
||||||
tax ; store byte value for next key check
|
|
||||||
bcs joyCheckDown ; if CF = 1, then key was not depressed, so skip and check next...
|
|
||||||
; ... else key was depressed!
|
|
||||||
lda direction ; check for not overlapping direction (turn over yourself)
|
|
||||||
cmp #2
|
|
||||||
beq joyEndCheck
|
|
||||||
lda #8
|
|
||||||
sta direction
|
|
||||||
jmp joyEndCheck
|
|
||||||
joyCheckDown:
|
|
||||||
txa
|
|
||||||
ror
|
|
||||||
tax
|
|
||||||
bcs joyCheckLeft
|
|
||||||
lda direction
|
|
||||||
cmp #8
|
|
||||||
beq joyEndCheck
|
|
||||||
lda #2
|
|
||||||
sta direction
|
|
||||||
jmp joyEndCheck
|
|
||||||
joyCheckLeft:
|
|
||||||
txa
|
|
||||||
ror
|
|
||||||
tax
|
|
||||||
bcs joyCheckRight
|
|
||||||
lda direction
|
|
||||||
cmp #6
|
|
||||||
beq joyEndCheck
|
|
||||||
lda #4
|
|
||||||
sta direction
|
|
||||||
jmp joyEndCheck
|
|
||||||
joyCheckRight:
|
|
||||||
txa
|
|
||||||
ror
|
|
||||||
tax
|
|
||||||
bcs joyCheckFire
|
|
||||||
lda direction
|
|
||||||
cmp #4
|
|
||||||
beq joyEndCheck
|
|
||||||
lda #6
|
|
||||||
sta direction
|
|
||||||
jmp joyEndCheck
|
|
||||||
joyCheckFire: ; `Fire` joystick key used to pause game
|
|
||||||
txa
|
|
||||||
ror
|
|
||||||
tax
|
|
||||||
bcs joyEndCheck
|
|
||||||
lda #5
|
|
||||||
sta direction
|
|
||||||
joyEndCheck:
|
|
||||||
|
|
||||||
; Get direction and move head accordingly
|
|
||||||
lda direction
|
|
||||||
dirCheck2: ; check if direction is down...
|
|
||||||
cmp #2
|
|
||||||
bne dirCheck4 ; if not down, then skip and check next direction,
|
|
||||||
ldy snakeY ; else, direction is down, so get snakeY
|
|
||||||
iny ; increment snakeY (keep in mind that screen up/down coordinates are reversed)
|
|
||||||
sty snakeY ; update snakeY
|
|
||||||
dirCheck4: ; simply re-do for other directions...
|
|
||||||
cmp #4
|
|
||||||
bne dirCheck6
|
|
||||||
ldx snakeX
|
|
||||||
dex
|
|
||||||
stx snakeX
|
|
||||||
dirCheck6:
|
|
||||||
cmp #6
|
|
||||||
bne dirCheck8
|
|
||||||
ldx snakeX
|
|
||||||
inx
|
|
||||||
stx snakeX
|
|
||||||
dirCheck8:
|
|
||||||
cmp #8
|
|
||||||
bne dirCheck5
|
|
||||||
ldy snakeY
|
|
||||||
dey
|
|
||||||
sty snakeY
|
|
||||||
dirCheck5:
|
|
||||||
cmp #5
|
|
||||||
bne dirEndCheck
|
|
||||||
jmp skipPauseTests
|
|
||||||
dirEndCheck:
|
|
||||||
|
|
||||||
; Check screen boundaries overflow
|
|
||||||
lda snakeX
|
|
||||||
cmp #40
|
|
||||||
bne overCheckX0 ; if snakeX is not 40, then all ok, skip to next test
|
|
||||||
lda #0 ; else, there is an overflow, so trespass screen border
|
|
||||||
sta snakeX
|
|
||||||
overCheckX0: ; simply re-do for every side of the screen
|
|
||||||
lda snakeX
|
|
||||||
cmp #$ff
|
|
||||||
bne overCheckY1
|
|
||||||
lda #39
|
|
||||||
sta snakeX
|
|
||||||
overCheckY1:
|
|
||||||
lda snakeY
|
|
||||||
cmp #25
|
|
||||||
bne overCheckY0
|
|
||||||
lda #1
|
|
||||||
sta snakeY
|
|
||||||
overCheckY0
|
|
||||||
lda snakeY
|
|
||||||
cmp #0
|
|
||||||
bne overEndCheck
|
|
||||||
lda #24
|
|
||||||
sta snakeY
|
|
||||||
overEndCheck:
|
|
||||||
|
|
||||||
; Put new head coordinates in list
|
|
||||||
ldy listStart
|
|
||||||
lda snakeX
|
|
||||||
sta listX,y
|
|
||||||
lda snakeY
|
|
||||||
sta listY,y
|
|
||||||
iny
|
|
||||||
sty listStart
|
|
||||||
|
|
||||||
ldy #0
|
|
||||||
|
|
||||||
; Check for food eat / wall hit / self-eat
|
|
||||||
; - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
; --- Food eat ---
|
|
||||||
lda snakeX ; calc head location in memory
|
|
||||||
sta calcTileX
|
|
||||||
lda snakeY
|
|
||||||
sta calcTileY
|
|
||||||
jsr calcTileMem
|
|
||||||
lda (tileMem),y ; read content of head memory location
|
|
||||||
cmp #FOOD_TILE
|
|
||||||
beq foodEaten ; if memory does contain food, then perform foodEaten actions,
|
|
||||||
jmp checkSelfEat ; else just loooong jump to test if I ate myself
|
|
||||||
foodEaten:
|
|
||||||
ldx length ; else, increment snake length,
|
|
||||||
inx
|
|
||||||
stx length
|
|
||||||
genFood:
|
|
||||||
ldx random
|
|
||||||
inx
|
|
||||||
stx random
|
|
||||||
|
|
||||||
txa
|
|
||||||
genFoodX: ; calculate `random` modulo SCREEN_W
|
|
||||||
sec
|
|
||||||
sbc #SCREEN_W
|
|
||||||
cmp #SCREEN_W
|
|
||||||
bcs genFoodX
|
|
||||||
sta calcTileX
|
|
||||||
|
|
||||||
txa
|
|
||||||
genFoodY: ; calculate `random` modulo 22 (22 = SCREEN_H - 1)
|
|
||||||
sec
|
|
||||||
sbc #22
|
|
||||||
cmp #22
|
|
||||||
bcs genFoodY
|
|
||||||
clc ; add 1 because 1st line can not be used
|
|
||||||
adc #1
|
|
||||||
sta calcTileY
|
|
||||||
|
|
||||||
; Now I have X and Y coordinate for food stored in calcTileX, calcTileY
|
|
||||||
; and I must check it is not the location that I am going to overwrite
|
|
||||||
; with the head in draw snake head...
|
|
||||||
lda calcTileX
|
|
||||||
cmp snakeX
|
|
||||||
bne foodOK
|
|
||||||
lda calcTileY
|
|
||||||
cmp snakeY
|
|
||||||
beq genFood
|
|
||||||
foodOK:
|
|
||||||
; debug -- print choosen X,Y for food
|
|
||||||
; ldy #$18
|
|
||||||
; lda calcTileX
|
|
||||||
; jsr printByte
|
|
||||||
; ldy #$1b
|
|
||||||
; lda calcTileY
|
|
||||||
; jsr printByte
|
|
||||||
|
|
||||||
ldy #0
|
|
||||||
jsr calcTileMem ; calc food address in memory
|
|
||||||
lda (tileMem),y ; check if memory is empty
|
|
||||||
cmp #$20 ; is there a space?
|
|
||||||
bne genFood ; if not, must generate another number
|
|
||||||
lda #FOOD_TILE ; else, just put that fucking piece of food there
|
|
||||||
sta (tileMem),y
|
|
||||||
|
|
||||||
lda #$d4
|
|
||||||
clc
|
|
||||||
adc tileMem + 1
|
|
||||||
sta tileMem + 1
|
|
||||||
lda #FOOD_COLOR
|
|
||||||
sta (tileMem),y
|
|
||||||
|
|
||||||
; print score at $10th column
|
|
||||||
ldy #$10
|
|
||||||
lda length
|
|
||||||
jsr printByte
|
|
||||||
|
|
||||||
jmp checkEndSelfEat
|
|
||||||
checkEndFood:
|
|
||||||
|
|
||||||
; --- Self eat ---
|
|
||||||
checkSelfEat:
|
|
||||||
cmp #SNAKE_TILE
|
|
||||||
bne checkEndSelfEat
|
|
||||||
jmp gameover
|
|
||||||
checkEndSelfEat:
|
|
||||||
|
|
||||||
; Draw snake head
|
|
||||||
ldy #0
|
|
||||||
lda snakeX ; calc char address in video memory, and put SNAKE_TILE
|
|
||||||
sta calcTileX
|
|
||||||
lda snakeY
|
|
||||||
sta calcTileY
|
|
||||||
jsr calcTileMem
|
|
||||||
lda #SNAKE_TILE
|
|
||||||
sta (tileMem),y
|
|
||||||
|
|
||||||
lda #$d4 ; add #$d400 to previous address (obtain color memory
|
|
||||||
clc ; correspondent), and put SNAKE_COLOR
|
|
||||||
adc tileMem + 1
|
|
||||||
sta tileMem + 1
|
|
||||||
lda #SNAKE_COLOR
|
|
||||||
sta (tileMem),y
|
|
||||||
|
|
||||||
; Erase snake tail
|
|
||||||
lda listStart ; take start of list, and subtract snake length,
|
|
||||||
sec ; to obtain index of end of list
|
|
||||||
sbc length
|
|
||||||
tax ; use previous value as index in list, and calc video memory address
|
|
||||||
lda listX,x
|
|
||||||
sta calcTileX
|
|
||||||
lda listY,x
|
|
||||||
sta calcTileY
|
|
||||||
jsr calcTileMem
|
|
||||||
lda #$20 ; just put a space to erase snake tail tile
|
|
||||||
sta (tileMem),y
|
|
||||||
|
|
||||||
skipPauseTests:
|
|
||||||
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Game is over
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
gameover:
|
|
||||||
lda #<gameoverString
|
|
||||||
sta printStatusString
|
|
||||||
lda #>gameoverString
|
|
||||||
sta printStatusString + 1
|
|
||||||
jsr printStatus
|
|
||||||
|
|
||||||
; Set gameover and outro status
|
|
||||||
lda #$ff
|
|
||||||
sta outroDelay
|
|
||||||
lda #ST_OUTRO
|
|
||||||
sta status
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Decrement outroDelay, just to let player see her/his end screen
|
|
||||||
; with score
|
|
||||||
statusOutro:
|
|
||||||
ldy outroDelay ; load outroDelay and decrement
|
|
||||||
dey
|
|
||||||
sty outroDelay
|
|
||||||
cpy #0
|
|
||||||
beq statusOutroEnd
|
|
||||||
rts
|
|
||||||
statusOutroEnd:
|
|
||||||
; Set status as ST_END: this way, the loop out of this interrupt,
|
|
||||||
; will know that we finished, and will play the intro again
|
|
||||||
lda #ST_END
|
|
||||||
sta status
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Subroutines
|
|
||||||
; ----------------------------------------------------------------------
|
|
||||||
; Do some math to calculate tile address in video memory
|
|
||||||
; using x,y coordinates
|
|
||||||
; Formula: addr = $400 + y * SCREEN_W + x
|
|
||||||
calcTileMem:
|
|
||||||
; Save registers
|
|
||||||
pha
|
|
||||||
txa
|
|
||||||
pha
|
|
||||||
tya
|
|
||||||
pha
|
|
||||||
|
|
||||||
; Set tileMem to $400
|
|
||||||
lda #$00
|
|
||||||
sta tileMem
|
|
||||||
lda #$04
|
|
||||||
sta tileMem + 1
|
|
||||||
|
|
||||||
ldy calcTileY ; Get head Y coordinate
|
|
||||||
calcTileMult:
|
|
||||||
tya
|
|
||||||
beq calcTileEnd ; if Y is equal to zero, nothing to do, just skip moltiplication, else...
|
|
||||||
dey ; decrement Y
|
|
||||||
clc
|
|
||||||
lda #SCREEN_W ; A = screen width = 40
|
|
||||||
adc tileMem ; A = screen width + tileMem (low)
|
|
||||||
sta tileMem ; update tileMem (low)
|
|
||||||
lda #0 ; do the same with higher byte: A = 0
|
|
||||||
adc tileMem + 1 ; add (eventual) carry
|
|
||||||
sta tileMem + 1 ; update tileMem (high)
|
|
||||||
jmp calcTileMult ; do again until Y == 0
|
|
||||||
calcTileEnd: ; now multiplication is ended, so add X
|
|
||||||
lda calcTileX
|
|
||||||
adc tileMem
|
|
||||||
sta tileMem
|
|
||||||
lda #0
|
|
||||||
adc tileMem + 1
|
|
||||||
sta tileMem + 1
|
|
||||||
|
|
||||||
; Restore old registers
|
|
||||||
pla
|
|
||||||
tay
|
|
||||||
pla
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Print a byte in hexadecimal
|
|
||||||
; A input register for byte to print
|
|
||||||
; Y input register for printing colum (on first line)
|
|
||||||
printByte:
|
|
||||||
; Copy parameter also in X
|
|
||||||
tax
|
|
||||||
|
|
||||||
lsr ; Take most significant nibble
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
lsr
|
|
||||||
jsr printDigit
|
|
||||||
sta $400,y ; print msb char
|
|
||||||
|
|
||||||
txa ; Take least significant nibble (use previous copy)
|
|
||||||
and #$0f
|
|
||||||
jsr printDigit
|
|
||||||
sta $401,y ; print lsb char
|
|
||||||
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Transform a base-36 digit into a Commodore screen code
|
|
||||||
; Leave input digit in accumulator; returns output screen code in accumulator
|
|
||||||
printDigit:
|
|
||||||
cmp #10
|
|
||||||
bcs printDigitL ; if it is not a decimal digit, then go to printDigitL
|
|
||||||
clc ; it is a decimal digit! Just add `0` (48)
|
|
||||||
adc #48
|
|
||||||
ora #$80 ; reverse color
|
|
||||||
rts
|
|
||||||
printDigitL: ; it is not a decimal digit, then...
|
|
||||||
sec
|
|
||||||
sbc #10 ; take away 10
|
|
||||||
clc
|
|
||||||
adc #1 ; add 1, so you obtain something in [A-F]
|
|
||||||
ora #$80 ; reverse color
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Print null-terminated string on status bar
|
|
||||||
; address of string is given in input using memory location printStatusString
|
|
||||||
printStatus:
|
|
||||||
ldy #0
|
|
||||||
printStatusLoop:
|
|
||||||
lda (printStatusString),y
|
|
||||||
beq printStatusEnd
|
|
||||||
cmp #$20
|
|
||||||
bne printStatusSkipSpace
|
|
||||||
lda #$60
|
|
||||||
printStatusSkipSpace:
|
|
||||||
sec
|
|
||||||
sbc #$40 ; convert from standard ASCII to Commodore screen code
|
|
||||||
ora #$80 ; reverse color
|
|
||||||
sta $413,y
|
|
||||||
iny
|
|
||||||
jmp printStatusLoop
|
|
||||||
printStatusEnd:
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Print string for intro
|
|
||||||
; Input parameters:
|
|
||||||
; printIntroString pointer to string to be printed (source)
|
|
||||||
; introScreenStart pointer to text video memory on screen where to print (dest)
|
|
||||||
printIntro:
|
|
||||||
ldy #0
|
|
||||||
printIntroLoop:
|
|
||||||
lda (printIntroString),y ; get char from string
|
|
||||||
beq printIntroEnd ; if zero, then end (string must be null-terminated)
|
|
||||||
cmp #$40 ; is char greater or equal to #$40 = #64 = `@' ?
|
|
||||||
bcc printIntroEndCheck ; if not, it is less, thus it must be
|
|
||||||
; a full stop, comma, colon or something
|
|
||||||
; that actually has the same value in both
|
|
||||||
; true ASCII and in PET screen codes
|
|
||||||
; otherwise, it is greater than `@`, so must
|
|
||||||
; subtract 64 because CBM and its encodings
|
|
||||||
; are simply a big shit
|
|
||||||
sec
|
|
||||||
sbc #$40
|
|
||||||
|
|
||||||
printIntroEndCheck:
|
|
||||||
sta (introScreenStart),y ; put screen code to screen
|
|
||||||
iny ; next char in string
|
|
||||||
jmp printIntroLoop
|
|
||||||
printIntroEnd:
|
|
||||||
rts
|
|
||||||
|
|
||||||
; Include
|
|
||||||
; ______________________________________________________________________
|
|
||||||
INCLUDE "multicolor.asm"
|
|
||||||
|
|
||||||
#if DEBUG = 1
|
|
||||||
ECHO "Program ends at: ",.
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
; coded during december 2017
|
|
||||||
; by giomba -- giomba at glgprograms.it
|
|
||||||
; this software is free software and is distributed
|
|
||||||
; under the terms of GNU GPL v3 license
|
|
||||||
;
|
|
||||||
|
|
||||||
; vim: set expandtab tabstop=4 shiftwidth=4:
|
|
135
subroutines.asm
Normal file
135
subroutines.asm
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
; Subroutines
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
; Do some math to calculate tile address in video memory
|
||||||
|
; using x,y coordinates
|
||||||
|
; Formula: addr = $400 + y * SCREEN_W + x
|
||||||
|
calcTileMem:
|
||||||
|
; Save registers
|
||||||
|
pha
|
||||||
|
txa
|
||||||
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
|
||||||
|
; Set tileMem to $400
|
||||||
|
lda #$00
|
||||||
|
sta tileMem
|
||||||
|
lda #$04
|
||||||
|
sta tileMem + 1
|
||||||
|
|
||||||
|
ldy calcTileY ; Get head Y coordinate
|
||||||
|
calcTileMult:
|
||||||
|
tya
|
||||||
|
beq calcTileEnd ; if Y is equal to zero, nothing to do, just skip moltiplication, else...
|
||||||
|
dey ; decrement Y
|
||||||
|
clc
|
||||||
|
lda #SCREEN_W ; A = screen width = 40
|
||||||
|
adc tileMem ; A = screen width + tileMem (low)
|
||||||
|
sta tileMem ; update tileMem (low)
|
||||||
|
lda #0 ; do the same with higher byte: A = 0
|
||||||
|
adc tileMem + 1 ; add (eventual) carry
|
||||||
|
sta tileMem + 1 ; update tileMem (high)
|
||||||
|
jmp calcTileMult ; do again until Y == 0
|
||||||
|
calcTileEnd: ; now multiplication is ended, so add X
|
||||||
|
lda calcTileX
|
||||||
|
adc tileMem
|
||||||
|
sta tileMem
|
||||||
|
lda #0
|
||||||
|
adc tileMem + 1
|
||||||
|
sta tileMem + 1
|
||||||
|
|
||||||
|
; Restore old registers
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Print a byte in hexadecimal
|
||||||
|
; A input register for byte to print
|
||||||
|
; Y input register for printing colum (on first line)
|
||||||
|
printByte:
|
||||||
|
; Copy parameter also in X
|
||||||
|
tax
|
||||||
|
|
||||||
|
lsr ; Take most significant nibble
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
lsr
|
||||||
|
jsr printDigit
|
||||||
|
sta $400,y ; print msb char
|
||||||
|
|
||||||
|
txa ; Take least significant nibble (use previous copy)
|
||||||
|
and #$0f
|
||||||
|
jsr printDigit
|
||||||
|
sta $401,y ; print lsb char
|
||||||
|
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Transform a base-36 digit into a Commodore screen code
|
||||||
|
; Leave input digit in accumulator; returns output screen code in accumulator
|
||||||
|
printDigit:
|
||||||
|
cmp #10
|
||||||
|
bcs printDigitL ; if it is not a decimal digit, then go to printDigitL
|
||||||
|
clc ; it is a decimal digit! Just add `0` (48)
|
||||||
|
adc #48
|
||||||
|
ora #$80 ; reverse color
|
||||||
|
rts
|
||||||
|
printDigitL: ; it is not a decimal digit, then...
|
||||||
|
sec
|
||||||
|
sbc #10 ; take away 10
|
||||||
|
clc
|
||||||
|
adc #1 ; add 1, so you obtain something in [A-F]
|
||||||
|
ora #$80 ; reverse color
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Print null-terminated string on status bar
|
||||||
|
; address of string is given in input using memory location printStatusString
|
||||||
|
printStatus:
|
||||||
|
ldy #0
|
||||||
|
printStatusLoop:
|
||||||
|
lda (printStatusString),y
|
||||||
|
beq printStatusEnd
|
||||||
|
cmp #$20
|
||||||
|
bne printStatusSkipSpace
|
||||||
|
lda #$60
|
||||||
|
printStatusSkipSpace:
|
||||||
|
sec
|
||||||
|
sbc #$40 ; convert from standard ASCII to Commodore screen code
|
||||||
|
ora #$80 ; reverse color
|
||||||
|
sta $413,y
|
||||||
|
iny
|
||||||
|
jmp printStatusLoop
|
||||||
|
printStatusEnd:
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Print string for intro
|
||||||
|
; Input parameters:
|
||||||
|
; printIntroString pointer to string to be printed (source)
|
||||||
|
; introScreenStart pointer to text video memory on screen where to print (dest)
|
||||||
|
printIntro:
|
||||||
|
ldy #0
|
||||||
|
printIntroLoop:
|
||||||
|
lda (printIntroString),y ; get char from string
|
||||||
|
beq printIntroEnd ; if zero, then end (string must be null-terminated)
|
||||||
|
cmp #$40 ; is char greater or equal to #$40 = #64 = `@' ?
|
||||||
|
bcc printIntroEndCheck ; if not, it is less, thus it must be
|
||||||
|
; a full stop, comma, colon or something
|
||||||
|
; that actually has the same value in both
|
||||||
|
; true ASCII and in PET screen codes
|
||||||
|
; otherwise, it is greater than `@`, so must
|
||||||
|
; subtract 64 because CBM and its encodings
|
||||||
|
; are simply a big shit
|
||||||
|
sec
|
||||||
|
sbc #$40
|
||||||
|
|
||||||
|
printIntroEndCheck:
|
||||||
|
sta (introScreenStart),y ; put screen code to screen
|
||||||
|
iny ; next char in string
|
||||||
|
jmp printIntroLoop
|
||||||
|
printIntroEnd:
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
20
zeropage.asm
Normal file
20
zeropage.asm
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
; Zero page utilities
|
||||||
|
; ----------------------------------------------------------------------
|
||||||
|
; Where is the snake head in video memory? Do math to calculate address
|
||||||
|
; using pointer at tileMem,tileMem+1
|
||||||
|
tileMem DS 2
|
||||||
|
|
||||||
|
; Pointer to status string
|
||||||
|
printStatusString DS 2
|
||||||
|
|
||||||
|
; Pointer to intro string
|
||||||
|
printIntroString DS 2
|
||||||
|
; Pointer to screen position where to print intro string ($fb-$fc)
|
||||||
|
introScreenStart DS 2
|
||||||
|
|
||||||
|
#if DEBUG = 1
|
||||||
|
; Locations $90-$FF in zeropage are used by kernal
|
||||||
|
ECHO "End of zeropage variables. Space left: ",($90 - .)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user