junglejourney
view mapcode.oph @ 215:3ae571b43ba0
Made it explicit that the version of the game is a tape version.
(I was experimenting with a ROM version.)
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sun Oct 16 03:04:19 2011 +0200 |
| parents | 66abf7c5cf63 |
| children | cdceac4f5ea8 |
line source
1 ; Copyright (C) 2011 David Boddie <david@boddie.org.uk>
2 ;
3 ; This program is free software: you can redistribute it and/or modify
4 ; it under the terms of the GNU General Public License as published by
5 ; the Free Software Foundation, either version 3 of the License, or
6 ; (at your option) any later version.
7 ;
8 ; This program is distributed in the hope that it will be useful,
9 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ; GNU General Public License for more details.
12 ;
13 ; You should have received a copy of the GNU General Public License
14 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
16 jmp main
18 seeds: .byte 100, 239, 183, 144 ; $ef, $b7, $90, $d6, $89
19 start_rooms_x: .byte 5, 3, 5, 10
20 start_rooms_y: .byte 5, 8, 1, 8
21 exit_rooms_x: .byte 7, 9, 3, 0
22 exit_rooms_y: .byte 0, 0, 9, 10
24 ; These values need to be kept in sync - the room numbers must match their
25 ; positions in the room array.
26 key_rooms_x: .byte 1, 5, 10, 1
27 key_rooms_y: .byte 0, 2, 6, 4
28 key_rooms: .byte 1, 27, 76, 45 ; ky*11 + kx
30 treasure_table: .byte 6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7
31 treasure_table_: .byte 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0
33 unlimited_values: ; $7c,$7d=first,second
34 ; Add $7c and $7d, store the result in $7d and the original
35 ; $7d value in $7c, returning the sum in the accumulator.
36 lda $7c
37 sta $7b
38 lda $7d
39 sta $7c
40 adc $7b
41 sta $7d
42 clc
43 rts
45 mod9: ; A = value
46 divide_loop:
47 cmp #9
48 bcc after_divide_loop ; bmi should work here, I think, but it doesn't
49 sec
50 sbc #9
51 jmp divide_loop
53 after_divide_loop:
54 clc
55 rts ; A % 9
57 tile_values_map: .byte 0,1,0,0,0,0,2,3
59 next_value: ; no argument
60 jsr unlimited_values
61 lda $7d
62 jsr mod9
63 and #7 ; (next value % 9) & 7
64 tax
65 lda tile_values_map,x
66 sta $7b
67 rts
69 ; Room filling routines, writing to 0x579c to 0x57ff.
71 draw_top_line: ; $76=tile number for exit/wall
72 ldx #9
73 lda #2
75 draw_top_line_loop0:
76 sta $579c,x
77 dex
78 bpl draw_top_line_loop0
80 ldx #3 ; draw the exit or wall
81 lda $76
82 draw_top_line_loop1:
83 sta $579f,x
84 dex
85 bpl draw_top_line_loop1
86 clc
87 rts
89 draw_left_line: ; $77=tile number for exit/wall
90 ldx #90
91 draw_left_line_loop0:
92 lda #2
93 sta $579c,x
94 txa
95 sec
96 sbc #10
97 tax
98 bpl draw_left_line_loop0
100 ldx #30
101 draw_left_line_loop1:
102 lda $77
103 sta $57ba,x
104 txa
105 sec
106 sbc #10
107 tax
108 bpl draw_left_line_loop1
109 clc
110 rts
112 draw_bottom_line: ; $76=tile number for exit/wall
113 ldx #9
114 lda #2
115 draw_bottom_line_loop0:
116 sta $57f6,x
117 dex
118 bpl draw_bottom_line_loop0
120 ldx #3
121 lda $76
122 draw_bottom_line_loop1:
123 sta $57f9,x
124 dex
125 bpl draw_bottom_line_loop1
126 clc
127 rts
129 draw_right_line: ; $77=tile number for exit/wall
130 ldx #99
131 draw_right_line_loop0:
132 lda #2
133 sta $579c,x
134 txa
135 sec
136 sbc #10
137 tax
138 bpl draw_right_line_loop0
140 ldx #30
141 draw_right_line_loop1:
142 lda $77
143 sta $57c3,x
144 txa
145 sec
146 sbc #10
147 tax
148 bpl draw_right_line_loop1
149 clc
150 rts
152 make_empty_room:
154 ldx #99
155 make_empty_room_loop:
156 lda #0
157 sta $579c,x
158 dex
159 bpl make_empty_room_loop
161 rts
163 make_room: ; $78,$79=i,j
165 ; Fills the room array at 579c with values.
166 ; Tiles 0,1,2,3 are map tiles that will be shown by the plot_tile routine.
167 ; Other tiles are plotted separately:
168 ; 4 = exit
169 ; 5 = final exit
170 ; 6 = weapon (bits 3,4 are type)
171 ; 7 = treasure (bits 3,4 are type)
173 ; Fill the room with empty space.
175 jsr make_empty_room
177 ; Determine if there is a top exit.
179 lda #0
180 sta $76
182 lda $78 ; i == 0
183 cmp #0
184 bne not_top_screen
185 lda #2
186 sta $76
187 jmp do_top_exit
189 not_top_screen:
190 clc
192 lda $78
193 and #7 ; i & 7
194 sta $70 ; temporary result
195 lda $79
196 and #7 ; j & 7
197 cmp $70
198 beq do_top_exit
199 clc
201 lda $78
202 eor $79 ; i ^ j
203 adc $78 ; + i
204 clc
205 cmp $79 ; (i ^ j) + i == j
206 bne do_top_exit
207 lda #2
208 sta $76 ; top exit
210 do_top_exit:
211 jsr draw_top_line
213 ; Determine if there is a left exit.
214 lda #0
215 sta $77
217 lda $79
218 cmp #0
219 bne not_left_screen
220 lda #2
221 sta $77
222 jmp do_left_exit
224 not_left_screen:
225 clc
227 lda $78
228 and #3 ; i & 3
229 sta $70 ; temporary result
230 lda $79
231 and #3 ; j & 3
232 cmp $70
233 beq do_left_exit
234 clc
236 lda $78
237 ora $79 ; i | j
238 eor $79 ; ^ j
239 cmp $78 ; (i | j) ^ j == i
240 bne do_left_exit
241 lda #2
242 sta $77 ; left exit
244 do_left_exit:
245 jsr draw_left_line
247 ; Determine if there is a right exit.
248 lda #0
249 sta $77
251 lda $79
252 cmp #10
253 bne not_right_screen
254 lda #2
255 sta $77
256 jmp do_right_exit
258 not_right_screen:
259 clc
261 lda $78
262 and #3 ; i & 3
263 sta $70 ; temporary result
264 lda $79
265 adc #1
266 and #3 ; j & 3
267 cmp $70
268 beq do_right_exit
269 clc
271 lda $79
272 adc #1
273 sta $70
275 lda $78
276 ora $70 ; i | j
277 eor $70 ; ^ j
278 cmp $78 ; (i | j) ^ j == i
279 bne do_right_exit
280 lda #2
281 sta $77 ; right exit
283 do_right_exit:
284 jsr draw_right_line
286 ; Determine if there is a bottom exit.
287 lda #0
288 sta $76
290 lda $78
291 cmp #10
292 bne not_bottom_screen
293 lda #2
294 sta $76
295 jmp do_bottom_exit
297 not_bottom_screen:
298 clc
300 lda $78
301 adc #1
302 and #7 ; i & 7
303 sta $70 ; temporary result
304 lda $79
305 and #7 ; j & 7
306 cmp $70
307 beq do_bottom_exit
308 clc
310 lda $78
311 adc #1
312 sta $70
314 eor $79 ; i ^ j
315 adc $70 ; + i
316 cmp $79 ; (i ^ j) + i == j
317 bne do_bottom_exit
318 lda #2
319 sta $76 ; bottom exit
321 do_bottom_exit:
322 jsr draw_bottom_line
324 ; Add the final exit.
326 lda $578a
327 cmp #3
328 bmi make_room_no_final_exit
330 lda $78
331 cmp #0
332 bne make_room_no_final_exit
334 lda $79
335 cmp #2
336 bne make_room_no_final_exit
338 lda #6
339 sta $57a0
340 lda #7
341 sta $57a1
343 make_room_no_final_exit:
345 ; Make sure that the starting, exit, key rooms are empty.
347 ldx $578a ; level number
348 lda start_rooms_y,x
349 cmp $78
350 bne make_room_not_starting_room
351 lda start_rooms_x,x
352 cmp $79
353 bne make_room_not_starting_room
355 lda #3
356 sta $70
357 jmp add_room_decoration ; optimise away the rts
359 make_room_not_starting_room:
361 lda exit_rooms_y,x
362 cmp $78
363 bne make_room_not_exit_room
364 lda exit_rooms_x,x
365 cmp $79
366 bne make_room_not_exit_room
368 ; Add an exit to the room.
369 lda $78
370 eor $79
371 and #15
372 tax
373 lda exit_room_offsets,x
374 tax
375 lda $5780
376 and #1
377 beq exit_not_open
379 lda #5
380 sta $579c,x
381 jmp exit_decoration
383 exit_not_open:
384 clc
385 lda #4
386 sta $579c,x
388 exit_decoration:
389 lda #3
390 sta $70
391 jmp add_room_decoration ; optimise away the rts
393 make_room_not_exit_room:
395 lda key_rooms_y,x
396 cmp $78
397 bne make_room_not_key_room
398 lda key_rooms_x,x
399 cmp $79
400 bne make_room_not_key_room
402 lda #1
403 sta $70
404 jmp add_room_decoration ; optimise away the rts
406 make_room_not_key_room:
407 clc
409 ; Fill in the room details.
411 lda $79
412 sta $7c
413 sec
414 ldx $578a
415 lda seeds,x
416 sbc $78
417 sec
418 sta $7d
419 clc
421 ; Discard the first ten values.
423 ldy #10
424 make_room_loop0:
425 jsr unlimited_values
426 dey
427 bne make_room_loop0
429 ; Fill the room array with values.
431 lda #$a7
432 sta $70
433 lda #$57
434 sta $71
436 ldy #0
437 make_room_loop1:
439 jsr next_value
440 sta ($70),y
441 iny
442 cpy #8
443 bne make_room_loop1 ; continue the same row
445 lda $70
446 cmp #$ed
447 beq make_room_loop1_exit ; exit after the last row
449 adc #10
450 sta $70
451 ldy #0 ; reset the row counter
452 jmp make_room_loop1
454 make_room_loop1_exit:
455 rts
457 decoration_offsets: .byte 11,18,81,88
459 add_room_decoration:
461 lda #$9c
462 sta $8e
463 lda #$57
464 sta $8f
466 ldx #3
467 add_room_decoration_loop:
469 lda decoration_offsets,x
470 tay
471 lda $70
472 sta ($8e),y
473 dex
474 bpl add_room_decoration_loop
476 clc
477 rts
479 exit_room_offsets: .byte 35,66,63,56,34,44,64,33,36,55,65,53,45,46,54,43
480 treasure_x: .byte 3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6
481 treasure_y: .byte 1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2
483 eleven_times_table: .byte 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110
485 add_treasure: ; $78,$79 = i,j
487 lda $78
488 tax
489 lda eleven_times_table,x
490 adc $79
491 tax
493 lda $5200,x
494 ora #$80
495 sta $5200,x ; set the top bit (room visited)
496 and #$7f ; mask off the top bit to obtain the item number + 1
497 cmp #0
498 beq add_treasure_exit
500 sec
501 sbc #1
502 sta $528d ; store weapon/treasure type
503 clc
505 lda $78
506 eor $79
507 adc $528d
508 and #15
509 sta $70
511 lda #15
512 sta $8c
513 ldy #0
514 add_treasure_loop:
516 clc
518 ldx $70
519 lda treasure_y,x ; y
520 sta $8d
521 tax
522 lda room_row_offsets_low,x
523 sta $80
525 ldx $70
526 lda treasure_x,x ; x
527 sta $8e
528 adc $80
529 sta $80
531 lda #$57
532 adc #0
533 sta $81
534 clc
536 lda ($80),y ; tile
537 cmp #0
538 bne add_treasure_loop_next
540 lda #4 ; type (weapon/treasure)
541 sta $528c
542 lda $8d ; y
543 sta $528e
544 lda #1 ; dy
545 sta $528f
546 lda $8e ; x
547 sta $5290
548 lda #0 ; dx
549 sta $5291
551 lda #$8c
552 sta $74
553 lda #$52
554 sta $75
555 jmp plot_character ; optimise away the rts
557 add_treasure_loop_next:
558 dec $8c
559 bmi add_treasure_exit
561 dec $70
562 bpl add_treasure_loop
564 lda #15
565 sta $70
566 jmp add_treasure_loop
568 add_treasure_exit:
569 clc
570 rts
572 create_enemy_positions:
574 lda #31 ; counter
575 sta $7e
577 lda #1 ; x
578 sta $70
580 lda #1 ; y
581 sta $71
583 lda #$a7
584 sta $72
585 lda #$57
586 sta $73
588 ldx #15 ; offset into position areas
589 ldy #0
591 create_enemy_positions_loop:
593 jsr unlimited_values
594 and #7
595 sta $80 ; store temporarily
597 lda $72
598 adc $80
599 sta $72 ; update the offset into the room data
600 clc
602 lda $70
603 adc $80 ; update x
604 cmp #10
605 bpl create_enemy_positions_next_row
607 sta $70 ; store x
608 jmp create_enemy_positions_check_tile
610 create_enemy_positions_next_row:
612 sec
613 sbc #10
614 sta $70 ; store the x position on the next row
615 clc
617 lda $71
618 adc #1 ; update the y position
619 cmp #10
620 bpl create_enemy_positions_to_top
622 sta $71 ; store the y position for the next row
623 jmp create_enemy_positions_check_tile
625 create_enemy_positions_to_top:
627 lda #1 ; reset the x, y and offset values
628 sta $70
629 sta $71
630 lda #$a7
631 sta $72
633 create_enemy_positions_check_tile:
635 lda ($72),y
636 cmp #0
637 bne create_enemy_positions_next
639 lda $70
640 sta $0ee0,x ; store the x value
642 lda $71
643 sta $0ef0,x ; store the y value
645 dex
646 bmi create_enemy_positions_exit
648 create_enemy_positions_next:
649 clc
650 dec $7e
651 bpl create_enemy_positions_loop
653 ; The position areas were not filled. Write invalid values into the
654 ; first area for the emerge routine to find.
656 lda #0
657 create_enemy_positions_fill_loop:
659 sta $0ee0,x
660 dex
661 bpl create_enemy_positions_fill_loop
663 create_enemy_positions_exit:
664 clc
665 rts
667 plot: ; $70,$71=source address
668 ; $72,$73=destination address
669 ldy #$1f
670 plotloop0:
671 lda ($70),y
672 sta ($72),y
673 dey
674 bpl plotloop0
676 lda $72
677 adc #$20
678 sta $72
679 lda $73
680 adc #$01
681 sta $73 ; next line minus 0x20
682 clc
684 ldy #$3f
685 plotloop1:
686 lda ($70),y
687 sta ($72),y
688 dey
689 cpy #$20
690 bpl plotloop1
692 lda $72
693 adc #$20
694 sta $72
695 lda $73
696 adc #$01
697 sta $73 ; next line minus 0x20
698 clc
700 ldy #$5f
701 plotloop2:
702 lda ($70),y
703 sta ($72),y
704 dey
705 cpy #$40
706 bpl plotloop2
708 sec
709 lda $72
710 sbc #$20
711 sta $72
712 lda $73
713 sbc #$02
714 sta $73 ; back two lines minus 0x20
715 clc
717 rts
721 plot_blank_xy: ; X=y, Y=x
723 lda screen_rows_low,x
724 sta $72
725 lda screen_rows_high,x
726 sta $73
728 tya
729 tax
730 lda screen_columns_low,x
731 adc $72
732 sta $72
733 lda screen_columns_high,x
734 adc $73
735 sta $73
736 clc
737 ; run on into plot_blank
739 plot_blank: ; $72,$73=destination address
741 ldy #$1f
742 lda #0
743 plot_blank_loop0:
744 sta ($72),y
745 dey
746 bpl plot_blank_loop0
748 lda $72
749 adc #$20
750 sta $72
751 lda $73
752 adc #$01
753 sta $73 ; next line minus 0x20
754 clc
756 ldy #$3f
757 lda #0
758 plot_blank_loop1:
759 sta ($72),y
760 dey
761 cpy #$20
762 bpl plot_blank_loop1
764 lda $72
765 adc #$20
766 sta $72
767 lda $73
768 adc #$01
769 sta $73 ; next line minus 0x20
770 clc
772 ldy #$5f
773 lda #0
774 plot_blank_loop2:
775 sta ($72),y
776 dey
777 cpy #$40
778 bpl plot_blank_loop2
780 sec
781 lda $72
782 sbc #$20
783 sta $72
784 lda $73
785 sbc #$02
786 sta $73 ; back two lines minus 0x20
787 clc
789 rts
791 tile_addresses_low: .byte $00, $60, $c0, $00, $60, $c0, $20
792 tile_addresses_high: .byte $54, $54, $54, $50, $50, $50, $51
794 plot_tile: ; $7b=tile number
795 ; 1 = flowers/decoration
796 ; 2 = trees/wall
797 ; 3 = trees
798 ; 4 = exit
799 ; 5 = open exit
800 ; 6 = final exit (left)
801 ; 7 = final exit (right)
802 ; $72,$73=screen position
804 lda $7b
805 cmp #0
806 bne plot_tile_sprite
807 clc
808 jmp plot_blank ; optimise away the rts
810 plot_tile_sprite:
811 clc
812 tax
813 dex
814 lda tile_addresses_low,x
815 sta $70
816 lda tile_addresses_high,x
817 sta $71
819 lda $7b
820 cmp #4
821 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
823 clc
824 lda $578a
825 and #3 ; change the tile set for later levels
826 tax
828 plot_not_blank_add_loop:
830 cpx #2
831 bne plot_not_blank_not_2
832 dex
833 jmp plot_not_blank_not_0
835 plot_not_blank_not_2:
836 beq plot_not_blank_add_loop
837 cpx #0
839 plot_not_blank_not_0:
840 beq plot_not_blank_after_add_loop
841 clc
842 lda $70
843 adc #$20
844 sta $70
845 lda $71
846 adc #$01
847 sta $71
848 dex
849 jmp plot_not_blank_add_loop
851 plot_not_blank_after_add_loop:
852 clc
853 jsr plot
854 rts
856 plot_room: ; $78,$79 = i,j (from $5782,$5783)
857 jsr blank_screen
859 lda $5782
860 sta $78
861 lda $5783
862 sta $79
864 jsr make_room
865 ; Run on into the next piece of code.
867 plot_room_tiles:
869 lda #$80
870 sta $72
871 lda #$5a
872 sta $73 ; $72,$73 = screen position
874 lda #0
875 sta $7a
876 row_loop:
878 lda #9
879 sta $76
881 column_loop:
882 lda $7a
883 tax
884 lda $579c,x
885 sta $7b
886 jsr plot_tile
888 inc $7a
889 lda $76
890 sec
891 sbc #1
892 sta $76
893 clc
894 cmp #0
895 bpl column_loop
897 clc
899 lda $72
900 adc #$80
901 sta $72
902 lda $73
903 adc #$02
904 sta $73
905 clc
906 cmp #$80
907 beq end_rows
909 jmp row_loop
911 end_rows:
912 rts
914 set_room_palette: ; $78=i; $79=j
916 lda #1
917 sta $70
918 lda $78
919 eor $79
920 and #3
921 tax
922 lda room_palettes,x
923 sta $71
924 jsr set_palette
926 jsr set_core_palette
927 rts
929 room_palettes: .byte 1, 6, 5, 7
931 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
933 plot8x24_y0: ; $70,$71=source address
934 ; $72,$73=destination address
936 ldx #2
938 plot8x24_y0_loop:
940 ldy #15
942 plotloop8x24_y0_0:
943 lda ($70),y
944 eor ($72),y
945 sta ($72),y
946 dey
947 bpl plotloop8x24_y0_0
949 dex
950 bmi plot8x24_y0_exit
952 lda $72
953 adc #$40
954 sta $72
955 lda $73
956 adc #$01
957 sta $73
958 clc
960 lda $70
961 adc #16
962 sta $70
963 lda $71
964 adc #0
965 sta $71
966 clc
968 jmp plot8x24_y0_loop
970 plot8x24_y0_exit:
971 clc
972 jmp plot_buffer_loop_next
975 plot8x8_y1: ; $70,$71=source address
976 ; $72,$73=destination address
977 lda #2
978 sta $7e
979 lda #10
980 sta $7f
982 lda #0 ; plotting 1 8x8 piece
983 sta $8a
985 jmp plot8x24_y123 ; optimise away the rts
987 plot8x24_y1: ; $70,$71=source address
988 ; $72,$73=destination address
989 lda #2
990 sta $7e
991 lda #10
992 sta $7f
994 lda #2 ; plotting 3 8x8 pieces
995 sta $8a
997 jmp plot8x24_y123 ; optimise away the rts
999 plot8x8_y2: ; $70,$71=source address
1000 ; $72,$73=destination address
1001 lda #4
1002 sta $7e
1003 lda #12
1004 sta $7f
1006 lda #0 ; plotting 1 8x8 piece
1007 sta $8a
1009 jmp plot8x24_y123 ; optimise away the rts
1011 plot8x24_y2: ; $70,$71=source address
1012 ; $72,$73=destination address
1013 lda #4
1014 sta $7e
1015 lda #12
1016 sta $7f
1018 lda #2 ; plotting 3 8x8 pieces
1019 sta $8a
1021 jmp plot8x24_y123 ; optimise away the rts
1023 plot8x8_y3: ; $70,$71=source address
1024 ; $72,$73=destination address
1025 lda #6
1026 sta $7e
1027 lda #14
1028 sta $7f
1030 lda #0 ; plotting 1 8x8 piece
1031 sta $8a
1033 jmp plot8x24_y123 ; optimise away the rts
1035 plot8x24_y3: ; $70,$71=source address
1036 ; $72,$73=destination address
1037 lda #6
1038 sta $7e
1039 lda #14
1040 sta $7f
1042 lda #2 ; plotting 3 8x8 pieces
1043 sta $8a
1045 ; Run on into the next routine.
1047 plot8x24_y123: ; $70,$71=source address
1048 ; $72,$73=destination address
1049 ; $7e=offset into source data for first column
1050 ; $7f=offset into source data for second column
1052 plot8x24_y123_loop:
1054 ldx #0
1055 plot8x24_y123_upper_loop_outer:
1057 ldy $7e,x
1058 lda plot_upper_offsets,x
1059 sta $89
1061 plot8x24_y123_upper_loop_inner: ; plot the first column until
1062 dey ; we reach the start
1063 cpy $89
1064 bmi plot8x24_y123_upper_loop_inner_endloop
1065 lda ($70),y
1066 eor ($72),y
1067 sta ($72),y
1068 jmp plot8x24_y123_upper_loop_inner
1070 plot8x24_y123_upper_loop_inner_endloop:
1071 clc
1073 inx
1074 cpx #2
1075 bne plot8x24_y123_upper_loop_outer
1077 clc
1078 lda $72 ; move the destination pointer to refer to the next line
1079 adc #$38
1080 sta $72
1081 lda $73
1082 adc #$01
1083 sta $73
1084 clc
1086 ldx #0
1087 plot8x24_y123_lower_loop_outer:
1089 lda plot_lower_offsets,x
1090 tay
1091 lda $7e,x
1092 sta $89
1094 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1095 lda ($70),y ; offset for the column
1096 eor ($72),y
1097 sta ($72),y
1098 dey
1099 cpy $89
1100 bpl plot8x24_y123_lower_loop_inner
1102 inx
1103 cpx #2
1104 bne plot8x24_y123_lower_loop_outer
1106 dec $8a
1107 bmi plot8x24_y123_exit
1109 clc
1110 lda $70 ; update the source pointer to refer to the next piece
1111 adc #16 ; of sprite data
1112 sta $70
1113 lda $71
1114 adc #0
1115 sta $71
1116 clc
1118 lda $72 ; update the destination pointer to point to the next
1119 adc #8 ; space
1120 sta $72
1121 lda $73
1122 adc #0
1123 sta $73
1124 clc
1126 jmp plot8x24_y123_loop
1128 plot8x24_y123_exit:
1129 clc
1130 jmp plot_buffer_loop_next
1132 plot16x16_y0: ; $70,$71=source address
1133 ; $72,$73=destination address
1134 ldy #31
1136 plotloop16x16_y0_0:
1137 lda ($70),y
1138 eor ($72),y
1139 sta ($72),y
1140 dey
1141 bpl plotloop16x16_y0_0
1142 clc
1144 lda $72
1145 adc #$20
1146 sta $72
1147 lda $73
1148 adc #$01
1149 sta $73 ; 0x140 - 32
1150 clc
1152 ldy #63
1154 plotloop16x16_y0_1:
1155 lda ($70),y
1156 eor ($72),y
1157 sta ($72),y
1158 dey
1159 cpy #32
1160 bpl plotloop16x16_y0_1
1161 clc
1163 jmp plot_buffer_loop_next
1165 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1167 plot16x16_y1: ; $70,$71=source address
1168 ; $72,$73=destination address
1170 lda #2
1171 sta $7e
1172 lda #10
1173 sta $7f
1174 lda #18
1175 sta $80
1176 lda #26
1177 sta $81
1178 jmp plot16x16_y123 ; optimise away the rts
1180 plot16x16_y2: ; $70,$71=source address
1181 ; $72,$73=destination address
1183 lda #4
1184 sta $7e
1185 lda #12
1186 sta $7f
1187 lda #20
1188 sta $80
1189 lda #28
1190 sta $81
1191 jmp plot16x16_y123 ; optimise away the rts
1193 plot16x16_y3: ; $70,$71=source address
1194 ; $72,$73=destination address
1196 lda #6
1197 sta $7e
1198 lda #14
1199 sta $7f
1200 lda #22
1201 sta $80
1202 lda #30
1203 sta $81
1204 ; Run on into the next routine.
1206 plot16x16_y123: ; $70,$71=source address
1207 ; $72,$73=destination address
1208 ; $7e=offset into source data for first column
1209 ; $7f=offset into source data for second column
1210 ; $80=offset into source data for third column
1211 ; $81=offset into source data for fourth column
1213 lda #1
1214 sta $8a
1216 plot16x16_y123_loop:
1218 ldx #0
1219 plot16x16_y123_upper_loop_outer:
1221 ldy $7e,x
1222 lda plot_upper_offsets,x
1223 sta $89
1225 plot16x16_y123_upper_loop_inner:
1227 dey
1228 cpy $89
1229 bmi plot16x16_y123_upper_loop_inner_endloop
1230 lda ($70),y
1231 eor ($72),y
1232 sta ($72),y
1233 jmp plot16x16_y123_upper_loop_inner
1235 plot16x16_y123_upper_loop_inner_endloop:
1236 clc
1238 inx
1239 cpx #4
1240 bne plot16x16_y123_upper_loop_outer
1242 clc
1243 lda $72 ; move the destination pointer to refer to the next line
1244 adc #$38
1245 sta $72
1246 lda $73
1247 adc #$01
1248 sta $73
1249 clc
1251 ldx #0
1252 plot16x16_y123_lower_loop_outer:
1254 lda plot_lower_offsets,x
1255 tay
1256 lda $7e,x
1257 sta $89
1259 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1260 lda ($70),y ; for the column
1261 eor ($72),y
1262 sta ($72),y
1263 dey
1264 cpy $89
1265 bpl plot16x16_y123_lower_loop_inner
1267 inx
1268 cpx #4
1269 bne plot16x16_y123_lower_loop_outer
1271 dec $8a
1272 bmi plot16x16_y123_exit
1274 clc
1275 lda $70 ; update the source pointer to refer to the next piece
1276 adc #32 ; of sprite data
1277 sta $70
1278 lda $71
1279 adc #0
1280 sta $71
1281 clc
1283 lda $72 ; update the destination pointer to point to the next
1284 adc #8 ; space
1285 sta $72
1286 lda $73
1287 adc #0
1288 sta $73
1289 clc
1291 jmp plot16x16_y123_loop
1293 plot16x16_y123_exit:
1294 clc
1295 jmp plot_buffer_loop_next
1297 plot_upper_offsets: .byte 0, 8, 16, 24
1298 plot_lower_offsets: .byte 7, 15, 23, 31
1300 plot8x8_y0: ; $70,$71=source address
1301 ; $72,$73=destination address
1302 ldy #15
1304 plotloop8x8_y0_0:
1305 lda ($70),y
1306 eor ($72),y
1307 sta ($72),y
1308 dey
1309 bpl plotloop8x8_y0_0
1310 clc
1312 jmp plot_buffer_loop_next
1315 check_key: ; x=key code
1316 lda #129 ; returns y=255 or 0
1317 ldy #255
1318 jsr $fff4
1319 rts
1321 player_direction_chars_low: .byte $00,$30,$60,$90,$c0,$f0,$20,$50, $80,$b0,$e0,$10
1322 player_direction_chars_high: .byte $3f,$3f,$3f,$3f,$3f,$3f,$40,$40, $40,$40,$40,$41
1324 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1325 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1326 screen_subrows_low: .byte $00,$06,$44,$82
1327 screen_subrows_high: .byte $00,$00,$01,$02
1329 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1330 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1331 screen_subcolumns_low: .byte $00,$08,$10,$18
1333 enemy_direction_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1334 enemy_direction_chars_high: .byte $41,$42,$42,$42,$42,$43,$43,$43
1336 emerge_explode_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1337 emerge_explode_chars_high: .byte $4b,$4c,$4c,$4c,$4c,$4d,$4d,$4d
1339 item_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80,$c0
1340 item_chars_high: .byte $4d,$4e,$4e,$4e,$4e,$4f,$4f,$4f,$4f
1342 projectile_chars_low: .byte $40,$50,$60,$70,$80,$90,$a0,$b0
1344 unplot_character: ; $74,$75=character address
1346 lda $82 ; store the unplot buffer address in $78,$79
1347 sta $78
1348 lda $83
1349 sta $79
1350 jsr plot_character_sprite
1351 lda $78
1352 sta $82 ; update the latest space in the unplot buffer
1353 rts
1355 plot_character: ; $74,$75=character address
1357 lda $84 ; store the plot buffer address in $78,$79
1358 sta $78
1359 lda $85
1360 sta $79
1361 jsr plot_character_sprite
1362 lda $78
1363 sta $84 ; update the latest space in the plot buffer
1364 rts
1366 plot_character_sprite: ; $74,$75=character address
1367 ; $78,$79=unplot/plot buffer address
1369 ldy #0
1370 lda ($74),y
1371 cmp #0
1372 bne plot_characters_read_character
1373 jmp plot_characters_next
1375 plot_characters_read_character:
1376 clc
1378 sta $77 ; temporarily store the object type
1380 ; Use lookup tables to load the offsets into the sprite.
1382 ; Direction
1383 iny
1384 lda ($74),y
1385 sta $80 ; temporarily store the direction
1387 ; y
1388 iny
1389 lda ($74),y
1390 tax
1391 lda screen_rows_low,x
1392 sta $72
1393 lda screen_rows_high,x
1394 sta $73
1395 clc
1397 ; dy
1398 iny
1399 lda ($74),y
1400 sta $76
1401 tax
1402 lda screen_subrows_low,x
1403 adc $72
1404 sta $72
1405 lda screen_subrows_high,x
1406 adc $73
1407 sta $73
1408 clc
1410 ; x
1411 iny
1412 lda ($74),y
1413 tax
1414 lda screen_columns_low,x
1415 adc $72
1416 sta $72
1417 lda screen_columns_high,x
1418 adc $73
1419 sta $73
1420 clc
1422 ; dx
1423 iny
1424 lda ($74),y
1425 tax
1426 lda screen_subcolumns_low,x
1427 adc $72
1428 sta $72
1429 clc
1431 lda $77
1432 cmp #1
1433 bne plot_characters_loop_not_player
1435 ; Plot 8x24 sprites (player)
1437 ldx $80
1438 lda player_direction_chars_low,x
1439 sta $70
1440 lda player_direction_chars_high,x
1441 sta $71
1443 ; Use the dy value to determine which plotting routine to use.
1445 ldy #0
1446 ldx $76
1447 lda plot_routine_indices_8x24,x
1449 sta ($78),y
1450 jmp plot_characters_stored
1453 plot_characters_loop_not_player:
1454 cmp #2
1455 bne plot_characters_loop_not_projectile
1457 ; Plot 8x8 sprites (projectiles)
1459 lda $80
1460 and #7
1461 tax
1462 lda projectile_chars_low,x
1463 sta $70
1464 lda #$41
1465 sta $71
1467 ; Use the dy value to determine which plotting routine to use.
1469 ldy #0
1470 ldx $76
1471 lda plot_routine_indices_8x8,x
1473 sta ($78),y
1474 jmp plot_characters_stored
1477 plot_characters_loop_not_projectile:
1478 cmp #3
1479 bne plot_characters_loop_not_explosion
1481 ; Plot 16x16 sprites (emerging, explosions)
1483 ; Select the sprites to use.
1485 lda $80
1486 and #7 ; only keep the bits required to find the correct sprite
1487 clc
1488 tax
1489 lda emerge_explode_chars_low,x
1490 sta $70
1491 lda emerge_explode_chars_high,x
1492 sta $71
1494 jmp plot_characters_16x16
1496 plot_characters_loop_not_explosion:
1497 cmp #4
1498 bne plot_characters_loop_not_item
1500 ; Plot 16x16 sprites (items)
1502 ; Select the sprites to use.
1504 lda $80
1505 and #$0f ; only keep the bits required to find the correct sprite
1506 clc
1507 tax
1508 lda item_chars_low,x
1509 sta $70
1510 lda item_chars_high,x
1511 sta $71
1513 jmp plot_characters_16x16
1515 plot_characters_loop_not_item:
1516 cmp #8
1517 bmi plot_characters_loop_not_enemy
1519 ; Plot 16x16 sprites (enemies)
1521 ; Select the set of sprites to use.
1523 and #$70
1524 lsr
1525 lsr
1526 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1527 clc
1528 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1530 lda $80
1531 and #7 ; keep the animation bits
1532 tax
1533 lda enemy_direction_chars_low,x
1534 sta $70
1535 lda enemy_direction_chars_high,x
1536 adc $71
1537 sta $71
1539 plot_characters_16x16:
1541 ; Use the dy value to determine which plotting routine to use.
1543 ldy #0
1544 ldx $76
1545 lda plot_routine_indices_16x16,x
1547 sta ($78),y
1549 plot_characters_stored:
1551 iny
1552 lda $70
1553 sta ($78),y
1554 iny
1555 lda $71
1556 sta ($78),y
1557 iny
1558 lda $72
1559 sta ($78),y
1560 iny
1561 lda $73
1562 sta ($78),y
1564 clc
1565 lda $78
1566 adc #12
1567 sta $78
1569 plot_characters_loop_not_enemy:
1571 plot_characters_next:
1573 lda #255 ; terminate this stream of entries in the plot buffer
1574 ldy #0
1575 sta ($78),y
1576 clc
1577 rts
1579 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1580 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1581 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1583 reset_plot_buffer:
1584 lda #$06 ; reset the index into the plot buffer
1585 sta $84
1586 lda #$53
1587 sta $85
1589 lda #255 ; terminate the plot list
1590 ldy #0
1591 sta ($84),y
1592 rts
1594 reset_unplot_buffer:
1595 lda #$00 ; reset the index into the plot buffer
1596 sta $82
1597 lda #$53
1598 sta $83
1600 lda #255 ; terminate the unplot list
1601 ldy #0
1602 sta ($82),y
1603 rts
1605 plot_buffer_types_low: .byte <plot_buffer_loop_next
1606 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1607 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1608 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1610 plot_buffer_types_high: .byte >plot_buffer_loop_next
1611 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1612 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1613 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1615 plot_buffer:
1617 lda #$00
1618 sta $84
1619 lda #$53
1620 sta $85
1622 lda #6
1623 sta $88
1625 plot_buffer_loop:
1627 ldy #0
1628 lda ($84),y
1629 cmp #255
1630 beq plot_buffer_loop_skip
1632 clc
1633 tax
1634 lda plot_buffer_types_low,x
1635 sta $86
1636 lda plot_buffer_types_high,x
1637 sta $87
1639 iny
1640 lda ($84),y
1641 sta $70
1643 iny
1644 lda ($84),y
1645 sta $71
1647 iny
1648 lda ($84),y
1649 sta $72
1651 iny
1652 lda ($84),y
1653 sta $73
1655 jmp ($86) ; returns to plot_buffer_loop_next
1657 plot_buffer_loop_skip:
1659 lda $88
1660 cmp #12
1661 beq plot_buffer_exit ; both unplot and plot lists have terminated
1663 lda #12
1664 sta $88
1665 lda $84
1666 adc #6
1667 sta $84
1668 jmp plot_buffer_loop
1670 plot_buffer_loop_next:
1671 clc
1673 lda $84
1674 adc $88
1675 sta $84
1676 jmp plot_buffer_loop
1678 plot_buffer_exit:
1679 clc
1680 rts
1682 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1684 animate_player_left:
1686 ; Set the direction and toggle the animation bit.
1688 lda $5281
1689 and #1
1690 eor #1 ; toggle animation flag
1691 sta $5281 ; left (directional bits are 0)
1693 jsr plot_character
1694 rts
1696 animate_player_right:
1698 ; Set the direction and toggle the animation bit.
1700 lda $5281
1701 and #1 ; remove direction information (result is 0)
1702 eor #1 ; toggle animation flag
1703 ora #2 ; right
1704 sta $5281
1706 jsr plot_character
1707 rts
1709 animate_player_up:
1711 ; Set the direction and toggle the animation bit.
1713 lda $5281
1714 and #1 ; remove direction information (result is 0)
1715 eor #1 ; toggle animation flag
1716 ora #4 ; up
1717 sta $5281
1719 jsr plot_character
1720 rts
1722 animate_player_down:
1724 ; Set the direction and toggle the animation bit.
1726 lda $5281
1727 and #1 ; remove direction information (result is 0)
1728 eor #1 ; toggle animation flag
1729 ora #6 ; down
1730 sta $5281
1732 jsr plot_character
1733 rts
1735 move_player:
1737 lda $578e
1738 and #1
1739 beq move_player_allowed
1741 clc
1742 rts
1744 move_player_allowed:
1746 lda #$80 ; set up the address of the player character
1747 sta $74
1748 lda #$52
1749 sta $75
1751 ; Handle joystick
1753 lda $577e
1754 cmp #0
1755 beq move_player_handle_left_key
1757 lda #128
1758 ldx #1
1759 jsr $fff4
1760 cpy #112 ; <= -16
1761 bcs move_player_check_joystick_left
1762 jmp move_player_right
1764 move_player_check_joystick_left:
1765 cpy #144 ; >= 16
1766 bcc move_player_handle_joystick_up_down
1767 jmp move_player_left
1769 move_player_handle_joystick_up_down:
1771 lda #128
1772 ldx #2
1773 jsr $fff4
1774 cpy #112 ; <= -16
1775 bcs move_player_check_joystick_up
1776 jmp move_player_down
1778 move_player_check_joystick_up:
1779 cpy #144
1780 bcc move_player_no_joystick_input
1781 jmp move_player_up ; >= 16
1783 move_player_no_joystick_input:
1784 clc
1785 rts
1787 move_player_handle_left_key:
1789 ; Handle the left key.
1791 ldx #158 ; (Z)
1792 jsr check_key
1793 cpy #255
1794 bne move_player_not_left_key
1796 move_player_left:
1798 lda $5285 ; read dx
1799 cmp #0
1800 beq move_player_left_check_x
1802 jsr unplot_character ; unplot the player character
1803 dec $5285
1804 clc
1805 jmp animate_player_left ; optimise away the rts
1807 move_player_left_check_x: ; Check the x offset.
1809 lda $5284
1810 cmp #0
1811 beq move_player_leave_room_left
1813 clc
1814 tay
1815 dey ; x - 1
1816 lda $5282 ; load the y offset
1817 tax ; as an index
1818 lda room_row_offsets_low,x ; read the address of the row
1819 sta $70
1820 lda #$57
1821 sta $71
1822 lda ($70),y ; load the tile to the left
1824 cmp #5 ; check for the open exit or final exit
1825 bmi move_player_not_left_exit1
1826 jmp try_to_exit_level ; optimise away the rts
1828 move_player_not_left_exit1:
1829 cmp #0
1830 bne move_player_not_left_key
1832 lda $5283 ; dy
1833 cmp #0
1834 beq move_player_allow_left
1836 clc
1837 lda $70 ; dy > 0 so we need to check another tile
1838 adc #10
1839 sta $70
1840 lda ($70),y ; load the tile below and to the left
1842 cmp #5 ; check for the open exit or final exit
1843 bmi move_player_not_left_exit2
1844 jmp try_to_exit_level ; optimise away the rts
1846 move_player_not_left_exit2:
1847 cmp #0
1848 bne move_player_not_left_key
1850 move_player_allow_left:
1851 tya
1852 sta $81 ; temporary
1853 jsr unplot_character ; unplot the player character
1854 lda $81
1855 sta $5284 ; store the new room x offset
1856 lda #3
1857 sta $5285 ; dx = 3
1858 clc
1859 jmp animate_player_left ; optimise away the rts
1861 move_player_leave_room_left:
1862 sec
1863 lda $5783
1864 sbc #1
1865 sta $5783
1866 clc
1868 ; Set the player's position on the right of the screen.
1870 ; No need to unplot.
1872 lda #9 ; x = 9
1873 sta $5284
1874 lda #2 ; dx = 2
1875 sta $5285
1877 jsr animate_player_left
1878 sec ; indicate to the calling routine that the player
1879 rts ; has left the room
1881 move_player_not_left_key:
1883 ; Handle the right key.
1885 ldx #189 ; (X)
1886 jsr check_key
1887 cpy #255
1888 beq move_player_right
1889 jmp move_player_not_right_key
1891 move_player_right:
1893 lda $5285 ; read dx
1894 cmp #2
1895 beq move_player_right_check_x
1896 cmp #3
1897 beq move_player_right_tile
1899 jsr unplot_character ; unplot the player character
1900 inc $5285
1901 clc
1902 jmp animate_player_right ; optimise away the rts
1904 move_player_right_check_x: ; Check the x offset.
1906 lda $5284
1907 cmp #9
1908 beq move_player_leave_room_right
1910 clc
1911 tay
1912 iny ; x + 1
1913 lda $5282 ; load the y offset
1914 tax ; as an index
1915 lda room_row_offsets_low,x ; read the address of the row
1916 sta $70
1917 lda #$57
1918 sta $71
1919 lda ($70),y ; load the tile to the right
1921 cmp #5 ; check for the open exit or final exit
1922 bmi move_player_not_right_exit1
1923 jmp try_to_exit_level ; optimise away the rts
1925 move_player_not_right_exit1:
1926 cmp #0
1927 bne move_player_not_right_key
1929 lda $5283 ; dy
1930 cmp #0
1931 beq move_player_allow_right
1933 clc ; dy > 0 so we need to check another tile
1934 lda $70
1935 adc #10
1936 sta $70
1937 lda ($70),y ; load the tile below and to the right
1939 cmp #5 ; check for the open exit or final exit
1940 bmi move_player_not_right_exit2
1941 jmp try_to_exit_level ; optimise away the rts
1943 move_player_not_right_exit2:
1944 cmp #0
1945 bne move_player_not_right_key
1947 move_player_allow_right:
1949 jsr unplot_character ; unplot the player character
1950 inc $5285 ; update dx
1951 clc
1952 jmp animate_player_right ; optimise away the rts
1954 move_player_right_tile:
1956 jsr unplot_character ; unplot the player character
1957 inc $5284 ; store the new room x offset
1958 lda #0
1959 sta $5285 ; dx = 0
1960 clc
1961 jmp animate_player_right ; optimise away the rts
1963 move_player_leave_room_right:
1964 clc
1965 inc $5783
1966 clc
1968 ; Set the player's position on the left of the screen.
1970 ; No need to unplot.
1972 lda #0 ; x = 0
1973 sta $5284
1974 lda #0 ; dx = 0
1975 sta $5285
1977 jsr animate_player_right
1978 sec ; indicate to the calling routine that the
1979 rts ; player has left the room
1981 move_player_not_right_key:
1983 ; Handle the up key.
1985 ldx #183 ; (:)
1986 jsr check_key
1987 cpy #255
1988 bne move_player_not_up_key
1990 move_player_up:
1992 lda $5283 ; read dy
1993 cmp #0
1994 beq move_player_up_check_y
1996 jsr unplot_character ; unplot the player character
1997 dec $5283
1998 clc
1999 jmp animate_player_up ; optimise away the rts
2001 move_player_up_check_y: ; Check the y offset.
2003 lda $5282
2004 cmp #0
2005 beq move_player_leave_room_up
2007 tax ; use the y offset as an index
2008 dex ; y - 1
2009 ldy $5284 ; load the x offset
2010 lda room_row_offsets_low,x ; read the address of the row
2011 sta $70
2012 lda #$57
2013 sta $71
2014 lda ($70),y ; load the tile above
2016 cmp #5 ; check for the open exit or final exit
2017 bmi move_player_not_up_exit1
2018 jmp try_to_exit_level ; optimise away the rts
2020 move_player_not_up_exit1:
2021 cmp #0
2022 bne move_player_not_up_key
2024 lda $5285 ; dx
2025 cmp #3
2026 bmi move_player_allow_up
2028 clc ; dx > 2 so we need to check another tile
2029 iny
2030 lda ($70),y ; load the tile above and to the right
2032 cmp #5 ; check for the open exit or final exit
2033 bmi move_player_not_up_exit2
2034 jmp try_to_exit_level ; optimise away the rts
2036 move_player_not_up_exit2:
2037 cmp #0
2038 bne move_player_not_up_key
2040 move_player_allow_up:
2041 txa
2042 sta $81 ; temporary
2043 jsr unplot_character ; unplot the player character
2044 lda $81
2045 sta $5282 ; store the new room y offset
2046 lda #3
2047 sta $5283 ; dy = 3
2048 clc
2049 jmp animate_player_up ; optimise away the rts
2051 move_player_leave_room_up:
2052 sec
2053 lda $5782
2054 sbc #1
2055 sta $5782
2056 clc
2058 ; Set the player's position on the bottom of the screen.
2060 ; No need to unplot.
2062 lda #9 ; y = 9
2063 sta $5282
2064 lda #0 ; dy = 0
2065 sta $5283
2067 jsr animate_player_up
2068 sec ; indicate to the calling routine that the player
2069 rts ; has left the room
2071 move_player_not_up_key:
2073 ; Handle the down key.
2075 ldx #151 ; (/)
2076 jsr check_key
2077 cpy #255
2078 beq move_player_down
2079 jmp move_player_not_down_key
2081 move_player_down:
2083 lda $5283 ; read dy
2084 cmp #0
2085 beq move_player_down_check_y
2086 cmp #3
2087 beq move_player_down_tile
2089 jsr unplot_character ; unplot the player character
2090 inc $5283 ; 0 <= dy < 3
2091 clc
2092 jmp animate_player_down ; optimise away the rts
2094 move_player_down_check_y: ; Check the y offset.
2096 lda $5282
2097 cmp #9
2098 beq move_player_leave_room_down
2100 clc
2101 tax
2102 inx ; y + 1
2103 ldy $5284 ; load the x offset
2104 lda room_row_offsets_low,x ; read the address of the row
2105 sta $70
2106 lda #$57
2107 sta $71
2108 lda ($70),y ; load the tile below
2110 cmp #5 ; check for the open exit or final exit
2111 bmi move_player_not_down_exit1
2112 jmp try_to_exit_level ; optimise away the rts
2114 move_player_not_down_exit1:
2115 cmp #0
2116 bne move_player_not_down_key
2118 lda $5285 ; dx
2119 cmp #3
2120 bmi move_player_allow_down
2122 clc ; dx > 2 so we need to check another tile
2123 iny
2124 lda ($70),y ; load the tile below and to the right
2126 cmp #5 ; check for the open exit or final exit
2127 bmi move_player_not_down_exit2
2128 jmp try_to_exit_level ; optimise away the rts
2130 move_player_not_down_exit2:
2131 cmp #0
2132 bne move_player_not_down_key
2134 move_player_allow_down:
2136 jsr unplot_character ; unplot the player character
2137 inc $5283 ; update dy
2138 clc
2139 jmp animate_player_down ; optimise away the rts
2141 move_player_down_tile:
2143 jsr unplot_character ; unplot the player character
2144 inc $5282 ; store the new room y offset
2145 lda #0
2146 sta $5283 ; dy = 0
2147 clc
2148 jmp animate_player_down ; optimise away the rts
2150 move_player_leave_room_down:
2151 inc $5782
2152 clc
2154 ; Set the player's position on the top of the screen.
2156 ; No need to unplot.
2158 lda #0 ; y = 0
2159 sta $5282
2160 lda #0 ; dy = 0
2161 sta $5283
2163 jsr animate_player_down
2164 sec ; indicate to the calling routine that the
2165 rts ; player has left the room
2167 move_player_not_down_key:
2168 clc
2169 rts
2171 try_to_exit_level:
2173 cmp #6
2174 bmi just_exit_level
2176 lda $5780 ; set the complete game flag
2177 ora #$02
2178 jmp try_to_exit_level_exit
2180 just_exit_level:
2181 lda $5780 ; set the exit level flag
2182 ora #$80
2184 try_to_exit_level_exit:
2185 sta $5780
2187 lda #$80
2188 sta $74
2189 lda #$52
2190 sta $75
2191 jsr unplot_character ; remove the player sprite
2192 jmp destroy_enemies ; optimise away the rts
2194 check_fire_key:
2196 lda $578d
2197 bne check_fire_key_exit
2199 lda $577e
2200 beq check_fire_key_no_joystick
2202 lda #128
2203 ldx #0
2204 jsr $fff4
2205 txa
2206 and #1
2207 bne check_fire_key_fire
2209 clc
2210 rts
2212 check_fire_key_no_joystick:
2214 ldx #182 ; (Return)
2215 jsr check_key
2216 cpy #255
2217 bne check_fire_key_exit
2219 check_fire_key_fire:
2221 lda $5286
2222 cmp #0
2223 bne check_fire_key_exit
2225 lda #16
2226 sta $578d
2228 jmp create_projectile ; optimise away the rts
2230 check_fire_key_exit:
2231 clc
2232 rts
2234 create_projectile:
2236 lda #2
2237 sta $5286
2239 lda $5281
2240 and #$06 ; copy the direction information
2241 asl
2242 asl
2243 asl
2244 ora $5789 ; apply the projectile type
2245 sta $5287
2247 lda $5283 ; player dy
2248 adc $577f ; add the weapon counter
2249 adc #1
2250 cmp #4 ; if dy > 3, create the projectile on the tile below
2251 bpl create_projectile_below
2253 clc
2254 sta $5289 ; dy + weapon counter + 1
2255 lda $5282 ; y
2256 sta $5288
2257 jmp create_projectile_continue
2259 create_projectile_below:
2260 sec
2261 sbc #4
2262 sta $5289 ; dy + weapon counter + 1 - 4
2263 clc
2264 lda $5282 ; y
2265 adc #1
2266 sta $5288
2268 create_projectile_continue:
2269 lda $5284 ; x
2270 sta $528a
2272 lda $5285 ; dx
2273 sta $528b
2275 lda $577f ; toggle the weapon counter
2276 eor #1
2277 sta $577f
2279 ; Move the projectile away from the player.
2281 lda #$86
2282 sta $74
2283 lda #$52
2284 sta $75
2285 jsr move_projectile_after_unplot
2287 jsr move_projectile
2289 clc
2290 rts
2292 emerge_type: ; returns A=type
2293 jsr unlimited_values
2294 lda $7d
2295 and #7
2296 cmp #5
2297 bmi emerge_type_ok
2299 sec
2300 sbc #5
2301 clc
2303 emerge_type_ok:
2304 cmp $5781 ; only allow the appropriate enemies for this level
2305 bmi emerge_type_exit
2306 beq emerge_type_reduce
2308 sec
2309 sbc #1
2311 emerge_type_reduce:
2312 sec
2313 sbc $5781
2314 clc
2316 emerge_type_exit:
2317 asl
2318 asl
2319 asl
2320 asl
2321 clc
2322 rts
2324 emerge_character: ; $74,$75=character address
2326 lda #63
2327 sta $578f
2329 jsr unlimited_values
2330 and #$0f
2331 tax
2332 lda $0ee0,x
2333 cmp #0 ; check for an invalid value and exit if found
2334 beq emerge_character_exit
2336 sta $80 ; temporary
2337 lda $0ef0,x
2338 tax
2340 ; Add an emerging enemy.
2342 ldy #0
2343 lda #3 ; emerge/explosion
2344 sta ($74),y
2346 jsr emerge_type ; obtain an enemy type
2347 iny
2348 sta ($74),y
2350 txa
2351 iny
2352 sta ($74),y ; store the y position
2353 lda #1
2354 iny
2355 sta ($74),y ; store the dy offset
2357 lda $80
2358 iny
2359 sta ($74),y ; store the x position
2360 lda #0
2361 iny
2362 sta ($74),y ; store the dx offset
2364 jsr plot_character
2366 ldx #5
2367 jsr play_sound
2369 emerge_character_exit:
2370 clc
2371 rts
2373 emerge_explode: ; $74,$75=character address
2375 jsr unplot_character
2377 ldy #1
2378 lda ($74),y ; direction/animation
2379 tax
2380 adc #1 ; update the counter
2381 and #3 ; mask off everything else
2382 sta $80 ; store the masked counter value
2383 bne move_characters_explosion_not_finished
2385 txa
2386 and #4
2387 bne move_characters_remove_character
2389 ; For emerges, convert into an enemy.
2390 txa
2391 and #$70 ; only keep bits 4,5,6
2392 ora #8 ; make this an enemy
2394 ldy #0
2395 sta ($74),y ; update the type (>= 8)
2396 iny
2397 lda $7d ; prepare the direction and animation offset
2398 and #$0c
2399 sta ($74),y
2401 jsr plot_character
2402 jmp emerge_explode_exit
2404 move_characters_remove_character:
2406 ; For finished explosions, just write 0 into the character array.
2407 lda #0
2408 ldy #0
2409 sta ($74),y
2410 jmp emerge_explode_exit
2412 move_characters_explosion_not_finished:
2413 txa
2414 and #$fc
2415 ora $80
2417 ldy #1
2418 sta ($74),y
2420 jsr plot_character
2422 emerge_explode_exit:
2423 clc
2424 rts
2426 animate_enemy_left: ; $74,$75=character address
2428 ; Set the direction and toggle the animation bit.
2430 ldy #1
2431 lda ($74),y
2432 and #$fb ; keep vertical direction bit and animation bits
2433 sta ($74),y ; left (horizontal directional bit is 0)
2435 rts
2437 move_enemy_left: ; $74,$75=character address
2439 ldy #5
2440 lda ($74),y ; read dx
2441 cmp #0
2442 beq move_enemy_left_check_x
2444 sec
2445 sbc #1
2446 ldy #5
2447 sta ($74),y ; dx
2448 clc
2449 jmp animate_enemy_left ; optimise away the rts
2451 move_enemy_left_check_x:
2453 ; Check the x offset.
2455 ldy #4
2456 lda ($74),y ; x
2457 cmp #0
2458 beq move_enemy_left_exit
2460 sec
2461 sbc #1 ; x - 1
2462 sta $81 ; temporary
2463 ldy #2
2464 lda ($74),y ; load the y offset
2465 tax ; as an index
2466 lda room_row_offsets_low,x ; read the address of the row
2467 sta $70
2468 lda #$57
2469 sta $71
2470 ldy $81 ; temporary (x - 1)
2471 lda ($70),y ; load the tile to the left
2473 cmp #0
2474 bne move_enemy_left_exit
2476 ldy #3
2477 lda ($74),y ; dy
2478 cmp #2
2479 bmi move_enemy_allow_left
2481 clc
2482 lda $70 ; dy > 1 so we need to check another tile
2483 adc #10
2484 sta $70
2485 ldy $81 ; temporary (x - 1)
2486 lda ($70),y ; load the tile below and to the left
2488 cmp #0
2489 bne move_enemy_left_exit
2491 move_enemy_allow_left:
2492 lda $81
2493 ldy #4
2494 sta ($74),y ; store the new room x offset
2495 lda #3
2496 ldy #5
2497 sta ($74),y ; dx = 3
2498 clc
2499 jmp animate_enemy_left ; optimise away the rts
2501 move_enemy_left_exit:
2502 sec
2503 rts
2505 animate_enemy_right: ; $74,$75=character address
2507 ; Set the direction and toggle the animation bit.
2509 ldy #1
2510 lda ($74),y
2511 ora #$04 ; right (keep vertical direction bit and animation bits)
2512 sta ($74),y
2514 rts
2516 move_enemy_right: ; $74,$75=character_address
2518 ldy #5
2519 lda ($74),y ; read dx
2520 cmp #0
2521 beq move_enemy_right_check_x
2522 cmp #3
2523 beq move_enemy_right_tile
2525 clc
2526 adc #1
2527 ldy #5
2528 sta ($74),y
2529 jmp animate_enemy_right ; optimise away the rts
2531 move_enemy_right_check_x: ; Check the x offset.
2533 ldy #4
2534 lda ($74),y ; x
2535 cmp #9
2536 beq move_enemy_right_exit
2538 clc
2539 adc #1 ; x + 1
2540 sta $81 ; temporary (x + 1)
2541 ldy #2
2542 lda ($74),y ; load the y offset
2543 tax ; as an index
2544 lda room_row_offsets_low,x ; read the address of the row
2545 sta $70
2546 lda #$57
2547 sta $71
2548 ldy $81 ; temporary (x + 1)
2549 lda ($70),y ; load the tile to the right
2551 cmp #0
2552 bne move_enemy_right_exit
2554 ldy #3
2555 lda ($74),y ; dy
2556 cmp #2
2557 bmi move_enemy_allow_right
2559 clc ; dy > 1 so we need to check another tile
2560 lda $70
2561 adc #10
2562 sta $70
2563 ldy $81 ; temporary (x + 1)
2564 lda ($70),y ; load the tile below and to the right
2566 cmp #0
2567 bne move_enemy_right_exit
2569 move_enemy_allow_right:
2570 clc
2572 ldy #5
2573 lda ($74),y ; dx
2574 adc #1
2575 sta ($74),y ; update dx
2576 clc
2577 jmp animate_enemy_right ; optimise away the rts
2579 move_enemy_right_tile:
2580 clc
2582 ldy #4
2583 lda ($74),y ; x
2584 adc #1
2585 sta ($74),y ; store the new room x offset
2586 lda #0
2587 iny
2588 sta ($74),y ; dx = 0
2589 clc
2590 jmp animate_enemy_right ; optimise away the rts
2592 move_enemy_right_exit:
2593 sec
2594 rts
2596 animate_enemy_up: ; $74,$75=character address
2598 ; Set the direction and toggle the animation bit.
2600 ldy #1
2601 lda ($74),y
2602 and #$f7 ; keep horizontal direction bit and animation bits
2603 sta ($74),y
2605 rts
2607 move_enemy_up: ; $74,$75=character address
2609 ldy #3
2610 lda ($74),y ; read dy
2611 cmp #0
2612 beq move_enemy_up_check_y
2614 sec
2615 sbc #1
2616 ldy #3
2617 sta ($74),y ; dy
2618 clc
2619 jmp animate_enemy_up ; optimise away the rts
2621 move_enemy_up_check_y:
2623 ; Check the y offset.
2625 ldy #2
2626 lda ($74),y ; y
2627 cmp #0
2628 beq move_enemy_up_exit
2630 tax ; use the y offset as an index
2631 dex ; y - 1
2632 ldy #4
2633 lda ($74),y ; load the x offset
2634 sta $81 ; temporary (x)
2635 tay
2636 lda room_row_offsets_low,x ; read the address of the row
2637 sta $70
2638 lda #$57
2639 sta $71
2640 lda ($70),y ; load the tile above
2642 cmp #0
2643 bne move_enemy_up_exit
2645 ldy #5
2646 lda ($74),y ; dx
2647 cmp #0
2648 beq move_enemy_allow_up
2650 clc ; dx != 0 so we need to check another tile
2651 ldy $81
2652 iny
2653 lda ($70),y ; load the tile above and to the right
2655 cmp #0
2656 bne move_enemy_up_exit
2658 move_enemy_allow_up:
2659 txa
2660 ldy #2
2661 sta ($74),y ; store the new room y offset
2662 lda #3
2663 iny
2664 sta ($74),y ; dy = 3
2665 clc
2666 jmp animate_enemy_up ; optimise away the rts
2668 move_enemy_up_exit:
2669 sec
2670 rts
2672 animate_enemy_down: ; $74,$75=character address
2674 ; Set the direction and toggle the animation bit.
2676 ldy #1
2677 lda ($74),y
2678 ora #$08 ; down
2679 sta ($74),y
2681 rts
2683 move_enemy_down: ; $74,$75=character address
2685 ldy #3
2686 lda ($74),y ; dy
2687 cmp #1
2688 beq move_enemy_down_check_y
2689 cmp #3
2690 beq move_enemy_down_tile
2692 adc #1
2693 ldy #3
2694 sta ($74),y ; dy
2695 clc
2696 jmp animate_enemy_down ; optimise away the rts
2698 move_enemy_down_check_y:
2700 ; Check the y offset.
2702 ldy #2
2703 lda ($74),y
2704 cmp #9
2705 beq move_enemy_down_exit
2707 clc
2708 adc #1 ; y + 1
2709 tax
2710 ldy #4
2711 lda ($74),y ; load the x offset
2712 sta $81 ; temporary
2713 tay
2714 lda room_row_offsets_low,x ; read the address of the row
2715 sta $70
2716 lda #$57
2717 sta $71
2718 lda ($70),y ; load the tile below
2720 cmp #0
2721 bne move_enemy_down_exit
2723 ldy #5
2724 lda ($74),y ; dx
2725 cmp #0
2726 beq move_enemy_allow_down
2728 clc ; dx != 0 so we need to check another tile
2729 ldy $81 ; x
2730 iny
2731 lda ($70),y ; load the tile below and to the right
2733 cmp #0
2734 bne move_enemy_down_exit
2736 move_enemy_allow_down:
2737 clc
2739 ldy #3
2740 lda ($74),y ; dy
2741 adc #1
2742 sta ($74),y ; update dy
2743 clc
2744 jmp animate_enemy_down ; optimise away the rts
2746 move_enemy_down_tile:
2747 clc
2749 ldy #2
2750 lda ($74),y ; y
2751 adc #1
2752 sta ($74),y ; store the new room y offset
2753 lda #0
2754 iny
2755 sta ($74),y ; dy = 0
2756 clc
2757 jmp animate_enemy_down ; optimise away the rts
2759 move_enemy_down_exit:
2760 sec
2761 rts
2763 move_enemy_animate: ; $74,$75=character address
2765 ldy #1
2766 lda ($74),y ; direction/animation
2767 sta $81
2768 and #$03
2769 adc #1
2770 and #$03 ; keep animation bits
2771 sta $8f
2772 lda $81
2773 and #$fc ; mask off the animation bits
2774 ora $8f
2775 sta ($74),y
2776 rts
2778 move_enemy_next_direction: .byte $04, $0c, $00, $08
2780 move_enemy: ; $74,$75=character address
2782 lda #0
2783 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2784 lda #0
2785 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2787 lda ($74),y ; read the enemy number (Y should be zero)
2788 and #$10
2789 beq move_enemy_homing
2790 clc
2792 ; This enemy is a non-homing enemy.
2794 jsr unplot_character ; unplot now before we change the sprite used
2796 ldy #1
2797 lda ($74),y
2798 and #$f0
2799 cmp #$f0
2800 bne move_enemy_set_direction
2801 clc
2803 ldy #1
2804 lda ($74),y
2805 and #$0c
2806 ror
2807 ror
2808 tax
2809 lda move_enemy_next_direction,x
2810 sta ($74),y
2812 move_enemy_set_direction:
2813 clc
2815 ldy #1
2816 lda ($74),y
2817 sta $7b
2819 adc #$10
2820 sta ($74),y
2821 clc
2823 lda $7b
2824 and #$04
2825 ror
2826 ror
2827 adc #1
2828 sta $8e
2830 lda $7b
2831 and #$08
2832 ror
2833 ror
2834 ror
2835 adc #1
2836 sta $8d
2838 jmp move_enemy_with_direction
2840 move_enemy_homing:
2842 ldy #2
2843 lda ($74),y ; y
2844 cmp $5282 ; player y
2845 bmi move_enemy_downwards
2846 bne move_enemy_upwards
2848 ldy #3
2849 lda ($74),y ; dy
2850 cmp $5283 ; player y
2851 beq move_enemy_horizontally
2852 bpl move_enemy_upwards
2854 move_enemy_downwards:
2855 lda #2
2856 sta $8d
2857 jmp move_enemy_horizontally
2859 move_enemy_upwards:
2860 lda #1
2861 sta $8d
2862 ;jmp move_enemy_horizontally
2864 move_enemy_horizontally:
2865 ldy #4
2866 lda ($74),y ; x
2867 cmp $5284 ; player x
2868 bmi move_enemy_rightwards
2869 bne move_enemy_leftwards
2871 ldy #5
2872 lda ($74),y ; dx
2873 cmp #0
2874 beq move_enemy_with_direction_unplot
2875 bpl move_enemy_leftwards
2877 move_enemy_rightwards:
2878 lda #2
2879 sta $8e
2880 jmp move_enemy_with_direction_unplot
2882 move_enemy_leftwards:
2883 lda #1
2884 sta $8e
2886 move_enemy_with_direction_unplot:
2887 clc
2889 jsr unplot_character
2891 move_enemy_with_direction:
2892 clc
2894 lda $8e
2895 cmp #1
2896 bne move_enemy_not_left
2897 jsr move_enemy_left
2898 clc
2899 jmp move_enemy_not_right
2901 move_enemy_not_left:
2902 lda $8e
2903 cmp #2
2904 bne move_enemy_not_right
2905 jsr move_enemy_right
2906 clc
2908 move_enemy_not_right:
2909 lda $8d
2910 cmp #1
2911 bne move_enemy_not_up
2912 jsr move_enemy_up
2913 clc
2914 jmp move_enemy_toggle
2916 move_enemy_not_up:
2917 lda $8d
2918 cmp #2
2919 bne move_enemy_toggle
2920 jsr move_enemy_down
2922 move_enemy_toggle:
2923 clc
2924 jsr move_enemy_animate
2925 jmp plot_character ; optimise away the rts
2927 move_enemy_exit:
2928 clc
2929 rts
2931 create_explosion: ; X=y, Y=x
2933 lda #3
2934 sta $52a4
2935 lda #4
2936 sta $52a5
2937 txa
2938 sta $52a6
2939 lda #1
2940 sta $52a7
2941 tya
2942 sta $52a8
2943 lda #0
2944 sta $52a9
2945 rts
2947 move_projectile_left:
2949 lda $528b
2950 cmp #0
2951 beq move_projectile_left_check_x
2953 dec $528b
2954 clc
2955 rts
2957 move_projectile_left_check_x:
2959 lda $528a
2960 cmp #0
2961 bne move_projectile_left_in_room
2962 jmp move_projectile_left_exit
2964 move_projectile_left_in_room:
2965 tay
2966 dey ; x - 1
2967 ldx $5288 ; y
2968 lda room_row_offsets_low,x ; read the address of the row
2969 sta $70
2970 lda #$57
2971 sta $71
2972 lda ($70),y ; load the tile to the left
2974 cmp #0
2975 bne move_projectile_left_wall
2977 lda $5289 ; dy
2978 cmp #3
2979 bmi move_projectile_allow_left
2981 clc ; dy > 2 so we need to check another tile
2982 lda $70
2983 adc #10
2984 sta $70
2985 lda ($70),y ; load the tile below and to the left
2986 inx ; y += 1
2988 cmp #0
2989 bne move_projectile_left_wall
2991 move_projectile_allow_left:
2993 sty $528a ; x
2994 lda #3
2995 sta $528b ; dx = 3
2997 clc
2998 rts
3000 move_projectile_left_wall: ; the projectile hit a wall
3001 clc
3003 lda $5287 ; type 2 can pass through walls
3004 and #$06
3005 cmp #4
3006 beq move_projectile_allow_left
3008 cmp #2
3009 bne move_projectile_left_not_boomerang
3011 lda $5287
3012 and #$0f
3013 cmp #8
3014 bpl move_projectile_left_exit
3016 ldx $577f ; weapon counter
3017 ora boomerang_horizontal,x
3018 sta $5287
3019 clc
3020 rts ; exit without moving or registering a collision
3022 move_projectile_left_not_boomerang:
3024 cmp #6 ; type 3 can destroy certain walls
3025 bne move_projectile_left_exit
3027 lda ($70),y ; load the tile to the left
3028 cmp #1 ; decoration can be destroyed
3029 bne move_projectile_left_exit
3030 clc
3032 lda #0
3033 sta ($70),y
3035 ; X=y, Y=x
3036 jsr create_explosion
3037 jsr plot_blank_xy ; corrupted X
3039 lda #$a4
3040 sta $74
3041 lda #$52
3042 sta $75
3043 jsr plot_character
3045 ldx #0
3046 jsr play_sound
3048 lda #16 ; prevent the player from firing a new
3049 sta $578d ; projectile until the explosion has finished
3051 move_projectile_left_exit:
3052 sec
3053 rts
3055 boomerang_horizontal: .byte $28, $38
3057 move_projectile_right:
3059 ; Fire right.
3061 lda $528b
3062 cmp #2
3063 beq move_projectile_right_check_x
3064 cmp #3
3065 beq move_projectile_right_tile
3067 inc $528b
3068 clc
3069 rts
3071 move_projectile_right_check_x:
3073 lda $528a ; x
3074 cmp #9
3075 bne move_projectile_right_not_edge
3076 jmp move_projectile_right_exit
3078 move_projectile_right_not_edge:
3079 clc
3080 tay
3081 iny ; x + 1
3082 ldx $5288 ; y
3083 lda room_row_offsets_low,x ; read the address of the row
3084 sta $70
3085 lda #$57
3086 sta $71
3087 lda ($70),y ; load the tile to the right
3089 cmp #0
3090 bne move_projectile_right_wall
3092 lda $5289 ; dy
3093 cmp #3
3094 bmi move_projectile_allow_right
3096 clc ; dy > 2 so we need to check another tile
3097 lda $70
3098 adc #10
3099 sta $70
3100 lda ($70),y ; load the tile below and to the right
3101 inx ; y += 1
3103 cmp #0
3104 bne move_projectile_right_wall
3106 move_projectile_allow_right:
3108 inc $528b ; dx
3109 clc
3110 rts
3112 move_projectile_right_tile:
3114 inc $528a ; x
3115 lda #0
3116 sta $528b ; dx
3117 clc
3118 rts
3120 move_projectile_right_wall: ; the projectile hit a wall
3121 clc
3123 lda $5287 ; type 2 can pass through walls
3124 and #$06
3125 cmp #4
3126 beq move_projectile_allow_right
3128 cmp #2
3129 bne move_projectile_right_not_boomerang
3131 lda $5287
3132 and #$0f
3133 cmp #8
3134 bpl move_projectile_right_exit
3136 ldx $577f ; weapon counter
3137 ora boomerang_horizontal,x
3138 sta $5287
3139 clc
3140 rts ; exit without moving or registering a collision
3142 move_projectile_right_not_boomerang:
3144 cmp #6 ; type 3 can destroy certain walls
3145 bne move_projectile_right_exit
3147 lda ($70),y ; load the tile to the right
3148 cmp #1 ; decoration can be destroyed
3149 bne move_projectile_right_exit
3150 clc
3152 lda #0
3153 sta ($70),y
3155 ; X=y, Y=x
3156 jsr create_explosion
3157 jsr plot_blank_xy ; corrupted X
3159 lda #$a4
3160 sta $74
3161 lda #$52
3162 sta $75
3163 jsr plot_character
3165 ldx #0
3166 jsr play_sound
3168 lda #16 ; prevent the player from firing a new
3169 sta $578d ; projectile until the explosion has finished
3171 move_projectile_right_exit:
3172 sec
3173 rts
3175 move_projectile_up:
3177 lda $5289 ; read dy
3178 cmp #0
3179 beq move_projectile_up_check_y
3181 dec $5289
3182 clc
3183 rts
3185 move_projectile_up_check_y: ; Check the y offset.
3187 lda $5288
3188 cmp #0
3189 bne move_projectile_up_not_edge
3190 jmp move_projectile_up_exit
3192 move_projectile_up_not_edge:
3193 tax ; use the y offset as an index
3194 dex ; y - 1
3195 ldy $528a ; load the x offset
3196 lda room_row_offsets_low,x ; read the address of the row
3197 sta $70
3198 lda #$57
3199 sta $71
3200 lda ($70),y ; load the tile above
3202 cmp #0
3203 bne move_projectile_up_wall
3205 lda $528b ; dx
3206 cmp #3
3207 bmi move_projectile_allow_up
3209 clc ; dx > 2 so we need to check another tile
3210 iny
3211 lda ($70),y ; load the tile above and to the right
3213 cmp #0
3214 bne move_projectile_up_wall
3216 move_projectile_allow_up:
3217 txa
3218 sta $5288 ; store the new room y offset
3219 lda #3
3220 sta $5289 ; dy = 3
3222 clc
3223 rts
3225 move_projectile_up_wall: ; the projectile hit a wall
3226 clc
3228 lda $5287 ; type 2 can pass through walls
3229 and #$06
3230 cmp #4
3231 beq move_projectile_allow_up
3233 cmp #2
3234 bne move_projectile_up_not_boomerang
3236 lda $5287
3237 and #$0f
3238 cmp #8
3239 bpl move_projectile_up_exit
3241 ldx $577f ; weapon counter
3242 ora boomerang_vertical,x
3243 sta $5287
3244 clc
3245 rts ; exit without moving or registering a collision
3247 move_projectile_up_not_boomerang:
3249 cmp #6 ; type 3 can destroy certain walls
3250 bne move_projectile_up_exit
3252 lda ($70),y ; load the tile above
3253 cmp #1 ; decoration can be destroyed
3254 bne move_projectile_up_exit
3255 clc
3257 lda #0
3258 sta ($70),y
3260 ; X=y, Y=x
3261 jsr create_explosion
3262 jsr plot_blank_xy ; corrupted X
3264 lda #$a4
3265 sta $74
3266 lda #$52
3267 sta $75
3268 jsr plot_character
3270 ldx #0
3271 jsr play_sound
3273 lda #16 ; prevent the player from firing a new
3274 sta $578d ; projectile until the explosion has finished
3276 move_projectile_up_exit:
3277 sec
3278 rts
3280 boomerang_vertical: .byte $08, $18
3282 move_projectile_down:
3284 lda $5289 ; read dy
3285 cmp #2
3286 beq move_projectile_down_check_y
3287 cmp #3
3288 beq move_projectile_down_tile
3290 inc $5289 ; 0 <= dy < 3
3291 clc
3292 rts
3294 move_projectile_down_check_y: ; Check the y offset.
3296 lda $5288
3297 cmp #9
3298 bne move_projectile_down_in_room
3299 jmp move_projectile_down_exit
3301 move_projectile_down_in_room:
3302 clc
3303 tax
3304 inx ; y + 1
3305 ldy $528a ; load the x offset
3306 lda room_row_offsets_low,x ; read the address of the row
3307 sta $70
3308 lda #$57
3309 sta $71
3310 lda ($70),y ; load the tile below
3312 cmp #0
3313 bne move_projectile_down_wall
3315 lda $528b ; dx
3316 cmp #3
3317 bmi move_projectile_allow_down
3319 clc ; dx > 2 so we need to check another tile
3320 iny
3321 lda ($70),y ; load the tile below and to the right
3323 cmp #0
3324 bne move_projectile_down_wall
3326 move_projectile_allow_down:
3328 inc $5289 ; update dy
3329 clc
3330 rts
3332 move_projectile_down_tile:
3334 inc $5288 ; store the new room y offset
3335 lda #0
3336 sta $5289 ; dy = 0
3337 clc
3338 rts
3340 move_projectile_down_wall: ; the projectile hit a wall
3341 clc
3343 lda $5287 ; type 2 can pass through walls
3344 and #$06
3345 cmp #4
3346 beq move_projectile_allow_down
3348 cmp #2
3349 bne move_projectile_down_not_boomerang
3351 lda $5287
3352 and #$0f
3353 cmp #8
3354 bpl move_projectile_down_exit
3356 ldx $577f ; weapon counter
3357 ora boomerang_vertical,x
3358 sta $5287
3359 clc
3360 rts ; exit without moving or registering a collision
3362 move_projectile_down_not_boomerang:
3364 cmp #6 ; type 3 can destroy certain walls
3365 bne move_projectile_down_exit
3367 lda ($70),y ; load the tile below
3368 cmp #1 ; decoration can be destroyed
3369 bne move_projectile_down_exit
3370 clc
3372 lda #0
3373 sta ($70),y
3375 ; X=y, Y=x
3376 jsr create_explosion
3377 jsr plot_blank_xy ; corrupted X
3379 lda #$a4
3380 sta $74
3381 lda #$52
3382 sta $75
3383 jsr plot_character
3385 ldx #0
3386 jsr play_sound
3388 lda #16 ; prevent the player from firing a new
3389 sta $578d ; projectile until the explosion has finished
3391 move_projectile_down_exit:
3392 sec
3393 rts
3395 move_projectile_animate:
3397 lda $5287
3398 eor #1
3399 sta $5287
3400 rts
3402 move_projectile:
3404 lda $5286
3405 cmp #0
3406 bne move_projectile_move
3407 jmp move_projectile_exit
3409 move_projectile_move:
3410 clc
3412 lda #$86
3413 sta $74
3414 lda #$52
3415 sta $75
3416 jsr unplot_character
3418 move_projectile_after_unplot:
3420 lda $5287
3421 and #$30 ; direction
3423 cmp #0
3424 bne move_projectile_not_left
3426 jsr move_projectile_left
3427 bcc move_projectile_toggle
3428 bcs move_projectile_destroy
3430 move_projectile_not_left:
3431 cmp #$10
3432 bne move_projectile_not_right
3434 jsr move_projectile_right
3435 bcc move_projectile_toggle
3436 bcs move_projectile_destroy
3438 move_projectile_not_right:
3439 cmp #$20
3440 bne move_projectile_not_up
3442 jsr move_projectile_up
3443 bcc move_projectile_toggle
3444 bcs move_projectile_destroy
3446 move_projectile_not_up:
3447 cmp #$30
3448 bne move_projectile_toggle
3450 jsr move_projectile_down
3451 bcs move_projectile_destroy
3453 move_projectile_toggle:
3455 jsr projectile_collide
3456 bcs move_projectile_destroy
3458 jsr move_projectile_animate
3460 lda #$86
3461 sta $74
3462 lda #$52
3463 sta $75
3464 jmp plot_character ; optimise away the rts
3466 move_projectile_destroy:
3467 clc
3469 ldy #0
3470 lda ($74),y ; type
3471 cmp #8
3472 bmi move_projectile_no_enemy_collision
3474 and #$70 ; increase the player's score
3475 lsr
3476 lsr
3477 lsr
3478 adc #2
3479 sta $70
3480 jsr add_score
3481 jmp move_projectile_create_explosion
3483 move_projectile_no_enemy_collision:
3485 cmp #4 ; items can be destroyed as well
3486 bne move_projectile_no_item_collision
3488 ldy #1 ; but not keys
3489 lda ($74),y
3490 cmp #4 ; even the mace is stopped by a key
3491 beq move_projectile_remove_projectile
3492 clc
3494 jsr remove_room_item
3496 move_projectile_create_explosion:
3498 ; Unplot the item/enemy and replace it with an explosion.
3500 jsr unplot_character
3502 lda #3 ; explosion
3503 ldy #0
3504 sta ($74),y
3506 lda #4
3507 ldy #1
3508 sta ($74),y
3510 jsr plot_character
3512 ; Play a sound.
3513 ldx #0
3514 jsr play_sound
3516 move_projectile_no_item_collision:
3518 lda $5287 ; type 2 projectiles pass through everything
3519 and #$06
3520 cmp #4
3521 bne move_projectile_remove_projectile
3523 ; Ideally, we would have recorded if the projectile left the screen so
3524 ; that we don't perform these checks again here, but it would just add
3525 ; overhead to the normal movement routines for the other weapons.
3527 lda $5288 ; y
3528 cmp #0
3529 beq move_projectile_remove_projectile
3530 cmp #9
3531 beq move_projectile_remove_projectile
3533 lda $528a ; x
3534 cmp #0
3535 beq move_projectile_remove_projectile
3536 cmp #9
3537 beq move_projectile_remove_projectile
3539 clc
3540 lda #$86
3541 sta $74
3542 lda #$52
3543 sta $75
3545 jsr plot_character
3546 jmp move_projectile_exit
3548 move_projectile_remove_projectile:
3550 lda #0 ; remove the projectile from the character list
3551 sta $5286
3553 move_projectile_exit:
3554 clc
3555 rts
3557 emerge_characters:
3559 lda #$8c ; set the character address
3560 sta $74
3561 lda #$52
3562 sta $75
3564 emerge_characters_loop:
3566 ldy #0
3567 lda ($74),y
3568 cmp #0
3569 bne emerge_characters_next
3571 jmp emerge_character ; optimise away the rts
3573 emerge_characters_next:
3574 clc
3576 ; Examine the next character.
3577 lda $74
3578 adc #6
3580 cmp #$a4
3581 bpl emerge_characters_exit
3582 sta $74
3583 jmp emerge_characters_loop
3585 emerge_characters_exit:
3586 clc
3587 rts
3589 enemy_slots: .byte 0, 6, 12, 18
3591 move_characters:
3593 lda #$8c ; set the character address
3594 sta $74
3595 lda #$52
3596 sta $75
3598 lda $578e ; read a value from 0 to 3 from the motion counter
3599 and #3
3600 tax
3601 lda enemy_slots,x ; look up the corresponding slot in the character list
3602 adc $74
3603 sta $74 ; update the character address
3605 move_characters_loop:
3607 ldy #0
3608 lda ($74),y
3609 cmp #3
3610 bne move_characters_not_emerge_explode
3612 jsr emerge_explode
3613 jmp move_characters_next
3615 move_characters_not_emerge_explode:
3616 cmp #8
3617 bmi move_characters_next
3619 jsr move_enemy
3621 move_characters_next:
3622 clc
3624 lda $74 ; for the last enemy, check the next slot
3625 cmp #$9e ; for the presence of an explosion
3626 bne move_characters_endloop ; otherwise leave the loop (only performing
3627 clc ; one iteration)
3629 adc #6
3630 sta $74
3631 jmp move_characters_loop
3633 move_characters_endloop:
3634 clc
3636 ; Check collisions with the player.
3638 jsr player_collide
3639 bcs move_characters_collisions
3640 jmp move_characters_exit
3642 move_characters_collisions:
3643 clc
3645 ldy #0
3646 lda ($74),y ; type
3647 cmp #8
3648 bpl move_character_destroy_enemy
3650 ; Unplot the item.
3651 jsr unplot_character
3653 ; Remove it from the item table.
3654 jsr remove_room_item
3656 lda #0 ; remove the item from the character list
3657 ldy #0
3658 sta ($74),y
3660 iny
3661 lda ($74),y ; get the item type
3663 sta $8d ; temporarily store A and increase the score
3664 tax
3665 lda item_scores,x
3666 sta $70
3667 jsr add_score
3668 lda $8d
3670 ; Check the item type.
3671 cmp #8
3672 bmi move_characters_not_health
3674 lda #20
3675 sta $70
3676 jsr add_strength
3677 clc
3679 ldx #2
3680 jsr play_sound
3682 rts
3684 move_characters_not_health:
3685 cmp #5
3686 bmi move_characters_not_treasure
3688 ldx #2
3689 jsr play_sound
3691 clc
3692 rts
3694 move_characters_not_treasure:
3695 cmp #4
3696 bmi move_characters_not_key
3698 ; Key - update the item/player flags byte.
3699 lda $5780
3700 ora #$01
3701 sta $5780
3702 clc
3704 ldx #3
3705 jsr play_sound
3707 rts
3709 move_characters_not_key:
3711 ; Update the player's weapon.
3712 asl
3713 sta $5789
3714 clc
3716 ldx #2
3717 jsr play_sound
3719 rts
3721 move_character_destroy_enemy:
3723 ; Unplot the enemy and replace it with an explosion.
3725 jsr unplot_character
3727 lda #3 ; explosion
3728 ldy #0
3729 sta ($74),y
3731 lda #4
3732 ldy #1
3733 sta ($74),y
3735 jsr plot_character
3737 ; Reduce the player's strength.
3739 ldx #1
3740 jsr play_sound
3742 lda #1
3743 sta $70
3744 jmp reduce_strength ; optimise away the rts
3746 move_characters_exit:
3747 clc
3748 rts
3750 remove_room_item:
3752 ldx $5782 ; current room row number
3753 lda eleven_times_table,x
3754 adc $5783 ; current room column number
3755 tax
3756 lda #$80 ; store a value with the top bit set instead of zero because we
3757 sta $5200,x ; have visited this room if we can collect the object within it
3758 clc
3759 rts
3761 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3762 score_vdu_bytes: .byte 1,1,31 ; reversed
3763 score_digits: .byte "0123456789"
3765 add_score: ; $70=score to add
3767 sed
3768 lda $5786
3769 adc $70
3770 sta $5786
3771 lda $5787
3772 adc #0
3773 sta $5787
3774 lda $5788
3775 adc #0
3776 sta $5788
3777 cld
3779 write_score:
3781 lda #$86
3782 sta $70
3783 lda #$57
3784 sta $71
3786 ldx #2
3787 write_score_vdu_bytes:
3788 lda score_vdu_bytes,x
3789 jsr $ffee
3790 dex
3791 bpl write_score_vdu_bytes
3793 write_score_digits: ; $70,$71=address of score bytes
3795 ldy #2
3796 write_score_loop:
3798 lda ($70),y
3799 lsr
3800 lsr
3801 lsr
3802 lsr
3803 tax
3804 lda score_digits,x
3805 jsr $ffee
3807 lda ($70),y
3808 and #$0f
3809 tax
3810 lda score_digits,x
3811 jsr $ffee
3813 dey
3814 bpl write_score_loop
3816 clc
3817 rts
3819 strength_units: .byte $00,$88,$cc,$ee
3821 add_strength: ; $70=strength to add
3823 ; Divide the initial strength by 4 to determine which half character to
3824 ; start plotting at, and multiply by 8 to get the address. The net result
3825 ; is to mask off the bottom two bits and shift left once.
3826 lda $5784
3827 and #$fc
3828 sta $71 ; strength rounded down to a multiple of four units
3829 asl
3830 clc
3831 tay
3833 lda $5784
3834 adc $70
3835 cmp #65
3836 bmi add_strength_update
3838 lda #64
3840 add_strength_update:
3841 clc
3842 sta $5784 ; the final strength
3844 sec
3845 sbc $71
3846 clc
3847 tax ; the number of units to add between the rounded original
3848 ; strength and the final strength
3850 lda #$f3 ; the start of the strength bar
3851 sta $72
3852 lda #$59
3853 sta $73
3855 cpx #4
3856 bmi add_strength_loop_extra
3858 add_strength_loop:
3860 clc
3861 lda #$ff
3862 sta ($72),y
3864 tya
3865 adc #8
3866 tay
3868 txa
3869 sec
3870 sbc #4
3871 clc
3872 tax
3874 cmp #4
3875 bpl add_strength_loop
3877 add_strength_loop_extra:
3878 cpx #0
3879 beq add_strength_exit
3881 ; For any remaining units in excess of the multiples of four units, plot
3882 ; the appropriate byte.
3883 lda $5784
3884 and #3
3885 tax
3887 lda strength_units,x
3888 sta ($72),y
3890 add_strength_exit:
3891 clc
3892 rts
3894 reduce_strength: ; $70=strength to remove
3896 lda $5784
3897 tax
3898 sec
3899 sbc $70
3900 bpl reduce_strength_update
3902 lda #0
3904 reduce_strength_update:
3905 clc
3906 sta $5784
3908 ; Divide the final strength by 4 to determine which half character to
3909 ; plot, and multiply by 8 to get the address. The net result is to mask off
3910 ; the bottom two bits and shift left once.
3911 and #$fc
3912 asl
3913 tay
3915 lda #$f3 ; the start of the strength bar
3916 sta $70
3917 lda #$59
3918 sta $71
3920 lda $5784
3921 and #3
3922 tax
3923 lda strength_units,x
3924 sta ($70),y
3926 lda $5784
3927 cmp #0
3928 bne reduce_strength_exit
3930 lda $5780 ; the player ran out of strength
3931 ora #$40
3932 sta $5780
3934 lda #64 ; reset the delay counter
3935 sta $5785
3937 lda #$80 ; unplot the player
3938 sta $74
3939 lda #$52
3940 sta $75
3942 jsr unplot_character
3944 lda #8 ; change the player's direction to the demise animation
3945 sta $5281
3947 jsr plot_character
3948 jmp destroy_enemies ; optimise away the rts
3950 reduce_strength_exit:
3951 clc
3952 rts
3954 destroy_enemies:
3956 lda #$8c
3957 sta $74
3958 lda #$52
3959 sta $75
3961 destroy_enemies_loop:
3963 ldy #0
3964 lda ($74),y
3965 cmp #8
3966 bmi destroy_enemies_not_enemy
3968 jsr unplot_character
3970 lda #3 ; emerge/explosion
3971 ldy #0
3972 sta ($74),y
3974 iny
3975 lda #4 ; explosion
3976 sta ($74),y
3978 jsr plot_character
3979 jmp destroy_enemies_not_emerging_enemy
3981 destroy_enemies_not_enemy:
3982 cmp #3
3983 bne destroy_enemies_not_emerging_enemy
3985 jsr unplot_character
3987 iny ; whether emerging or exploding, ensure that the enemy
3988 lda ($74),y ; is now exploding
3989 ora #4
3990 sta ($74),y
3992 jsr plot_character
3994 destroy_enemies_not_emerging_enemy:
3995 clc
3996 lda $74
3997 adc #6
3998 sta $74
3999 cmp #$a4
4000 bmi destroy_enemies_loop
4002 clc
4003 rts
4005 remove_characters:
4007 ; Clear the character table.
4009 ldx #6
4010 remove_characters_loop:
4011 lda #0
4012 sta $5280,x
4013 txa
4014 adc #6
4015 tax
4016 cpx #$2a
4017 bmi remove_characters_loop
4019 rts
4021 ; The player collision masks use bits to represent where the player is in a
4022 ; tile. See the collisions.txt file for more information.
4024 ; Player is above, enemy is below, checking the overlap in the lower tile.
4025 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4027 projectile_collision_mask_above: .byte $00, $00, $00, $80
4029 ; Player and enemy share the same tile or player is on the tile below.
4030 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4032 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4034 ; Player is above or on the same tile, enemy is below, checking the overlap in
4035 ; the lower tile.
4036 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4038 ; Enemy is above, player is below, checking the overlap in the lower tile.
4039 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4041 ; Player is to the left, enemy is to the right, checking the overlap in the
4042 ; right hand tile.
4043 player_collision_mask_left:
4044 projectile_collision_mask_left: .byte $00, $00, $00, $08
4046 ; Player and enemy share the same tile or player is on the tile to the right.
4047 player_collision_mask_right:
4048 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4050 ; Player is to the left, enemy is to the right or on the same tile, checking
4051 ; the overlap in the right hand tile.
4052 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4054 ; Enemy is to the left, player is to the right, checking the overlap in the
4055 ; right hand tile.
4056 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4058 player_collide:
4060 lda $5282 ; player y
4061 sta $8a
4062 lda $5284 ; player x
4063 sta $8b
4065 ldx $5283 ; player dy
4066 lda player_collision_mask_above,x
4067 sta $86
4068 lda player_collision_mask_below,x
4069 sta $88
4070 ldx $5285 ; player dx
4071 lda player_collision_mask_left,x
4072 sta $87
4073 lda player_collision_mask_right,x
4074 sta $89
4076 jmp collide ; optimise away the rts
4078 projectile_collide:
4080 lda $5288 ; projectile y
4081 sta $8a
4082 lda $528a ; projectile x
4083 sta $8b
4085 ldx $5289 ; projectile dy
4086 lda projectile_collision_mask_above,x
4087 sta $86
4088 lda projectile_collision_mask_below,x
4089 sta $88
4090 ldx $528b ; projectile dx
4091 lda projectile_collision_mask_left,x
4092 sta $87
4093 lda projectile_collision_mask_right,x
4094 sta $89
4096 ; Run on into the next routine.
4098 collide:
4100 lda #$8c ; set the character address
4101 sta $74
4102 lda #$52
4103 sta $75
4105 collide_loop:
4107 ldy #0
4108 lda ($74),y ; type
4109 cmp #4
4110 bpl collide_check
4112 jmp collide_next
4114 collide_check:
4116 ldy #2
4117 lda ($74),y ; y
4118 sec
4119 sbc $8a ; y - player/projectile y
4120 beq check_collide_y_equal
4121 cmp #1
4122 beq check_collide_y_greater
4123 cmp #255
4124 beq check_collide_y_less
4126 jmp collide_next
4128 check_collide_y_equal:
4129 ; The enemy is on the same tile as the player/projectile so look at the
4130 ; collision on their common tile.
4131 ldy #3
4132 lda ($74),y ; dy
4133 tax
4134 lda enemy_collision_mask_above,x
4135 and $88 ; player/projectile mask below
4136 bne check_collide_x
4138 jmp collide_next
4140 check_collide_y_greater:
4141 ; The enemy is on the tile below the player/projectile so look at the
4142 ; collision on the enemy's tile.
4143 ldy #3
4144 lda ($74),y ; dy
4145 tax
4146 lda enemy_collision_mask_above,x
4147 and $86 ; player mask above
4148 bne check_collide_x
4150 jmp collide_next
4152 check_collide_y_less:
4153 ; The enemy is on the tile above the player/projectile so look at the
4154 ; collision on the player's tile.
4155 ldy #3
4156 lda ($74),y ; dy
4157 tax
4158 lda enemy_collision_mask_below,x
4159 and $88 ; player mask below
4160 bne check_collide_x
4162 jmp collide_next
4164 check_collide_x:
4165 ldy #4
4166 lda ($74),y ; x
4167 sec
4168 sbc $8b ; x - player/projectile x
4169 beq check_collide_x_equal
4170 cmp #1
4171 beq check_collide_x_greater
4172 cmp #255
4173 beq check_collide_x_less
4175 jmp collide_next
4177 check_collide_x_equal:
4178 ; The enemy is on the same tile as the player/projectile so look at the
4179 ; collision on their common tile.
4180 ldy #5
4181 lda ($74),y ; dx
4182 tax
4183 lda enemy_collision_mask_left,x
4184 and $89 ; player mask right
4185 bne check_collide_destroy
4187 jmp collide_next
4189 check_collide_x_greater:
4190 ; The enemy is the tile to the right of the player/projectile so look
4191 ; at the collision on the enemy's tile.
4192 ldy #5
4193 lda ($74),y ; dx
4194 tax
4195 lda enemy_collision_mask_left,x
4196 and $87 ; player mask left
4197 bne check_collide_destroy
4199 jmp collide_next
4201 check_collide_x_less:
4202 ; The enemy is the tile to the left of the player/projectile so look at
4203 ; the collision on the player's tile.
4204 ldy #5
4205 lda ($74),y ; dx
4206 tax
4207 lda enemy_collision_mask_right,x
4208 and $89 ; player mask right
4209 bne check_collide_destroy
4211 collide_next:
4212 clc
4214 ; Examine the next character.
4215 lda $74
4216 adc #6
4218 cmp #$a4
4219 bpl collide_exit
4220 sta $74
4221 jmp collide_loop
4223 check_collide_destroy:
4225 sec ; set the carry flag to inform the caller that the
4226 rts ; player/projectile should be destroyed
4228 collide_exit:
4229 clc
4230 rts
4232 blank_screen:
4233 lda #1
4234 sta $70
4235 lda #0
4236 sta $71
4237 jsr set_palette
4238 lda #2
4239 sta $70
4240 lda #0
4241 sta $71
4242 jsr set_palette
4243 lda #3
4244 sta $70
4245 lda #0
4246 sta $71
4247 ; Run on into set_palette.
4249 set_palette:
4250 ; $70=logical colour
4251 ; $71=physical colour
4252 lda $70
4253 sta $578b
4254 lda $71
4255 sta $578c
4256 lda #0
4257 sta $578d
4258 sta $578e
4259 sta $578f
4261 lda #$c
4262 ldx #$8b
4263 ldy #$57
4264 jsr $fff1
4265 rts
4267 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4268 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4270 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4271 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4272 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4273 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4274 note_sound: .byte $13,0, 241,255
4275 note_pitch: .byte 0,0
4276 note_duration: .byte 4,0
4277 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4279 play_note: ; A=pitch, Y=duration
4281 sta note_pitch
4282 sty note_duration
4283 ldx #4
4284 ; Run on into the next routine.
4286 play_sound: ; X=sound number
4288 lda sounds_high,x
4289 tay
4290 lda sounds_low,x
4291 tax
4292 lda #7
4293 jsr $fff1
4295 rts
4297 copy_title_up:
4299 lda #$00
4300 sta $70
4301 lda #$18
4302 sta $71
4304 lda #$a0
4305 sta $72
4306 lda #$5a
4307 sta $73
4309 ldx #5
4310 ; Run on into the next routine.
4312 copy_title:
4314 copy_title_loop1:
4316 ldy #0
4317 copy_title_loop2:
4319 lda ($70),y
4320 sta ($72),y
4321 iny
4322 cpy #0
4323 bne copy_title_loop2
4325 clc
4326 lda $72
4327 adc #$40
4328 sta $72
4329 lda $73
4330 adc #$01
4331 sta $73
4332 clc
4334 lda $71
4335 adc #$01
4336 sta $71
4337 clc
4339 dex
4340 bpl copy_title_loop1
4342 rts
4344 copy_completed_screen_up:
4346 lda #$00
4347 sta $70
4348 lda #$0f
4349 sta $71
4351 lda #$60
4352 sta $72
4353 lda #$5e
4354 sta $73
4356 ldx #8
4357 jmp copy_title ; optimise away the rts
4359 init:
4360 jsr cls ; clear the text window
4362 lda #26 ; unset the text window
4363 jsr $ffee
4365 ; Define the default high scores.
4366 ldy #0
4367 lda #$80
4368 sta $70
4369 lda #$51
4370 sta $71
4371 lda #$16
4372 sta $72
4374 ldx #0
4375 init_define_high_scores_loop:
4377 lda #0
4378 sta ($70),y
4379 iny
4380 lda $72
4381 sta ($70),y
4382 iny
4383 lda #0
4384 sta ($70),y
4386 iny
4387 init_define_high_score_name_loop:
4389 lda high_score_default_name1,x
4390 sta ($70),y
4391 iny
4392 inx
4393 cpx #9
4394 beq init_define_high_scores_next
4395 cpx #18
4396 bne init_define_high_score_name_loop
4398 ldx #0
4399 init_define_high_scores_next:
4401 sed
4402 lda $72
4403 sec
4404 sbc #2
4405 sta $72
4406 cld
4407 clc
4409 cpy #96
4410 bne init_define_high_scores_loop
4412 ; Disable joystick support.
4413 lda #0
4414 sta $577e
4416 rts
4418 high_score_default_name1: .byte "RETRO "
4419 high_score_default_name2: .byte " SOFTWARE"
4421 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4422 input_message: .byte 17,2, 31,2,27, "Press SPACE/FIRE"
4423 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4424 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4425 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4426 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4428 set_standard_palette:
4430 lda #1
4431 sta $70
4432 lda #1
4433 sta $71
4434 jsr set_palette
4436 jmp set_core_palette ; optimise away the rts
4438 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4440 set_complete_palette:
4442 lda #0
4443 sta $80
4444 lda #25
4445 sta $81
4447 set_complete_palette_loop:
4449 jsr wait_for_vsync
4451 dec $81
4452 lda $81
4453 cmp #0
4454 bne set_complete_palette_loop
4456 lda #25
4457 sta $81
4459 ldx $80
4460 lda complete_palette_bytes,x
4461 sta $70
4462 inx
4463 lda complete_palette_bytes,x
4464 sta $71
4465 inx
4466 stx $80
4467 jsr set_palette
4469 lda $80
4470 cmp #10
4471 bne set_complete_palette_loop
4473 rts
4475 set_hidden_palette:
4477 lda #1
4478 sta $70
4479 lda #0
4480 sta $71
4481 jsr set_palette
4483 ; Run on into the next routine.
4485 set_core_palette:
4487 lda #2
4488 sta $70
4489 lda #2
4490 sta $71
4491 jsr set_palette
4493 lda #3
4494 sta $70
4495 lda #3
4496 sta $71
4497 jsr set_palette
4499 rts
4501 show_title:
4503 jsr set_standard_palette
4505 ldx #0
4506 write_title_text_loop:
4507 lda title_vdu_bytes,x
4508 jsr $ffee
4509 inx
4510 cpx #12
4511 bmi write_title_text_loop
4513 jsr show_input_message
4515 ; Show the title.
4516 jsr copy_title_up
4518 ; Show the high scores.
4520 jsr colour1
4522 lda #$80
4523 sta $70
4524 lda #$51
4525 sta $71
4527 lda #8
4528 sta $80
4530 show_title_high_scores_loop:
4532 lda #31
4533 jsr $ffee
4534 lda #2
4535 jsr $ffee
4536 lda $80
4537 adc #2
4538 sta $80
4539 clc
4540 jsr $ffee
4542 jsr write_score_digits
4544 lda #32
4545 jsr $ffee
4547 ldx #8
4548 ldy #3
4549 show_title_high_scores_vdu_loop2:
4551 lda ($70),y
4552 cmp #32
4553 bmi ignore_char
4554 cmp #123
4555 bpl ignore_char
4556 jsr $ffee
4558 ignore_char:
4559 iny
4560 dex
4561 bpl show_title_high_scores_vdu_loop2
4563 lda $70
4564 adc #12
4565 sta $70
4566 cmp #$e0
4567 bne show_title_high_scores_loop
4569 lda #0 ; message counter
4570 sta $72
4572 show_title_wait_loop:
4574 lda #150
4575 sta $5785
4577 ldx $72
4578 ldy #22
4579 show_title_wait_message_loop:
4581 lda title_vdu_bytes1,x
4582 jsr $ffee
4583 inx
4584 dey
4585 bpl show_title_wait_message_loop
4587 cpx #92
4588 beq show_title_wait_reset_offset
4590 txa
4591 sta $72
4592 jmp show_title_wait_inner_loop
4594 show_title_wait_reset_offset:
4595 lda #0
4596 sta $72
4598 show_title_wait_inner_loop:
4599 jsr wait_for_vsync
4601 dec $5785
4602 beq show_title_wait_loop
4604 show_title_wait_loop_no_update:
4605 lda #128
4606 ldx #0
4607 jsr $fff4
4608 cpx #0 ; fire button pressed?
4609 beq show_title_no_joystick
4611 lda #1 ; enable joystick support
4612 sta $577e
4613 jmp show_title_exit
4615 show_title_no_joystick:
4616 ldx #157 ; SPACE
4617 jsr check_key
4618 cpy #255
4619 bne show_title_wait_inner_loop
4621 lda #0 ; disable joystick support
4622 sta $577e
4624 show_title_exit:
4625 clc
4626 rts
4628 show_input_message:
4630 ldx #0
4631 show_input_message_loop:
4633 lda input_message,x
4634 jsr $ffee
4635 inx
4636 cpx #23
4637 bne show_input_message_loop
4639 rts
4641 wait_for_vsync:
4643 lda #19
4644 jmp $fff4 ; optimise away the rts
4646 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4648 delay:
4650 delay_loop:
4652 jsr wait_for_vsync
4653 dec $5785
4654 bne delay_loop
4656 rts
4658 show_game_over:
4660 lda #128
4661 sta $5785
4662 jsr delay
4664 ldx #0
4665 write_game_over_text_loop:
4666 lda game_over_vdu_bytes,x
4667 jsr $ffee
4668 inx
4669 cpx #33
4670 bmi write_game_over_text_loop
4672 lda #192
4673 sta $5785
4674 jsr delay
4676 rts
4678 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4679 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4681 show_end_of_level_screen:
4683 ; Draw a decorative room.
4685 jsr make_empty_room
4687 ldx #5
4688 end_of_level_h_walls_loop:
4690 lda #3
4691 sta $57b2,x
4692 sta $57e4,x
4693 dex
4694 bpl end_of_level_h_walls_loop
4696 ldx #30
4697 end_of_level_v_walls_loop:
4699 lda #3
4700 sta $57bc,x
4701 sta $57c1,x
4702 txa
4703 sec
4704 sbc #10
4705 tax
4706 bpl end_of_level_v_walls_loop
4708 jsr plot_room_tiles
4709 jsr set_standard_palette
4711 ldx #0
4712 end_of_level_text_loop1:
4714 lda end_of_level_bytes1,x
4715 jsr $ffee
4716 inx
4717 cpx #28
4718 bne end_of_level_text_loop1
4720 ; Count the number of rooms explored.
4721 ldx #0
4722 lda #0
4723 sta $8d
4724 sta $8e
4725 end_of_level_room_count_loop:
4727 lda $5200,x
4728 and #$80
4729 beq end_of_level_room_count_loop_next
4731 sed
4732 lda $8d
4733 adc #1
4734 sta $8d
4735 lda $8e
4736 adc #0
4737 sta $8e
4738 cld
4739 clc
4741 end_of_level_room_count_loop_next:
4742 inx
4743 cpx #121
4744 bne end_of_level_room_count_loop
4746 ; Position the player so that we can perform an animation.
4747 jsr position_player_set_up_plotting
4749 lda $8d
4750 sta $70
4751 lda $8e
4752 sta $71
4753 jsr write_bonus
4755 lda #0 ; reset motion counter
4756 sta $578e
4758 show_end_of_level_bonus_loop:
4760 jsr wait_for_vsync
4762 clc
4763 lda $578e
4764 and #15
4765 bne end_of_level_no_animation
4767 ; Animate the player.
4769 jsr reset_unplot_buffer
4770 jsr reset_plot_buffer
4772 ; $74,$75 should be unchanged
4773 jsr unplot_character
4775 lda $5281
4776 eor #1
4777 sta $5281
4778 jsr plot_character
4780 jsr plot_buffer
4782 end_of_level_no_animation:
4783 clc
4784 lda $578e
4785 and #3
4786 bne end_of_level_no_countdown
4788 ; Transfer the bonus to the score.
4790 sed
4791 sec
4792 lda $8d
4793 sbc #1
4794 sta $8d
4795 sta $70
4796 lda $8e
4797 sbc #0
4798 sta $8e
4799 sta $71
4800 cld
4801 clc
4803 jsr write_bonus
4805 lda #9
4806 sta $70
4807 jsr add_score
4809 lda $8d
4810 and #$3f
4811 asl
4812 ldy #1
4813 jsr play_note
4815 end_of_level_no_countdown:
4816 inc $578e ; update motion counter
4817 clc
4819 lda $8d
4820 cmp #0
4821 bne show_end_of_level_bonus_loop
4823 lda $8e
4824 cmp #0
4825 bne show_end_of_level_bonus_loop
4827 lda #64 ; initialise delay counter
4828 sta $5785
4829 jsr delay
4831 ldx #0
4832 end_of_level_text_loop2:
4834 lda end_of_level_bytes2,x
4835 jsr $ffee
4836 inx
4837 cpx #25
4838 bne end_of_level_text_loop2
4840 lda $578a
4841 cmp #3
4842 bpl show_end_of_level_screen_exit
4844 lda #192 ; initialise delay counter
4845 sta $5785
4846 jsr delay
4848 show_end_of_level_screen_exit:
4849 rts
4851 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4853 write_bonus: ; $70,$71=value
4854 ; $72,$73=address of VDU codes
4856 ldx #4
4857 write_bonus_vdu_bytes:
4859 lda level_bonus_vdu_bytes,x
4860 jsr $ffee
4861 dex
4862 bpl write_bonus_vdu_bytes
4864 ldy #1
4865 write_bonus_loop:
4867 tya
4868 tax ; temporary
4870 lda $70,x
4871 sta $80
4872 lsr
4873 lsr
4874 lsr
4875 lsr
4876 tax
4877 lda score_digits,x
4878 jsr $ffee
4880 lda $80
4881 and #$0f
4882 tax
4883 lda score_digits,x
4884 jsr $ffee
4886 dey
4887 bpl write_bonus_loop
4889 clc
4890 rts
4892 position_player_set_up_plotting:
4894 jsr reset_player_position
4895 jsr remove_characters
4897 jsr reset_unplot_buffer
4898 jsr reset_plot_buffer
4900 ; Run on into the next routine.
4902 plot_the_player:
4904 lda #$80 ; plot the player
4905 sta $74
4906 lda #$52
4907 sta $75
4908 jsr plot_character
4910 jsr plot_buffer
4911 rts
4913 complete_game_vdu_bytes1: .byte 12
4914 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4915 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4916 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4918 show_complete_game:
4920 jsr blank_screen
4922 ldx #0
4923 show_complete_game_vdu_loop:
4925 lda complete_game_vdu_bytes1,x
4926 jsr $ffee
4927 inx
4928 cpx #68
4929 bne show_complete_game_vdu_loop
4931 jsr copy_completed_screen_up
4933 jsr set_complete_palette
4935 lda #255
4936 sta $5785
4938 show_complete_game_delay_loop:
4940 jsr wait_for_vsync
4942 dec $5785
4943 bne show_complete_game_no_message
4945 jsr colour1
4946 jsr show_input_message
4948 show_complete_game_no_message:
4950 lda #128
4951 ldx #0
4952 jsr $fff4
4953 cpx #0 ; fire button pressed?
4954 beq show_complete_game_no_joystick
4955 jmp show_complete_game_exit
4957 show_complete_game_no_joystick:
4959 ldx #157
4960 jsr check_key
4961 cpy #255
4962 bne show_complete_game_delay_loop
4964 show_complete_game_exit:
4965 clc
4966 rts
4968 check_high_scores:
4970 ; Start at the bottom of the table, moving scores down as necessary, and
4971 ; write in the current score at the appropriate place.
4973 lda #$86 ; current score
4974 sta $70
4975 lda #$57
4976 sta $71
4978 lda #$80
4979 sta $72
4980 lda #$51
4981 sta $73
4983 check_high_scores_loop:
4985 ldy #2
4986 check_high_scores_digits_loop:
4988 lda ($72),y
4989 cmp ($70),y ; existing score less than current score?
4990 bmi check_high_scores_move_down
4991 beq check_high_scores_digits_next ; keep checking digits if equal
4992 jmp check_high_scores_next
4994 check_high_scores_digits_next:
4995 dey
4996 bpl check_high_scores_digits_loop
4998 check_high_scores_next:
4999 clc
5000 lda $72
5001 adc #12
5002 sta $72
5003 cmp #$e0
5004 bne check_high_scores_loop
5006 ; The player's score didn't make it into the high score table.
5007 rts
5009 check_high_scores_move_down: ; $70,$71=pointer to current score
5010 ; $72,$73=pointer to old score
5012 ; The current score exceeded the existing entry. Make a note of the
5013 ; position in the high score table, insert the player's score, and take
5014 ; the old score
5016 lda $72 ; Record the position in the high score table of the
5017 sta $8d ; player's score.
5018 lda $73
5019 sta $8e
5021 lda #$e0
5022 sta $74
5023 lda #$51
5024 sta $75
5026 ldy #0
5027 insert_blank_player_name_loop:
5029 cpy #3
5030 bpl insert_blank_player_name_score_only
5032 lda ($70),y
5033 jmp insert_blank_player_name_store
5035 insert_blank_player_name_score_only:
5036 lda #32
5038 insert_blank_player_name_store:
5039 sta ($74),y
5040 iny
5041 cpy #12
5042 bne insert_blank_player_name_loop
5044 check_high_scores_move_down_loop:
5046 ldy #0
5047 check_high_scores_copy_score_and_name:
5049 lda ($72),y ; swap the current score with the score in the table
5050 tax
5051 lda ($74),y
5052 sta ($72),y
5053 txa
5054 sta ($74),y
5055 iny
5056 cpy #12
5057 bne check_high_scores_copy_score_and_name
5059 clc
5060 lda $72
5061 adc #12
5062 sta $72
5063 cmp #$e0
5064 bne check_high_scores_move_down_loop
5066 ; Draw a decorative room.
5068 jsr set_hidden_palette
5070 jsr make_empty_room
5072 lda #3
5073 sta $76
5074 sta $77
5075 jsr draw_top_line
5076 jsr draw_bottom_line
5077 jsr draw_left_line
5079 lda #0
5080 sta $77
5081 jsr draw_right_line
5083 jsr plot_room_tiles
5085 ; Add text characters to the room.
5086 jsr colour3
5088 lda #3 ; x
5089 sta $70
5090 lda #6 ; y
5091 sta $71
5093 lda #65
5094 sta $72
5096 ldx #3
5097 plot_text_characters_loop:
5099 jsr print_xy
5101 lda $70
5102 adc #4
5103 sta $70
5105 dex
5106 bpl plot_text_characters_next
5108 lda #3
5109 sta $70
5110 lda $71
5111 adc #3
5112 sta $71
5114 ldx #3
5116 plot_text_characters_next:
5118 inc $72
5119 lda $72
5120 cmp #91
5121 bne plot_text_characters_loop
5123 lda #11
5124 sta $70
5125 lda #95 ; _ representing a space
5126 sta $72
5127 jsr print_xy
5129 lda #15
5130 sta $70
5131 lda #60 ; < representing delete
5132 sta $72
5133 jsr print_xy
5135 ; Put the player in the centre of the room.
5136 jsr position_player_set_up_plotting
5138 lda #0 ; reset motion counter
5139 sta $578e
5141 lda #0 ; not on a character
5142 sta $578d
5144 lda #0 ; reset the level number so that the correct tiles are used
5145 sta $578a
5147 lda #3 ; cursor position in the high score entry held in $8d,$8e
5148 sta $8f
5150 jsr set_standard_palette
5152 ldx #0
5153 high_score_vdu_loop:
5155 lda high_score_vdu_bytes,x
5156 jsr $ffee
5157 inx
5158 cpx #39
5159 bne high_score_vdu_loop
5161 high_score_entry_loop:
5163 jsr reset_unplot_buffer
5164 jsr reset_plot_buffer
5166 jsr move_player
5167 ; Check if the player leaves the room.
5168 bcc high_score_entry_check_position
5169 jmp high_score_entry_after_loop
5171 high_score_entry_check_position:
5173 lda $5285 ; dx
5174 cmp #2
5175 beq high_score_entry_maybe_aligned
5176 jmp high_score_entry_not_aligned
5178 high_score_entry_maybe_aligned:
5180 lda $5282 ; y
5181 tay
5182 cmp #8
5183 bpl high_score_entry_not_aligned
5185 lda $5284 ; x
5186 tax
5187 cmp #9
5188 beq high_score_entry_not_aligned
5189 and #1
5190 beq high_score_entry_not_aligned
5192 lda $5283 ; dy
5193 cmp #2
5194 bmi high_score_entry_aligned
5195 jmp high_score_entry_not_aligned
5197 lda $5282 ; y again (don't apply the touching rule to the bottom
5198 cmp #7 ; row of characters)
5199 beq high_score_entry_not_aligned
5201 iny ; we are really touching the character below
5203 high_score_entry_aligned:
5205 lda $578d
5206 cmp #1
5207 beq high_score_entry_next
5209 ; The player is aligned with a letter.
5210 txa
5211 sec
5212 sbc #1
5213 lsr
5214 sta $7e ; record (x - 1) / 2
5216 tya ; recall y
5217 sec
5218 sbc #1
5219 asl
5220 asl ; (y - 1) * 4
5221 clc
5223 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5224 adc #65
5225 sta $7e ; record the ASCII code
5227 cmp #91
5228 bmi insert_character
5230 cmp #92
5231 beq delete_character
5233 ; Insert a space.
5234 lda #32
5235 sta $7e
5237 insert_character:
5238 lda $8f
5239 cmp #12
5240 bpl high_score_entry_pressed
5242 tay ; insert the character
5243 lda $7e
5244 sta ($8d),y
5245 jsr print_high_score_character
5247 inc $8f
5248 jmp high_score_entry_pressed
5250 delete_character:
5251 lda $8f
5252 cmp #4
5253 bmi high_score_entry_pressed
5255 cmp #12
5256 beq high_score_delete_previous_character
5258 tay
5259 lda #32 ; insert a space
5260 sta ($8d),y
5261 jsr print_high_score_character
5263 high_score_delete_previous_character:
5264 dec $8f
5265 lda $8f
5266 tay ; insert a space
5267 lda #32
5268 sta ($8d),y
5269 jsr print_high_score_character
5271 high_score_entry_pressed:
5272 lda #1
5273 sta $578d
5274 jmp high_score_entry_next
5276 high_score_entry_not_aligned:
5277 lda #0
5278 sta $578d
5280 high_score_entry_next:
5282 jsr wait_for_vsync
5283 jsr plot_buffer
5285 jmp high_score_entry_loop
5287 inc $578e
5288 clc
5290 high_score_entry_after_loop:
5291 clc
5293 jsr cls
5294 jsr set_hidden_palette
5296 rts
5298 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5300 cls:
5301 lda #12
5302 jsr $ffee
5303 rts
5305 colour1:
5306 lda #17
5307 jsr $ffee
5308 lda #1
5309 jsr $ffee
5310 rts
5312 colour3:
5313 lda #17
5314 jsr $ffee
5315 lda #3
5316 jsr $ffee
5317 rts
5319 print_high_score_character: ; A=ASCII code
5321 clc
5322 sta $72 ; store the character
5323 lda $8f
5324 adc #3
5325 sta $70 ; store the x position of the character
5326 lda #30
5327 sta $71
5328 ; Run on into the next routine.
5330 print_xy:
5332 lda #31
5333 jsr $ffee
5334 lda $70
5335 jsr $ffee
5336 lda $71
5337 jsr $ffee
5338 lda $72
5339 jsr $ffee
5340 rts
5342 disable_sound: ; X=1 (disable); X=0 (enable)
5344 lda #210
5345 ldy #0
5346 jmp $fff4 ; optimise away the rts
5348 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5349 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5351 start_new_game:
5353 ; Clear the screen.
5354 jsr cls
5356 ; Set the level.
5357 lda #0
5358 sta $578a
5360 ; Set the score.
5361 lda #0
5362 sta $5786
5363 lda #0
5364 sta $5787
5365 lda #0
5366 sta $5788
5368 ; Blank the screen now because it will be blanked before the room is shown
5369 ; and otherwise the strength bar will show briefly.
5370 jsr blank_screen
5372 ; Set the player's strength.
5373 lda #0
5374 sta $5784
5375 lda #64
5376 sta $70
5377 jsr add_strength
5379 ; Set the projectile type.
5380 lda #0
5381 sta $5789
5383 rts
5385 reset_player_position:
5387 lda #1 ; player
5388 sta $5280
5389 lda #6 ; down (first frame)
5390 sta $5281
5391 lda #4 ; y=4
5392 sta $5282
5393 lda #2 ; dy=2
5394 sta $5283
5395 lda #4 ; x=4
5396 sta $5284
5397 lda #3 ; dx=3
5398 sta $5285
5400 rts
5402 start_level:
5404 ; Clear the item/player flags.
5405 lda #0
5406 sta $5780
5408 ; Set current room.
5410 ldx $578a
5411 lda start_rooms_y,x
5412 sta $5782
5413 lda start_rooms_x,x
5414 sta $5783
5416 ; Set the player's position.
5418 jsr reset_player_position
5420 ; Reset the weapon counter.
5421 lda #0
5422 sta $577f
5424 ; Fill the treasure table with objects.
5425 ldx $578a ; level
5426 lda key_rooms,x
5427 sta $80
5429 ldx $578a ; level
5430 lda seeds,x
5431 adc #1
5432 and #31
5433 sta $7c
5434 clc
5435 lda seeds,x
5436 adc #2
5437 and #31
5438 sta $7d
5439 clc
5441 lda $578a ; create an upper limit on the weapon type found in this level
5442 adc #2
5443 sta $5781
5444 clc
5446 lda #$00
5447 sta $8e
5448 lda #$52
5449 sta $8f
5451 ldy #0
5452 start_level_add_treasure_loop:
5454 cpy $80 ; check for the key room
5455 bne start_level_add_treasure_item
5457 lda #5 ; the value to store is type + 1
5458 jmp start_level_add_treasure_store
5460 start_level_add_treasure_item:
5461 clc
5462 jsr unlimited_values
5463 and #$0f
5464 cmp #0
5465 beq start_level_add_treasure_none
5467 clc
5468 sta $8c
5469 tya
5470 adc $8c
5471 and #31
5472 clc
5473 tax
5474 lda treasure_table,x
5476 cmp #4
5477 bmi start_level_add_treasure_weapon
5479 clc
5480 adc #1
5481 jmp start_level_add_treasure_store
5483 start_level_add_treasure_weapon:
5485 ; Only add weapons with types that equal the level number or exceed it
5486 ; by one.
5487 cmp $5781
5488 bcs start_level_add_treasure_none
5490 clc
5491 adc #1 ; store values 0-8 as values 1-9
5492 jmp start_level_add_treasure_store
5494 start_level_add_treasure_none:
5495 clc
5496 lda #0 ; do not put treasure in this room
5498 start_level_add_treasure_store:
5499 clc
5500 sta ($8e),y ; add the item to the table
5502 iny
5503 cpy #121
5504 bmi start_level_add_treasure_loop
5506 ; Write the status text.
5507 ldx #0
5508 write_status_text_loop:
5509 lda status_vdu_bytes,x
5510 jsr $ffee
5511 inx
5512 cpx #25
5513 bmi write_status_text_loop
5515 jsr write_score
5517 clc
5518 rts
5520 main:
5521 jsr init
5523 main_loop:
5525 jsr show_title
5527 jsr start_new_game
5529 level_loop:
5531 jsr start_level
5533 game_loop:
5535 jsr remove_characters
5537 jsr reset_unplot_buffer
5538 jsr reset_plot_buffer
5540 lda $5782 ; current room (y)
5541 sta $78
5542 lda $5783 ; current room (x)
5543 sta $79
5544 jsr plot_room
5545 jsr set_room_palette
5546 jsr create_enemy_positions
5547 jsr add_treasure
5549 jsr plot_the_player
5551 lda #0 ; reset projectile counter
5552 sta $578d
5554 lda #0 ; reset motion counter
5555 sta $578e
5557 lda #63 ; reset generation counter
5558 sta $578f
5560 room_loop:
5561 jsr reset_unplot_buffer
5562 jsr reset_plot_buffer
5564 jsr move_characters
5565 jsr move_projectile
5567 lda $5780 ; is player out of strength ($40), leaving the
5568 and #$c2 ; level (0x80) or completing the game (0x02)?
5569 beq room_loop_player_move
5570 clc
5572 dec $5785 ; leave the loop when the delay
5573 bne room_loop_delay_next
5574 jmp after_room_loop ; counter is about to reset
5576 room_loop_delay_next:
5578 lda $5281 ; leave the loop when the player demise
5579 cmp #11 ; animation has finished
5580 beq room_loop_after_player_move
5581 clc
5583 lda $578e
5584 and #7
5585 bne room_loop_after_player_move
5587 lda $5780 ; skip the animation if leaving the level or
5588 and #$82 ; completing the game
5589 bne room_loop_after_player_move
5591 ; Show the demise animation when appropriate.
5593 lda #$80
5594 sta $74
5595 lda #$52
5596 sta $75
5598 jsr unplot_character
5600 inc $5281
5601 jsr plot_character
5602 jmp room_loop_after_player_move
5604 room_loop_player_move:
5606 ; See if it is time to generate a new enemy.
5607 lda $578f
5608 cmp #0
5609 bne no_emerge_characters
5610 jsr emerge_characters
5612 no_emerge_characters:
5613 clc
5615 jsr check_fire_key
5616 jsr move_player
5617 bcs after_room_loop ; check if we are leaving the level
5619 room_loop_after_player_move:
5620 clc
5622 lda #19
5623 jsr $fff4
5624 jsr plot_buffer
5626 ldx #143 ; Escape key check
5627 jsr check_key
5628 cpy #255
5629 beq main_loop_play_again
5631 ldx #174 ; S key check
5632 jsr check_key
5633 cpy #255
5634 bne no_set_sound
5636 ldx #0
5637 jsr disable_sound
5638 jmp after_sound_checks
5640 no_set_sound:
5642 ldx #239 ; Q key check
5643 jsr check_key
5644 cpy #255
5645 bne after_sound_checks
5647 ldx #1
5648 jsr disable_sound
5650 after_sound_checks:
5652 ldx #200 ; P key check
5653 jsr check_key
5654 cpy #255
5655 bne no_pause
5657 pause_loop:
5659 ldx #201 ; O key check
5660 jsr check_key
5661 cpy #255
5662 bne pause_loop
5664 no_pause:
5665 clc
5667 lda $578d
5668 cmp #0
5669 beq room_loop_no_update_projectile_counter
5671 dec $578d
5673 room_loop_no_update_projectile_counter:
5675 dec $578f ; update generation counter
5677 inc $578e ; update motion counter
5678 clc
5679 jmp room_loop
5681 after_room_loop:
5682 clc
5684 lda $5780
5685 and #$80
5686 bne exit_level
5688 lda $5780
5689 and #$40
5690 bne game_over
5692 lda $5780
5693 and #$02
5694 bne complete_game
5696 jmp game_loop
5698 exit_level:
5700 jsr show_end_of_level_screen
5702 inc $578a
5703 clc
5704 jmp level_loop
5706 game_over:
5707 jsr show_game_over
5708 jmp main_loop_play_again
5710 complete_game:
5711 jsr show_end_of_level_screen
5712 jsr show_complete_game
5713 jmp main_loop_play_again
5715 main_loop_play_again:
5716 jsr cls
5718 ; Check the score against the high scores.
5719 jsr check_high_scores
5721 jmp main_loop
5723 exit:
5724 clc
5725 rts
