-
Notifications
You must be signed in to change notification settings - Fork 0
/
pitfall.asm
3405 lines (3226 loc) · 116 KB
/
pitfall.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
; *** P I T F A L L ! ***
; Copyright 1982 Activision
; Designer: David Crane
; Analyzed, labeled and commented
; by Thomas Jentzsch (JTZ)
; Last Update: 09.10.2001 (v0.9)
; Scene generation:
; The 255 scenes are randomly generated through a "bidirecional" LFSR. This
; means, that the process of generating the next random number is reversible,
; which is necessary to allow traveling though the jungle in both directions.
; The random number defines the scene with the following bits:
; - 0..2: type of object(s) on the ground (logs, fire, cobra, treasure etc.)
; - 3..5: type of scene (holes, pits, crocdiles, treasures etc.)
; - 6..7: type of the tree pattern
; - 7 : position of the wall (left or right)
;
; Kernel:
; The kernel is very large. There are special loops for several horizontal
; stripes. Before the main kernel the game draws the score and the lives with
; the timer. Then follow nine stripes, which do:
; 1. draw the trees and the branches
; 2. draw the top of the liana and x-position Harry and the ground object
; 3. draw Harry and the middle of the liana
; 4. draw Harry and the bottom of the liana
; 5. draw Harry and the top of the ground object
; 6. draw the bottom of the ground object and the top of the holes/pits (no Harry)
; 7. draw Harry, holes/pits and the top of the ladder
; 8. draw Harry, the ladder and the top of the wall
; 9. draw Harry, the bottom of the ladder and the wall or the scorpion
; Finally after that, the copyright message is drawn.
;
; Misc:
; - 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.).
; - The timer is also running slower, it would have been quite easy to adjust
; that (s. FRAMERATE etc.).
processor 6502
include vcs.h
;===============================================================================
; A S S E M B L E R - S W I T C H E S
;===============================================================================
OPTIMIZE = 0 ; enable some possible optimizations
FILL_OPT = 1 ; fill optimized bytes with NOPs
SCREENSAVER = 1 ; compile with screensaver code
TRAINER = 0 ; enable training mode
NTSC = 1 ; compile for NTSC
IF NTSC
FRAMERATE = 60
STARTTIME = $20
ELSE
FRAMERATE = 60 ; 50 use these values to..
STARTTIME = $20 ; $24 ..adjust the PAL timer
ENDIF
;===============================================================================
; C O N S T A N T S
;===============================================================================
; initial value for the random number generator:
RAND_SEED = $c4 ; defines the start scene of the game
; color constants:
IF NTSC
BROWN = $12
YELLOW = $1e
ORANGE = $3e
RED = $48
GREEN = $d6
BLUE = $a4
YELLOW_GREEN = $c8
PINK = $4a
ELSE
BROWN = $22
YELLOW = $2e
ORANGE = $4e
RED = $68
GREEN = $56
BLUE = $b4
YELLOW_GREEN = $78
PINK = $4a
ENDIF
BLACK = $00
GREY = $06
WHITE = $0e
DARK_GREEN = GREEN - $04
DARK_RED = RED - $06
; x constants:
SCREENWIDTH = 160
XMIN_HARRY = 8 ; minimal position before next left scene
XMAX_HARRY = 148 ; maximal position before next right scene
; y-size constants:
HARRY_H = 22 ; height of Harry
OBJECT_H = 16 ; maximum object height
DIGIT_H = 8 ; height of the score and time digits
COPYRIGHT_H = 16 ; height of copyright message
; some defined y-positions of Harry:
JUNGLE_GROUND = 32
UNDER_GROUND = 86
; positions of Harry at ladder:
LADDER_TOP = 11
LADDER_BOTTOM = 22
; lenght of a jump:
JUMP_LEN = 32
; Harry pattern ids:
ID_KNEEING = 0
ID_RUNNING4 = 4 ; 0..3 are running ids too
ID_STANDING = 5
ID_SWINGING = 6
ID_CLIMBING = 7
; objectType ids:
ID_STATIONARY = 4 ; stationary logs (0..5 are log types)
ID_FIRE = 6
ID_COBRA = 7
ID_TREASURES = 8 ; 8..11 are treasures
ID_NOTHING = 12
; sceneType constants:
HOLE1_SCENE = 0
HOLE3_SCENE = 1
CROCO_SCENE = 4
TREASURE_SCENE = 5
; flags for ladder:
NOLADDER = %00000000
WITHLADDER = %11111111
; flags for pit color:
BLUEPIT = %00000000
BLACKPIT = %10000000
; offsets in SoundTab for tunes:
SOUND_JUMP = $20 ; Harry is jumping
SOUND_TREASURE = $25 ; Harry is collecting a treasure
SOUND_DEAD = $31 ; Harry is killed
SOUND_FALLING = $53 ; Harry is falling into a hole
; values for NUSIZx:
ONE_COPY = %000
TWO_COPIES = %001
TWO_WIDE_COPIES = %010
THREE_COPIES = %011
DOUBLE_SIZE = %101
THREE_MED_COPIES = %110
QUAD_SIZE = %111
; mask for SWCHB:
BW_MASK = %1000 ; black and white bit
; SWCHA joystick bits:
MOVE_RIGHT = %0111
MOVE_LEFT = %1011
MOVE_DOWN = %1101
MOVE_UP = %1110
NO_MOVE = %1111
JOY_RIGHT = ~MOVE_RIGHT & NO_MOVE
JOY_LEFT = ~MOVE_LEFT & NO_MOVE
JOY_DOWN = ~MOVE_DOWN & NO_MOVE
JOY_UP = ~MOVE_UP & NO_MOVE
JOY_HORZ = JOY_RIGHT|JOY_LEFT
JOY_VERT = JOY_DOWN |JOY_UP
; values for ENAxy:
DISABLE = %00
ENABLE = %10 ; value for enabling a missile
; values for REFPx:
NOREFLECT = %0000
REFLECT = %1000
;===============================================================================
; Z P - V A R I A B L E S
;===============================================================================
SEG.U Variables
ORG $80
livesPat .byte ; number of lives, stored as displayed pattern ($a0 = 3, $80 = 2, $00 = 1)
random .byte ; all scenes are generated randomly with this
random2 .byte ; used for random object animation
joystick .byte ; stores joystick directions
fireButton .byte ; stores fire button state
hitLiana .byte ; Harry collided with liana? (bit 6 = 1 -> yes)
cxHarry .byte ; Harry's collisions (stored but _never_ read!)
IF SCREENSAVER
SS_XOR .byte ; change colors in screensaver mode (0/$01..$ff)
SS_Mask .byte ; darker colors in screensaver mode ($ff/$f7)
ELSE
dummy .word
ENDIF
colorLst ds 9 ; some (mostly constant!?) colors
lianaBottom .byte ; bottom row of liana
objectType .byte ; type of the objects on the ground (hazards & treasures)
sceneType .byte ; type of the scene (0..7
HMFineLst ds 3 ; fine positioning value for: Harry, ground-object, underground-object
HMCoarseLst ds 3 ; coars positioning value for: Harry, ground-object, underground-object
posLeftBranch .byte ; values for positioning left branch graphics
posRightBranch .byte ; values for positioning right branch graphics
ladderFlag .byte ; 0 = no ladder, $ff = with ladder
noGameScroll .byte ; 0 = game is running
PF2QuickSand .byte ; PF2 data for top quicksand row
PF2Lst ds 7 ; copied pit pattern data
objColLst ds 7 ; copied object colors
objPatLst ds 7 ; copied object patterns
harryPatPtr .word ; = $b5 pointer to Pitfall Harry patterns
objPatPtr .word ; pointer to object (hazards, treasure) patterns
harryColPtr .word ; pointer to Pitfall Harry colors
objColPtr .word ; pointer to object (hazards, treasure) colors
wallPatPtr .word ; pointer to wall patterns
wallColPtr .word ; pointer to wall colors
undrPatPtr .word ; pointer to underground object (wall, scorpion) patterns
undrColPtr .word ; pointer to underground object (wall, scorpion) colors
digitPtr ds.w 6 ; pointers for score display
IF SCREENSAVER
SS_Delay .byte ; = $d1
SS_DelayLo .byte
ENDIF
frameCnt .byte ; frame counter (increased every frame)
nusize1 .byte ; number of ground-objects
scoreHi .byte ; 3 BCD score bytes
scoreMed .byte
scoreLo .byte
timerHi .byte ; 2 BCD timer bytes
timerMed .byte
timerLo .byte ; decease timer every 60th frame
hmblSum .byte ; used to generate liana line
hmblAdd .byte ; depends on the liana angle
hmblDir .byte ; move liana +/-1
lianaPosHi .byte ; high x-position of liana bottom
lianaPosLo .byte ; low x-position of liana bottom
soundIdx .byte ; index of sound-table (0 = no sound)
xPosHarry .byte ; x-position of Pitfall Harry
xPosObject .byte ; x-position of hazards & treasures
xPosScorpion .byte ; x-position of the scorpion (and the wall)
patIdHarry .byte ; id of the animation for Harry
reflectHarry .byte ; reflect Harry graphics
reflectScorpion .byte ; reflect scorpion graphics
jumpIndex .byte ; index of jump-table (0..32)
oldJoystick .byte ; saved old joystick direction
yPosHarry .byte ; y-position of Pitfall Harry
atLiana .byte ; Harry at liana? (0 = no, -1 = yes)
treePat .byte ; id of the leaves pattern (0..3)
climbPos .byte ; position of Harry at ladder (0/11..22)
treasureBits ds 4 ; remember which treasures haven't been found
treasureCnt .byte ; = $f1 number of remaining treasures-1
patOfsHarry .byte ; pattern offset (5 while kneeing, 0 else)
soundDelay .byte ; play a new note every 4th frame
xPosQuickSand .byte ; border of quicksand
jumpMode .byte ; = $f5 similar to jumpIndex (JTZ: superfluous?)
temp1 .byte
temp2 .byte
temp3 .byte
;===============================================================================
; 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)
;===============================================================================
SEG Code
ORG $f000, 0
START:
sei ; 2
cld ; 2
ldx #$00 ; 2
Reset:
lda #$00 ; 2
.loopClear:
sta $00,x ; 4
txs ; 2
inx ; 2
bne .loopClear ; 2³
jsr InitGame ; 6
MainLoop:
ldx #8 ; 2
.loopColors:
lda ColorTab,x ; 4
IF SCREENSAVER
eor SS_XOR ; 3
and SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
sta colorLst,x ; 4 store color in list
cpx #4 ; 2
bcs .skipTIA ; 2³
sta COLUP0,x ; 4 store color in TIA too
.skipTIA:
dex ; 2
bpl .loopColors ; 2³
; process underground objects (scorpion, wall):
; Only one object at a time is visible, but two different
; pointer sets are used, because the wall is much taller than
; the scorpion.
; JTZ: two color pointers aren't necessary!
ldy #<ScorpionColor ; 2
ldx #<Scorpion0 ; 2
lda xPosScorpion ; 3
lsr ; 2 animate scorpion
bcc .scorpion0 ; 2³
ldx #<Scorpion1 ; 2
.scorpion0:
lda #<Nothing ; 2
sta wallPatPtr ; 3 clear ladder data pointer
lda ladderFlag ; 3 ladder in scene
beq .noLadder ; 2³ no, skip
ldy #<WallColor ; 2 yes,..
ldx #<Wall ; 2
stx wallPatPtr ; 3 ..load pointers at ladder data
sty wallColPtr ; 3
.noLadder:
stx undrPatPtr ; 3 set scorpion or ladder pointers
sty undrColPtr ; 3
; calculate pits, quicksand etc.:
ldx sceneType ; 3
lda LadderTab,x ; 4 blue swamp?
bpl .noPit ; 2³ yes, skip
lda colorLst+4 ; 3 no, black tar pit
sta colorLst+8 ; 3
.noPit:
ldy #0 ; 2 disable quicksand
lda GroundTypeTab,x ; 4
bpl .noQuickSand ; 2³
lda yPosHarry ; 3
cmp #55 ; 2 Harry in underground?
bcs .doQuickSand ; 2³ yes, animate quicksand
cmp #JUNGLE_GROUND+1 ; 2 stop quicksand animation when..
bcs .stopQuickSand ; 2³ ..Harry is falling into the pit
.doQuickSand:
lda noGameScroll ; 3 game running?
bne .stopQuickSand ; 2³ no, skip
lda frameCnt ; 3
lsr ; 2
lsr ; 2
pha ; 3
lsr ; 2
lsr ; 2
lsr ; 2
lsr ; 2
tax ; 2 x = framecount / 64
pla ; 4 only bits 2..5 of framecounter used
and QuickSandTab+2,x ; 4 calculate size of the quicksand pit
eor QuickSandTab,x ; 4
pha ; 3
tay ; 2
lda QuickSandSize,y ; 4
tay ; 2
pla ; 4
clc ; 2
adc #16 ; 2
.noQuickSand:
clc ; 2
sty xPosQuickSand ; 3
adc #6 ; 2
tay ; 2
ldx #6 ; 2
lda ladderFlag ; 3 no swamp etc. when ladder
eor #$ff ; 2
sta temp1 ; 3
.loopPF2Lst:
lda PF2PatTab,y ; 4
sta PF2Lst,x ; 4
ora temp1 ; 3
sta PF2QuickSand ; 3
dey ; 2
dex ; 2
bpl .loopPF2Lst ; 2³
.stopQuickSand:
; calculate x-positioning values:
ldx #2 ; 2
lda #0 ; 2
IF SCREENSAVER
ldy SS_Delay ; 3 game running?
bmi .skipHarryPos ; 2³ no, don't draw Harry
ELSE
ldy noGameScroll ; TODO: bugfix, wall isn't drawn
bne .skipHarryPos ; 2³ no, don't draw Harry
ENDIF
.loopPos:
lda xPosHarry,x ; 4
.skipHarryPos:
jsr CalcPosX ; 6
sta HMFineLst,x ; 4
sty HMCoarseLst,x ; 4
stx hmblSum ; 3 -> hmblSum = 0
dex ; 2
bpl .loopPos ; 2³
; load branches x-positioning values:
ldx treePat ; 3
lda BranchPosLTab,x ; 4
sta posLeftBranch ; 3
lda BranchPosRTab,x ; 4
sta posRightBranch ; 3
; copy bottom object data:
ldy #14 ; 2
ldx #6 ; 2
.loopObjLst:
lda (objColPtr),y ; 5
IF SCREENSAVER
eor SS_XOR ; 3
and SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
sta objColLst,x ; 4
lda (objPatPtr),y ; 5
sta objPatLst,x ; 4
dey ; 2
dex ; 2
bpl .loopObjLst ; 2³
.waitTim:
lda INTIM ; 4
bne .waitTim ; 2³
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta VBLANK ; 3
sta CXCLR ; 3
sta temp3 ; 3 don't show anything before score
jsr ShowDigits ; 6 draw score
; set digitPtrs for timer:
ldx #timerHi-scoreHi ; 2
ldy #2 ; 2 minutes
jsr BCD2DigitPtrs ; 6
inx ; 2 seconds
ldy #8 ; 2
jsr BCD2DigitPtrs ; 6
lda livesPat ; 3 show lives before time
sta temp3 ; 3
lda #<Space ; 2
sta digitPtr ; 3
ldy digitPtr+2 ; 3
bne .noSpace ; 2³ replaced leading zero in timer with space
sta digitPtr+2 ; 3
.noSpace:
lda #<DoublePoint ; 2
sta digitPtr+6 ; 3
jsr ShowDigits ; 6 draw lives and timer
sta WSYNC ; 3
;---------------------------------------
; Here starts the main kernel. Actually there are nine(!)
; specialized kernel loops. Together with extra code before and
; after the loops, this makes the kernel very huge [~900 bytes).
; draw branches at top of the logs:
sta HMOVE ; 3
lda #$00 ; 2
sta VDELP1 ; 3 disable vertical delay for object
sta GRP0 ; 3
sta GRP1 ; 3
lda colorLst+5 ; 3 branches color (always BROWN-2)
sta COLUP0 ; 3
sta COLUP1 ; 3
lda #TWO_WIDE_COPIES ; 2 draw four branches
sta NUSIZ0 ; 3
sta NUSIZ1 ; 3
lda posLeftBranch ; 3
and #$0f ; 2
tax ; 2 x = coarse x-positioning value of left branch
lda posRightBranch ; 3
and #$0f ; 2
tay ; 2 y = coarse x-positioning value of right branch
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
nop ; 2
.waitPos0:
dex ; 2
bpl .waitPos0 ; 2³
sta RESP0 ; 3
lda posLeftBranch ; 3
sta HMP0 ; 3
lda posRightBranch ; 3
sta HMP1 ; 3
.waitPos1:
dey ; 2
bpl .waitPos1 ; 2³
sta RESP1 ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
lda #%101 ; 2 enable playfield priority, now..
sta CTRLPF ; 3 ..the leaves overlap the branches
ldy #31 ; 2
lda treePat ; 3
asl ; 2
asl ; 2
tax ; 2
; Kernel 1 (31 lines): draw liana, branches and bottom of leaves:
.loopBranches:
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
sta HMCLR ; 3
bcc .noMove0 ; 2³
lda hmblDir ; 3
sta HMBL ; 3
.noMove0:
lda #0 ; 2
cpy #9 ; 2 draw branches in lower 9 lines
bcs .noBranch ; 2³
tya ; 2
lsr ; 2
lda BranchTab,y ; 4
.noBranch:
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta GRP0 ; 3
sta GRP1 ; 3
bcs .noChangePF ; 2³ two line resolution for leaves
lda PFLeavesTab,x ; 4 x = 0..3
inx ; 2
sta PF0 ; 3
sta PF1 ; 3
sta PF2 ; 3
.noChangePF:
dey ; 2
bne .loopBranches ; 2³
; prepare Kernel 2: draw liana, disable branches, draw logs:
ldx treePat ; 3
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
bcc .noMove1 ; 2³
ldy hmblDir ; 3
.noMove1:
sty HMBL ; 3
lda #%001 ; 2
sta CTRLPF ; 3 disable playfield priority
lda PF1LogTab,x ; 4
ldy PF2LogTab,x ; 4
ldx nusize1 ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta PF1 ; 3 draw outer logs
lda colorLst+5 ; 3 always BROWN-2
sta COLUPF ; 3
lda #0 ; 2
sta GRP0 ; 3
sta GRP1 ; 3
sta NUSIZ0 ; 3
sta PF0 ; 3
sty PF2 ; 3 draw inner logs
stx NUSIZ1 ; 3
; Kernel 2 (4 lines): draw liana, position Harry and other object:
ldx #1 ; 2
.loopLianaPos:
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
lda #$00 ; 2
bcc .noMove2 ; 2³
lda hmblDir ; 3
.noMove2:
sta HMBL ; 3
clc ; 2 precalc liana for next line
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
lda #$00 ; 2
bcc .noMove3 ; 2³
lda hmblDir ; 3
.noMove3:
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
ldy #0 ; 2 do the coarse positions
sty temp1,x ; 4
ldy HMCoarseLst,x ; 4 position at the very left?
bne .waitPos ; 2³ no, skip
ldy #$60 ; 2 yes, use special code
sty temp1,x ; 4
sta RESP0,x ; 4
sta HMBL ; 3
bne .endPos0 ; 3
.waitPos:
dey ; 2 "normal" position
bne .waitPos ; 2³
sta.w HMBL ; 4
sta RESP0,x ; 4
.endPos0:
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
dex ; 2
bpl .loopLianaPos ; 2³
jsr DrawLiana ;31/33
lda HMFineLst ; 3
sta HMP0 ; 3 do the fine positions
lda HMFineLst+1 ; 3
sta HMP1 ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
jsr DrawLiana ;31/33
lda temp1 ; 3
sta HMP0 ; 3
lda temp2 ; 3
sta HMP1 ; 3
lda yPosHarry ; 3 calculate offset for Harry's pattern
clc ; 2
adc patOfsHarry ; 3
adc #21 ; 2
tay ; 2
lda reflectHarry ; 3
sta REFP0 ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta CXCLR ; 3
ldx #20 ; 2
stx VDELP0 ; 3 disable vertical delay for Harry
; Kernel 3 (21 lines): draw liana and Harry:
.loopLianaHarry:
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
lda #$00 ; 2
sta HMCLR ; 3
bcc .noMove4 ; 2³
lda hmblDir ; 3
.noMove4:
sta HMBL ; 3
jsr DrawHarry ;27/37
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta COLUP0 ; 3
dex ; 2
bpl .loopLianaHarry ; 2³
stx VDELP0 ; 3 enable vertical delay for Harry
inx ; 2
stx GRP1 ; 3
beq .endLiana ; 3
.skipHarry:
lda #0 ; 2
sta GRP0 ; 3
beq .contendLiana ; 3
.endLiana:
ldx #23 ; 2
; Kernel 4 (24 lines): draw end of liana, draw Harry:
.loopEndLiana:
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
lda #$00 ; 2
bcc .noMove5 ; 2³
lda hmblDir ; 3
.noMove5:
sta HMBL ; 3
dey ; 2
cpy #HARRY_H ; 2
bcs .skipHarry ; 2³
lda (harryPatPtr),y ; 5
sta GRP0 ; 3
lda (harryColPtr),y ; 5
IF SCREENSAVER
eor SS_XOR ; 3
and SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
.contendLiana:
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta COLUP0 ; 3
lda #DISABLE ; 2
cpx lianaBottom ; 3 bottom of liana reached?
bcs .skipDisable ; 2³ no, skip
sta ENABL ; 3 yes, disable liana
.skipDisable:
sta GRP1 ; 3
dex ; 2
bpl .loopEndLiana ; 2³
jsr DrawHarry ;27/37
ldx CXP0FB-$30 ; 3
stx hitLiana ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta COLUP0 ; 3
lda colorLst+7 ; 3
sta COLUPF ; 3
ldx #$ff ; 2 draw the jungle ground
stx PF0 ; 3
stx PF1 ; 3
stx PF2 ; 3
lda colorLst+8 ; 3
sta COLUBK ; 3
inx ; 2
stx GRP1 ; 3
ldx #6 ; 2
; Kernel 5: draw Harry, holes, top of object on the ground:
.loopGround:
jsr DrawHarry ;27/37
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta COLUP0 ; 3
lda objColLst,x ; 4
sta COLUP1 ; 3
lda objPatLst,x ; 4 draw object (crocodiles, logs, snake...)
sta GRP1 ; 3
lda PF2Lst,x ; 4 draw pits
sta PF2 ; 3
dex ; 2
bpl .loopGround ; 2³=31/32
tya ; 2 calculate and save..
sec ; 2 ..Harry's pattern..
sbc #8 ; 2 ..offset for kernel 7
sta temp1 ; 3
ldx #0 ; 2
ldy #7 ; 2
; Kernel 6 (8 lines): draw bottom of object on the ground, holes in the ground:
.loopHoles:
lda #0 ; 2
sta GRP0 ; 3
lda (objColPtr),y ; 5
IF SCREENSAVER
eor SS_XOR ; 3
and SS_Mask ; 3
ELSE
FILL_NOP 4
ENDIF
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
sta COLUP1 ; 3
lda (objPatPtr),y ; 5
sta GRP1 ; 3
dey ; 2
bmi .exitHoles ; 2³ exit loop here
lda PF2Lst,x ; 4
sta PF2 ; 3
inx ; 2
bne .loopHoles ; 3 loop always
.exitHoles:
lda #0 ; 2
sta GRP0 ; 3 clear Harry again (JTZ: superfluous)
ldx HMCoarseLst+2 ; 3
bne .notZero ; 2³
lda #$60 ; 2 special HMOV when scorpion is at the very left
.notZero:
sta temp3 ; 3
; check Harry's collisions (JTZ: superfluous code!)
lda CXPPMM-$30 ; 3 Harry collided with other objects?
asl ; 2
lda CXP0FB-$30 ; 3 Harry collided with playfield?
ror ; 2
sta cxHarry ; 3 store here (this variable isn't used somewhere else!)
; prepare some underground data:
lda reflectScorpion ; 3 set player 1 reflection
sta REFP1 ; 3
lda ladderFlag ; 3 calculate playfield reflection
and #%000100 ; 2
eor #%100101 ; 2 ball is 4 clocks wide (ladder)
tax ; 2
ldy colorLst+6 ; 3 underground color (always BROWN+2)
lda colorLst+4 ; 3 hole, blackground and tar pit color
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
jmp ContKernel ; 3
ShowDigits SUBROUTINE
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
lda colorLst ; 3
sta COLUP0 ; 3
sta COLUP1 ; 3
ldy #0 ; 2
sty REFP0 ; 3
sty REFP1 ; 3
ldx #$10|THREE_COPIES; 2
stx NUSIZ0 ; 3
sta RESP0 ; 3
sta RESP1 ; 3
stx HMP1 ; 3
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
stx NUSIZ1 ; 3
iny ; 2
sty CTRLPF ; 3 enable playfield reflection
lda #DIGIT_H-1 ; 2
sta VDELP0 ; 3
sta VDELP1 ; 3
sta temp2 ; 3
sta HMCLR ; 3
jsr SkipIny ;22 just waste 22 cycles
lda temp3 ; 3 just waste three cycles
.loopDigits:
ldy temp2 ; 3
lda (digitPtr+10),y ; 5
sta temp1 ; 3
lda (digitPtr+8),y ; 5
tax ; 2
lda (digitPtr),y ; 5
ora temp3 ; 3 show lives when drawing time
sta HMOVE ; 3 produce HMOVE blanks
sta GRP0 ; 3
lda (digitPtr+2),y ; 5
sta GRP1 ; 3
lda (digitPtr+4),y ; 5
sta GRP0 ; 3
lda (digitPtr+6),y ; 5
ldy temp1 ; 3
sta GRP1 ; 3
stx GRP0 ; 3
sty GRP1 ; 3
sta GRP0 ; 3
dec temp2 ; 5
bpl .loopDigits ; 2³
sta WSYNC ; 3
;---------------------------------------
sta HMOVE ; 3
lda #0 ; 2
sta GRP0 ; 3
sta GRP1 ; 3
sta GRP0 ; 3
rts ; 6
DrawHarry SUBROUTINE
; called from kernel:
dey ; 2
cpy #HARRY_H ; 2
bcs .skipDraw ; 2³
lda (harryPatPtr),y ; 5
sta GRP0 ; 3
lda (harryColPtr),y ; 5
IF SCREENSAVER
eor SS_XOR ; 3
and SS_Mask ; 3
ELSE
FILL_NOP 3
ENDIF
.exitDraw:
rts ; 6 = 21/31
IF SCREENSAVER = 0
; do some missing nops:
FILL_NOP 2
ENDIF
.skipDraw: ; 7
lda #0 ; 2
sta GRP0 ; 3
beq .exitDraw ; 3
CalcPosX SUBROUTINE
; calculate coarse and fine x-positioning values:
tay ; 2
iny ; 2
tya ; 2
and #$0f ; 2
sta temp1 ; 3
tya ; 2
lsr ; 2
lsr ; 2
lsr ; 2
lsr ; 2
tay ; 2
clc ; 2
adc temp1 ; 3
cmp #$0f ; 2
bcc SkipIny ; 2³
sbc #$0f ; 2
iny ; 2
SkipIny:
eor #$07 ; 2
asl ; 2
asl ; 2
asl ; 2
asl ; 2
rts ; 6
DrawLiana SUBROUTINE
clc ; 2
lda hmblSum ; 3
adc hmblAdd ; 3
sta hmblSum ; 3
lda #$00 ; 2
bcc .noMove6 ; 2³
lda hmblDir ; 3
.noMove6:
sta HMBL ; 3
rts ; 6 = 25/27
BCD2DigitPtrs SUBROUTINE
lda scoreHi,x ; 4
and #$f0 ; 2
lsr ; 2
sta digitPtr,y ; 5
lda scoreHi,x ; 4
and #$0f ; 2
asl ; 2
asl ; 2
asl ; 2
sta digitPtr+2,y ; 5
sta WSYNC ; 3
sta HMOVE ; 3
rts ; 6
DecScoreLo SUBROUTINE
lda #$07 ; 2
sta AUDC1 ; 3
lda #$99 ; 2 decrease scoreLo by 1
DecScoreHi: ; decrease scoreHi by 1
sed ; 2
clc ; 2
adc scoreLo ; 3
sta scoreLo ; 3
lda scoreMed ; 3
sbc #$00 ; 2
sta scoreMed ; 3
lda scoreHi ; 3
sbc #$00 ; 2
bcs .notZero ; 2³
lda #$00 ; 2 limit score at zero
sta scoreMed ; 3
sta scoreLo ; 3
.notZero:
sta scoreHi ; 3
cld ; 2
rts ; 6
PFLeavesTab:
.byte %11111111 ; |XXXXXXXX|
.byte %11001111 ; |XX XXXX|
.byte %10000011 ; |X XX|
.byte %00000001 ; | X|
.byte %01111111 ; | XXXXXXX|
.byte %00111101 ; | XXXX X|
.byte %00011000 ; | XX |