-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatrix.p8
227 lines (185 loc) · 6.54 KB
/
matrix.p8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
; Make it rain PETSCII, Matrix-style, on the CX16
; Mark J. Reed, 2023
%import math
%import palette
%import syslib
%import textio
%option no_sysinit
%zeropage basicsafe
main {
; the bit in the VERA layer configuration register that toggles 256-color
; text mode
const ubyte T256C = 8
; number of colors and names for them
const ubyte color_range = 3
const ubyte GREEN = 0
const ubyte YELLOW = 1
const ubyte PURPLE = 2
; range of possible speeds for individual drops
const ubyte speed_range = 4
; color gradients from the default palette
ubyte[] greens = [ $01, $8f, $88, $8e, $87, $8d, $86, $8c,
$85, $8b, $84, $8a, $83, $89, $82, $00 ]
ubyte[] yellows = [ $01, $50, $57, $4f, $56, $4e, $55, $4d,
$54, $4c, $53, $4b, $52, $4a, $51, $00 ]
ubyte[] purples = [ $01, $e3, $dc, $e2, $db, $e1, $da, $e0,
$d9, $df, $d8, $de, $d7, $dd, $d6, $00 ]
; Y coordinate of the bottom of the drop in each column (1-based; 0 means no drop there)
ubyte[80] bottom
; speed of each drop
ubyte[80] speed
; color of each drop
ubyte[80] color
; a place to save colors from the palette so they can be restored
uword[256] @split saved_colors
; flag indicating whether colors have been saved above or not
bool saved
; dimensions of the screen
ubyte width, height
; ye standard loop control variables
ubyte i, j, j1, j2, dj
; user input
ubyte key
; a clock for managing drop speed
ubyte ticks
; count of columns currently missing drops
ubyte available
; delay between ticks to adjust overall run speed
ubyte delay = 1
; get screen size from KERNAL
asmsub get_screen() {
%asm{{
jsr cbm.SCREEN
stx p8v_width
sty p8v_height
}}
}
; look up a palette color
sub get_color(ubyte index) -> uword {
ubyte low, high
low = cx16.vpeek(1, $fa00 + (index as uword << 1))
high = cx16.vpeek(1, $fa01 + (index as uword << 1))
return mkword(high, low)
}
; switch to all-green theme
sub all_green() {
for i in 0 to len(greens) {
if not saved {
saved_colors[yellows[i]] = get_color(yellows[i])
saved_colors[purples[i]] = get_color(purples[i])
}
palette.set_color(yellows[i], get_color(greens[i]))
palette.set_color(purples[i], get_color(greens[i]))
}
saved = true
}
; switch to Mardi Gras theme
sub mardi_gras() {
if saved {
for i in 0 to len(greens) {
palette.set_color(yellows[i], saved_colors[yellows[i]])
palette.set_color(purples[i], saved_colors[purples[i]])
}
}
}
sub start() {
; seed RNG from RTC
void cx16.clock_get_date_time()
math.rndseed(cx16.r2, cx16.r1)
; enable 256-color text mode
cx16.VERA_L1_CONFIG = (cx16.VERA_L1_CONFIG & ~T256C) | T256C
; get screen dimensions - works in non-default resolutions
get_screen()
txt.clear_screen()
; initialize all drops to offscreen
for i in 0 to width - 1 {
bottom[i] = 0
}
; start at time 0
ticks = 0
; default to all green
all_green()
do {
for i in 0 to width - 1 {
; update all the drops moving fast enough to move this tick
if bottom[i] != 0 and ticks % speed_range < speed[i] {
; determine the visible portion of the trail
j1 = bottom[i]
if j1 <= height {
; if the bottom of drop is visible, put a random white character there
txt.setcc(i, j1-1, math.rnd()>>1, 1)
} else {
; otherwise cut off at the bottom of the screen
j1 = height
}
j2 = j1 - len(greens) + 1
if j2 < 1 or j2 >= 96 {
j2 = 1
}
; color the rest of the trail
for j in j2 to j1 {
dj = bottom[i] - j
if dj >= 128 {
dj = 0
}
if dj >= len(greens) {
dj = len(greens) - 1
}
when color[i] {
GREEN -> txt.setclr(i, j-1, greens[dj])
YELLOW -> txt.setclr(i, j-1, yellows[dj])
PURPLE -> txt.setclr(i, j-1, purples[dj])
}
}
bottom[i] = bottom[i] + 1
; turn this drop off if it's fallen offscreen
if bottom[i] >= height + len(greens) {
bottom[i] = 0
}
}
}
; flip a coin to see if we add a new drop
if math.rnd() < 128 {
; pick randomly from the columns not already in use
available = 0
for i in 0 to width -1 {
if bottom[i] == 0 { available += 1 }
}
if available != 0 {
i = math.rnd() % available
for j in 0 to width - 1 {
if bottom[j] == 0 {
if i==0 {
i = j
break
} else {
i -= 1
}
}
}
; start at the top
bottom[i] = 1
; assign a random speed and color
speed[i] = math.rnd() % speed_range + 1
color[i] = math.rnd() % color_range
}
}
; sleep until next tick
sys.wait(delay)
ticks += 1
; handle any keypress that came in
key = cbm.GETIN2()
when key {
'0' -> { delay=0 key=0 }
'+' -> { if delay != 0 { delay-- } key = 0 }
'-' -> { if delay < $ff { delay++ } key = 0 }
'g' -> { all_green() key = 0 }
'm' -> { mardi_gras() key = 0 }
}
} until key != 0
; clean up
txt.color2(5,0)
txt.clear_screen()
mardi_gras()
}
}