-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathHarvey.asm
855 lines (800 loc) · 22.9 KB
/
Harvey.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
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
; ======================================
; HARVEY WALLBANGER by Charles Bachand
; ======================================
; ======================================
; Copyright (C) 1982 ANALOG Magazine
; ======================================
; ------------------------
; Operating System Equates
; ------------------------
HPOSP0 = $D000 ;player 0 horizontal position
M0PF = $D000 ;missile 0/playfield collision
HPOSP2 = $D002 ;player 2 horizontal position
HPOSP3 = $D003 ;player 3 horizontal position
HPOSM0 = $D004 ;missile 0 horizontal position
P0PF = $D004 ;player 0/playfield collisions
P0PL = $D00C ;player 0 to player collisions
GRP2 = $D00F ;player 2 graphics register
COLBK = $D01A ;background color
GRACTL = $D01D ;graphics control register
HITCLR = $D01E ;collision 'HIT' clear
CONSOL = $D01F ;console switch port
AUDF1 = $D200 ;audio frequency 1
AUDC1 = $D201 ;audio volume 1
AUDF2 = $D202 ;audio frequency 2
AUDC2 = $D203 ;audio volume 2
AUDF3 = $D204 ;audio frequency 3
AUDC3 = $D205 ;audio volume 3
AUDF4 = $D206 ;audio frequency 4
AUDC4 = $D207 ;audio volume 4
RANDOM = $D20A ;random number generator
IRQEN = $D20E ;IRQ interrupt enable
PMBASE = $D407 ;P/M base address
WSYNC = $D40A ;wait for horizontal sync
VCOUNT = $D40B ;scan line counter
SETVBV = $E45C ;set vertical blank vector
XITVBV = $E462 ;vertical blank exit vector
SIOINT = $E465 ;serial I/O initialization
ATRACT = $004D ;atract mode counter
; -----------------------
; System Shadow Registers
; -----------------------
RTCLOK = $0012 ;system clock
CDTMV1 = $0218 ;system timer 1
CDTMV2 = $021A ;system timer 2
CDTMA1 = $0226 ;system timer 1 vector
CDTMA2 = $0228 ;system timer 2 vector
SDMCTL = $022F ;DMA control
SDLSTL = $0230 ;display list pointer
GPRIOR = $026F ;graphics priority
STICK0 = $0278 ;joystick 1
STRIG0 = $0284 ;trigger 1
PCOLR0 = $02C0 ;player 0 color
PCOLR1 = $02C1 ;player 1 color
PCOLR2 = $02C2 ;player 2 color
PCOLR3 = $02C3 ;player 3 color
COLOR2 = $02C6 ;playfield 2 color
COLOR3 = $02C7 ;playfield 3 color
COLOR4 = $02C8 ;background color
; -------------------
; Page Zero Variables
; -------------------
ORG $0080 ;area not used by system
PIC DS 2 ;rabbit image pointer
; --------------------------
; Player / Missile RAM Space
; --------------------------
ORG $3000 ;out of everyones way
PM DS $180 ;first area not used
MISL DS $80 ;Missile graphics area
PLR0 DS $80 ;player 0 graphics area
PLR1 DS $80 ;player 1 graphics area
PLR2 DS $80 ;player 2 graphics area
PLR3 DS $80 ;player 3 graphics area
; -------------------
; Program entry point
; -------------------
JMP HARVEY
; -----------------
; Game display list
; -----------------
DL DB $70,$70 ;32 blank scan lines
DB $70,$70
DB $47 ;mode 2 line w/LMS bit
DW DISP ;address of game display
DB $07,$07 ;9 more mode 2 lines
DB $07,$07
DB $07,$07
DB $07,$07
DB $07
DB $70,$70 ;skip 16 lines
DB $46 ;mode 1 line w/LMS bit
DW SLINE ;address of score line
DB $41 ;jump on vertical blank
DW DL ;to start of display list
; ---------------
; Score line data
; ---------------
SLINE DB 'R'+$A0
DB 'A'+$A0
DB 'B'+$A0
DB 'B'+$A0
DB 'I'+$A0
DB 'T'+$A0
DB 'S'+$A0
DB ':'+$A0
RNUM DB '3'+$A0 ;number of rabbits
DB ' '+$A0
DB 'S'+$A0
DB 'C'+$A0
DB 'O'+$A0
DB 'R'+$A0
DB 'E'+$A0
DB ':'+$A0
SNUM DB '0'+$A0 ;score display
DB '0'+$A0
DB '0'+$A0
DB '0'+$A0
; -----------------
; Game over message
; -----------------
GOMSG DB 'game'
DB 0,0,'ov'
DB 'er',$80
PSMSG DB 'pres'
DB 's',0,0,'s'
DB 'tart',$80
; -------------------
; Initialization Code
; -------------------
HARVEY CLD ;clear decimal flag
JSR SIOINT ;stop cassette
LDA #'3'+$A0;display for '3'
STA RNUM ;3 lives (display)
LDA #3 ;get 3 lives
STA LIVES ;initialize counter
LDA #'0'+$A0;display for '0'
STA SNUM ;store in the four
STA SNUM+1 ;bytes used for the
STA SNUM+2 ;score display
STA SNUM+3 ;area.
MORE LDA #60 ;get 1 second count
STA TIM2ST ;set reset value
STA CDTMV2 ;set system timer #2
JSR CLSCRN ;clear game playfield
LDY #2 ;display 3 numbers (0-2)
INUMS JSR PUTNUM ;put the number on screen
DEY ;decrement number counter
BPL INUMS ;done yet? No.
LDA #DL&$FF ;Yes. low byte DL address
STA SDLSTL ;DL pointer (low)
LDA #DL/256 ;high byte DL address
STA SDLSTL+1;DL pointer (high)
LDA #$04 ;set PF over PLAYER
STA GPRIOR ;graphics priority
LDA #40 ;high wall
STA BYLOC ;starting location
LDA #196 ;low wall
STA BYLOC+1 ;starting location
LDA #60 ;left wall
STA BXLOC ;starting location
STA HPOSP2 ;hardware register
LDA #184 ;right wall
STA BXLOC+1 ;starting location
STA HPOSP3 ;hardware register
LDA #122 ;center screen-4 color clocks
STA HARX ;Harvey's initial X position
LDA #55 ;center P/M-8 bytes
STA HARY ;Harvey's initial Y position
LDA #$2E ;set P/M DMA on bits
STA SDMCTL ;store in DMA control
LDA #3 ;set P/M enable bits on
STA GRACTL ;store in graphics control
LDA #PM/256 ;get high byte of P/M addr
STA PMBASE ;point hardware to it
LDA #$96 ;light blue color
STA COLOR2 ;default color too dark
LDA #$48 ;pink color
STA COLOR3 ;same here
LDA #$18 ;gold color
STA PCOLR0 ;set rabbit color
LDA #$98 ;blue color
STA PCOLR1 ;set missile 1 color
LDA #$34 ;red-orange color
STA PCOLR2 ;left wall color
LDA #$C4 ;green color
STA PCOLR3 ;right wall color
LDA #1 ;initialize trigger flag-
STA STRIGF ;to no shot fired
LDX #VB/256 ;address of VB (MSB)
LDY #VB&$FF ;address of VB (LSB)
LDA #7 ;deferred vertical blank opt
JSR SETVBV ;set deferred Vblank vector
LDA #T1&$FF ;addr of timer 1 routine LSB
STA CDTMA1 ;set timer 1 vector LSB
LDA #T1/256 ;addr of timer 1 routine MSB
STA CDTMA1+1;set timer 1 vector MSB
LDA #T2&$FF ;addr of timer 2 routine LSB
STA CDTMA2 ;set timer 2 vector LSB
LDA #T2/256 ;addr of timer 2 routine MSB
STA CDTMA2+1;set timer 2 vector MSB
LDA #1 ;get 4.25 second count
STA CDTMV1+1;set system timer #1
LDA #0 ;get a zero
STA HITCLR ;reset collision registers
STA DIESW ;rabbit is alive
STA TICTOC ;reset tictoc counter
STA VOL1 ;start with no tictoc sound
STA VOL2 ;start with no shuffle noise
STA IRQEN ;disable all IRQ interrupts
LDX #3 ;set index value to 3
WINCZ STA WINC,X ;zero wall mover counter
STA SHOTX,X ;zero X missile location
STA SHOTY,X ;zero Y missile location
STA SINCX,X ;zero X missile increment
STA SINCY,X ;zero Y missile increment
DEX ;next wall mover counter
BPL WINCZ ;more walls/missiles? Yes.
TAX ;set index to zero
IM01 STA MISL,X ;clear Missile area
STA PLR0,X ;clear Player 0, 1 area
INX ;do next byte
BNE IM01 ;done yet? No.
LDA #$FF ;turn on pixels
IM23 STA PLR2,X ;set Player 2, 3 area
INX ;do next byte
BNE IM23 ;done yet? No.
; ------------------------------------------
; Main program used to generate the display.
; Actual game done entirely during display's
; vertical blank processing routine.
; ------------------------------------------
HBARS INX ;increment wall pointer
TXA ;transfer pointer to Acc
AND #1 ;mask off lowest bit
TAX ;put back in X register
LDA BYLOC,X ;get wall vertical position
LSR A ;divide by 2, odd=carry set
PHP ;save carry flag
VCHECK CMP VCOUNT ;compare with line counter
BNE VCHECK ;not yet!
STA WSYNC ;start at new line
PLP ;get carry flag back
BCC ONELIN ;branch on even line number
STA WSYNC ;wait for next line
ONELIN LDA RANDOM ;random background color
AND #$F6 ;max lum of 6
STA COLBK ;for horizontal walls
LDY #10 ;let's have 10 lines of this
LINES LDA #0 ;get a zero for overlap
STA GRP2,X ;background overlaps player
STA WSYNC ;wait for next line
LDA RANDOM ;random background color
AND #$F6 ;max lum of 6
STA COLBK ;for horizontal walls
DEY ;decrement line counter
BNE LINES ;10 lines done yet? No!
LDA COLOR4 ;get original background
STA COLBK ;store in background
LDA LIVES ;more lives
BEQ HB1 ;No. skip code
LDA DIESW ;a new life?
BPL HB1 ;No.
JMP MORE ;Yes. more lives
HB1 LDA CONSOL ;check for start switch
AND #$01 ;mask off bit
BNE HBARS ;start? No.
JMP HARVEY ;restart game
; -----------------------------------------
; System timer #1 interrupt handler.
; Used to speed up walls every 4.25 seconds.
; -----------------------------------------
T1 LDA TIM2ST ;get wall speed
CMP #2 ;must stop at two
BEQ TIM1 ;is it two? Yes.
DEC TIM2ST ;No, then decrement
TIM1 LDA #1 ;get 4.25 second cycle time
STA CDTMV1+1;reset timer #1
RTS ;return
; -------------------------------------------
; System timer #2 interrupt handler.
; Used to move walls and initiate wall noise.
; -------------------------------------------
T2 LDA TIM2ST ;get timer #2 value
STA CDTMV2 ;reset timer #2
INC BYLOC ;move top wall down
DEC BYLOC+1 ;move bottom wall up
INC BXLOC ;change left wall location
LDA BXLOC ;get new location
STA HPOSP2 ;change player 2 position
DEC BXLOC+1 ;change right wall location
LDA BXLOC+1 ;get new location
STA HPOSP3 ;change player 3 position
INC TICTOC ;increment TIC-TOC counter
LDA TICTOC ;get counter value
AND #1 ;just need 0 or 1 value
TAX ;use for index
LDA METRO,X ;get sound frequency
STA AUDF1 ;change frequency
LDA #$08 ;get volume value
STA VOL1 ;save in volume counter
RTS ;return
; -------------------------------------------
; Deferred vertical blank processing routine.
; Here is where all the actual game playing
; takes place. This could be quite long.
; -------------------------------------------
VB LDA DIESW ;rabbit dying?
BNE VB0 ;He sure is.
LDA LIVES ;any lives left?
BNE VB0 ;There sure are.
JSR CLSCRN ;clear screen of numbers
LDX #0 ;initialize X with zero
STX AUDC1 ;stop tictoc sound
STX AUDC2 ;stop dying sound
STX AUDC3 ;stop gun noise
STX AUDC4 ;stop number sound
STX CDTMV1 ;shut off the two timers
STX CDTMV1+1;ditto.
STX CDTMV2 ;same here.
GOPRT LDA GOMSG,X ;get a character
BMI PSINIT ;end of scring? Yes.
STA DISP+85,X;put on screen
INX ;increment index
JMP GOPRT ;continue
PSINIT LDX #0 ;zero the index
PSPRT LDA PSMSG,X ;get another character
BMI VBXIT ;end of string? Yes.
STA DISP+144,X;put on screen
INX ;increment index
JMP PSPRT ;continue
VBXIT JMP VBX ;exit vertical blank
VB0 LDA P0PL ;player/player collisions
STA P0PLT ;store in temp variable
LDA P0PF ;player to PF collisions
STA P0PFT ;store in temp variable
LDA NSOUND ;treasure sound counter
BMI NOSND ;end of sound? Yes.
DEC NSOUND ;decrement volume
LSR A ;divide volume by 2
ORA #$A0 ;add pure tone
STA AUDC4 ;change volume
NOSND LDA VOL1 ;get tictoc volume value
BMI SND2 ;if <0 we produce no sound
DEC VOL1 ;decrement volume value
ORA #$C0 ;mask on the distortion
STA AUDC1 ;generate the tictoc sound
SND2 LDA VOL2 ;get shuffle volume
BMI SND3 ;if <0 we produce no sound
DEC VOL2 ;decrement volume value
ORA #$80 ;mask on the distortion
STA AUDC2 ;generate the shuffle noise
SND3 LDA FREQ3 ;get shot frequency
INC FREQ3 ;increment shot frequency
INC FREQ3 ;do it again
INC FREQ3 ;and one last time
STA AUDF3 ;change frequency (lower)
LDA DIESW ;is rabbit dying
BEQ TMOV1 ;No. continue
INC DIESW ;Yes. 2 second die period
INC PCOLR0 ;change rabbit colors
INC PCOLR0 ;again
LDA PCOLR0 ;get number
ASL A ;*2
ASL A ;*4
ASL A ;*8
STA AUDF2 ;use as frequency
LDA #$88 ;get distortion
STA AUDC2 ;make sound
JMP VBX ;exit vertical blank
TMOV1 LDA WINC ;check push wall up
BEQ TMOV2 ;push up? No.
DEC WINC ;decrement push up counter
LDA BYLOC ;get top wall location
CMP #28 ;compare with top of screen
BEQ TMOV2 ;at top? Yes.
DEC BYLOC ;move wall up
TMOV2 LDA WINC+1 ;check push wall down
BEQ TMOV3 ;push down? No.
DEC WINC+1 ;decrement push down counter
LDA BYLOC+1 ;get bottom wall location
CMP #204 ;compare bottom of screen
BEQ TMOV3 ;at bottom? Yes.
INC BYLOC+1 ;move wall down
TMOV3 LDA WINC+2 ;check push wall left
BEQ TMOV4 ;push left? No.
DEC WINC+2 ;decrement push left counter
LDA BXLOC ;get left wall position
STA HPOSP2 ;move left wall player
CMP #39 ;check for left wall limit
BEQ TMOV4 ;at limit? Yes.
DEC BXLOC ;move wall left
TMOV4 LDA WINC+3 ;check push wall right
BEQ TMOVX ;push right? No.
DEC WINC+3 ;decrement push right counter
LDA BXLOC+1 ;get right wall position
STA HPOSP3 ;move right wall player
CMP #208 ;check for right wall limit
BEQ TMOVX ;at limit? Yes.
INC BXLOC+1 ;move wall right
TMOVX LDA #0 ;get a zero
STA ATRACT ;poke out atract mode
STA XTEMP ;zero rabbit X increment
STA YTEMP ;zero rabbit Y increment
LDA STICK0 ;get joystick value
CMP #$0F ;at center position?
BEQ CENTER ;Yes. skip code
LDA RTCLOK+2;get real time clock LSB
AND #$07 ;at 1/7.5 second mark?
BNE CENTER ;No. skip code
LDA #$10 ;get shuffle frequency
STA AUDF2 ;set frequency register
LDA #$04 ;get volume value
STA VOL2 ;set shuffle volume
CENTER LDA STICK0 ;get joystick value
SEC ;set carry for subtract
SBC #5 ;values 5-15 only
ASL A ;5-15 now 0,2,4,...
TAX ;use for index
LDA RTCLOK+2;get real time clock LSB
ROR A ;divide by 2
ROR A ;divide by 4
ROR A ;divide by 8
ROR A ;carry set/reset at .13 sec
LDA PK1,X ;get rabbit picture LSB
BCC PICMVL ;other pic at .13 sec? No.
LDA PK2,X ;get alternate picture LSB
PICMVL STA PIC ;store LSB of pic address
LDA PK1+1,X ;get rabbit picture MSB
BCC PICMVH ;other pic at .13 sec? No.
LDA PK2+1,X ;get alternate picture MSB
PICMVH STA PIC+1 ;store MSB of pic address
LDX #3 ;count 3 downto 0
CHKSTK LSR STICK0 ;shift bit into carry
BCS CHKNXT ;correct direction? No.
LDA STBLX,X ;check X movement direction
BEQ CHK0 ;movement allowed? No.
STA XTEMP ;store X movement value
CHK0 LDA STBLY,X ;check Y movement direction
BEQ CHKNXT ;movement allowed? No.
STA YTEMP ;store Y movement value
CHKNXT DEX ;do next stick position
BPL CHKSTK ;done yet? No.
LDA P0PLT ;get player 0 collision
CMP #$0C ;left/right squeze?
BNE NOSQUE ;No. Check indvdual walls
DEC RNUM ;decrement lives display
DEC LIVES ;decrement lines counter
INC DIESW ;the rabbit has died switch
NOSQUE AND #$04 ;check left wall collision
BEQ BMPRT ;hit left wall? No.
INC HARX ;Yes. Move rabbit to right
LDA #0 ;get zero value
STA XTEMP ;stop rabbit X movement
BMPRT LDA P0PLT ;get player 0 collision
AND #$08 ;check right wall collision
BEQ BMPUP ;hit right wall? No.
DEC HARX ;Yes. Move rabbit to left
LDA #0 ;get zero value
STA XTEMP ;stop rabbit X movement
BMPUP CLC ;clear carry for add
LDA BYLOC ;top wall Y location
ADC #4 ;offset by 4
LSR A ;divide by 2
CMP HARY ;compare rabbit Y location
BCC BMPDN ;hit top wall? No.
DEC RNUM ;decrement lives display
DEC LIVES ;decrement lines counter
INC DIESW ;the rabbit has died switch
BMPDN LDA HARY ;get rabbit Y location
ADC #10 ;offset by 10
ASL A ;multiply by 2
CMP BYLOC+1 ;compare bottom wall Y
BCC NOBMP ;hit bottom wall? No.
DEC RNUM ;decrement lives display
DEC LIVES ;decrement lines counter
INC DIESW ;the rabbit has died switch
NOBMP CLC ;clear carry for add
LDA HARX ;get rabbit X position
ADC XTEMP ;add X increment
STA HARX ;save new rabbit X position
STA HPOSP0 ;position rabbit player 0
CLC ;clear carry for add
LDA HARY ;get rabbit Y position
ADC YTEMP ;add Y increment
STA HARY ;save new rabbit Y position
TAX ;use position as index
LDY #0 ;initialize picture counter
MOVHAR LDA (PIC),Y ;get rabbit picture byte
STA PLR0,X ;store in player 0 area
INX ;increment player pointer
INY ;increment picture pointer
CPY #14 ;check for end of picture
BNE MOVHAR ;at end? No.
LDA STRIG0 ;get trigger value
CMP STRIGF ;compare with trigger flag
STA STRIGF ;save new trigger flag
BCS NOFIRE ;shot fired? No.
LDA XTEMP ;rabbit X increment
ORA YTEMP ;OR rabbit Y increment
BNE FIREGN ;rabbit stationary? No.
INC STRIGF ;set trigger flag to 1
BNE NOFIRE ;skip fire routine
FIREGN LDA #$40 ;initialize frequency
STA FREQ3 ;zero audio freq 3
LDA #$04 ;shot volume + distortion
STA AUDC3 ;enable volume 3
INC SHOTS ;increment shot pointer
LDA SHOTS ;get shot pointer
AND #3 ;make it 0-3 only
TAX ;use pointer for index
LDA XTEMP ;get rabbit X increment
ASL A ;make shot twice as fast
STA SINCX,X ;set missile X increment
LDA YTEMP ;get rabbit Y increment
ASL A ;make shot twice as fast
STA SINCY,X ;set missile Y increment
CLC ;clear carry for add
LDA HARX ;get rabbit X position
ADC #3 ;move to center X of rabbit
STA SHOTX,X ;shot initial X position
LDA HARY ;get rabbit Y position
ADC #8 ;its move to center Y of rabbit
STA SHOTY,X ;shot initial Y position
NOFIRE LDA #0 ;zero accumulator
TAX ;zero X index
ERASES STA MISL,X ;zero all missiles
INX ;next missile byte
BPL ERASES ;done? No.
LDX #3 ;count 3 downto 0
PLOTS LDA SINCX,X ;get missile X increment
ORA SINCY,X ;OR missile Y increment
BEQ NOPLOT ;any movement? No.
LDA SHOTY,X ;missile Y position
CLC ;clear carry for add
ADC SINCY,X ;add Y increment
STA SHOTY,X ;store new Y position
TAY ;Y position now index
ASL A ;multiply by 2
ADC #2 ;offset for compare
CMP BYLOC+1 ;compare with bottom wall
BCC HITTP ;hit bottom wall? No.
JSR ZINCXY ;zero missile increments
ADC WINC+1 ;add 8 to wall increment
STA WINC+1 ;new bottom wall increment
JMP PLOTNH ;continue
HITTP SBC #12 ;offset for bottom side
CMP BYLOC ;compare with top wall
BCS PLOTNH ;hit top wall? No.
JSR ZINCXY ;zero missile increments
ADC WINC ;add 8 to wall increment
STA WINC ;new top wall increment
PLOTNH LDA MISL,Y ;get missile byte
ORA MISMSK,X;OR missile mask
STA MISL,Y ;store new byte
LDA MISL+1,Y;get next missile byte
ORA MISMSK,X;OR missile mask
STA MISL+1,Y;store new next byte
LDA M0PF,X ;missile/playfield collision
LDY #0 ;init Y register
MHPF ROR A ;collision?
BCC MHPF0 ;No. No. No.
JMP MHIT ;Yes. Yes. Yes.
MHPF0 INY ;try next bit
CPY #4 ;any more bits?
BNE MHPF ;Certainly! Yuk. Yuk.
CLC ;clear carry for add
LDA SHOTX,X ;get missile X position
ADC SINCX,X ;add X increment
STA SHOTX,X ;store new X position
STA HPOSM0,X;position missile
CMP BXLOC+1 ;compare missile with wall
BCC HITLF ;hit right wall? No.
JSR ZINCXY ;zero missile increments
ADC WINC+3 ;add 8 to wall increment
STA WINC+3 ;new wall increment
JMP NOPLOT ;continue
HITLF SBC #6 ;offset for right side
CMP BXLOC ;compare with left wall
BCS NOPLOT ;hit left wall? No.
JSR ZINCXY ;zero missile increments
ADC WINC+2 ;add 8 to wall increment
STA WINC+2 ;new wall increment
NOPLOT DEX ;next missile
BMI NOPL1 ;missiles done? Yes.
JMP PLOTS ;continue loop
NOPL1 LDX #3 ;set up pointer
LDA #0 ;zero accumulator
CHKMIS ORA SINCX,X ;OR in X increments
ORA SINCY,X ;OR in Y increments
DEX ;decrement pointer
BPL CHKMIS ;at end? No.
CMP #0 ;check shot increments
BNE NOSSND ;any increments? Yes.
STA AUDC3 ;end shot sound
NOSSND LDY #0 ;initialize Y index
MISHIT LSR P0PFT ;shift collision to carry
BCC MH1 ;collision w/number? No.
JSR ERANUM ;erase the number
LDA VTBL,Y ;get value of number
PHA ;save on stack
JSR PUTNUM ;put out a new number
PLA ;get old number
TAY ;use as counter value
BEQ SCX ;was it zero? Yes.
SCORER LDX #3 ;point to score low digit
SC1 INC SNUM,X ;increment digit
LDA SNUM,X ;get digit
CMP #'9'+$A1;past ATASCII '9'+color?
BNE SCY ;No. continue
LDA #'0'+$A0;reset digit
STA SNUM,X ;change score display
DEX ;point to next digit
BPL SC1 ;score rolled over? No.
SCY DEY ;decrement value
BNE SCORER ;scoring done? No.
SCX JMP VBX ;exit routine
MH1 INY ;check next color digit
CPY #3 ;done 0-2 yet?
BNE MISHIT ;No. continue
VBX STA HITCLR ;clear collision registers
JMP XITVBV ;exit deferred vertical blank
MHIT TXA ;save X register
PHA ;on stack
JSR ERANUM ;erase number hit and
JSR PUTNUM ;put a new one on screen
PLA ;pull X register
TAX ;from stack
JMP NOPLOT ;continue on
; -------------------------
; Commonly used subroutines
; -------------------------
; Clear missile display area
ZINCXY LDA #0 ;get zero value
STA SINCX,X ;zero missile X increment
STA SINCY,X ;zero missile Y increment
CLC ;clear carry for add
LDA #8 ;get value for add
RTS ;we return to the program
; Clear the game playfield
CLSCRN LDX #200 ;set 0-199 bytes
LDA #0 ;to zero
CL0 STA DISP-1,X;store in display
DEX ;count down
BNE CL0 ;past zero yet? No.
RTS ;return to program
; Put random number from 0-9 on screen at
; a random location 0-199
PUTNUM LDX RANDOM ;get random number
CPX #200 ;is number < 200?
BCS PUTNUM ;No. try another
LDA DISP,X ;see if space is occupied
BNE PUTNUM ;Yes. try again
PN0 LDA RANDOM ;get another random number
AND #$0F ;limit it to 0-15
CMP #10 ;is number < 10?
BCS PN0 ;No. try another
STA VTBL,Y ;save number
ORA CTBL,Y ;OR with color
STA DISP,X ;put number on screen
TXA ;move screen offset to A
STA ATBL,Y ;save screen offset
RTS ;end of routine
; Erase number from screen
ERANUM LDA #0 ;get zero for blank
LDX ATBL,Y ;get # position on screen
STA DISP,X ;blank number on screen
LDA RANDOM ;get random number
AND #$1F ;mask off high bits
ORA #$10 ;make it $10-$1F
STA AUDF4 ;use as sound frequency
LDA #30 ;initialize-
STA NSOUND ;volume counter
RTS ;end of routine
; ----------------------------
; Program tables and constants
; ----------------------------
MISMSK DB $03 ;missile 0 mask
DB $0C ;missile 1 mask
DB $30 ;missile 2 mask
DB $C0 ;missile 3 mask
HARLF1 DB 0,0 ;left view #1
DB $12,$0A
DB $3C,$74
DB $3C,$1C
DB $1E,$3E
DB $3F,$7E
HARLF2 DB 0,0 ;left view #2
DB $0B,$0A
DB $3C,$74
DB $3C,$1C
DB $1E,$3E
DB $3E,$F7
HARRT1 DB 0,0 ;right view #1
DB $48,$50
DB $3C,$2E
DB $3C,$38
DB $78,$7C
DB $FC,$7E
HARRT2 DB 0,0 ;right view #2
DB $D0,$50
DB $3C,$2E
DB $3C,$38
DB $78,$7C
DB $7C,$EF
HARFR1 DB 0,0 ;front view #1
DB $42,$24
DB $3C,$14
DB $3C,$18
DB $3C,$7E
DB $7E,$E7
HARFR2 DB 0,0 ;front view #2
DB $42,$24
DB $3C,$28
DB $3C,$18
DB $3C,$7E
DB $7E,$E7
HARDN1 DB 0,0 ;down view #1
DB $44,$24
DB $3C,$14
DB $3C,$18
DB $3C,$7E
DB $FE,$07
HARDN2 DB 0,0 ;down view #2
DB $22,$24
DB $3C,$28
DB $3C,$18
DB $3C,$7E
DB $7F,$E0
HARUP1 DB 0,0 ;up view #1
DB $44,$24
DB $3C,$3C
DB $3C,$18
DB $3C,$66
DB $FE,$07
HARUP2 DB 0,0 ;up view #2
DB $22,$24
DB $3C,$3C
DB $3C,$18
DB $3C,$66
DB $7F,$E0
DB 0,0
PK1 DW HARRT1 ;rabbit pictures set 1
DW HARRT1
DW HARRT1
DW 0
DW HARLF1
DW HARLF1
DW HARLF1
DW 0
DW HARDN1
DW HARUP1
DW HARFR1
PK2 DW HARRT2 ;rabbit pictures set 2
DW HARRT2
DW HARRT2
DW 0
DW HARLF2
DW HARLF2
DW HARLF2
DW 0
DW HARDN2
DW HARUP2
DW HARFR2
CTBL DB $10,$50 ;color offset table
DB $90
METRO DB 38,41 ;tictoc tones
STBLX DB $01,$FF ;joystick X increments
DB $00,$00
STBLY DB $00,$00 ;joystick Y increments
DB $01,$FF
; ---------------------
; Variable Storage Area
; ---------------------
HARX DS 1 ;Harvey's X locatin
HARY DS 1 ;Harvey's Y location
BYLOC DS 2 ;horizontal wall Y locations
BXLOC DS 2 ;vertical wall X locations
VOL1 DS 1 ;tictoc volume
VOL2 DS 1 ;shuffle volume
FREQ3 DS 1 ;shot frequency
NSOUND DS 1 ;pick number up sound
TICTOC DS 1 ;tictoc sound counter
TIM2ST DS 1 ;wall speed timer
WINC DS 4 ;wall mover counters
STRIGF DS 1 ;trigger compare register
XTEMP DS 1 ;temporary variable
YTEMP DS 1 ;temporary variable
P0PLT DS 1 ;player 0 collision shadow
P0PFT DS 1 ;PL to PF collision shadow
VTBL DS 3 ;value of #'s on screen
ATBL DS 3 ;screen offset to #'s
SHOTS DS 1 ;shot enable counter
LIVES DS 1 ;number of lives left
DIESW DS 1 ;rabbit dying switch
SHOTX DS 4 ;missile X location
SHOTY DS 4 ;missile Y location
SINCX DS 4 ;missile X increment
SINCY DS 4 ;missile Y increment
DISP DS 200 ;screen display area
END HARVEY