Created
February 25, 2019 06:27
-
-
Save unbibium/67a1b47eb338b7c1e716bbbfc3ac71c9 to your computer and use it in GitHub Desktop.
Matrix rain effect for Commodore 64 and unexpanded Vic 20
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
processor 6502 | |
; This is supposed to generate a Matrix code rain effect. | |
; | |
; It is designed to be run inside a loop in BASIC, so that | |
; RUN/STOP and keyboard checks can be done from BASIC. | |
; For the C64 $C000 build, for example, you could do | |
; something like this: | |
; FOR X=1 TO 3000:SYS 49152:NEXT X | |
; | |
; Compiler flags (-D in dasm): | |
; | |
; BASIC: | |
; builds as a BASIC program. SYS 2063:RUN | |
; VIC20: | |
; builds for an unexpanded VIC-20. This version | |
; fits in the tape buffer so you can call it with | |
; SYS 828. | |
; | |
; the arcane method of performing the row multiplication is | |
; important, not only to be able to build both C64 and VIC | |
; versions, but also to eventually build a version for the | |
; VIC that will fill the screen by declaring more rows and | |
; columns. | |
mscr = $FB | |
mcolor = $FD | |
IFCONST VIC20 | |
WIDTH = 22 | |
HEIGHT = 23 | |
; unexpanded vic | |
SCRMEM = 7680 | |
COLMEM = 38400 | |
PAGES = 2 | |
IFCONST BASIC | |
ORG $1001 | |
ELSE | |
ORG $033c | |
ENDIF | |
ELSE | |
; screen dimensions | |
WIDTH = 40 | |
HEIGHT = 25 | |
SCRMEM = 1024 | |
COLMEM = 55296 | |
PAGES = 4 | |
IFCONST BASIC | |
ORG $0801 | |
ELSE | |
ORG $c000 | |
ENDIF | |
ENDIF | |
IFCONST BASIC | |
word ENDBASIC ; pointer to next line | |
word 2019 ; line number | |
byte $9e ; SYS | |
; INIT address in ASCII decimal. calculating | |
; it this way instead of using dasm expressions | |
; because dasm gets confused, and we know it's | |
; always 4 bytes. | |
byte INIT / 1000 | $30 | |
byte INIT % 1000 / 100 | $30 | |
byte INIT % 100 / 10 | $30 | |
byte INIT % 10 | $30 | |
byte ': | |
byte $8a ; RUN | |
byte $00 ; end of statement | |
ENDBASIC: | |
byte $00,$00 | |
ENDIF | |
INIT: | |
; turn screen black | |
IFCONST VIC20 | |
lda #8 | |
sta 36879 | |
ELSE | |
lda #0 | |
sta $d020 | |
sta $d021 | |
ENDIF | |
; main loop | |
LOOP | |
ldy #WIDTH-1 | |
LOOP1: | |
lda raindrops,y ;get raindrop position | |
; reset if >64 | |
bmi LOOPA | |
cmp #HEIGHT+numcolors | |
bmi LOOPA | |
; get random number -16 <= n <= -1 | |
jsr GETRAND | |
ora #$F0 | |
sta raindrops,y | |
LOOPA: | |
jsr MULROW | |
; see if (mscr),y falls within screen boundary | |
ldx mscr+1 | |
tya | |
clc | |
adc mscr | |
bcc LOOPB | |
inx | |
LOOPB: | |
cpx #>SCRMEM | |
bmi DRAWTRAIL ; lower bound check | |
cpx #>SCRMEM+PAGES | |
bpl DRAWTRAIL | |
jsr GETRAND | |
sta (mscr),y | |
DRAWTRAIL: | |
; draw color trail | |
ldx #numcolors-1 ; color index | |
TRAILLOOP: | |
; see if (mcolor),y falls within screen boundary | |
tya | |
clc | |
adc mcolor | |
lda #0 | |
adc mcolor+1 | |
cmp #>COLMEM | |
bmi NEXTTRAIL | |
cmp #>COLMEM+PAGES | |
bpl NEXTTRAIL | |
lda COLORS,x | |
sta (mcolor),y | |
NEXTTRAIL: | |
lda mcolor | |
sec | |
sbc #WIDTH | |
sta mcolor | |
bcs NEXTTRAIL2 | |
dec mcolor+1 | |
NEXTTRAIL2: | |
dex | |
bpl TRAILLOOP | |
LOOP2 | |
tya | |
tax | |
inc raindrops,x | |
dey | |
bpl LOOP1 | |
ENDUT: | |
rts | |
; | |
; Multiply a row number by WIDTH | |
; | |
MULROW: | |
; store value to be multiplied into | |
; low byte temporarily. | |
sta mscr | |
ldx #0 | |
stx mscr+1 | |
; use a loop to build the appropriate | |
; multiplication routine | |
MASKBIT SET $80 ; will cover each bit | |
TRAILING SET 1 ; trailing zeroes flag, will clear on | |
; first 1 bit found. | |
; loop through each bit | |
REPEAT 8 | |
IF MASKBIT <= WIDTH ; skip if trailing 0 | |
IF TRAILING | |
; found leftmost '1' bit. | |
TRAILING SET 0 ; no longer need to skip trailing 0s | |
; we can start shifting more bits from the right | |
ELSE ; multiply by two | |
asl | |
rol mscr+1 | |
IF WIDTH & MASKBIT ; push a 1 | |
adc mscr | |
bcc .+4 | |
inc mscr+1 | |
ENDIF ; whether to push a 1 | |
ENDIF ; whether we're flipping the trailing bit | |
ENDIF ; whether we're in a trailing zero | |
MASKBIT SET MASKBIT >> 1 | |
REPEND | |
; write low byte | |
sta mscr | |
sta mcolor | |
; add high byte for screen memory | |
lda mscr+1 | |
clc | |
adc #>SCRMEM | |
sta mscr+1 | |
; add high byte for color memory | |
adc #>COLMEM->SCRMEM | |
sta mcolor+1 | |
rts | |
; use ROM as a substitute for random bytes | |
ROMRAND = $e000 | |
GETRAND: | |
inc RANDPTR | |
bne GETRAND2 | |
inc RANDPTR+1 | |
bne GETRAND2 | |
lda #>ROMRAND | |
sta RANDPTR+1 | |
GETRAND2: | |
lda ROMRAND | |
rts | |
RANDPTR = GETRAND2+1 | |
COLORS: | |
IFCONST VIC20 | |
byte 0,5,0,5,5,3,5,3,3,1 | |
ELSE | |
byte 0,5,0,5,5,13,5,13,13,1 | |
ENDIF | |
ENDCOLORS | |
numcolors = ENDCOLORS-COLORS | |
; TODO: randomize in assembler? | |
; Memory for raindrop's vertical positions | |
; one raindrop for each column on the screen | |
raindrops: | |
byte 3,9,13,7,10,8,4,16 | |
byte 2,19,3,0,12,10,9,4 | |
byte 3,9,12,5,13,1 | |
IF WIDTH > 22 | |
byte 4,16,2,19,3 | |
IF WIDTH > 27 | |
byte 1,12,10,9,4 | |
byte 3,19,14,8,10,1,4,6 | |
ENDIF | |
ENDIF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment