forked from johnidm/asm-atari-2600
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRiverRaid.asm
3645 lines (3436 loc) · 129 KB
/
RiverRaid.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
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; *** R I V E R R A I D ***
; Copyright 1982 Activision
; Designer: Carol Shaw
; Analyzed, labeled and commented
; by Thomas Jentzsch (JTZ)
; Last Update: 13.08.2001 (v0.9)
; Section generation:
; The river is divided into sections which are generated by random. The random
; number generator can generate 57337 different sections. Each section is
; divided into 16 blocks. The last block is the bridge. For each other block a
; random Id is generated, which defines the shape of the river. The river is
; randomly generated with or without islands.
; Each block is 32 lines high and is divided into two parts. Those parts are
; neccessary for the bridge only, because it is smaller than a whole block.
;
; All objects are also randomly generated. There is one object in each block.
; First the game randomly selects if a fuel tank, an enemy object (ship, plane
; or helicopter) or a house should be generated. Then a starting x-position is
; defined and finally the direction (left/right) of the object is set.
; The ships and helicopters start patroling also randomly.
;
; Kernel:
; The main display is 160 lines tall. Below is the state display (score, fuel,
; lives and copyright).
; The kernel displays five or six of the section blocks. When a block leaves
; the display, it is replaced on the fly by a new generated one.
; It's basically a two line kernel, which is repeated twelve times. After that,
; there is code for eight more lines, where the block is iterated and all new
; parameter are set. (12 * 2 + 8 = 32!)
; The parameters for each block are:
; - a pointer to the current playfield pattern
; - a flag for a bright or dark green playfield
; - two pointers for the current object, the data is displayed interlaced,
; this gives in a single line resolution here
; - a color pointer for the object
; - x-positioning values for the object
; - some flags for the object (size, reflection...)
; All collisons are checked for each displayed block and only the hardware
; collision registers are used for that (no software calculations).
; Misc:
; - There are no score variables, the score is stored and changed directly in
; the display pointers!
; - The are no variables to store the x-positions of the objects, all
; calculations are done directly with the position values.
; (There aren't any BCD calculations in this code!)
; - All variables for the players are swapped, when the players change.
; - The game speeds aren't adjusted for PAL, the PAL game run's about 16% slower.
; (This seems to be true for most PAL conversions.)
; - ...
processor 6502
include vcs.h
;===============================================================================
; A S S E M B L E R - S W I T C H E S
;===============================================================================
FILL_OPT = 1 ; fill optimized bytes with NOPs
SCREENSAVER = 1 ; compile with screensaver code
TRAINER = 0 ; enable training mode
NTSC = 1 ; compile for NTSC
;===============================================================================
; C O N S T A N T S
;===============================================================================
; initial values for the random number generator:
SEED_LO = $14 ; change "to go, where no one has gone before" :)
SEED_HI = $A8
; color constants:
BLACK = $00
GREY = $06
ORANGE = $2A
IF NTSC
YELLOW = $1C
RED = $48
BLUE = $84
CYAN = $B0
GREEN = $D2
ELSE
YELLOW = $2C
RED = $68
BLUE = $B4
CYAN = $70
GREEN = $52
ENDIF
DARK_RED = RED - $6
LIGHT_GREEN = GREEN + $8
BROWN = YELLOW - $C
LIGHT_GREY = GREY + $6
DARK_BLUE = BLUE - $4
; main game constants:
NUM_BLOCKS = 6 ; max. number of block on screen
SECTION_BLOCKS = 16 ; number of blocks/stage
BLOCK_PARTS = 2 ; each block has two parts
BLOCK_SIZE = 32 ; number of lines/block
NUM_LINES = 160 ; number of lines in main kernel
MAX_LEVEL = 48 ; number of difficulty levels
DIGIT_H = 8 ; height of the score digits
JET_Y = 19 ; fixed y-position for jet
MIN_MISSILE = JET_Y-6 ; starting position of player missile
MAX_MISSILE = NUM_LINES+1
MISSILE_SPEED = 6 ; y-speed of the jet missile
ROAD_HEIGHT = 13 ; number of lines for road
INTRO_SCROLL = 48 ; counter for scrolling into new game
SWITCH_PAGE_ID = 9 ; first pattern id with data on different page
; constants for shape-ids:
ID_EXPLOSION0 = 0 ; used for explosion end
ID_EXPLOSION1 = 1
ID_EXPLOSION2 = 2
ID_EXPLOSION3 = 3
ID_PLANE = 4
ID_HELI0 = 5
ID_HELI1 = 6
ID_SHIP = 7
ID_BRIDGE = 8
ID_HOUSE = 9
ID_FUEL = 10
; flags for blockLst:
PF1_PAGE_FLAG = %00000001 ; pattern for PF1 in page $FC or $FD
PF2_PAGE_FLAG = %00000010 ; pattern for PF1 in page $FC or $FD
PF_COLOR_FLAG = %00000100 ; bright or dark green PF
PATROL_FLAG = %00010000 ; enemy is patroling (change directions)
PF_COLLIDE_FLAG = %00100000 ; enemy collided with playfield
ENEMY_MOVE_FLAG = %01000000 ; enemy is moving
PF_ROAD_FLAG = %10000000 ; display road and bridge
; flags for State1Lst:
DIRECTION_FLAG = %00001000 ; move direction of object
FINE_MASK = %11110000 ; mask bits for HMxy
NUSIZ_MASK = %00000111 ; mask bits for NUSIx
; flags for PF_State:
ISLAND_FLAG = %10000000 ; island displayed in block
CHANGE_FLAG = %01000000 ; begin or end of island (JTZ: this interpretation might be wrong)
; joystick bits:
MOVE_RIGHT = %00001000
MOVE_LEFT = %00000100
MOVE_DOWN = %00000010
MOVE_UP = %00000001
; values for ENAxy:
DISABLE = %00
ENABLE = %10 ; value for enabling a missile
; values for NUSIZx:
TWO_COPIES = %001
THREE_COPIES = %011
DOUBLE_SIZE = %101
QUAD_SIZE = %111
; mask for SWCHB:
BW_MASK = %1000 ; black and white bit
;===============================================================================
; Z P - V A R I A B L E S
;===============================================================================
gameVariation = $80 ; one or two player game
gameDelay = $81 ; delay before gameVariation changes
frameCnt = $82 ; simple frame counter
random = $83 ; 8 bit random number (used for: start of ship and helicopter, sound)
joystick = $84 ; saved joystick value (?000rldu)
IF SCREENSAVER
SS_XOR = $85 ; change colors in screensaver mode (0/$01..$ff)
SS_Mask = $86 ; darker colors in screensaver mode ($ff/$f7)
ENDIF
dXSpeed = $87 ; x-acceleration
prevPF1PatId = $88 ; playfield pattern Id of the previous block
PF_State = $89 ; io000000
sectionEnd = $8A ; 0 = end of section
blockOffset = $8B ; offset into first displayed block
posYLo = $8C ; low value of blockOffset
bridgeExplode = $8D ; counter for bridge explosion
; the next 36 bytes are used to save all variables for six blocks:
;---------------------------------------
blockLst = $8E ; ..$93 flags for block definition
blockLstEnd = blockLst+NUM_BLOCKS-1
;---------------------------------------
XPos1Lst = $94 ; ..$99 coarse value for x-positioning of object
XPos1LstEnd = XPos1Lst+NUM_BLOCKS-1
;---------------------------------------
State1Lst = $9A ; ..$9F bit 0..2 = NUSIZ1, bit 3 = REFP1, 4..7 = fine move
State1LstEnd = State1Lst+NUM_BLOCKS-1
;---------------------------------------
Shape1IdLst = $A0 ;.. $A5 ids for object
Shape1IdLstEnd = Shape1IdLst+NUM_BLOCKS-1
;---------------------------------------
PF1Lst = $A6 ; ..$AB low pointer for PF1 data
PF1LstEnd = PF1Lst+NUM_BLOCKS-1
;---------------------------------------
PF2Lst = $AC ; ..$B1 low pointer for PF2 data
PF2LstEnd = PF2Lst+NUM_BLOCKS-1
;---------------------------------------
; end of block variables
missileY = $B2 ; y-position of player missile
playerX = $B3 ; x-position of player jet
speedX = $B4 ; x-speed of player jet
speedY = $B5 ; y-speed of play jet
blockPart = $B6 ; 1/2 (used for bridge)
fuelHi = $B7 ; high value of fuel (displayed)
fuelLo = $B8 ; low value of fuel
sectionBlock = $B9 ; number of block in current section (16..1)
shapePtr0 = $BA ; ..$BB pointer to the shape for the player jet
PF1PatId = $BC ; playfield pattern Id for the new generated block
;---------------------------------------
player1State = $BD ; ..$C1
level = player1State ; difficulty level for current player (1..48)
randomLoSave = player1State+1; saved random generator values for begin of level
randomHiSave = player1State+2;
livesPtr = player1State+3; ..$C1
;---------------------------------------
player2State = $C2 ; ..$C5
livesPtr2 = player2State+3; the high pointer is not saved here, because it's const
;---------------------------------------
gameMode = $C6 ; 0 = running; -1 = game over; 1..48 = scroll into game
shapePtr1a = $C7 ; ..$C8
shapePtr1b = $C9 ; ..$CA
colorPtr = $CB ; ..$CC
scorePtr1 = $CD ; ..$D8 12 bytes for the score display of current player
PF1Ptr = $D9 ; ..$DA
PF2Ptr = $DB ; ..$DC
;---------------------------------------
scorePtr2 = $DD ; ..$E7 12 bytes for the score display of other player
; the constant hi-pointers are temporary used:
blockNum = scorePtr2+1 ; current block in kernel
reflect0 = scorePtr2+3 ; flag for GRP0 (player jet) reflection
hitEnemyIdx = scorePtr2+5 ; index of enemy that was hit by missile
PFCrashFlag = scorePtr2+7 ; jet crashed into playfield
missileFlag = scorePtr2+9 ; $ff means: missile enabled
;---------------------------------------
collidedEnemy = $E8 ; jet collided with enemy (id)
randomLo = $E9 ; current number generator values
randomHi = $EA
randomLoSave2 = $EB ; saved number generator values for current player
randomHiSave2 = $EC
temp2 = $ED ;
roadBlock = temp2 ; bit 7 = 1: road in block
PFcolor = $EE ; color of river banks
valleyWidth = PFcolor ; define minimum width of valley in first levels (6/0)
playerColor = $EF ; YELLOW/BLACK
stateBKColor = $F0 ; GREY (const!)
statePFColor = $F1 ; YELLOW+2 (const!)
temp = $F2 ; main temporary variable
diffPF = temp ; difference between to PF pattern ids
zero1 = $f3 ; always zero!
player = $F4 ; 0/1
missileX = $F5 ; x-position of player missile
zero2 = $F6 ; always zero!
IF SCREENSAVER
SS_Delay = $F7 ; screensaver delay
ENDIF
sound0Id = $F8 ;
sound0Cnt = $F9
bridgeSound = $FA ; bridge is exploding
missileSound = $FB ; missile fired
temp3 = $FC
blockLine = temp3 ; current displayed line of block in kernel
maxId = temp3
lineNum = $FD ; counter for kernel lines
;===============================================================================
; M A C R O S
;===============================================================================
MAC FILL_NOP
IF FILL_OPT
REPEAT {1}
NOP
REPEND
ENDIF
ENDM
;===============================================================================
; R O M - C O D E (Part 1)
;===============================================================================
ORG $F000
START:
SEI ; 2
CLD ; 2
LDX #0 ; 2
Reset:
LDA #0 ; 2
.loopClear:
STA $00,X ; 4
TXS ; 2
INX ; 2
BNE .loopClear ; 2
JSR SetScorePtrs ; 6
LDA #>Zero ; 2
LDX #12-1 ; 2
JSR SetScorePtr1 ; 6 set high-pointers to $FB
LDX #colorPtr+1-PF1Lst; 2 #38
JSR GameInit ; 6
LDA random ; 3
BNE MainLoop ; 2
INC random ; 5
STA livesPtr ; 3 = 0!
LDA #<One ; 2
STA scorePtr1+10 ; 3
MainLoop:
LDX #4 ; 2 offset ball
LDA fuelHi ; 3
LSR ; 2
LSR ; 2
LSR ; 2
CLC ; 2
ADC #69 ; 2
JSR SetPosX ; 6 position ball for fuel display
; *** prepare everything for the main kernel: ***
; set all color registers (and NUSIZ1 = 0)
INX ; 2 x = 5!
.loopSetColors:
LDA ColorTab,X ; 4
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
STA PFcolor,X ; 4
STA NUSIZ1,X ; 4
DEX ; 2
BPL .loopSetColors ; 2
TAY ; 2 y = 0!
LDA scorePtr1+10 ; 3
CMP #<Two ; 2
BEQ .skipTwo ; 2
LDA SWCHB ; 4
LSR ; 2 reset pressed?
BCC .skipTwo ; 2 yes, skip player 2
LDA player ; 3 current player = 2?
BEQ .skipTwo ; 2 no, skip
STY playerColor ; 3 yes, set..
STY COLUP0 ; 3 ..and player 2 color = 0
.skipTwo:
; flicker background when bridge explodes:
LDA bridgeExplode ; 3
BEQ .skipExplosion ; 2
DEC bridgeExplode ; 5
LSR ; 2
BCC .skipExplosion ; 2
LDA #DARK_RED ; 2 flicker background red
IF SCREENSAVER
AND SS_Mask ; 3
ELSE
FILL_NOP 2
ENDIF
STA COLUBK ; 3
.skipExplosion:
INX ; 2 x = 0!
STX temp ; 3
STX NUSIZ0 ; 3
LDY playerX ; 3
LDA reflect0 ; 3
STA REFP0 ; 3
BEQ .noReflect ; 2
INY ; 2 adjust x-pos
.noReflect:
TYA ; 2
JSR SetPosX ; 6 x-position player jet
INX ; 2
STX CTRLPF ; 3 reflect playfield
STX VDELP1 ; 3 enable vertical delay for player 1
; set size, reflect and postion for top enemy object;
LDY XPos1Lst +NUM_BLOCKS-1; 3
LDA State1Lst+NUM_BLOCKS-1; 3
STA NUSIZ1 ; 3
STA REFP1 ; 3
JSR SetPosX2 ; 6 position top enemy object
; x-position missile:
INX ; 2
LDA missileX ; 3
JSR SetPosX ; 6 position missile
JSR DoHMove ; 6
STY PF0 ; 3 enable complete PF0 (y=$ff)
; clear collsion variables:
STY hitEnemyIdx ; 3
STY PFCrashFlag ; 3
STY missileFlag ; 3
STY collidedEnemy ; 3
; set variables for top block:
LDX #NUM_BLOCKS-1 ; 2
JSR SetPFxPtr ; 6
LDA blockOffset ; 3
CMP #3 ; 2 top block just started?
BCS .skipDex ; 2 no, skip
DEX ; 2 yes, start at block 4
.skipDex:
STX blockNum ; 3
LDY Shape1IdLst,X ; 4
LDX shapePtr1aTab,Y ; 4
STX shapePtr1a ; 3
LDX shapePtr1bTab,Y ; 4
STX shapePtr1b ; 3
LDX ColorPtrTab,Y ; 4
STX colorPtr ; 3
STA CXCLR ; 3 clear all collison registers
STA HMCLR ; 3
; calculate offset into first block:
TAX ; 2
SEC ; 2
SBC #1 ; 2
AND #$1F ; 2
STA blockLine ; 3
LSR blockLine ; 5 0..15
CMP #26 ; 2
BCC lowOffset ; 2
SBC #22 ; 2
BNE endOffset ; 2
lowOffset:
CMP #4 ; 2
BCC endOffset ; 2
AND #%01 ; 2
ORA #%10 ; 2
endOffset:
; set entrypoint into kernel:
TAY ; 2
LDA JmpHiTab,Y ; 4
PHA ; 3
LDA JmpLoTab,Y ; 4
PHA ; 3
; prepare graphics for first line of kernel:
TXA ; 2
LSR ; 2
TAY ; 2
LDA (shapePtr1a),Y ; 5
BCC .evenLine ; 2 even blockOffset!
LDA (shapePtr1b),Y ; 5
.evenLine:
CPX #26 ; 2 blockoffset >= 26?
BCS .noShape ; 2 yes, skip enemy shape
CPX #3 ; 2 blockoffset < 3?
BCC .noShape ; 2 yes, skip enemy shape
STA GRP1 ; 3 no, display enemy shape in first row
LDA #0 ; 2
STA GRP0 ; 3 VDELP1!
.noShape:
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3
LDA (colorPtr),Y ; 5
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
STA COLUP1 ; 3
LDX blockNum ; 3
LDA blockLst,X ; 4
STA roadBlock ; 3 save road-state
AND #PF_COLOR_FLAG ; 2
ORA #GREEN ; 2
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
STA PFcolor ; 3
BIT blockLstEnd ; 3 road in first block?
BPL .noRoad ; 2 no, use green color
CPY #ROAD_HEIGHT ; 2 offset inside road?
BCS .noRoad ; 2 no, use green color
LDA RoadColorTab,Y ; 4 yes, use road colors
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
.noRoad:
STA COLUPF ; 3
LDY #NUM_LINES ; 2
STY lineNum ; 3
.waitTim:
LDA INTIM ; 4
BNE .waitTim ; 2
STA WSYNC ; 3
STA HMOVE ; 3
STA VBLANK ; 3
RTS ; 6 jump into kernel!
; *** main display kernel: ***
DisplayKernel SUBROUTINE
; first some external code to save cycles in the kernel:
JmpPoint2: ;12
INC lineNum ; 5
LDY blockLine ; 3
BPL enterKernel2 ; 3
.skipJet0:
LDX zero2 ; 3 load 0 with exactly 3 cylces
BEQ .contJet0 ; 3
.noRoad:
LDA PFcolor ; 3
JMP .contPFColor ; 3
.doJet0a:
LDA (shapePtr0),Y ; 5
TAX ; 2
LDA #$00 ; 2
.loopKernel1: ; @19
BEQ .contJet0a ; 2 this jump is taken when comming from .doJet0a
BNE .contKernel1 ; 3 this jump is taken when comming from .loopkernel1
IF SCREENSAVER = 0
FILL_NOP 1
ENDIF
JmpPoint3: ;12
JSR Wait12 ;12
.contKernel1:
NOP ; 2 @26
;--------------------------------------
; even line:
; - ...
; - draw player jet
; - load new P1 shape
; *** here starts the main kernel loop: ***
.loopKernel: ;
CPY #JET_Y ; 2 draw player jet?
BCS .skipJet0 ; 2 no, skip
LDA (shapePtr0),Y ; 5 yes, load data..
TAX ; 2 ..into x
.contJet0:
LDY blockLine ; 3
BIT roadBlock ; 3 road displayed?
BPL .noRoad ; 2 no, normal PF color
LDA RoadColorTab,Y ; 4 yes, load road colors
IF SCREENSAVER
EOR SS_XOR ; 3
.contPFColor:
AND SS_Mask ; 3
ELSE
FILL_NOP 2
.contPFColor:
FILL_NOP 1
ENDIF
STA.w temp ; 4
LDA (shapePtr1b),Y ; 5
STA GRP1 ; 3 time doesn't matter (VDELP1!)
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3 @75
;--------------------------------------
; new line starts here!
; odd line:
; - set PF color
; - set P1 color
; - change PF
STA HMOVE ; 3
STX GRP0 ; 3 @2 this also updates GRP1
LDA temp ; 3
STA COLUPF ; 3 @8
LDA (colorPtr),Y ; 5
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
STA COLUP1 ; 3 @22
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3 @30
enterKernel2:
LDA (shapePtr1a),Y ; 5
STA GRP1 ; 3 time doesn't matter (VDELP1!)
LDY lineNum ; 3
DEY ; 2
BEQ .exitKernel2 ; 2
CPY #JET_Y ; 2
BCC .doJet0a ; 2
TYA ; 2
SBC missileY ; 3
AND #$F8 ; 2
BNE .skipEnable0 ; 2
LDA #ENABLE ; 2
.skipEnable0:
LDX #$00 ; 2
.contJet0a:
DEY ; 2
STY lineNum ; 3
STA WSYNC ; 3
;--------------------------------------
; even line:
; - en-/disable missile
; - update P0 and P1 graphics
; - decrease block-line
; - ...
STA HMOVE ; 3
STA ENAM0 ; 3
STX GRP0 ; 3 @6 this also updates GRP1
BEQ .exitKernel2 ; 2
DEC blockLine ; 5
BNE .loopKernel1 ; 2
;*** start of next block (requires eight extra kernel lines): ***
; new block, line 1
; - dec block-number
; - set new road-state
; - get new PF color
; - set new shape-pointer 1a
DEC blockNum ; 5
JmpPoint1:
LDX blockNum ; 3
BMI LF202 ; 2
LDA blockLst,X ; 4 save road-state
STA roadBlock ; 3
AND #PF_COLOR_FLAG ; 2 bright or dark..
ORA #GREEN ; 2 ..green
IF SCREENSAVER
EOR SS_XOR ; 3
AND SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
STA PFcolor ; 3
LDA Shape1IdLst,X ; 4 set
TAX ; 2 shape-pointer
LDA shapePtr1aTab,X ; 4 for the
STA shapePtr1a ; 3 next enemy
LF1CE:
LDA #$00 ; 2
STA GRP1 ; 3
CPY #JET_Y ; 2
STA WSYNC ; 3
;--------------------------------------
; new block, line 2
; x = shape-id
; - set jet
; - set PF
; - set new shape-pointer 1b
; - set new color-pointer
STA HMOVE ; 3
BCS .skipJet1 ; 2
LDA (shapePtr0),Y ; 5
.skipJet1:
STA GRP0 ; 3
LDY #0 ; 2 display last line of playfield pattern
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3
LDY lineNum ; 3
DEY ; 2
.exitKernel2:
BEQ .exitKernel1 ; 2
LDA shapePtr1bTab,X ; 4
STA shapePtr1b ; 3
LDA ColorPtrTab,X ; 4
STA colorPtr ; 3
JmpPoint0:
CPY #JET_Y ; 2
BCS .skipJet2 ; 2
LDA (shapePtr0),Y ; 5
TAX ; 2
LDA #DISABLE ; 2
BEQ .contJet2 ; 3
LF202: INX ; 2
BEQ LF1CE ; 2
JmpPoint9:
NOP ; 2
SEC ; 2
BCS .enterKernel9 ; 3
.skipJet2:
TYA ; 2
SBC missileY ; 3
AND #$F8 ; 2
BNE .skipEnable1 ; 2
LDA #ENABLE ; 2
.skipEnable1:
LDX #$00 ; 2
.contJet2:
STA WSYNC ; 3
;--------------------------------------
; new block, line 3
; - en-/disabvle missile
; - set jet
; - set new PF pointers
STA HMOVE ; 3
STA ENAM0 ; 3
STX GRP0 ; 3
DEY ; 2
STY lineNum ; 3
.exitKernel1:
BEQ .exitKernel ; 2
LDX blockNum ; 3
.enterKernel9:
JSR SetPFxPtr ;50
LDA PFcolor ; 3
CPY #JET_Y ; 2
NOP ; 2 @76
;--------------------------------------
; new block, line 4
; - set new PF color
; - set PF
; - load fine movement
STA HMOVE ; 3
STA COLUPF ; 3
BCS .skipJet3 ; 2
LDA (shapePtr0),Y ; 5
STA GRP0 ; 3
.skipJet3:
LDY #SECTION_BLOCKS-1 ; 2
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3
DEC lineNum ; 5
BEQ .exitKernel ; 2
JmpPoint8:
LDA State1Lst,X ; 4 put fine move-value
STA temp ; 3 into temp
LDY lineNum ; 3
CPY #JET_Y ; 2
BCC .skipJet4 ; 2
TYA ; 2
SBC missileY ; 3
AND #$F8 ; 2
BNE .skipEnable2 ; 2
LDA #ENABLE ; 2
.skipEnable2:
LDY #0 ; 2
.contJet4:
STA WSYNC ; 3
;--------------------------------------
; new block, line 5
; - en-/disable missile
; - set jet
; - position new shape
STA HMOVE ; 3
STA ENAM0 ; 3
STY GRP0 ; 3
; position player 1:
LDA XPos1Lst,X ; 4 load coarse move-value
BEQ .posVeryLeft ; 2
TAX ; 2
CPX #7 ; 2
BCS .posRight ; 2
.waitLeft:
DEX ; 2
BNE .waitLeft ; 2
STA RESP1 ; 3
.contLeft:
DEC lineNum ; 5
LDY lineNum ; 3
BNE .contPos ; 2
.exitKernel:
JMP DisplayState ; 3 exit the kernel
.posVeryLeft:
NOP ; 2
NOP ; 2
LDA #$60 ; 2
STA RESP1 ; 3
STA HMP1 ; 3
BNE .contLeft ; 2
.skipJet4:
LDA (shapePtr0),Y ; 5
TAY ; 2
LDA #$00 ; 2
BEQ .contJet4 ; 2
.posRight:
SBC #4 ; 2
TAX ; 2
DEC lineNum ; 5
LDY lineNum ; 3
BEQ .exitKernel ; 2
.waitRight:
DEX ; 2
BPL .waitRight ; 2
STA RESP1 ; 3
JmpPoint7:
.contPos:
STA WSYNC ; 3
;--------------------------------------
; new block, line 6
STA HMOVE ; 3
CPY #JET_Y ; 2
BCS .skipJet5 ; 2
LDA (shapePtr0),Y ; 5
STA GRP0 ; 3
.skipJet5:
LDY #SECTION_BLOCKS-2 ; 2
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3
LDY lineNum ; 3
DEY ; 2
BEQ .exitKernel ; 2
LDX blockNum ; 3
LDA temp ; 3
STA HMP1 ; 3
JmpPoint6:
LDA #[BLOCK_SIZE-8]/2 ; 2
STA blockLine ; 3
TYA ; 2
SEC ; 2
SBC missileY ; 3
AND #$F8 ; 2
BNE .skipEnable3 ; 2
LDA #ENABLE ; 2
.skipEnable3:
CPY #JET_Y ; 2
STA WSYNC ; 3
;--------------------------------------
; new block, line 7
STA HMOVE ; 3
STA ENAM0 ; 3
BCS .skipJet6 ; 2
LDA (shapePtr0),Y ; 5
STA GRP0 ; 3
.skipJet6:
LDA State1Lst,X ; 4
STA NUSIZ1 ; 3
STA REFP1 ; 3
DEY ; 2
STY lineNum ; 3
BEQ DisplayState ; 2
STA HMCLR ; 3
; check collisions:
; (the collsion check between jet or missile and playfield aren't
; really neccessary for each block, but the collison registers
; are cleared after each block)
INX ; 2
BIT CXM0P-$30 ; 3 player missile hit enemy?
BPL .notHit ; 2
STX hitEnemyIdx ; 3 save block number
.notHit:
IF TRAINER
BIT zero1
ELSE
BIT CXP0FB-$30 ; 3 jet hit PF?
ENDIF
BPL .noPFCrash ; 2
STX PFCrashFlag ; 3
.noPFCrash:
IF TRAINER
BIT zero1
ELSE
BIT CXM0FB-$30 ; 3 player missile hit PF?
ENDIF
BPL .notHitPF ; 2
STX missileFlag ; 3
.notHitPF:
IF TRAINER
BIT zero1
ELSE
BIT CXPPMM-$30 ; 3 jet crashed into enemy?
ENDIF
BPL .noCrash ; 2
STX collidedEnemy ; 3 save block number
.noCrash:
.enterKernel5:
;--------------------------------------
; new block, line 8
STA WSYNC ; 3
STA HMOVE ; 3
CPY #JET_Y ; 2
BCS .skipJet7 ; 2
LDA (shapePtr0),Y ; 5
STA GRP0 ; 3
.skipJet7:
LDY #SECTION_BLOCKS-3 ; 2
LDA (PF1Ptr),Y ; 5
STA PF1 ; 3
LDA (PF2Ptr),Y ; 5
STA PF2 ; 3
LDY lineNum ; 3
DEY ; 2
BEQ DisplayState ; 2
BIT CXP1FB-$30 ; 3 enemy hit PF?
BPL .notEnemyPF ; 2 no, skip
LDA blockLst,X ; 4
ORA #PF_COLLIDE_FLAG ; 2 yes, set collision flag
STA blockLst,X ; 4
.notEnemyPF:
STA CXCLR ; 3 clear all collison registers
.enterKernel4:
TYA ; 2
SEC ; 2
SBC missileY ; 3
AND #$F8 ; 2
BNE .skipEnable4 ; 2
LDA #ENABLE ; 2
.skipEnable4:
CPY #JET_Y ; 2
STA WSYNC ; 3
;--------------------------------------
; new block, line 9 (= begin of even line)
STA HMOVE ; 3
STA ENAM0 ; 3
BCS .skipJet8 ; 2
LDA (shapePtr0),Y ; 5
STA GRP0 ; 3
.contJet8:
DEY ; 2
STY lineNum ; 3
BEQ DisplayState ; 2 exit the kernel
JMP .loopKernel ; 3 @26
JmpPoint5:
LDA #[BLOCK_SIZE-8]/2 ; 2
STA blockLine ; 3
BNE .enterKernel5 ; 3
JmpPoint4:
LDA #[BLOCK_SIZE-8]/2 ; 2 12
STA blockLine ; 3
BNE .enterKernel4 ; 3
.skipJet8: ; waste some time
NOP ; 2
NOP ; 2
BCS .contJet8 ; 3
DisplayState SUBROUTINE
; finish display kernel:
STA WSYNC ; 3
STA HMOVE ; 3
LDY #$00 ; 2
STY GRP1 ; 3
STY GRP0 ; 3
LDA zero1 ; 3 waste one extra cylce (but also wastes a variable!)
STA COLUBK ; 3
STY PF0 ; 3
STY PF1 ; 3
STY PF2 ; 3
STY REFP0 ; 3
STY REFP1 ; 3
STY reflect0 ; 3
; prepare state display:
LDA #$11 ; 2 reflect PF, 2 pixel ball width, also for HMP0!
STA RESP0 ; 3
STA RESP1 ; 3
STA CTRLPF ; 3
STA HMP0 ; 3
LDA #$20 ; 2
STA HMP1 ; 3
LDA playerColor ; 3
JSR SetColPx ; 6
LDA stateBKColor ; 3
STA COLUBK ; 3
LDA #THREE_COPIES ; 2
STA NUSIZ0 ; 3
STA NUSIZ1 ; 3
LDA statePFColor ; 3
STA COLUPF ; 3
LDY #$07 ; 2
STY VDELP0 ; 3
STY lineNum ; 3
STA HMCLR ; 3
; display score:
.loopScore:
LDA (scorePtr1+8),Y ; 5
TAX ; 2