-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfred.txt
1770 lines (1662 loc) · 53.7 KB
/
fred.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
;get a level block code for provided level coordinates
;current labyrinth is stored at $E000, it's dimensions are 32x32, from left to right, from top to bottom
;inputs: reg D - level row (0 - 31), reg E - level column (0 - 31)
;result: reg A - block value
$61EA XOR A
LD L, A
PUSH DE ; no need to push/pop, DE doesn't change
LD A, D ; we will shift level row index by 3 bits to the left
SRL A
RR L
SRL A
RR L
SRL A
RR L
OR $E0 ; base address of level map is E000
LD H, A ; high byte of level element goes to H
LD A, L
OR E ; low byte of level element is composed of horizontal coord (lower 5 bits)
LD L, A ; and 3 bits of vertical coord
LD A, (HL) ;get level element
POP DE
$6202 RET
;calculate video mem addr corresponding to pixel row and num of byte in a row
;params: reg D - pixel row, reg E - num of byte inside a row
;uses: A, HL
;returns: HL
$62D3 LD A, D
LD HL, $4000
AND $C0
SRL A
SRL A
SRL A
ADD A, H
LD H, A
LD A, D
AND $07
ADD A, H
LD H, A
LD A, D
AND $38
SLA A
SLA A
LD L, A
LD A, E
AND $1F
ADD A, L
LD L, A
$62F3 RET
;
;initial screen preparation?
;
$62F4 LD HL, $5800 ;start addr of screen attribute area
LD DE, $5801 ;next addr
LD BC, $02FF ;length of attr area - 1
LD (HL), $32 ;a value which will be set for all attributes
LDIR ;do set
LD B, $18
LD A, $55 ;value wich will be set for video-mem bytes
LD HL, $4000 ;start addr of video mem
LD DE, $4001 ;next addr
LD C, $08 ;how many lines
$630D LD (HL), A ;set initial byte
PUSH BC
LD BC, $001F ;how many bytes will be set
LDIR ;set remaining bytes
POP BC
INC HL
INC DE
DEC C ;decrement line counter
$6318 JR NZ, $630D ;move to next line, if there are any remaining
CPL ;for next lines, we switch bits of reg A, to get a checkered square
$631B DJNZ $630B ;another loop
631D: LD B, $16
631F: LD HL, $5821
6322: LD DE, $5822
6325: PUSH BC
6326: LD (HL), $06
6328: LD BC, $0017
632B: LDIR
632D: LD BC, $0009
6330: ADD HL, BC
6331: EX DE, HL
6332: ADD HL, BC
6333: EX DE, HL
6334: POP BC
6335: DJNZ $6325
6337: LD B, $B0
6339: LD DE, $0801
633C: PUSH BC
633D: PUSH DE
633E: CALL $62D3
6341: PUSH HL
6342: POP DE
6343: INC DE
6344: LD BC, $0017
6347: LD (HL), $00
6349: LDIR
634B: POP DE
634C: INC D
634D: POP BC
634E: DJNZ $633C
6350: RET
;
;Main video loop. Draw a screen based on encoded representation which uses 2-byte codes for 8*8 pixel screen cells.
;
$6391 LD HL,($638F) ;reg HL points to top-left cell
$6394 LD DE, $0801 ;initialize pixel row and column pointers. reg D - initial pixel row (8), reg E - column (1)
LD C, $16 ;height of game screen, number of 8-pixel rows
;outermost loop
$6399 PUSH DE
PUSH HL
LD B, $18 ;width of game screen, number of cells in row
;outer loop, go by columns from left to right in one 8-pixel row
$639D PUSH BC
PUSH DE
LD E, (HL) ; get first byte of a cell value
INC HL ;
LD D, (HL) ; get second byte of a cell value
INC HL ; move to next cell
;top 3 bits of cell code is a paper color for screen block, remaining bits, if multiplied by 8, are offset to 8 bytes of pixels
;to extract this info from cell code, it's value is shifted left 3 times
XOR A
LD B, $03
$63A6 SLA E
RL D
RL A
DJNZ $63A6
; after this loop, reg A is paper color, reg DE is offset to pixel data
PUSH HL ; store cell pointer, since we need HL
LD HL, $9400 ; base of pixel data, each unit is 8 bytes
ADD HL, DE ; add offset, now HL point to pixel data
POP BC
POP DE ; this is what we actually want to restore - screen row and column pointer
PUSH DE ; but still want it to be preserved for later
PUSH BC
PUSH HL ; save source pixel pointer
PUSH AF
CALL $62D3 ; calculate video mem address into HL based on screen row and column values from DE
POP AF
PUSH HL ; save video mem addr
CALL $6442 ; update from reg A an attribute area corresponding to video mem addr in HL
POP HL ; restore video mem
LD B, $08 ; loop counter, will draw 8 bytes on screen, one 8x8 box, each byte is row of 8 pixels
POP DE ; restore pointer to source pixels
;innermost loop, transfer pixels into video mem
$63C5 LD A, (DE) ; get pixels byte from source
LD (HL), A ; put pixels byte into video mem
INC DE ; to next pixels byte
INC H ; down to next video mem row
$63C9 DJNZ $63C5 ; loop 8 times
$63CB POP HL ; restore source cell pointer
POP DE ; restore screen pixel row and column pointers
INC E ; move to next column to the right
POP BC ; restore row and column counters
$63CF DJNZ $639D ; loop to fill next screen cell
$63D1 POP HL ; restore cell pointer at the begining of a row
LD DE, $0040 ; how many bytes to add to get to cell which is 1 row down
ADD HL, DE ; now HL points to the leftmost cell of next row of cells
POP DE ; restore screen pixel row and column pointers
LD A, D
ADD A, $08 ;move to next pixel row
LD D, A
DEC C ;number of remaining rows
JR NZ, $6399 ;outermost loop, go and fill next row
$63DE RET
; Draw player
$63DF LD HL, ($638F) ; top-left cell
LD DE, ($6514) ; player offset on screen ?
ADD HL, DE
LD ($643C), HL ; screen area address, param for $6409
LD ($6438), HL ; and we will memorize it for later when we will restore copied screen data
LD HL, $6518 ; static location where screen background will be stored so player will be drawn over it
LD ($6436), HL ; buffer to store screen content
LD HL, ($6516) ; player's current sprite code. Possible values are: [$0A - $13]
LD B, $04
$63F8 SLA L
RL H ; multiply by 16, since player's sprite is 4*4 cells
DJNZ $63F8
LD DE, $C000 ; sprite base
ADD HL, DE
LD ($643A), HL ; source of sprite to be drawn
CALL $6409
$6408 RET
;
;copy content of some rectangle of a screen into buffer, then draw a sprite over it
;params:
; ($643C) - 2 bytes, destination in encoded screen area
; ($6436) - 2 bytes, location of a buffer where previous content of a screen will be stored
; ($643A) - 2 bytes, source of a sprite to be drawn
; code of this procedure is modified by a caller, it will change width and height by modifying bytes at $6411 and $6413
;
$6409 LD HL, ($6436) ; address of a buffer where content of a screen will be stored
PUSH HL ; will be saved on stack
LD HL, ($643C) ; destination in encoded screen area
$6410 LD C, $04 ; height of sprite, this value at $6411 is modified by a caller
$6412 LD B, $04 ; width of sprite, this value at $6413 is modified by a caller
;first we copy content from the screen into a buffer
$6414 LD E, (HL) ; get first byte of cell code
INC HL
LD D, (HL) ; get second byte of cell code
EX (SP), HL ; now HL points to buffer area
LD (HL), E ; store first byte of cell code
INC HL
LD (HL), D ; store second byte of cell code
INC HL
EX (SP), HL ; buffer pointer will go on stack, and address of encoded screen area goes into HL
DEC HL
;now we draw sprite on screen
$641E LD DE, ($643A) ; cell of sprite to be drawn next time
LD (HL), E ; we store it on encoded screen area
INC HL
LD (HL), D
INC HL
INC DE ; increment cell code!
$6427 LD ($643A), DE ; memorize next cell code
$642B DJNZ $6414 ; loop
LD DE, $0038 ; offset to be added to encoded screen area to move to next row. This value is modified by caller
ADD HL, DE ; moving to next row
DEC C ; decrement row counter
JR NZ, $6412 ; loop
POP HL
$6435 RET
; vars:
;
; ($6436) - 2 bytes, param for $6409, buffer where previous content of a screen will be stored
; ($6438) - 2 bytes, here a last screen position of player will be memorized (by $63DF) , so it could be restored late (by $64E1)
; ($643A) - 2 bytes, param for $6409, initial cell of a sprite to be drawn
; ($643C) - 2 bytes, param for $6409, destination in encoded screen area
;
; params for $64F1
; ($643E) 2 bytes, a destination in screen cells area
; ($6440) 2 bytes, a source
;
;calculate a attr address which corresponds to video-mem addr provided in HL, and update this attr byte with value from reg A
;
$6442 PUSH AF ;memorize arg
LD A, H ;attribute addr has the same low byte as video mem addr, so we only need to calculate high byte
AND $18 ;keep only those 2 bits
SRA A
SRA A
SRA A
ADD A,$58
LD H, A ;now HL contains addr in attribute area
POP AF ;restore arg
OR $40 ;always set this bit (brightness ?)
LD (HL),A ;update attribute
$6453 RET
; multiply A by 5.
; This seem to be called only from $6E14, so could be inlined by replacing CALL with [ ADD A,A ADD A,A ADD A,D]
$6454 PUSH BC
LD B, A
AND A
JR Z, $645E
XOR A
$645A ADD A, $05
DJNZ $645A
$645E POP BC
$645F RET
;
;generate encoded representation of visible part of current level, for subsequent rendering by main video loop
;encoded representation will be generated for 6x8 blocks
;each labyrinth block is converted into 5x4 cells of a same color
;So whole representation takes 6*8*4*5 = 960 cells, which take 1920 ($780) bytes
;Representation is stored at [$ECC0 - $F43F]
;
$6460 LD DE, ($6649) ; coordinates of player (center of a screen), reg D - vertical coord, reg E - horizontal coord
DEC D
DEC D ; top visible row of labyrinth is current row - 2, it may be negative!
DEC E
DEC E
DEC E ; left visible column of labyrinth is current column - 3
LD HL, $ECC0 ; base for encoded screen representation
LD C, $06 ; number of visible rows
;outer loop, encode level rows
$646E PUSH DE
PUSH HL
LD B, $08 ; number of visible columns
;inner loop, encode level elements
PUSH BC
LD A, D ;checking vertical coord
CP $21 ;compare with level size + 1
JR C, $6486 ;it is below, ok, so it is possibly block of a labyrinth, let's check another coordinate
CP $80 ;otherwise, let's check if it greater than level's height, but not negative
JR C, $6481 ;if yes, then encode a sand block
LD BC, $E078 ;if here, then coord is negative, which means it's above the level, so we should encode stars
JR $64A4 ;jump directly to encoding
$6481 LD BC, $C08C ;code for a sand block
JR $64A4 ;jump directly to encoding
$6486 LD A, E ;check horizontal coord
CP $20 ;compare with level width
JR C, $6492 ;if lower, then it is a labyrinth item, let's get it
JR NZ, $6481 ;otherwize, it's a sand block
LD BC, $A03C ;another kind of sand block
JR $64A4 ;jump directly to encoding
$6492 PUSH HL ;save HL (a destination in encoded screen)
$6493 CALL $61EA ;get block code
SLA A ;offset = blockcode*2, since each cell code is 2 bytes
LD HL, $64D3 ;base
ADD A, L
LD L, A ;add offset to base
JR NC, $64A0 ;check for overflow
INC H ;adjust high byte if overflow
;now HL contains pointer to encoded info (2 bytes) of top-left cell of a block
$64A0 LD C, (HL) ;read first byte of block info
INC HL
LD B, (HL) ;read second byte of block info
POP HL ;restore HL (a destination in encoded screen)
$64A4 PUSH DE ;store level coords
PUSH HL ;store destination in encoded screen
PUSH BC
POP DE ;now DE has value of encoded block
;at this point DE contains code for top-left cell of a level block, and HL contain destination address for cells
;all remaining cells for level block are just sequential increments starting from top-left cell
LD C, $05 ;each labyrinth block is 5 cells high
;inner loop, go by cell rows for labyrinth block
$64AA PUSH HL ;store destination pointer for beginning of cell row for current block
LD B, $04 ;labyrinth blocks are 4 cells wide
;innermost loop, go by cells in one row of a labyrinth block
$64AD LD (HL), E ;write low byte of encoded cell
INC HL ;increment destination address
LD (HL), D ;write high byte of encoded cell
INC HL ;increment destination address
INC DE ;increment cell code
$64B2 DJNZ $64AD ;loop
POP HL ;restore pointer so it points again to leftmost cell of current row
PUSH DE ;store cell code, since we need to use DE
LD DE, $0040
ADD HL, DE ;move to next row. each row is $40 bytes, which is (num of blocks $08)*(block width $04)*(bytes per cell $02)
POP DE ;restore cell code
DEC C ;decrement cell rows counter
JR NZ, $64AA ;move to encode next cell row for current level block
POP HL ;restore destination pointer for top-left cell of level block
LD DE, $0008
ADD HL, DE ;move 4 columns to right, since each cell is 2 bytes
POP DE ;restore coordinates
INC E ;move to next block to the right
POP BC ;restore counters of level columns and rows
DJNZ $6472 ;decrement column counter and repeat if there are any left
POP HL ;restore destination pointer of top-left cell of leftmost block on current row
LD DE, $0140
ADD HL, DE ;move 5 rows below, since each row is $40 bytes, which is (num of blocks $08)*(block width $04)*(bytes per cell $02)
POP DE ;restore coordinates
INC D ;move to next row
DEC C ;decrement row counter
JR NZ, $646E ;repeat for next row, if there is any
$64D2 RET
; $64D3-$64E0 here stored initial cell codes corresponding to level blocks, 2 bytes for each block code. So for 7 possible block codes we have 7*2=14 bytes
;restore level content behind player
;
$64E1 LD HL, ($6438)
LD ($643E), HL ; address in screen representation area
LD HL, $6518
LD ($6440), HL ; a source, an address of temp buffer where level background was stored earlier
CALL $64F1 ; do restore
$64F0 RET
;restore a previously stored rectangular part of visible area from buffer
;params:
; ($643E) 2 bytes, a destination in screen cells area
; ($6440) 2 bytes, a source, address which points to a sequence of 2-byte cell codes
$64F1 LD HL, ($643E) ;pointer where to put sprite cells, a pointer in cell area
PUSH HL ;top of the stack will be used as an exchanged temporary storage, so we put destination addr
LD HL, ($6440) ;a pointer to sprite source
$64F8 LD C, $04 ;sprite height. This code is modified by caller by changing value at $64F9 !
$64FA LD B, $04 ;width of sprite. This code is modified by caller by changing value at $64FB !
$64FC LD E, (HL) ;get first byte of sprite cell
INC HL
LD D, (HL) ;get second byte of sprite cell
INC HL
;; greatest idea!!! instead of EX (SP),HL use LDI!!!
EX (SP), HL ;exchange source and destination pointers
LD (HL), E ;put first byte of sprite
INC HL
LD (HL), D ;put second byte of sprite
INC HL
EX (SP), HL
$6506 DJNZ $64FC ;end of inner loop
EX (SP), HL
LD DE, $0038 ;move to next row of screen cell area. This value is modified by callers
ADD HL, DE
EX (SP), HL
DEC C
$650F JR NZ, $64FA ;outer loop
POP HL
$6512 RET
; $6513 ?? counter of remaining jumping frames ??
; $6514 player's offset on screen, 2 bytes
; $6516 player's current sprite code, 2 bytes. Possible values are: [$0A - $13]
; $6518 buffer (4*4=16 bytes) where screen/level backround is stored, so player is drawn over it
;
; player has jumped, set new current sprite code
;
$662B LD A, ($6516) ; player's current sprite code;
CP $0D ; check if facing left or right
JR NC, $6636 ; go if right
LD A, $0B ; set "jumping facing left" sprite code
JR $6638
$6636 LD A, $0E ; set "jumping facing right" sprite code
$6638 LD ($6516), A ; set new current sprite code for player
$663B RET
;handling of "up" key pressed
$663C LD A, ($6648) ;check "on rope" status
CP $01
JP NZ, $6698 ;go if not
$6644 JP $66AC ;go if on rope
; $6647 - 1 byte, horizontal offset from block grid
; $6648 - 1 byte, status "on rope"
; $6649 ?
; $664A ?
;climbing up
;here we will move visible view of screen, and check if block boundary is crossed
$664B LD A, ($6629) ;vertical offset of visible screen
DEC A ;reduce
LD ($6629), A ;store back
CALL $682C ;flip low bit of player's current sprite
LD A, $01
LD ($68E0), A ;??
LD HL, ($638F) ;pointer to top-left visible cell of encoded screen
LD DE, $0040 ;this offset should be subsctracted to make top-left visible cell to go 1 position up
AND A
SBC HL, DE ;substract, thus moving visible view up
LD ($638F), HL ;store back
LD A, ($662A) ;vertical offset of player relative to block grid
DEC A ;decrement
LD ($662A), A ;store back
CP $FF ;check if it was 0 before
JR Z, $6680 ;go if yes, handle crossing block boundary
$6671 RET
;player have just moved via block boundary up
;we should re-generate screen view based on new block coordinates, but move visible vew 5 rows low from block grid
$6672 CALL $6460 ;generate encoded representation of visible screen
LD HL, ($638F) ;pointer to top-left cell of visible screen
LD DE, $0140 ;add this value, so visible area is moved 5 rows below
ADD HL, DE
LD ($638F), HL ;store back
$667F RET
;move player up on rope via block boundary
$6680 LD A, $04 ;since blocks are 5-cells high, if we have just crossed a block boundary, then vertical offset will be 4
LD ($662A), A ;vertical offset from block grid
LD A, ($664A) ;vertical block coordinate of player
DEC A ;decrement
LD ($664A), A ;store back
CALL $6672 ;re-generate visible screen and move view lower from block grid
LD A, ($65BC) ;BCD-displayable player vertical coordinate
DEC A ;decrement
DAA ;BCD-correction
LD ($65BC), A ;store back
$6697 RET
;handle "jumping"
$6698 LD A, $03 ;?? initial value of how many jumping frames ??
LD ($6513), A ;?? set jumping frames ??
CALL $662B ;set new sprite "jumping"
LD HL, $0214 ;new location of player's sprite on a screen
LD ($6514), HL
LD A, $01
LD ($68E0), A ;?
$66AB RET
;handle "climbing"
$66AC LD A, ($6647) ;horizontal offset from grid
AND A ;check if 0
RET NZ ;exit if not 0, only 0 is ok value for player on rope
LD A, ($662A) ;vertical offset of player from block grid
AND A ;check if 0
JR NZ, $66C8 ;if not 0, then player is on rope, and can climb up, go to handle it
;we get here if player is on rope, but is aligned on block grid. We much check if he can move up
LD DE, ($6649) ;block-coordinates of player, reg D - vertical coord, reg E - horizontal coord
DEC D ; we will check block above
CALL $61EA ; get block code
AND A ; check if empty
JR Z, $66C8
CP $04 ;check if rope
RET C
CP $07
RET NC
$66C8 CALL $664B ;move up on rope
$66CB RET
;climbing down
$66CC LD A, ($6629) ;vertical offset of visible screen
INC A ;increment
LD ($6629), A ;store back
CALL $682C ;flip low bit of player's current sprite code, making a 2-frame animation sequence
LD A, $01
LD ($68E0), A ;?
LD HL, ($638F) ;top-left cell of visible screen
LD DE, $0040 ;offset to move 1 row down
ADD HL, DE ;add offset, so making a scroll down
LD ($638F), HL ;store back new value of top-left cell
LD A, ($662A) ;;vertical offset of player from block grid
INC A ;increment
LD ($662A), A ;store back
CP $05 ;check if we became aligned with block grid
JR Z, $6701 ;go if yes, we have crossed block grid boundary
$66F0 RET
;sub-proc to re-encode a new screen buffer, and move view to top-left
$66F1 CALL $6460 ;encode a visible screen
LD HL, ($638F) ;top-left cell
LD DE, $0140 ;this value will be substracted, so scrolled screen view will to back to top of screen buffer
AND A ;reset CF
SBC HL, DE
LD ($638F), HL ;store back top-left cell
$6700 RET
;continuation of proc, handling of crossing a block grid boundary situation
$6701 XOR A
LD ($662A), A ;reset relative vertical coordinate
LD A, ($664A) ;vertical block coordinate of player
INC A ;increment
LD ($664A), A ;store back
CALL $66F1 ;re-encode a new screen buffer, and move view to top-left
LD A, ($65BC) ;displayable vertical block-coordinate, in BCD
INC A ;increment
DAA ;BCD-correction
LD ($65BC), A ;store bacck
$6717 RET
;
; Handle "down" key
;
$6718 LD A, ($6647) ;horizontal offset from block grid
AND A ;check if 0
RET NZ ;exit if not 0, since 0 is the only way player could be on rope
LD A, ($662A) ; check if on rope and shifted vertically against grid
AND A
JR NZ, $6731 ; if yes, then will climb down
;otherwise player is aligned with block grid, so we must check if he can climb down
LD DE, ($6649) ; block-coordinates of player (center of a screen), reg D - vertical coord, reg E - horizontal coord
INC D ; we will check block below player
CALL $61EA ; get block code
CP $04 ; check if it is a rope
RET C
CP $07
RET NC
CALL $66CC ;handle climbing down
$6734 RET
;move left or jump left
$6735 LD A, ($6648) ;check "on rope" status ?
AND A
JR Z, $6759
;player is jumping left from rope to ground
$673B LD A, $03 ;initial value for jumping frames
LD ($6513), A ;jumping frame counter
LD A, $01 ; 1 means jumping left
LD ($68DF), A ;set jumping direction
LD HL, $0214 ;location of player on screen
LD ($6514), HL
LD A, $0B ;sprite code for player jumping left
LD ($6516), A ;set new sprite code
LD A, $01
LD ($68E0), A ;??
XOR A
6756: LD ($6648), A ;remove "on rope" status??
;moving/jumping left
$6759 LD A, ($6628) ;horizontal offset of visible screen ?
DEC A ;decrement, so scroll left
LD ($6628), A ;store back
LD A, $01
LD ($68E0), A ;??
LD A, ($68DF) ;check jumping direction
CP $01 ;check if "jumping left", this means we are jumping
JR Z, $676F ;if jumping, we don't need to animate/change player's sprite, so skip it
CALL $67EA ;animate one frame of walking left (set new sprite code)
$676F LD HL, ($638F) ;top-left cell of visible screen
DEC HL ;decrement twice, since each cell is 2-byte
DEC HL
LD ($638F), HL ;store back
LD A, ($6647) ;horizontal offset from block grid
DEC A ;decrement
LD ($6647), A ;store back
CP $FF ;check if it became less than 0, meaning we crossed block grid
JR Z, $6791
$6782 RET
;if crossed block grid from left to right, we need to recalc encoded screen from blocks,
;and also move visible view 4 cells right of origin
$6783 CALL $6460 ;encode visible screen
LD HL, ($638F) ;offset of visible top-left cell
LD DE, $0008 ;will move 4 cells to right from origin
ADD HL, DE
LD ($638F), HL ;store back
$6790 RET
;just crossed block grid from right to left
$6791 LD A, $03 ;set new horizontal offset from block grid
LD ($6647), A
LD A, ($6649) ;horizontal block coordinate of a player
DEC A ;decrement
LD ($6649), A ;store back
CALL $6783 ;recalc encoded visible screen, and set view 4-cells to the left of origin
$67A0 RET
;move left
$67A1 LD A, ($6516) ;player's current sprite code
CP $0D ;check if left-facing
JR C, $67BA ;go if yes
CP $10 ;check if on rope
JR NC, $67B2 ;go if yes
LD A, $0A ;if we are here, then player is standing right-facing, make him left-facing
$67AE LD ($6516), A ;set new sprite code
$67B1 RET
$67B2 CP $12 ;check if player is on rope right-facing
JR NC, $67BA ;go if yes
LD A, $12 ;if player is left-facing/right-body, then make him right-facing/left-body
JR $67AE ;go to set new sprite code
$67BA LD A, ($662A) ;vertical offset of player from block grid
AND A ;check if 0
RET NZ ;exit if 0
$67BF LD A, ($6647) ;horizontal offset from block grid
AND A ;check if 0
JR NZ, $67E6 ;go if no
LD DE, ($6649) ;block coordinates of player, reg D - vertical, reg E - horizontal
DEC E ;we will check block to the left of player
CALL $61EA ;get code of block
AND A ;check if 0
JR Z, $67D6 ;go if yes
CP $04 ;check if rope
RET C ;exit if no
CP $07 ;again check if rope
RET NC ;exit if no
$67D6 LD DE, ($6649) ;get block coordinates of a player
DEC E ;make it 1 block position to the left
INC D ;make it 1 block position down
CALL $61EA ;get block coordinate
CP $04 ;check if rope
LD A, $04
JP NC, $673D ;?? jump on rope ??
$67E6 CALL $6735 ;walk/jump to left
$67E9 RET
;"walking left", animate one frame. There are 3 sprites, 1 for standing, which is a mid-part of animation
;so animation sequence is 1-2-1-3-1-2-1-3
$67EA LD A, ($6516) ;player's current sprite code
CP $0A ;check if standing facing left
JR Z, $67F5 ;go if yes
LD A, $0A ;if no (meaning player's current sprite is stepping), then set standing code
JR $6802
$67F5 LD A, ($6647) ;horizontal offset from block grid
BIT 1, A ;check lower bit
JR Z, $6800 ;depending on it, set one of stepping sprite codes
LD A, $0B ;one of two possible stepping sprite codes
JR $6802
$6800 LD A, $0C ;another of two possible stepping sprite codes
$6802 LD ($6516), A ;store new sprite code
$6805 RET
6806: LD A, ($6648) ;? value is 0 if just turned right
6809: AND A
680A: JR Z, $6835
680C: LD A, $03 ; initial value for jumping frames
680E: LD ($6513), A ;set jumping frame counter
6811: LD A, $02 ;2 means jumping right
6813: LD ($68DF), A ;set jumping direction
6816: LD HL, $0214
6819: LD ($6514), HL
681C: LD A, $0E
681E: LD ($6516), A
6821: LD A, $01
6823: LD ($68E0), A
6826: XOR A
6827: LD ($6648), A
682A: JR $6835 ;move/jump right
;flip low bit of player's current sprite
;
$682C LD A, ($6516)
XOR $01
LD ($6516), A
$6834 RET
;walking/jumping right: screen scroll, player animation
;
$6835 LD A, ($6628) ;horizontal offset of visible screen
INC A ;increment
LD ($6628), A ;store back
LD A, $01
LD ($68E0), A ;?
LD HL, ($638F) ;pointer to top-left cell of encoded screen area
INC HL ;increment twice, since each cell is 2-byte, thus moving visible area to right
INC HL
LD ($638F), HL ;store back
LD A, ($68DF) ;check if player is jumping right, 0 for walking, 2 for jumping right (1 for jumping left, but we don't expect it)
CP $02 ;check if jumping right
JR Z, $6853 ;if jumping, we don't need to change player's sprite, so skip it
CALL $68C3 ;player walkes right, set new sprite for player for walking animation
$6853 LD A, ($6647) ;? horizontal offset from block grid ?
INC A ;increment
LD ($6647), A ;store back
CP $04 ;check if we hit this limit
JR Z, $686F
$685E RET
$685F CALL $6460 ;if hit a limit, re-generate encoded screen representation
LD HL, ($638F) ;offset of top-left cell of screen
LD DE, $0008 ;this value will be subtracted, so we move 4 cells to the left, to origin
AND A
SBC HL, DE
LD ($638F), HL ;store back
$686E RET
;handler for "right" button
;
$687E LD A, ($6516) ;player's current sprite code
CP $0D ;check if it is left-facing sprite
JR NC, $688B ;go if no
LD A, $0D ;if left-facing, change to right-facing
$6887 LD ($6516), A ;store new sprite code
RET ;and exit
$688B CP $12 ;check if it is a left-facing rope hanging
JR C, $6893 ;go if no
LD A, $10 ;set to right-facing
JR $6887 ;go to set it a new current sprite
$6893 LD A, ($662A) ;check if shifted vertically from block grid (on rope)
AND A
RET NZ ;do nothing if shifted, since left-right rotation on rope was already handled above
$6898 LD A, ($6647) ;check horizontal offset from block grid?
AND A
JR NZ, $68BF ;go if not
LD DE, ($6649) ;block coordinates of player, reg D - vertical coord, reg E - horizontal coord
INC E ;increment horizontal coord
CALL $61EA ;get code of a block (to the right of a player)
AND A ;check if empty
JR Z, $68AF ;go if yes
CP $04 ;check if rope
RET C ;exit if no
CP $07 ;again check if rope
RET NC ;exit if no
$68AF LD DE, ($6649) ;again block coordinates of player, reg D - vertical coord, reg E - horizontal coord
INC E ;increment horizontal coord
INC D ;increment vertical coord
CALL $61EA ;get block
CP $04 ;check if rope
LD A, $04 ;? some code for jumping to the right ?
JP NC, $680E ;go if yes (jump on rope)
$68BF CALL $6806
$68C2 RET
;set next sprite code for walking right
;if sprite code is "stepping", then set "standing" code
;is sprite code is "standing", select one of two "stepping" sprite codes
$68C3 LD A, ($6516) ;player's current sprite code
CP $0D ;check if right-facing standing (not stepping)
JR Z, $68CE ;go if standing
68CA: LD A, $0D ;sprite code for standing
JR $68DB ;go and set "standing" as a new sprite code
$68CE LD A, ($6647) ;? horizontal offset from block grid ?
BIT 1, A ;depending on this bit we will set one of two stepping sprites
JR Z, $68D9
LD A, $0E ;first stepping sprite code
JR $68DB
$68D9 LD A, $0F ;second stepping sprite code
$68DB LD ($6516), A ;set new sprite code
$68DE RET
;
;a small wrapper around $6409 which preserves HL and BC
;
$68F4 PUSH HL
PUSH BC
$68F6 CALL $6409
POP BC
POP HL
$68FB RET
;
;a small wrapper around $64F1 which preserves HL and BC
;
$68FC PUSH HL
PUSH BC
$68FE CALL $64F1
POP BC
POP HL
$6903 RET
;
;Draw a hedgehog, with copying content from screen into buffer
;
$696D LD A, ($68E8) ; number of monsters/hazards
LD B, A ; will b used as loop counter
LD HL, $BF68 ; start of list of monster info structures
$6974 CALL $697B ; check if visible
JR NC, $69D7 ; skip this monster if it is not visible
$6979 JR $69A4 ; draw a monster if it is visible
;sub-proc which will check if monster is visible
$697B LD E, (HL) ; horizontal coord
INC HL
LD D, (HL) ; vertical coord
INC HL
LD A, ($6629) ; vertical offset of visible screen
SUB $08 ; adjust
LD C, A
LD A, D
SUB C
LD D, A ; now reg D contains on-screen vertical coord
CP $16 ; check if this coord is visible
RET NC ; exit of no
LD A, ($6628) ; horizontal offset of visible screen
SUB $0A ; adjust
LD C, A
LD A, E
SUB C
LD E, A ; now reg E contains on-screen horizontal coord
CP $1A ; check if it is visible
RET NC ; exit if no
XOR A
SRL D
RRA
SRL D
RRA
SLA E
ADD A, E
LD E, A ; now DE contain offset of sprite on encoded screen
SCF ; carry flag indicates that sprite is visible
RET
;end of sub-proc
;back to outer proc, this part will copy sprite cell codes into encoded screen area
$69A4 PUSH HL
LD HL, ($638F) ; address of top-left corner of encoded screen area
ADD HL, DE ; add offset
LD ($643C), HL ; param for $6409, destination for a sprite
POP HL
INC HL ; HL points to +3 field of monster structure
LD ($6436), HL ; param for $6409, buffer where screen content will be stored
DEC HL ; HL points to +2 field of monster structure
PUSH HL
LD A, (HL) ; load monster animation step (sprite code)
AND $03 ; leave only 2 bits
LD E, A
LD D, $00
SLA E ; multiply by 2, it will make an offset
LD HL, $6140 ; that is a sprite base
ADD HL, DE ; add offset, now HL points to monster sprite initial cell code
LD ($643A), HL ; param for $6409, source of a sprite
POP HL
LD A, $01 ; height of a sprite
LD ($6411), A ; modify code of $6409
INC A ; width of a sprite
LD ($6413), A ; modify code of $6409
CALL $68F4 ; call $$68F4, which will call $6409
LD A, $04
LD ($6411), A ; restore code of $6409
LD ($6413), A ; restore code of $6409
$69D7 INC HL
INC HL
INC HL
INC HL
INC HL
INC HL
INC HL
DJNZ $6974 ;next loop
$69E0 RET
;
;restore screen content from temp buffers for hedgehogs
;
$69E1 LD A, ($68E8) ; example value: $28, number of monsters/hazards ?
LD B, A ; it will work as a loop counter
LD HL, $C0C7
$69E8 LD E, (HL) ; example value: $5A, coordinate?
INC HL
LD D, (HL) ; example value: $3B, coordinate?
INC HL
;looks like following code checks if monster is currently visible
;and also calculates on-screen coordinates
LD A, ($6629) ; example value: $72, screen offset?
SUB $08
LD C, A
LD A, D
SUB C
LD D, A ; example value: $D1
CP $16
JR NC, $6A33
LD A, ($6628) ;screen offset ?
SUB $0A
LD C, A
LD A, E
SUB C
LD E, A
CP $1A
JR NC, $6A33
;calculate offset in encoded screen based on on-screen coordinates in D and E
XOR A ;example value in DE: $0913
SRL D
RRA
SRL D
RRA
SLA E
ADD A, E
LD E, A ;example value in DE: $0266
PUSH HL
LD HL, ($638F) ;address of visible top-left cell of encoded screen
ADD HL, DE ;add offset, this makes HL to be address in encoded screen area
LD ($643E), HL ;sprite destination in cells area, param for proc $64F1
POP HL
INC HL
LD ($6440), HL ;sprite source, param for proc $64F1
DEC HL
LD A, $01
$6A21 LD ($64F9), A ;modify code in proc $64F1, sprite size
INC A
$6A25 LD ($64FB), A ;modify code in proc $64F1, sprite size
$6A28 CALL $68FC ;call a proc which then will call $64F1
LD A, $04
LD ($64F9), A ;restore default sprite size
LD ($64FB), A
$6A33 INC HL
INC HL
INC HL
INC HL
INC HL
INC HL
INC HL
$6A3A LD DE, $0012
AND A
SBC HL, DE
$6A40 DJNZ $69E8
$6A42 RET
; draw droplets
$6BBF LD A, ($68E9) ; number of items in list
LD B, A ; will be a loop counter
LD HL, $C184 ; base of a list
$6BC6 CALL $697B ; get screen offset, and check if it is visible
JR NC, $6BFE ; skip if not visible
PUSH HL ; store HL, it contains item base + 2
LD HL, ($638F) ; screen base
ADD HL, DE ; add offset
LD ($643C), HL ; destination in screen area, param for $6409
POP HL ; restore HL, it contains item base + 2
INC HL
LD ($6436), HL ; item base + 3, will be used as a buffer to store screen data, param for $6409
DEC HL ; item base + 2
PUSH HL
LD A, (HL) ; value at item base + 2 is a sprite code
AND $07 ; keep only 3 bits
LD E, A
LD D, $00
SLA E ; multiply by 2, this makes DE as offset
LD HL, $8148 ; base of sprite cell codes
ADD HL, DE ; add cell code offset
LD ($643A), HL ; initial sprite cell code, param for $6409
POP HL
LD A, $01 ; modify code of $6409, sprite height
LD ($6411), A
INC A
LD ($6413), A ; modify code of $6409, sprite width
CALL $68F4 ; copy screen content into a buffer, and draw a sprite based on initial cell code
LD A, $04
LD ($6411), A ; restore original values for $6409
LD ($6413), A