-
Notifications
You must be signed in to change notification settings - Fork 1
/
x16maze.asm
642 lines (603 loc) · 15.6 KB
/
x16maze.asm
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
; *****************************************************************************
; The original version of CX16Maze was written to use the standard C64
; Kernal routines as much as possible. This was mostly done becase, at the
; time, both the ROM, the emulator and VERA was very volatile. Things are
; still changing but have settled down somewhat.
; This version 2.x will take full advantage of direct writes to VERA and I
; will also try to make the adding of mazes easier.
; *****************************************************************************
!cpu w65c02 ; Pseudo code to tell ACME the CPU type
; Includes
!src "../cx16stuff/cx16.inc"
!src "../cx16stuff/vera0.9.inc"
; BASIC SYS command to start program at $810
+SYS_LINE
jmp main
!src "globals.inc"
!macro ADD16 .ptr, .byteval {
lda .ptr
clc
adc #.byteval
sta .ptr
lda .ptr+1
adc #0
sta .ptr+1
}
!macro ADD16 .ptr, ~.byteval {
lda .ptr
clc
adc .byteval
sta .ptr
lda .ptr+1
adc #0
sta .ptr+1
}
; *****************************************************************************
; This is the main entry point of the program. From here all the
; initialization and gameloop will be called.
; *****************************************************************************
main:
jsr init_screen
jsr show_welcome
- jsr GETIN
cmp #13
bne -
jsr init_play_screen
jsr load_mazes
bcs @end
lda #<RAM_BANK_START
sta MAZE_PTR
lda #>RAM_BANK_START
sta MAZE_PTR+1
@empty_loop:
jsr GETIN
bne @empty_loop
jsr load_level
- jsr GETIN
beq -
bra @empty_loop
@end:
rts
; *****************************************************************************
; Load a level from memory to screen, update the level counter and place the
; player
; *****************************************************************************
; *****************************************************************************
load_level:
lda (MAZE_PTR)
bne + ; If 0, start over from beginning of RAM bank
lda #<RAM_BANK_START
sta MAZE_PTR
lda #>RAM_BANK_START
sta MAZE_PTR+1
jsr init_play_screen
+ jsr inc_level
jsr get_maze_vals
jsr draw_maze
jsr place_player
+ADD16 MAZE_PTR, ~Size
; jsr prep_next_maze
rts
; *****************************************************************************
; *****************************************************************************
; *****************************************************************************
prep_next_maze:
lda Size
clc
adc MAZE_PTR
sta MAZE_PTR
lda #0
adc MAZE_PTR+1
sta MAZE_PTR+1
rts
; *****************************************************************************
; *****************************************************************************
; *****************************************************************************
place_player:
lda Maze_y
clc
adc Start_y
sta VERA_ADDR_M
lda Maze_x
clc
adc Start_x
asl
inc
sta VERA_ADDR_L
jsr set_trail_col
sta VERA_DATA0
rts
; *****************************************************************************
; *****************************************************************************
; *****************************************************************************
draw_maze:
@x_cnt = TMP0
@y_cnt = TMP1
jsr clear_field
lda #$20 ; Increment by 2 at each write to VERA
sta VERA_ADDR_H
+VERA_GOXY ~Maze_x, ~Maze_y
inc VERA_ADDR_L ; Ensure we change color settings
+ADD16 MAZE_PTR, 5 ; Move pointer to start of actual maze
lda Width ; Store width and height in temporary variables
sta @x_cnt
lda Height
sta @y_cnt
ldy #255
@sizeloop:
iny
lda (MAZE_PTR),Y
jsr draw_maze_byte ; Draw contents of 1 byte to screen
sec ; Subtract 8 from the maze-width to figure
lda @x_cnt ; out if we need to go to the next line
sbc #8
sta @x_cnt
beq @nextline ; If 0, we need to go to next line
bpl @sizeloop ; If number still positive, we do next byte
; Go to next line in maze
@nextline:
lda Width
sta @x_cnt ; Reset x_cnt
inc VERA_ADDR_M ; Go to next line in VERA
lda Maze_x ; Reset X coordinate in VERA
asl
inc
sta VERA_ADDR_L
dec @y_cnt
bne @sizeloop ; If y_cnt has reached 0, we are done
rts
; *****************************************************************************
; *****************************************************************************
; *****************************************************************************
draw_maze_byte:
ldx #8
@loop: asl
bcc @do_draw
; skip this character
inc VERA_ADDR_L
inc VERA_ADDR_L
bra @continue
@do_draw:
stz VERA_DATA0
@continue:
dex
bne @loop
rts
; *****************************************************************************
; Find maze height, width and size and calculate coordinates for top left corner
; of the maze.
; *****************************************************************************
; INPUTS: Expects MAZE_PTR to point to beginning of maze data
; OUTPUTS: Size, Width, Height, Maze_x, Maze_y, Start_x & Start_y
; *****************************************************************************
get_maze_vals:
ldy #0
lda (MAZE_PTR),Y ; Load total maze size
sec
sbc #5 ; Subtract size of header
sta Size
iny
lda (MAZE_PTR),Y ; Load width of maze
sta Width
sta Maze_x ; also store in Maze_x for later calculations
iny
lda (MAZE_PTR),Y ; Load height of maze
sta Height
sta Maze_y ; also store in Maze_y for later calculations
lsr Maze_x ; Calculate maze starting X coordinate
lda #40/2
sec
sbc Maze_x
sta Maze_x
lsr Maze_y ; Calculate maze starting Y coordinate
lda #30/2
sec
sbc Maze_y
sta Maze_y
iny
lda (MAZE_PTR),Y ; Load players starting x position
sta Start_x
iny
lda (MAZE_PTR),Y ; Load players starting y position
sta Start_y
rts
; *****************************************************************************
; Increment the level counter on screen (rolls over to 000 after 999)
; *****************************************************************************
; USES: .A
; *****************************************************************************
inc_level:
stz VERA_ADDR_H
+VERA_GOXY 39,0
lda VERA_DATA0
inc
cmp #$3A ; is value > $39 ?
bcc @end
lda #$30
sta VERA_DATA0
dec VERA_ADDR_L
dec VERA_ADDR_L
lda VERA_DATA0
inc
cmp #$3A
bcc @end
lda #$30
sta VERA_DATA0
dec VERA_ADDR_L
dec VERA_ADDR_L
lda VERA_DATA0
inc
cmp #$3A
bcc @end
lda #$30
@end: sta VERA_DATA0
rts
; *****************************************************************************
; Sets a random color for the trail of the maze.
; *****************************************************************************
; USES: .A, .X, .Y & TMP0
; OUTPUT: Trail_color global variable set to random number
; *****************************************************************************
set_trail_col:
jsr Entropy_get ; Get 24bit "random" number
stx TMP0 ; Combine to 4 bits
eor TMP0
sty TMP0
eor TMP0
sta TMP0
lsr
lsr
lsr
lsr
eor TMP0
and #$0F
cmp #BLACK ; Avoid Black
beq set_trail_col
cmp #LIGHTGRAY ; Avoid lightgray (background color)
beq set_trail_col
cmp #DARKGRAY ; Avoid darkgray
beq set_trail_col
cmp #BLUE ; Avoid blue
beq set_trail_col
asl
asl
asl
asl
sta Trail_color
rts
; *****************************************************************************
; Load mazes from MAZES.BIN into memory bank 1 starting at address $A000
; If the function returns with Carry Set, it was unable to load the mazes.
; *****************************************************************************
; USES: .A, .X, .Y
; *****************************************************************************
load_mazes:
lda #1 ; Logical filenumber (must be unique)
ldx #8 ; Device number (8 local filesystem)
ldy #255 ; Secondary command 255=none
jsr SETLFS
lda #(Mazes_end-Mazes) ; Length of filename
ldx #<Mazes ; Address of filename
ldy #>Mazes
jsr SETNAM
lda #1 ; Ensure RAM bank is set to 1
sta RAM_BANK
lda #0 ; 0=load, 1=verify
ldx #<RAM_BANK_START ; Address to load data to
ldy #>RAM_BANK_START
jsr LOAD
bcc @no_error ; Carry Clear = No error
clc
ldy #0 ; Move cursor to 0, 15
ldx #15
jsr PLOT
lda #PET_RED ; Write with white text
jsr CHROUT ; on red background
lda #PET_SWAP_FGBG
jsr CHROUT
lda #PET_WHITE
jsr CHROUT
@err_loop:
lda Err_Ld,Y ; Write the error message
beq @next
jsr CHROUT
iny
bra @err_loop
@next:
ldy #0
sec
@name_loop:
lda Mazes,Y ; Write the filename that failed.
beq @no_error
jsr CHROUT
iny
bra @name_loop
@no_error:
rts
; *****************************************************************************
; *****************************************************************************
; *****************************************************************************
clear_field:
lda #$10
sta VERA_ADDR_H
lda #1
sta VERA_ADDR_M
inc
sta VERA_ADDR_L
ldx #' '
ldy #((LIGHTGRAY<<4)|LIGHTGRAY)
@loop:
stx VERA_DATA0
sty VERA_DATA0
lda VERA_ADDR_L
cmp #(39*2)
bne @loop
lda #2
sta VERA_ADDR_L
inc VERA_ADDR_M
lda VERA_ADDR_M
cmp #28
bne @loop
rts
; *****************************************************************************
; Initializes the screen to start the game.
; *****************************************************************************
init_play_screen:
lda #PET_LIGHTGRAY ; Set background color
jsr CHROUT
lda #PET_SWAP_FGBG
jsr CHROUT
lda #PET_CLEAR ; Clear screen
jsr CHROUT
+VERA_GOXY 0, 0 ; Draw vertical line on left side of screen
lda #' '
ldx #(WHITE<<4)|RED
ldy #30
jsr draw_ver_line
+VERA_GOXY 39, 0 ; Draw vertical line on right side of screen
lda #' '
ldy #30
jsr draw_ver_line
+VERA_GOXY 1, 0 ; Draw horizontal line on top of screen
lda #' '
ldy #38
jsr draw_hor_line
+VERA_GOXY 1, 28 ; Draw 2 horizontal lines on bottom of screen
lda #' '
ldy #38
jsr draw_hor_line
+VERA_GOXY 1, 29
lda #' '
ldy #38
jsr draw_hor_line
+VERA_SET_STRIDE 2 ; Write strings without setting color
+VERA_GOXY 0, 0
lda #<Time ; Time digits in upper left corner
sta TMP_PTR0
lda #>Time
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 16, 0
lda #<Caption ; Headline on top middle of screen
sta TMP_PTR0
lda #>Caption
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 30, 0
lda #<Level ; Level information in top right screen
sta TMP_PTR0
lda #>Level
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 6, 28 ; Helpful text at bottom 2 lines of scren
lda #<Help0
sta TMP_PTR0
lda #>Help0
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 1, 29
lda #<Help1
sta TMP_PTR0
lda #>Help1
sta TMP_PTR0+1
jmp print_str ; print_str function will rts to caller
; of this function because it is not jsr'et to
; *****************************************************************************
; Draws a horizontal line from left to right starting at the current position
; in VERA memory.
; Assumes that VERA stride is set to 1.
; *****************************************************************************
; INPUTS: .A = Character to use for drawing
; .X = fg/bg color to use
; .Y = Length of line
; *****************************************************************************
draw_hor_line:
sta VERA_DATA0
stx VERA_DATA0
dey
bne draw_hor_line
rts
; *****************************************************************************
; Draws a vertical line from top to bottom starting at the current position
; in VERA memory.
; Assumes that VERA stride is set to 1
; *****************************************************************************
; INPUTS: .A = Character to use for drawing
; .X = fg/bg color to use
; .Y = Length of line
; *****************************************************************************
draw_ver_line:
sta VERA_DATA0
stx VERA_DATA0
dec VERA_ADDR_L
dec VERA_ADDR_L
inc VERA_ADDR_M
dey
bne draw_ver_line
rts
; *****************************************************************************
; This function displays the welcome screen.
; It is assumed that the screen has previously been cleared with green text
; on black background.
; *****************************************************************************
show_welcome:
+VERA_SET_STRIDE 2 ; Jump over color cells
+VERA_GOXY 8, 5 ; Commander 16
lda #<Cx16
sta TMP_PTR0
lda #>Cx16
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 7, 19 ; 1st line of MAZE
lda #<Maze
sta TMP_PTR0
lda #>Maze
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 7, 20 ; 2nd line of MAZE
lda #<(Maze+27)
sta TMP_PTR0
lda #>(Maze+27)
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 7, 21 ; 3rd line of MAZE
lda #<(Maze+27+27)
sta TMP_PTR0
lda #>(Maze+27+27)
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 7, 22 ; 4th line of MAZE
lda #<(Maze+27+27+27)
sta TMP_PTR0
lda #>(Maze+27+27+27)
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 7, 23 ; 5th line of MAZE
lda #<(Maze+27+27+27+27)
sta TMP_PTR0
lda #>(Maze+27+27+27+27)
sta TMP_PTR0+1
jsr print_str
+VERA_GOXY 19, 25 ; V2
lda #<V2
sta TMP_PTR0
lda #>V2
sta TMP_PTR0+1
jsr print_str
+VERA_SET_STRIDE 1 ; Include color cells when printing
+VERA_GOXY 15, 2 ; 1st line of X
ldx #(BLACK<<4)|PURPLE ; Black background and purple foreground
lda #<Xl0
sta TMP_PTR0
lda #>Xl0
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 15, 3 ; 2nd line of X
ldx #(BLACK<<4)|LIGHTBLUE
lda #<Xl1
sta TMP_PTR0
lda #>Xl1
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 15, 4 ; 3rd line of X
ldx #(BLACK<<4)|CYAN
lda #<Xl2
sta TMP_PTR0
lda #>Xl2
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 15, 6 ; 4th line of X
ldx #(BLACK<<4)|YELLOW
lda #<Xl3
sta TMP_PTR0
lda #>Xl3
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 15, 7 ; 5th line of X
ldx #(BLACK<<4)|ORANGE
lda #<Xl4
sta TMP_PTR0
lda #>Xl4
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 15, 8 ; 6th line of X
ldx #(BLACK<<4)|RED
lda #<Xl5
sta TMP_PTR0
lda #>Xl5
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 11, 14 ; Press Enter/Return
ldx #(BLACK<<4)|WHITE
lda #<Start
sta TMP_PTR0
lda #>Start
sta TMP_PTR0+1
jsr print_col_str
+VERA_GOXY 12, 28 ; By Jimmy Dansbo
ldx #(BLACK<<4)|WHITE
lda #<Jimmy
sta TMP_PTR0
lda #>Jimmy
sta TMP_PTR0+1
bra print_col_str ; Return from print_col_str will return to
; caller of this routine
; *****************************************************************************
; Print a zero-terminated string, no longer than 255 characters starting at
; the current VERA address.
; Function assumes that increment is set to 2 which means that color value
; for each character is not changed.
; *****************************************************************************
; INPUTS: TMP_PTR0 = pointer to start of string
; USES: .A & .Y
; *****************************************************************************
print_str:
ldy #0
@loop:
lda (TMP_PTR0),Y
beq @end ; If 0 read, we are done
sta VERA_DATA0
iny
bra @loop
@end:
rts
; *****************************************************************************
; Print a zero-terminated string, no longer than 255 characters starting at
; the current VERA address, set bg/fg color of each character to the value
; defined in .X register.
; Function assumes that increment is set to 1
; *****************************************************************************
; INPUTS: TMP_PTR0 = pointer to start of string
; .X = fg/bg color to use
; USES: .A & .Y
; *****************************************************************************
print_col_str:
ldy #0
@loop:
lda (TMP_PTR0),Y
beq @end ; If 0 read, we are done
sta VERA_DATA0
stx VERA_DATA0
iny
bra @loop
@end:
rts
; *****************************************************************************
; Use Kernal calls to initialize screen to 40x30 mode and set green text on
; black background.
; *****************************************************************************
init_screen:
; Use Kernal routine to set 40x30 text mode
lda #SCR_MOD_00
jsr Screen_set_mode
; Set green text on black background
lda #PET_BLACK
jsr CHROUT
lda #PET_SWAP_FGBG
jsr CHROUT
lda #PET_GREEN
jsr CHROUT
; Clear screen
lda #PET_CLEAR
jsr CHROUT
rts