-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsof.txt
7450 lines (6818 loc) · 242 KB
/
sof.txt
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
;Soldier of Fortune - disassembly
;Interrupts: IM2, mostly switched off, sometimes are switched on
;<======================================>
;1. Loader. After loading calls $A000
;2. $A000. Pause. Wait for any key to be presed, then overwrites itself with 00 and jumps to $9D72
;3. $9D72. Disables interrupts, then prepares interrupt table for IM2, by filling $100 bytes,
;starting with $FE00, by value $FD. This means that all interrupts will be handled by code located at $FDFD.
;By this address a command JP $A223 is put. Then IM2 mode is switched, but interrupts are still disabled.
;Register I is loaded with value $3F. If ROM address $1540 contains anything but $53, then $100 bytes
;are copied from $9DAD to $A272. Finally jumps to $A132 - main game loop
;<======================================>
;Video-mem:
;==========
;$4000 - $57FF - pixel data
;$5800 - $5AFF - color data
;Graphics data:
;==============
;(+16357)
;right after video memory
;$5B00 23296 6939 (4) - Graftgold logo big
; 7067 (3) - Graftgold logo small
;$5BB0 23472 7115 (1) - Font
7443 (5) - Labyrinth blocks (till 11888)
;$6E5E - packed levels
;<======================================>
;$77D2 (3*1) - dagger, 4 sprites right, 4 sprites left
;$78DA (3*1) - arrow
; (3*1) - gem, 8 sprites
; (3*1) - super weapon
;$7B92 (3*1) - bird A, 4 sprites right, 4 sprites left
; (3*1) - bird B
; 15661 (4) - cloud
; 15917 (4) - raft
; 16173 (4) - platform
; 16425 (4) - shooting block
; 33042 16685 (4) - elemental
; 33298 16941 (4) - skeleton
; 33558 (4*3) - enemy: monk, 4 sprites right, 4 sprites left
; 17965 (4) - enemy: monster
; 18733 (4) - enemy: dragon bird
; 19501 (4) - enemy: knight
;$8F12 36626 20269 (4) - rock ball
;$9612 38418 (4*3) - hero, 6 sprites right (4 steps + 1 jump + 1 crouch) + 6 sprites left
; 39922 (4*3) - blow, 4 sprites
;-----------------------------
;$9D72 - $A132: Temp area.
;Used for:
; * to create level's sprite set
; * to store unpacked map of current level. Each block takes 1 byte, each level row is $1E blocks wide
;-----------------------------
;$A132: Main loop - $A1F9 (+2 bytes)
$A132 CALL $E576 ;loop for menu,demo and high score table, exits when start key is pressed
$A139 CALL $A47B ;prepare game screen (and print "get ready")
$A13C XOR A
$A13D LD ($C4B1),A
$A140 CALL $A58D ;init graphics for new level
;$A143 - $A1F9 (+2 bytes) - main loop of game itself
$A143 CALL $A6C8 ;init data for new level
$A146 LD SP,$0000
CALL $A25F ;play sound or wait
CALL $C1B5 ;print the message
CALL $C573 ;Keyboard query
CALL $BAB2 ;Colliding dynamic objects list maintenance
CALL $A8D4 ;?? Decrement timer, print hurry up message ??
CALL $B5AD ;?? collision detection?
CALL $B4BB ;?? check location triggers, activate monsters ??
CALL $B527 ;check if player hits the monster
CALL $B118 ;?? check fire button, create a weapon missile if needed ??
$A164 CALL $AF90 ;??
LD C,$1B
LD A,($C4BA)
LD B,A
LD D, $0D
LD A,($C3A9)
AND A
JR NZ,$A177
LD D,$16
$A177 LD A,($C4B0)
CP $10
JR Z,$A182
CP $06
JR NZ,$A186
$A182 LD A,D
ADD A,$14
LD D,A
$A186 LD A,B
SUB D
NEG
$A18A LD B,C
$A18B DJNZ $A18B
DEC A
$A18E JR NZ,$A18A
$A190 CALL $D431 ;draw dynamic game screen
$A193 LD HL,$0000
LD ($C4E6), HL
CALL $A910 ;??? death handling ??
CALL $C5E7 ;handle moving left and right, jump, fall down and sit down, with collision detection
$A19F CALL $A44C ;screen scroll if we are riding a platform, or falling down
LD HL,$C4AE
LD A,(HL)
AND A
JP Z,$A1AE
DEC A
LD (HL), A
JR $A1D8
$A1AE LD A, ($C4B0)
LD B, A
LD A, ($C4B6)
LD C, A
LD A, ($C4DA)
LD D, A
LD A, ($C4BF)
OR B
OR C
OR D
JR NZ, $A1D8
LD A, $08
LD ($C4AE), A
LD HL, ($C3AA)
LD ($C4A6), HL
LD HL, $C4E8
LD DE, $C4A8
LD BC, $0006
LDIR
$A1D8 CALL $BED1 ;update coordinates of dynamic objects
CALL $C819 ;coord calculation
CALL $B7A0 ;Monster and missile movement, collision to walls, falling down
CALL $BDF7 ;Check if moving platform visible, and create a visible colliding object for it
CALL $BAF6 ;?? check if statically placed collectable object becomes visible, and create a visible object entry for it
CALL $B212 ;?? Generate random monster ??
CALL $C30E ;?? draw score on a screen ??
CALL $CEDC ;??
CALL $A1FC ;check pause?
$A1F3 JP C, $A146
$A1F6 CALL $A887
$A1F9 JP $A132
;-----------------------------
;$A1FC - ¯à®¢¥àª ¯ ã§ë? - $A222
$A1FC LD A,$22 ;ª®¤ ª« ¢¨è¨ P ?
CALL $C5AF ;¯à®¢¥à塞 ¦ ⨥
RET C ;¥á«¨ ¥ ¦ â , â® ¢ë室 (¥á«¨ ¥ ¯ 㧠?)
.......
$A222 RET
;<======================================>
;$A223: Ž¡à ¡®â稪 ¯à¥àë¢ ¨ï - $A22E
$A223 PUSH AF ;á®åà 塞 ॣ¨áâàë, ª®â®àë¥ ¡ã¤ãâ ¬¥ïâìáï
$A224 LD A,$3F
$A226 LD I,A ;¨§¬¥ï¥â 㪠§ ⥫ì â ¡«¨æë ¯à¥àë¢ ¨© (¤«ï § ¯ãâë¢ ¨ï?)
$A228 LD A,01
$A22A LD ($C4B9),A ;???? (ª ª®©-â® ä« £?)
$A22D POP AF ;¢®ááâ ¢«¨¢ ¥â ॣ¨áâàë
$A22E RET ;¢ë室 ¨§ ¯à¥àë¢ ¨ï
<======================================>
;$A241: Keyboard query - $A25B(+2)
;??? ‚ § ¢¨á¨¬®á⨠®â 5-£® ¡¨â ï祩ª¨ $C4B3 ®¯à 訢 ¥â ¨«¨ ¥â ¯à®¡¥«. ‚®§¢à â - ¢ ä« £¥ Z ???
;read port $BFFE (checks space?)
$A248 EX AF, AF'
$A249 CALL $C573 ;????
$A24C EX AF, AF'
$A24D LD B, A ;Š®¯¨àã¥â ¢ B § 票¥, áç¨â ®¥ ¨§ ¯®àâ
$A24E LD A,($C4B3)
...
;----------------------
;Variables:
;$A25C (1) : sound to play
;$A25E (1)
;----------------------
;$A25F: Play sound or wait - $A271
$A25F XOR A
LD ($C4B9),A ;clear flag that interrupt has happened
LD A,$FE
LD I,A
EI ;enable interrupts
CALL $A272 ;play sound, returns if nothing played or interrupt has happened
$A26B LD A,($C4B9)
AND A
JR Z,$A26B ;wait until interrupt flag will be set
$A271 RET
;----------------------
;$A272: Play sound - $A2C9
$A272 LD HL,$A25C
LD A,(HL) ;read variable
LD (HL),$00
LD HL,$A25E
AND A
JR Z,$A28D ;jump if reg A is 0
LD B,A ;save to B
LD A,(HL) ;read variable
AND A
JR Z,$A286 ;jump if reg A is 0
CP B ;compare
JR C,$A28D
$A286 LD A,B
LD (HL),A
LD A,$FF
LD ($A25D),A ;this value
$A28D LD A,(HL)
AND A
RET Z ;return if reg A is 0
ADD A,A ;*2
LD C,A
LD B,$00 ;into BC - offset
LD HL,$A2C8 ;table base
ADD HL,BC ;table entry
LD E,(HL)
INC HL
LD D,(HL) ;read two bytes into DE
LD HL,$A25D
INC (HL) ;increment
LD C,(HL) ;into C
EX DE,HL
ADD HL,BC
LD A,(HL) ;read frequency
CP $FF
JR NZ,$A2AC
XOR A
LD ($A25E),A ;if $FF then save 0
$A2AB RET ;and return
;play the sound, reg A holds the frequency
$A2AC LD H,A ;save reg A
LD L,$60 ;how many up-down sound cycles
$A2AF LD A,$10
OUT ($FE),A ;out to sound port?
LD B,H ;B is a delay for high sound amplitude
$A2B4 LD A,($C4B9)
AND A
RET NZ ;return if ($C4B9) is 0
DJNZ $A2B4 ;loop so sound is played
XOR A
OUT ($FE), A ;drop the sound amplitude
LD B,H ;B is a delay for low sound amplitude
$A2BF LD A,($C4B9) ;flag to exit
AND A
RET NZ
DJNZ $A2BF ;loop so sound is played
DEC L ;decrement up-down sound cycles
JR NZ,$A2AF ;keep playing the sound
$A2C9 RET
;----------------------
;$A378: Send hard-coded values to AY chip - $A397
$A378 XOR A
$A379 LD ($A25E),A ;???
$A37C LD D,$3F
$A37E LD A,$07
$A380 CALL $A38E ;these bytes to AY
$A383 LD D, $00
$A385 INC A
$A386 CALL $A38E ;these bytes to AY
$A389 INC A
$A38A CALL $A38E ;these bytes to AY
$A38D INC A
;fall to
;secondary entry point
;sends value of reg A into port $FFFD (AY sound chip)
; and value of reg D into port $BFFD (AY sound chip)
$A38E LD BC,$FFFD
$A391 OUT (C),A ;
$A393 LD B,$BF
$A395 OUT (C),D ;
$A397 RET ;ret
;----------------------
;$A44C: Ensure that screen is vertically aligned after falling down - $A479 (+2)
;when walking, screen is always aligned, so ($C4B6) is 0.
;when jumping, falling or riding a platform, we do nothing here
;at the end of falling, when we have determined that we are hitting a ground,
;then some alignment may be needed here
;if vertical shift is 2, then we, actually, need to scroll two times,
;but we scroll only once at time, and next call to this procedure will scroll once more
$A44C LD A,($C4BF) ;get jumping/falling frame
LD B,A
LD A,($C4B6) ;index of a platform we are riding on
OR B
RET NZ ;ret if at least one of them is not 0
LD A,($C4EB) ;vertical shift
AND A
RET Z ;ret if vertical shift is 0
DEC A
JR Z,$A469 ;go there if vertical shift is 1
DEC A ;
JR Z,$A472 ;go there if vertical shift is 2
;continue if vertical shift is 3
$A460 CALL $C9CF ;move screen down
LD HL,$C3AA ;vertical coord of player in pixels
DEC (HL) ;dec it
DEC (HL) ;dec it
$A468 RET
$A469 CALL $C991 ;move screen up
LD HL,$C3AA ;vertical coord of player in pixels
INC (HL) ;increment
INC (HL) ;increment
$A471 RET
$A472 LD A,($C3AA) ;depending on vertical coord, we decide to scroll up or down
CP $58 ;compare
JR C,$A469 ;go if less
$A479 JR $A460 ;go if not less
;----------------------
;$A47B: prepare a game screen - $A4DB (and falls further)
$A47B LD A,R
$A47D AND $07
$A47F INC A
$A480 LD C,A ;reg C contains lower 3 bytes of R incremented
$A481 XOR A ;A=0
$A482 LD ($C4B8),A ;???
$A485 LD ($C4B1),A ;???
$A488 LD ($A25C),A ;???
;outer loop
$A48B LD ($C398),A ;current level
$A48E CALL $A4EB ;find data structures for current level
$A491 LD B,C ;copy C to B, now it is inner loop counter
;inner loop
$A492 PUSH BC ;save
$A493 CALL $A53C ;????
$A496 POP BC ;restore
$A497 DJNZ $A492 ;end of inner loop
$A499 LD A,($C398) ;
$A49C INC A ;increment this variable
$A49D CP $09 ;check number of loops
$A49F JR NZ,$A48B ;repeat outer loop
$A4A1 CALL $A8B5 ;draw game screen border
$A4A4 CALL $C097 ;reset and print game score
$A4A7 XOR A ;will fill memory with 0
$A4A8 LD HL,$C398 ;starting from this address
$A4AB LD B,08 ;this amount of bytes
$A4AD CALL $C512 ;do it!
;set current weapon to 1, and weapon power to 1
$A4B0 INC A ;will fill memory with 1
$A4B1 LD B,$0A ;amount of bytes
$A4B3 CALL $C512 ;HL=$C3A0, call fill procedure
$A4B6 CALL $C113 ;draw current weapon and print all weapon's power
$A4B9 CALL $C0DC ;reset diamonds counter and their indicator
$A4BC CALL $C19E ;reset elemental counter and their indicator
$A4BF LD B,0 ;elemental kind (air)
$A4C1 CALL $A67D ;draw central elemental sprite
$A4C4 LD A,4
$A4C5 LD ($C3A7),A ;?? lives ??
$A4C9 LD HL,$C325 ; ?
$A4CC LD ($C323),HL
$A4CF LD A,($C4DA) ;get flag to skip "get ready" message and delay
$A4D2 AND A ;check for 0
$A4D3 RET NZ ;exit, if not 0
$A4D4 LD A,1
$A4D6 LD ($C397),A ;number of message, arg for $C1B5
$A4D9 CALL $C1B5 ;print the message
;execution falls to fixed length pause
;----------------------
$A4DC: fixed length pause - $A4DF
sets pause values in A,B,C, then falls to $A4E1
;----------------------
;$A4E1: Pause - $A4EA:
;time delay value - A,B,C
;just moves value from A to D, and falls to
;$A4E2: second entry point - D,B,C
;Just empty cycles.
;----------------------
;$A4EB: Find data lists for current level - $A539 (+2)
;Input: ($C398) current level
;Output: variables ($C4D0), ($C4CC), ($C4D2), ($C4CE), ($C4CA), ($A94E)
$A4EB LD HL,$DE52 ;base address of monster generation table (0-terminated) for level 1
LD DE,$000A ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($C4D0),HL ;store the result
$A4F7 LD HL,$E28B ;dynamic object coord/speed/time table for level 1
LD DE,$0009 ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($C4CC),HL ;store the result
$A503 LD HL,$DE2E ;some table for level 1
LD DE,$0003 ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($C4D2),HL ;store the result
$A50F LD HL,$E17A ;some table for level 1
LD DE,$0006 ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($C4CE),HL ;store the result
CALL $A844 ;reset 7-th bits
$A51E LD HL,$DF05 ;some table for level 1
LD DE,$0005 ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($C4CA),HL ;store the result
CALL $A844 ;reset 7-th bit
$A52D LD HL,$DDC5 ;teleport table for level 1
LD DE,$0002 ;entry size
CALL $A832 ;scan and find a beginning of a list for current level
LD ($A94E),HL ;store the result
$A539 JP $A844 ;shortcut for CALL $A844 + RET
;----------------------
;$A53‘: ??? - $A58B
;----------------------
;$A58D: Graphics init for new level ???
$A58D XOR A
LD ($C397),A ;ã«¥¢®© ®¬¥à á®®¡é¥¨ï
CALL $A378 ;send some values to AY chip
LD A,($C4B1) ;???
AND A ;compare with 0
$A598 JP NZ,$A62A ;go if not 0
$A59B LD A,($C399) ;??? current elemental
ADD A,A
ADD A,A ;multiply to 4
LD L,A
LD H,0
LD DE,$A66D ;?????
ADD HL,DE ;so: HL=($C399)*4 + $A66D
LD DE,$C4A6
LD BC,4
LDIR ;move 4 bytes
LD B,A ;row number = 4*($C399)
$A5B0 CALL $A67D ;draw elemental central sprite
$A5B3 XOR A
LD ($C4AF),A ;player's initial state (sprite)
LD H,A
LD L,A
LD ($C4AA),HL ;??
LD ($C4AC),HL ;??
LD HL,$2904 ;?? initial value for timer ??
LD ($C4D4),HL ;?? store
$A5C5 CALL $C19E ;reset elemental counter and indicator
LD A,($C398) ;current level
CP $08
JR Z,$A62A
LD A,($C399)
INC A
LD ($DC18),A
DEC A
JR Z,$A617
LD A,$46 ;attribute value
LD ($C32F),A
$A5DE CALL $A85A ;clear dynamic game window
LD A,$05
LD ($A645),A
$A5E6 LD B, $04
$A5E8 LD HL, $C39C
;loop
$A5EB LD A, (HL)
$A5EC INC HL
$A5ED AND A
$A5EE JR Z, $A612
$A5F0 PUSH HL
$A5F1 PUSH BC
$A5F2 LD A,B
$A5F3 SUB $04
$A5F5 NEG
$A5F7 LD DE,$A646 ;to this location
$A5FA CALL $A65C ;copy 5 bytes (elemental name? scene name?)
$A5FD LD HL,$A644 ;script with words to draw
$A600 CALL $C1FC ;draw a set of words on screen
$A603 LD HL, $A645
$A606 INC (HL)
$A607 INC (HL)
$A608 CALL $E6DC ;play sound
$A60B LD A, $02
$A60D CALL $A4E1 ;pause
$A610 POP BC
$A611 POP HL
$A612 DJNZ $A5EB ;jump to loop start
$A614 LD A,($C399)
$A617 LD DE,$DC01 ;to this location
$A61A CALL $A65C ;copy 5 bytes
$A61D CALL $C0B5 ;draw symbol ?
$A620 CALL $AA3D ;get value from table into reg A
$A623 JR NZ, $A62A ;if not 0, jump
$A625 LD A, $02
$A627 CALL $C1AD ;prepare to print message on screen
;lots of jumps here from other places
$A62A CALL $AA3D ;get value from table into reg A
$A62D LD ($C4B8),A
$A630 CALL $A4EB ;some search in memory
$A633 CALL $D920 ;prepare sprite-set for level's blocks
$A636 CALL $A753 ;unpack current level into area starting at $9D72
$A639 CALL $A934 ;find all teleports blocks
$A63C LD A, ($C39B)
$A63F AND A
$A640 RET NZ
$A641 JP $A69F ;.
... some data here ...
;entry point
;Param: DE
;Param: reg A
;copy to memory starting from DE 5 bytes from $DDB1 + 5*A
$A65C LD B,A
$A65D ADD A,A
$A65E ADD A,A
$A65F ADD A,B ; A = A * 5
$A660 LD L, A
$A661 LD H, $00 ; HL = param * 5
$A663 LD BC, $DDB1 ; base
$A666 ADD HL, BC ; add offset
$A667 LD BC, $0005 ; number of bytes
$A66A LDIR ; move
$A66C RET
.............
----------------------
$A66D
;----------------------
;$A67D: Draw elemental central sprite 2*2 (air, fire, ...)
;from the rightmost part of a pixel area, which is hidden behind
;black attributes, graphics is copied into visible area horizontally
;Input param: B - line number, identifies elemental sprite
$A67D LD C,$1F ;last column
$A67F CALL $C2D5 ;calculate pixel area address
$A682 EX DE,HL ;move it to DE
$A683 LD DE,$508F ;hardcoded address in video mem pixel area
$A686 CALL $A68B ;call first time
$A689 LD E,$AF ;DE=$50AF, another hardcoded address, 8 lines below
;first time a call is made here, second time execution falls here
; 2 8*8 pixel blocks, one under another, located at HL, are copied horizontally at DE
$A68B LD C,$02 ;block counter
$A68D LD B,$08 ;8 pixel lines
PUSH DE ;store
;copy loop
$A690 LD A,(HL)
LD (DE),A ;copy
INC H ;next source pixel line
INC D ;next dest pixel line
$A694 DJNZ $A690 ;repeat for all 8 pixel lines
$A696 POP DE ;restore DE
CALL $C2CA ;HL was pointing to last line of first block
;recalc so it points to first line of block just below
INC E ;DE moves to next block to the right
DEC C
JR NZ,$A68D ;repeat
$A69E RET ;exit.
;----------------------
;$A6C8: init for new level
$A6C8 LD A,($C4B8) ;??
AND A ;check if 0
LD A,$C5 ;ether this constant
JR Z,$A6D2
LD A,$41 ;or this
$A6D2 LD ($C3AF), A ;go here
CALL $C4EE ;clear list of colliding objects and list of visible objects
LD A,R
AND $07
LD H,A
LD ($C4D6),HL ;init random value
LD A,$50
LD ($C3A9),A ;??
LD A,$04
LD ($C4C0),A ;??
LD ($C4C6),A ;??
LD A,$32
LD ($C4BD),A ;??
LD ($C4BC),A ;??
CALL $A72A ;additional clear for level
LD C,$06
LD HL,($C4A6) ;?? initial coordinates of player on a screen ??
LD ($C3AA),HL ;current coordinates of player on screen, in pixels
LD HL,$C4A8 ;??
LD DE,$C4E8 ;??
LDIR
CALL $C819 ;calculate coordinates
CALL $C0C2 ;draw current number of lives
CALL $C113 ;draw weapon
LD A,($C398) ;current level
CP $08
$A716 RET NZ
LD A, ($C4C3) ;??
LD ($C398),A ;this is a level code
LD A,$07
LD ($C4B0),A ;and this value here
XOR A ;message number
CALL $C1AD ;print message
POP BC
$A727 JP $A193
;additional proc,
$A72A LD A,($C4AF) ;player's state
AND $80 ;reset all except direction
LD ($C4AF),A ;write back
XOR A
LD ($C4B6), A ;??
LD ($C4BA), A ;counter of dynamic colliding objects
LD ($C4BB), A ;??
LD ($C4BE), A ;??
LD ($C4B0), A ;??
LD ($C4C1), A ;??
$A745 LD HL,($C4CC) ;load address of list of script-moved objects (clouds)
LD BC,$0009 ;structure size
$A74B LD A,(HL) ;first byte (status)
AND $9F ;apply mask
RET Z ;exit if list end was reached
LD (HL), A
ADD HL,BC ;move to next structure
A751$ JR $A74B
;----------------------
;$A753: Unpack level block data into area starting at $9D72 - $A769 (+2)
$A753 LD HL,$6E5E ;start of packed level data
LD A,($C398) ;number of current level
AND A
JR Z,$A765 ;if 0, then nothing to search
LD B,A ;number of level will be a counter
$A75D LD A,(HL)
INC HL
CP $FF
JR NZ,$A75D ;scan until $FF (end of packed level data) will be found
DJNZ $A75D ;loop through levels until required will be found
$A765 EX DE,HL ;DE will point to packed data for current level
CALL $A7A4 ;unpack low half-bytes
JP $A7FC ;unpack high half-bytes and return
;----------------------
;$A76C: Unpack some bits and check if they are 0 - $A798
;Params: reg C: how many bits to get. Bits are counted in descending direction (from high to low)
; DE: memory address
; ($C4C8) : shift accumulator
;Return values:
; reg A - requested bits (shifted to low bits)
; flag Z if all these bits are 0
$A76C PUSH HL ;save
PUSH BC ;save
LD A,(DE)
LD H,A ;H <- (DE)
INC DE ;increment
LD A,(DE)
LD L,A ;L <- (DE)
DEC DE ;back
LD A,($C4C8) ;get "shift accumulator"
ADD A,C ;add
LD B,A ;save
CP $08 ;if more than 8 bits are required
JR C,$A780 ;then move DE
SUB $08
INC DE
$A780 LD ($C4C8),A ;save "shift accumulator"
;shift HL value to the right, throwing away all bits except requested high bits
LD A,B ;restore
SUB $10
NEG ;A = $10 - A
LD B,A ;how many shifts
$A789 SRL H ;
RR L ;shift HL right
$A78D DJNZ $A789 ;loop
;create a mask containing 1 bits
$A78F LD B,C ;how many low bits to set
XOR A ;all bits 0
$A791 SCF ;set CF
RLA ;rotate reg A left, CF goes to low bit
$A793 DJNZ $A791 ;loop
AND L ;mask (affects ZF)
POP BC ;restore
POP HL ;restore
$A798 RET
;----------------------
;$A799: Compare HL with value - $A7A3
$A799 PUSH HL
PUSH BC
$A79B LD BC,$FEBD ;this value is not hard-coded, it is injected externally
$A79E AND A
SBC HL,BC
POP BC
POP HL
$A7A3 RET
;----------------------
;$A7A4: Unpack low half-bytes from data pointed by DE into area $9D72 - $A7FB
;Params: DE points to packed data
;Format:
; 1 bit - if 0 then next 3 bits define how many 0 values to write
; if 1 then next 4 bits are value to write into memory
; if value repeats two times, then third value is a counter to write the same value into memory
$A7A4 LD HL,$A132
LD ($A79C),HL ;modify code of compare proc, set limit
XOR A
LD ($C4C8),A ;init "shift accumulator"
LD HL,$9D72 ;destination (temp area)
$A7B1 LD C,$01
CALL $A76C ;unpack 1 bit
JR Z,$A7EF ;if 0, jump to "write repeating zeroes"
LD C,$04
CALL $A76C ;unpack 4 bits into A
$A7BD LD (HL),A ;put
LD B,A ;save
INC HL
CALL $A799 ;compare with $A132
JR NC,$A7FA ;exit if done
LD C,$01
CALL $A76C ;unpack 1 bit
JR Z,$A7EF ;if 0, jump "write repeating zeroes"
LD C,$04
CALL $A76C ;unpack 4 bits into A
CP B ;compare with saved
$A7D2 JR NZ,$A7BD ;if they are different, just loop
;two same values means that next value is a counter of repeating value
;this same value is in regs B and A
$A7D4 LD (HL),A ;put
INC HL ;to next addr
LD C,$04
CALL $A76C ;unpack 4 bits into A - counter
CALL $A799 ;compare with $A132
JR NC,$A7FA ;exit if done
LD C,$0F
;loop to write the same value into memory. Value is reg B, counter is reg A, amount of bits in counter is reg C
$A7E2 DEC A ;decrement counter
AND C
JR Z,$A7B1 ;exit loop if 0
$A7E6 LD (HL),B ;write value
INC HL ;move to next addr
CALL $A799 ;compare with $A132
JR NC,$A7FA ;exit if done
JR $A7E2 ;loop
;unpack 3 bits as counter of how many 0 values to write, then jump to write those 0
$A7EF LD C,$03
CALL $A76C ;unpack 3 bits into reg A - counter of 0 bytes to write
LD B,$00 ;value 0 to write
LD C,$07 ;mask (since only 3 bits in A are real)
JR $A7E6 ;write into memory and
$A7FA INC DE ;exit
$A7FB RET
;----------------------
;$A7FC: Unpack high half-bytes and combine with existing memory data at $9D72 - $A830 (+2)
;Params: DE - address to unpack from
; HL - memory area to update
;Format: if bit 7 is 1, then set the same single high bit for a sequence of bytes
; if bit 7 is not set, skip bytes
$A7FC LD HL,$9D72 ;address of unpack area
$A7FF LD A,(DE) ;read byte
INC DE
CP $FF
RET Z ;if $FF then exit
BIT 7,A ;check high bit
JR Z,$A826 ;if not set, jump
;set the same high bits for a sequence of bytes
;bits 5+6 define position of bit 1 from the left (high bits), bits 0-4 define for how many bytes
$A808 LD C,A ;save into reg C
AND $60 ;mask, keeping bits 5 and 6, clear all other bits
RLCA
RLCA
RLCA ;rotate left, so bits 5 and 6 will move to bits 0 and 1
INC A ;increment, since we will start from carry flag
LD B,A ;this is a shift counter
XOR A ;clear to init
SCF ;set carry flag, it will go to high bit
$A812 RRA
DJNZ $A812 ;shift a 1 bit to the right as many as counter
LD B,A ;save
LD A,C ;restore initial value
AND $1F ;mask: clear bits 7,6,5, it will be a byte counter
;loop
$A819 LD C,A ;save loop counter
LD A,(HL) ;read from memory
OR B ;combine with reg B
LD (HL),A ;write back
INC HL ;to next addr
LD A,C ;restore loop counter
DEC A ;decrement it
AND $1F
JR NZ, $A819 ;loop
$A824 JR $A7FF ;big loop
;skip some bytes, bits 0-6 define how many bytes to skip
$A826 AND $7F ;clear high bit
JR NZ,$A82C
LD A,$80 ;if 0 then set $80
$A82C LD C,A
LD B,$00 ;reg BC contain offset
ADD HL,BC ;add to dest memory addr in HL
$A830 JR $A7FF ;back to big loop
;----------------------
;$A832: Find a start of an entry list for current level - $A843
;Scans the list until first byte of list entry will be 0, which is an end indicator
;Input: HL - initial addr; DE - search step. ($C398) - current level.
;Output: HL - addr of a beginning of a list
$A832 LD A,($C398) ;current level, shows how many lists should we skip
AND A
RET Z ;exit immediatelly if 0
$A837 LD B,A ;store in B, loop counter
;outer loop
;inner loop HL=HL+DE until (HL) will be 0
$A838 LD A,(HL) ;read first byte
AND A
JR Z,$A840 ;go if 0 was found, we reached the end of a list for one level
ADD HL,DE ;add list entry size, thus moving to next entry
$A83D JP $A838 ;end of inner loop
INC HL ;increment, so now HL is looking at the beginning of next list
$A841 DJNZ $A838 ;decrement B, end of outer loop
$A843 RET
;----------------------
;$A844: Memory modification, reset 7-th bit until 0 is found - $A857 (+2)
Input: HL - initial addr. DE - step
$A844 LD A,($C4B1)
$A847 LD B,A
$A848 LD A,($C4B8)
$A84B OR B
$A84C RET NZ ;if ($C4B1) or ($C4B8) are not 0, exit immediatelly
$A84D LD A,(HL)
$A84E AND A
$A84F RET Z ;exit if 0 is found
$A850 CP $80
$A852 JR Z,$A856 ;if $80, then don't reset bit 7
$A854 RES 7,(HL) ;otherwise, reset it
$A856 ADD HL,DE ;add step to the addr
$A857 JP $A844 ;repeat the loop (why not JP $A84D ?)
;----------------------
;$A85A: Clear dynamic game window - $A886
;Params: reg A - attribute value
$A85A EX AF,AF' ;save reg A
;clear video memory pixel area rectangle, $19*$10 blocks of 8*8 pixels
$A85B LD D,$10 ;number of 8*row groups (80 rows at all)
LD HL,$4043 ;from this address (video mem pixel area)
;clear 8 lines in video memory
$A860 XOR A ;value
LD E,L ;save
LD C,$08 ;line counter
$A864 LD B,$19 ;this amount of bytes
CALL $C512 ;fill memory
LD L,E ;restore
INC H ;to next line
DEC C ;decrement line counter
JR NZ, $A864 ;jump to loop start
CALL $C2CA ;calc start address of next line
DEC D ;decrement 8*row counter
$A872 JR NZ, $A860 ;jump to loop start
$A874 EX AF, AF' ;restore reg A
;fill attribute area with value of reg A
$A875 LD HL, $5843 ;address in attrib area
LD C, $10 ;number of attribute lines
LD DE, $0007 ;$07 + $19 = $20, whole attrib screen line
$A87D LD B, $19 ;number of attrib blocks in line
CALL $C512 ;fill memory
ADD HL, DE ;to next line
DEC C ;dec line counter
JR NZ, $A87D ;loop again
$A886 RET
;----------------------
;$A8B5: Clear screen and draw game border - $A8D2 (+2)
;
;Game border is stored at ($EBFD).
;Empty parts are packed: 0 then quantity of bytes
$A8B5 XOR A ;screen attribute will be 0
CALL $EAEE ;clear screen
LD HL,$EBFD ;game border address
LD DE,$4000 ;video mem pixel area start
;loop transferring border to video mem
$A8BF LD A,(HL) ;get byte
INC HL ;increment source pointer
AND A ;check for 0
JR Z,$A8CC ;special handling for 0
LD (DE),A ;just put in video memory
INC DE ;increment video memory pointer
$A8C6 LD A,D
CP $5B ;check for pixel area end
JR NZ $A8BF ;repeat otherwise
RET ;exit if that's all
$A8CC LD B,(HL) ;read amount of 0 bytes to draw
INC HL
$A8CE LD (DE),A ;small loop to set 0 to video mem
INC DE
DJNZ $A8CE ;end of small loop
$A8D2 JR $A8C6 ;back to main loop
;----------------------
;$A8D4 ?? Decrement timer, print hurry up message ?? - $A90F
$A8D4 LD A,($C4B0) ;??
CP $04
JR Z,$A8DD
AND A
RET NZ ;exit if not 0 or 4
;jumps here is A is either $04 or $00
$A8DD LD HL,($C4D4) ;load
DEC HL ;decrement
LD ($C4D4),HL ;and store back
LD A,H
OR L ;check if HL = 0
JR Z,$A900 ;go if it is
LD A,H
AND A
JR Z,$A8F4 ;go if H=0
CP $0A
RET NZ ;exit, if not $0A
LD A,$05 ;message number
JP $C1AD ;prepare to print message on a screen and exit
;this code is executed if H=0
$A8F4 LD A,L
CP $32 ;check if L = $32
LD A,$05 ;this will be the message if it is greater or equals
JR NC,$A8FD
LD A,$06 ;if less than $32, this will be the message code
$A8FD JP $C1AD ;prepare to print message on a screen and exit
;this code is executed if HL = 0, ?? player is dying ??
$A900 LD A,$06 ;message number
$A902 CALL $C1AD ;prepare to print the message
LD A,$05 ;put this value ???
LD ($C4B0),A ;here ??
LD A,$01 ;and this value ??
LD ($A25C),A ;here ??
$A90F RET
;----------------------