junglejourney

view mapcode.oph @ 240:42c8701f4bc7

Fixed an error in a collision detection mask, as reported by Kees.
author David Boddie <david@boddie.org.uk>
date Thu Oct 11 19:58:04 2012 +0200
parents bcad03cec5b9
children 94246db7b5e5
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 plot_tile: ; $7b=tile number
792 ; 1 = flowers/decoration
793 ; 2 = trees/wall
794 ; 3 = trees
795 ; 4 = exit
796 ; 5 = open exit
797 ; 6 = final exit (left)
798 ; 7 = final exit (right)
799 ; $72,$73=screen position
801 lda $7b
802 cmp #0
803 bne plot_tile_sprite
804 clc
805 jmp plot_blank ; optimise away the rts
807 plot_tile_sprite:
808 clc
809 tax
810 dex
811 lda tile_addresses_low,x
812 sta $70
813 lda tile_addresses_high,x
814 sta $71
816 lda $7b
817 cmp #4
818 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
820 clc
821 lda $578a
822 and #3 ; change the tile set for later levels
823 tax
825 plot_not_blank_add_loop:
827 cpx #2
828 bne plot_not_blank_not_2
829 dex
830 jmp plot_not_blank_not_0
832 plot_not_blank_not_2:
833 beq plot_not_blank_add_loop
834 cpx #0
836 plot_not_blank_not_0:
837 beq plot_not_blank_after_add_loop
838 clc
839 lda $70
840 adc #$20
841 sta $70
842 lda $71
843 adc #$01
844 sta $71
845 dex
846 jmp plot_not_blank_add_loop
848 plot_not_blank_after_add_loop:
849 clc
850 jsr plot
851 rts
853 plot_room: ; $78,$79 = i,j (from $5782,$5783)
854 jsr blank_screen
856 lda $5782
857 sta $78
858 lda $5783
859 sta $79
861 jsr make_room
862 ; Run on into the next piece of code.
864 plot_room_tiles:
866 lda #$80
867 sta $72
868 lda #$5a
869 sta $73 ; $72,$73 = screen position
871 lda #0
872 sta $7a
873 row_loop:
875 lda #9
876 sta $76
878 column_loop:
879 lda $7a
880 tax
881 lda $579c,x
882 sta $7b
883 jsr plot_tile
885 inc $7a
886 lda $76
887 sec
888 sbc #1
889 sta $76
890 clc
891 cmp #0
892 bpl column_loop
894 clc
896 lda $72
897 adc #$80
898 sta $72
899 lda $73
900 adc #$02
901 sta $73
902 clc
903 cmp #$80
904 beq end_rows
906 jmp row_loop
908 end_rows:
909 rts
911 set_room_palette: ; $78=i; $79=j
913 lda #1
914 sta $70
915 lda $78
916 eor $79
917 and #3
918 tax
919 lda room_palettes,x
920 sta $71
921 jsr set_palette
923 jsr set_core_palette
924 rts
926 room_palettes: .byte 1, 6, 5, 7
928 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
930 plot8x24_y0: ; $70,$71=source address
931 ; $72,$73=destination address
933 ldx #2
935 plot8x24_y0_loop:
937 ldy #15
939 plotloop8x24_y0_0:
940 lda ($70),y
941 eor ($72),y
942 sta ($72),y
943 dey
944 bpl plotloop8x24_y0_0
946 dex
947 bmi plot8x24_y0_exit
949 lda $72
950 adc #$40
951 sta $72
952 lda $73
953 adc #$01
954 sta $73
955 clc
957 lda $70
958 adc #16
959 sta $70
960 lda $71
961 adc #0
962 sta $71
963 clc
965 jmp plot8x24_y0_loop
967 plot8x24_y0_exit:
968 clc
969 jmp plot_buffer_loop_next
972 plot8x8_y1: ; $70,$71=source address
973 ; $72,$73=destination address
974 lda #2
975 sta $7e
976 lda #10
977 sta $7f
979 lda #0 ; plotting 1 8x8 piece
980 sta $8a
982 jmp plot8x24_y123 ; optimise away the rts
984 plot8x24_y1: ; $70,$71=source address
985 ; $72,$73=destination address
986 lda #2
987 sta $7e
988 lda #10
989 sta $7f
991 lda #2 ; plotting 3 8x8 pieces
992 sta $8a
994 jmp plot8x24_y123 ; optimise away the rts
996 plot8x8_y2: ; $70,$71=source address
997 ; $72,$73=destination address
998 lda #4
999 sta $7e
1000 lda #12
1001 sta $7f
1003 lda #0 ; plotting 1 8x8 piece
1004 sta $8a
1006 jmp plot8x24_y123 ; optimise away the rts
1008 plot8x24_y2: ; $70,$71=source address
1009 ; $72,$73=destination address
1010 lda #4
1011 sta $7e
1012 lda #12
1013 sta $7f
1015 lda #2 ; plotting 3 8x8 pieces
1016 sta $8a
1018 jmp plot8x24_y123 ; optimise away the rts
1020 plot8x8_y3: ; $70,$71=source address
1021 ; $72,$73=destination address
1022 lda #6
1023 sta $7e
1024 lda #14
1025 sta $7f
1027 lda #0 ; plotting 1 8x8 piece
1028 sta $8a
1030 jmp plot8x24_y123 ; optimise away the rts
1032 plot8x24_y3: ; $70,$71=source address
1033 ; $72,$73=destination address
1034 lda #6
1035 sta $7e
1036 lda #14
1037 sta $7f
1039 lda #2 ; plotting 3 8x8 pieces
1040 sta $8a
1042 ; Run on into the next routine.
1044 plot8x24_y123: ; $70,$71=source address
1045 ; $72,$73=destination address
1046 ; $7e=offset into source data for first column
1047 ; $7f=offset into source data for second column
1049 plot8x24_y123_loop:
1051 ldx #0
1052 plot8x24_y123_upper_loop_outer:
1054 ldy $7e,x
1055 lda plot_upper_offsets,x
1056 sta $89
1058 plot8x24_y123_upper_loop_inner: ; plot the first column until
1059 dey ; we reach the start
1060 cpy $89
1061 bmi plot8x24_y123_upper_loop_inner_endloop
1062 lda ($70),y
1063 eor ($72),y
1064 sta ($72),y
1065 jmp plot8x24_y123_upper_loop_inner
1067 plot8x24_y123_upper_loop_inner_endloop:
1068 clc
1070 inx
1071 cpx #2
1072 bne plot8x24_y123_upper_loop_outer
1074 clc
1075 lda $72 ; move the destination pointer to refer to the next line
1076 adc #$38
1077 sta $72
1078 lda $73
1079 adc #$01
1080 sta $73
1081 clc
1083 ldx #0
1084 plot8x24_y123_lower_loop_outer:
1086 lda plot_lower_offsets,x
1087 tay
1088 lda $7e,x
1089 sta $89
1091 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1092 lda ($70),y ; offset for the column
1093 eor ($72),y
1094 sta ($72),y
1095 dey
1096 cpy $89
1097 bpl plot8x24_y123_lower_loop_inner
1099 inx
1100 cpx #2
1101 bne plot8x24_y123_lower_loop_outer
1103 dec $8a
1104 bmi plot8x24_y123_exit
1106 clc
1107 lda $70 ; update the source pointer to refer to the next piece
1108 adc #16 ; of sprite data
1109 sta $70
1110 lda $71
1111 adc #0
1112 sta $71
1113 clc
1115 lda $72 ; update the destination pointer to point to the next
1116 adc #8 ; space
1117 sta $72
1118 lda $73
1119 adc #0
1120 sta $73
1121 clc
1123 jmp plot8x24_y123_loop
1125 plot8x24_y123_exit:
1126 clc
1127 jmp plot_buffer_loop_next
1129 plot16x16_y0: ; $70,$71=source address
1130 ; $72,$73=destination address
1131 ldy #31
1133 plotloop16x16_y0_0:
1134 lda ($70),y
1135 eor ($72),y
1136 sta ($72),y
1137 dey
1138 bpl plotloop16x16_y0_0
1139 clc
1141 lda $72
1142 adc #$20
1143 sta $72
1144 lda $73
1145 adc #$01
1146 sta $73 ; 0x140 - 32
1147 clc
1149 ldy #63
1151 plotloop16x16_y0_1:
1152 lda ($70),y
1153 eor ($72),y
1154 sta ($72),y
1155 dey
1156 cpy #32
1157 bpl plotloop16x16_y0_1
1158 clc
1160 jmp plot_buffer_loop_next
1162 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1164 plot16x16_y1: ; $70,$71=source address
1165 ; $72,$73=destination address
1167 lda #2
1168 sta $7e
1169 lda #10
1170 sta $7f
1171 lda #18
1172 sta $80
1173 lda #26
1174 sta $81
1175 jmp plot16x16_y123 ; optimise away the rts
1177 plot16x16_y2: ; $70,$71=source address
1178 ; $72,$73=destination address
1180 lda #4
1181 sta $7e
1182 lda #12
1183 sta $7f
1184 lda #20
1185 sta $80
1186 lda #28
1187 sta $81
1188 jmp plot16x16_y123 ; optimise away the rts
1190 plot16x16_y3: ; $70,$71=source address
1191 ; $72,$73=destination address
1193 lda #6
1194 sta $7e
1195 lda #14
1196 sta $7f
1197 lda #22
1198 sta $80
1199 lda #30
1200 sta $81
1201 ; Run on into the next routine.
1203 plot16x16_y123: ; $70,$71=source address
1204 ; $72,$73=destination address
1205 ; $7e=offset into source data for first column
1206 ; $7f=offset into source data for second column
1207 ; $80=offset into source data for third column
1208 ; $81=offset into source data for fourth column
1210 lda #1
1211 sta $8a
1213 plot16x16_y123_loop:
1215 ldx #0
1216 plot16x16_y123_upper_loop_outer:
1218 ldy $7e,x
1219 lda plot_upper_offsets,x
1220 sta $89
1222 plot16x16_y123_upper_loop_inner:
1224 dey
1225 cpy $89
1226 bmi plot16x16_y123_upper_loop_inner_endloop
1227 lda ($70),y
1228 eor ($72),y
1229 sta ($72),y
1230 jmp plot16x16_y123_upper_loop_inner
1232 plot16x16_y123_upper_loop_inner_endloop:
1233 clc
1235 inx
1236 cpx #4
1237 bne plot16x16_y123_upper_loop_outer
1239 clc
1240 lda $72 ; move the destination pointer to refer to the next line
1241 adc #$38
1242 sta $72
1243 lda $73
1244 adc #$01
1245 sta $73
1246 clc
1248 ldx #0
1249 plot16x16_y123_lower_loop_outer:
1251 lda plot_lower_offsets,x
1252 tay
1253 lda $7e,x
1254 sta $89
1256 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1257 lda ($70),y ; for the column
1258 eor ($72),y
1259 sta ($72),y
1260 dey
1261 cpy $89
1262 bpl plot16x16_y123_lower_loop_inner
1264 inx
1265 cpx #4
1266 bne plot16x16_y123_lower_loop_outer
1268 dec $8a
1269 bmi plot16x16_y123_exit
1271 clc
1272 lda $70 ; update the source pointer to refer to the next piece
1273 adc #32 ; of sprite data
1274 sta $70
1275 lda $71
1276 adc #0
1277 sta $71
1278 clc
1280 lda $72 ; update the destination pointer to point to the next
1281 adc #8 ; space
1282 sta $72
1283 lda $73
1284 adc #0
1285 sta $73
1286 clc
1288 jmp plot16x16_y123_loop
1290 plot16x16_y123_exit:
1291 clc
1292 jmp plot_buffer_loop_next
1294 plot_upper_offsets: .byte 0, 8, 16, 24
1295 plot_lower_offsets: .byte 7, 15, 23, 31
1297 plot8x8_y0: ; $70,$71=source address
1298 ; $72,$73=destination address
1299 ldy #15
1301 plotloop8x8_y0_0:
1302 lda ($70),y
1303 eor ($72),y
1304 sta ($72),y
1305 dey
1306 bpl plotloop8x8_y0_0
1307 clc
1309 jmp plot_buffer_loop_next
1312 check_key: ; x=key code
1313 lda #129 ; returns y=255 or 0
1314 ldy #255
1315 jsr $fff4
1316 rts
1318 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1319 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1320 screen_subrows_low: .byte $00,$06,$44,$82
1321 screen_subrows_high: .byte $00,$00,$01,$02
1323 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1324 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1325 screen_subcolumns_low: .byte $00,$08,$10,$18
1327 unplot_character: ; $74,$75=character address
1329 lda $82 ; store the unplot buffer address in $78,$79
1330 sta $78
1331 lda $83
1332 sta $79
1333 jsr plot_character_sprite
1334 lda $78
1335 sta $82 ; update the latest space in the unplot buffer
1336 rts
1338 plot_character: ; $74,$75=character address
1340 lda $84 ; store the plot buffer address in $78,$79
1341 sta $78
1342 lda $85
1343 sta $79
1344 jsr plot_character_sprite
1345 lda $78
1346 sta $84 ; update the latest space in the plot buffer
1347 rts
1349 plot_character_sprite: ; $74,$75=character address
1350 ; $78,$79=unplot/plot buffer address
1352 ldy #0
1353 lda ($74),y
1354 cmp #0
1355 bne plot_characters_read_character
1356 jmp plot_characters_next
1358 plot_characters_read_character:
1359 clc
1361 sta $77 ; temporarily store the object type
1363 ; Use lookup tables to load the offsets into the sprite.
1365 ; Direction
1366 iny
1367 lda ($74),y
1368 sta $80 ; temporarily store the direction
1370 ; y
1371 iny
1372 lda ($74),y
1373 tax
1374 lda screen_rows_low,x
1375 sta $72
1376 lda screen_rows_high,x
1377 sta $73
1378 clc
1380 ; dy
1381 iny
1382 lda ($74),y
1383 sta $76
1384 tax
1385 lda screen_subrows_low,x
1386 adc $72
1387 sta $72
1388 lda screen_subrows_high,x
1389 adc $73
1390 sta $73
1391 clc
1393 ; x
1394 iny
1395 lda ($74),y
1396 tax
1397 lda screen_columns_low,x
1398 adc $72
1399 sta $72
1400 lda screen_columns_high,x
1401 adc $73
1402 sta $73
1403 clc
1405 ; dx
1406 iny
1407 lda ($74),y
1408 tax
1409 lda screen_subcolumns_low,x
1410 adc $72
1411 sta $72
1412 clc
1414 lda $77
1415 cmp #1
1416 bne plot_characters_loop_not_player
1418 ; Plot 8x24 sprites (player)
1420 ldx $80
1421 lda player_direction_chars_low,x
1422 sta $70
1423 lda player_direction_chars_high,x
1424 sta $71
1426 ; Use the dy value to determine which plotting routine to use.
1428 ldy #0
1429 ldx $76
1430 lda plot_routine_indices_8x24,x
1432 sta ($78),y
1433 jmp plot_characters_stored
1436 plot_characters_loop_not_player:
1437 cmp #2
1438 bne plot_characters_loop_not_projectile
1440 ; Plot 8x8 sprites (projectiles)
1442 lda $80
1443 and #7
1444 tax
1445 lda projectile_chars_low,x
1446 sta $70
1447 lda #projectile_chars_high
1448 sta $71
1450 ; Use the dy value to determine which plotting routine to use.
1452 ldy #0
1453 ldx $76
1454 lda plot_routine_indices_8x8,x
1456 sta ($78),y
1457 jmp plot_characters_stored
1460 plot_characters_loop_not_projectile:
1461 cmp #3
1462 bne plot_characters_loop_not_explosion
1464 ; Plot 16x16 sprites (emerging, explosions)
1466 ; Select the sprites to use.
1468 lda $80
1469 and #7 ; only keep the bits required to find the correct sprite
1470 clc
1471 tax
1472 lda emerge_explode_chars_low,x
1473 sta $70
1474 lda emerge_explode_chars_high,x
1475 sta $71
1477 jmp plot_characters_16x16
1479 plot_characters_loop_not_explosion:
1480 cmp #4
1481 bne plot_characters_loop_not_item
1483 ; Plot 16x16 sprites (items)
1485 ; Select the sprites to use.
1487 lda $80
1488 and #$0f ; only keep the bits required to find the correct sprite
1489 clc
1490 tax
1491 lda item_chars_low,x
1492 sta $70
1493 lda item_chars_high,x
1494 sta $71
1496 jmp plot_characters_16x16
1498 plot_characters_loop_not_item:
1499 cmp #8
1500 bmi plot_characters_loop_not_enemy
1502 ; Plot 16x16 sprites (enemies)
1504 ; Select the set of sprites to use.
1506 and #$70
1507 lsr
1508 lsr
1509 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1510 clc
1511 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1513 lda $80
1514 and #7 ; keep the animation bits
1515 tax
1516 lda enemy_direction_chars_low,x
1517 sta $70
1518 lda enemy_direction_chars_high,x
1519 adc $71
1520 sta $71
1522 plot_characters_16x16:
1524 ; Use the dy value to determine which plotting routine to use.
1526 ldy #0
1527 ldx $76
1528 lda plot_routine_indices_16x16,x
1530 sta ($78),y
1532 plot_characters_stored:
1534 iny
1535 lda $70
1536 sta ($78),y
1537 iny
1538 lda $71
1539 sta ($78),y
1540 iny
1541 lda $72
1542 sta ($78),y
1543 iny
1544 lda $73
1545 sta ($78),y
1547 clc
1548 lda $78
1549 adc #12
1550 sta $78
1552 plot_characters_loop_not_enemy:
1554 plot_characters_next:
1556 lda #255 ; terminate this stream of entries in the plot buffer
1557 ldy #0
1558 sta ($78),y
1559 clc
1560 rts
1562 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1563 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1564 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1566 reset_plot_buffer:
1567 lda #$06 ; reset the index into the plot buffer
1568 sta $84
1569 lda #$53
1570 sta $85
1572 lda #255 ; terminate the plot list
1573 ldy #0
1574 sta ($84),y
1575 rts
1577 reset_unplot_buffer:
1578 lda #$00 ; reset the index into the plot buffer
1579 sta $82
1580 lda #$53
1581 sta $83
1583 lda #255 ; terminate the unplot list
1584 ldy #0
1585 sta ($82),y
1586 rts
1588 plot_buffer_types_low: .byte <plot_buffer_loop_next
1589 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1590 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1591 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1593 plot_buffer_types_high: .byte >plot_buffer_loop_next
1594 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1595 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1596 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1598 plot_buffer:
1600 lda #$00
1601 sta $84
1602 lda #$53
1603 sta $85
1605 lda #6
1606 sta $88
1608 plot_buffer_loop:
1610 ldy #0
1611 lda ($84),y
1612 cmp #255
1613 beq plot_buffer_loop_skip
1615 clc
1616 tax
1617 lda plot_buffer_types_low,x
1618 sta $86
1619 lda plot_buffer_types_high,x
1620 sta $87
1622 iny
1623 lda ($84),y
1624 sta $70
1626 iny
1627 lda ($84),y
1628 sta $71
1630 iny
1631 lda ($84),y
1632 sta $72
1634 iny
1635 lda ($84),y
1636 sta $73
1638 jmp ($86) ; returns to plot_buffer_loop_next
1640 plot_buffer_loop_skip:
1642 lda $88
1643 cmp #12
1644 beq plot_buffer_exit ; both unplot and plot lists have terminated
1646 lda #12
1647 sta $88
1648 lda $84
1649 adc #6
1650 sta $84
1651 jmp plot_buffer_loop
1653 plot_buffer_loop_next:
1654 clc
1656 lda $84
1657 adc $88
1658 sta $84
1659 jmp plot_buffer_loop
1661 plot_buffer_exit:
1662 clc
1663 rts
1665 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1667 animate_player_left:
1669 ; Set the direction and toggle the animation bit.
1671 lda $5281
1672 and #1
1673 eor #1 ; toggle animation flag
1674 sta $5281 ; left (directional bits are 0)
1676 jsr plot_character
1677 rts
1679 animate_player_right:
1681 ; Set the direction and toggle the animation bit.
1683 lda $5281
1684 and #1 ; remove direction information (result is 0)
1685 eor #1 ; toggle animation flag
1686 ora #2 ; right
1687 sta $5281
1689 jsr plot_character
1690 rts
1692 animate_player_up:
1694 ; Set the direction and toggle the animation bit.
1696 lda $5281
1697 and #1 ; remove direction information (result is 0)
1698 eor #1 ; toggle animation flag
1699 ora #4 ; up
1700 sta $5281
1702 jsr plot_character
1703 rts
1705 animate_player_down:
1707 ; Set the direction and toggle the animation bit.
1709 lda $5281
1710 and #1 ; remove direction information (result is 0)
1711 eor #1 ; toggle animation flag
1712 ora #6 ; down
1713 sta $5281
1715 jsr plot_character
1716 rts
1718 joystick_abs:
1720 cmp #160
1721 bcc joystick_abs_next1
1723 sec
1724 sbc #128
1725 clc
1726 rts
1728 joystick_abs_next1:
1730 cmp #97
1731 bcs joystick_abs_next2
1733 sta $81
1734 lda #128
1735 sec
1736 sbc $81
1737 clc
1738 rts
1740 joystick_abs_next2:
1741 lda #0
1742 clc
1743 rts
1745 read_joystick:
1747 lda #128
1748 ldx #2
1749 jsr $fff4
1750 tya
1751 sta $8e ; store the original vertical value
1753 jsr joystick_abs
1754 sta $8f ; absolute vertical value
1756 lda #128
1757 ldx #1
1758 jsr $fff4
1759 tya
1760 sta $8d ; store the original horizontal value
1762 jsr joystick_abs
1763 cmp #0
1764 beq read_joystick_vertical_check
1765 cmp $8f
1766 bcc read_joystick_vertical_check
1768 lda $8d
1769 cmp #128
1770 bcs read_joystick_left
1771 jmp move_player_right
1773 read_joystick_left:
1774 jmp move_player_left
1776 read_joystick_vertical_check:
1778 lda $8f
1779 cmp #0
1780 bne read_joystick_vertical
1781 clc
1782 rts
1784 read_joystick_vertical:
1786 lda $8e
1787 cmp #128
1788 bcs read_joystick_up
1789 jmp move_player_down
1791 read_joystick_up:
1792 jmp move_player_up
1794 move_player:
1796 lda $578e
1797 and #1
1798 beq move_player_allowed
1800 clc
1801 rts
1803 move_player_allowed:
1805 lda #$80 ; set up the address of the player character
1806 sta $74
1807 lda #$52
1808 sta $75
1810 ; Handle joystick
1812 lda $577e
1813 cmp #0
1814 beq move_player_handle_left_key
1815 jmp read_joystick
1817 move_player_handle_left_key:
1819 ; Handle the left key.
1821 ldx #158 ; (Z)
1822 jsr check_key
1823 cpy #255
1824 beq move_player_left
1825 jmp move_player_check_right_key
1827 move_player_left:
1829 lda $5285 ; read dx
1830 cmp #0
1831 beq move_player_left_check_x
1833 jsr unplot_character ; unplot the player character
1834 dec $5285
1835 clc
1836 jmp animate_player_left ; optimise away the rts
1838 move_player_left_check_x: ; Check the x offset.
1840 lda $5284
1841 cmp #0
1842 beq move_player_leave_room_left
1844 clc
1845 tay
1846 dey ; x - 1
1847 lda $5282 ; load the y offset
1848 tax ; as an index
1849 lda room_row_offsets_low,x ; read the address of the row
1850 sta $70
1851 lda #$57
1852 sta $71
1853 lda ($70),y ; load the tile to the left
1855 cmp #5 ; check for the open exit or final exit
1856 bmi move_player_not_left_exit1
1857 jmp try_to_exit_level ; optimise away the rts
1859 move_player_not_left_exit1:
1860 cmp #0
1861 beq move_player_left_check_dy
1862 jmp move_player_not_horizontal
1864 move_player_left_check_dy:
1866 lda $5283 ; dy
1867 cmp #0
1868 beq move_player_allow_left
1870 clc
1871 lda $70 ; dy > 0 so we need to check another tile
1872 adc #10
1873 sta $70
1874 lda ($70),y ; load the tile below and to the left
1876 cmp #5 ; check for the open exit or final exit
1877 bmi move_player_not_left_exit2
1878 jmp try_to_exit_level ; optimise away the rts
1880 move_player_not_left_exit2:
1881 cmp #0
1882 beq move_player_allow_left
1883 jmp move_player_not_horizontal
1885 move_player_allow_left:
1886 tya
1887 sta $81 ; temporary
1888 jsr unplot_character ; unplot the player character
1889 lda $81
1890 sta $5284 ; store the new room x offset
1891 lda #3
1892 sta $5285 ; dx = 3
1893 clc
1894 jmp animate_player_left ; optimise away the rts
1896 move_player_leave_room_left:
1897 sec
1898 lda $5783
1899 sbc #1
1900 sta $5783
1901 clc
1903 ; Set the player's position on the right of the screen.
1905 ; No need to unplot.
1907 lda #9 ; x = 9
1908 sta $5284
1909 lda #2 ; dx = 2
1910 sta $5285
1912 jsr animate_player_left
1913 sec ; indicate to the calling routine that the player
1914 rts ; has left the room
1916 move_player_check_right_key:
1918 ; Handle the right key.
1920 ldx #189 ; (X)
1921 jsr check_key
1922 cpy #255
1923 beq move_player_right
1924 jmp move_player_not_horizontal
1926 move_player_right:
1928 lda $5285 ; read dx
1929 cmp #2
1930 beq move_player_right_check_x
1931 cmp #3
1932 beq move_player_right_tile
1934 jsr unplot_character ; unplot the player character
1935 inc $5285
1936 clc
1937 jmp animate_player_right ; optimise away the rts
1939 move_player_right_check_x: ; Check the x offset.
1941 lda $5284
1942 cmp #9
1943 beq move_player_leave_room_right
1945 clc
1946 tay
1947 iny ; x + 1
1948 lda $5282 ; load the y offset
1949 tax ; as an index
1950 lda room_row_offsets_low,x ; read the address of the row
1951 sta $70
1952 lda #$57
1953 sta $71
1954 lda ($70),y ; load the tile to the right
1956 cmp #5 ; check for the open exit or final exit
1957 bmi move_player_not_right_exit1
1958 jmp try_to_exit_level ; optimise away the rts
1960 move_player_not_right_exit1:
1961 cmp #0
1962 bne move_player_not_horizontal
1964 lda $5283 ; dy
1965 cmp #0
1966 beq move_player_allow_right
1968 clc ; dy > 0 so we need to check another tile
1969 lda $70
1970 adc #10
1971 sta $70
1972 lda ($70),y ; load the tile below and to the right
1974 cmp #5 ; check for the open exit or final exit
1975 bmi move_player_not_right_exit2
1976 jmp try_to_exit_level ; optimise away the rts
1978 move_player_not_right_exit2:
1979 cmp #0
1980 bne move_player_not_horizontal
1982 move_player_allow_right:
1984 jsr unplot_character ; unplot the player character
1985 inc $5285 ; update dx
1986 clc
1987 jmp animate_player_right ; optimise away the rts
1989 move_player_right_tile:
1991 jsr unplot_character ; unplot the player character
1992 inc $5284 ; store the new room x offset
1993 lda #0
1994 sta $5285 ; dx = 0
1995 clc
1996 jmp animate_player_right ; optimise away the rts
1998 move_player_leave_room_right:
1999 clc
2000 inc $5783
2001 clc
2003 ; Set the player's position on the left of the screen.
2005 ; No need to unplot.
2007 lda #0 ; x = 0
2008 sta $5284
2009 lda #0 ; dx = 0
2010 sta $5285
2012 jsr animate_player_right
2013 sec ; indicate to the calling routine that the
2014 rts ; player has left the room
2016 move_player_not_horizontal:
2017 lda $577e
2018 cmp #0
2019 beq move_player_handle_up_key
2020 jmp read_joystick_vertical_check
2022 move_player_handle_up_key:
2024 ; Handle the up key.
2026 ldx #183 ; (:)
2027 jsr check_key
2028 cpy #255
2029 beq move_player_up
2031 ; Handle the down key.
2033 ldx #151 ; (/)
2034 jsr check_key
2035 cpy #255
2036 beq move_player_down
2037 jmp move_player_not_vertical
2039 move_player_up:
2041 lda $5283 ; read dy
2042 cmp #0
2043 beq move_player_up_check_y
2045 jsr unplot_character ; unplot the player character
2046 dec $5283
2047 clc
2048 jmp animate_player_up ; optimise away the rts
2050 move_player_up_check_y: ; Check the y offset.
2052 lda $5282
2053 cmp #0
2054 beq move_player_leave_room_up
2056 tax ; use the y offset as an index
2057 dex ; y - 1
2058 ldy $5284 ; load the x offset
2059 lda room_row_offsets_low,x ; read the address of the row
2060 sta $70
2061 lda #$57
2062 sta $71
2063 lda ($70),y ; load the tile above
2065 cmp #5 ; check for the open exit or final exit
2066 bmi move_player_not_up_exit1
2067 jmp try_to_exit_level ; optimise away the rts
2069 move_player_not_up_exit1:
2070 cmp #0
2071 beq move_player_up_check_dx
2072 clc
2073 rts
2075 move_player_up_check_dx:
2077 lda $5285 ; dx
2078 cmp #3
2079 bmi move_player_allow_up
2081 clc ; dx > 2 so we need to check another tile
2082 iny
2083 lda ($70),y ; load the tile above and to the right
2085 cmp #5 ; check for the open exit or final exit
2086 bmi move_player_not_up_exit2
2087 jmp try_to_exit_level ; optimise away the rts
2089 move_player_not_up_exit2:
2090 cmp #0
2091 beq move_player_allow_up
2092 clc
2093 rts
2095 move_player_allow_up:
2096 txa
2097 sta $81 ; temporary
2098 jsr unplot_character ; unplot the player character
2099 lda $81
2100 sta $5282 ; store the new room y offset
2101 lda #3
2102 sta $5283 ; dy = 3
2103 clc
2104 jmp animate_player_up ; optimise away the rts
2106 move_player_leave_room_up:
2107 sec
2108 lda $5782
2109 sbc #1
2110 sta $5782
2111 clc
2113 ; Set the player's position on the bottom of the screen.
2115 ; No need to unplot.
2117 lda #9 ; y = 9
2118 sta $5282
2119 lda #0 ; dy = 0
2120 sta $5283
2122 jsr animate_player_up
2123 sec ; indicate to the calling routine that the player
2124 rts ; has left the room
2126 move_player_down:
2128 lda $5283 ; read dy
2129 cmp #0
2130 beq move_player_down_check_y
2131 cmp #3
2132 beq move_player_down_tile
2134 jsr unplot_character ; unplot the player character
2135 inc $5283 ; 0 <= dy < 3
2136 clc
2137 jmp animate_player_down ; optimise away the rts
2139 move_player_down_check_y: ; Check the y offset.
2141 lda $5282
2142 cmp #9
2143 beq move_player_leave_room_down
2145 clc
2146 tax
2147 inx ; y + 1
2148 ldy $5284 ; load the x offset
2149 lda room_row_offsets_low,x ; read the address of the row
2150 sta $70
2151 lda #$57
2152 sta $71
2153 lda ($70),y ; load the tile below
2155 cmp #5 ; check for the open exit or final exit
2156 bmi move_player_not_down_exit1
2157 jmp try_to_exit_level ; optimise away the rts
2159 move_player_not_down_exit1:
2160 cmp #0
2161 bne move_player_not_vertical
2163 lda $5285 ; dx
2164 cmp #3
2165 bmi move_player_allow_down
2167 clc ; dx > 2 so we need to check another tile
2168 iny
2169 lda ($70),y ; load the tile below and to the right
2171 cmp #5 ; check for the open exit or final exit
2172 bmi move_player_not_down_exit2
2173 jmp try_to_exit_level ; optimise away the rts
2175 move_player_not_down_exit2:
2176 cmp #0
2177 bne move_player_not_vertical
2179 move_player_allow_down:
2181 jsr unplot_character ; unplot the player character
2182 inc $5283 ; update dy
2183 clc
2184 jmp animate_player_down ; optimise away the rts
2186 move_player_down_tile:
2188 jsr unplot_character ; unplot the player character
2189 inc $5282 ; store the new room y offset
2190 lda #0
2191 sta $5283 ; dy = 0
2192 clc
2193 jmp animate_player_down ; optimise away the rts
2195 move_player_leave_room_down:
2196 inc $5782
2197 clc
2199 ; Set the player's position on the top of the screen.
2201 ; No need to unplot.
2203 lda #0 ; y = 0
2204 sta $5282
2205 lda #0 ; dy = 0
2206 sta $5283
2208 jsr animate_player_down
2209 sec ; indicate to the calling routine that the
2210 rts ; player has left the room
2212 move_player_not_vertical:
2213 clc
2214 rts
2216 try_to_exit_level:
2218 cmp #6
2219 bmi just_exit_level
2221 lda $5780 ; set the complete game flag
2222 ora #$02
2223 jmp try_to_exit_level_exit
2225 just_exit_level:
2226 lda $5780 ; set the exit level flag
2227 ora #$80
2229 try_to_exit_level_exit:
2230 sta $5780
2232 lda #$80
2233 sta $74
2234 lda #$52
2235 sta $75
2236 jsr unplot_character ; remove the player sprite
2237 jmp destroy_enemies ; optimise away the rts
2239 check_fire_key:
2241 lda $578d
2242 bne check_fire_key_exit
2244 lda $577e
2245 beq check_fire_key_no_joystick
2247 lda #128
2248 ldx #0
2249 jsr $fff4
2250 txa
2251 and #1
2252 bne check_fire_key_fire
2254 clc
2255 rts
2257 check_fire_key_no_joystick:
2259 ldx #182 ; (Return)
2260 jsr check_key
2261 cpy #255
2262 bne check_fire_key_exit
2264 check_fire_key_fire:
2266 lda $5286
2267 cmp #0
2268 bne check_fire_key_exit
2270 lda #16
2271 sta $578d
2273 jmp create_projectile ; optimise away the rts
2275 check_fire_key_exit:
2276 clc
2277 rts
2279 create_projectile:
2281 lda #2
2282 sta $5286
2284 lda $5281
2285 and #$06 ; copy the direction information
2286 asl
2287 asl
2288 asl
2289 ora $5789 ; apply the projectile type
2290 sta $5287
2292 lda $5283 ; player dy
2293 adc $577f ; add the weapon counter
2294 adc #1
2295 cmp #4 ; if dy > 3, create the projectile on the tile below
2296 bpl create_projectile_below
2298 clc
2299 sta $5289 ; dy + weapon counter + 1
2300 lda $5282 ; y
2301 sta $5288
2302 jmp create_projectile_continue
2304 create_projectile_below:
2305 sec
2306 sbc #4
2307 sta $5289 ; dy + weapon counter + 1 - 4
2308 clc
2309 lda $5282 ; y
2310 adc #1
2311 sta $5288
2313 create_projectile_continue:
2314 lda $5284 ; x
2315 sta $528a
2317 lda $5285 ; dx
2318 sta $528b
2320 lda $577f ; toggle the weapon counter
2321 eor #1
2322 sta $577f
2324 ; Move the projectile away from the player.
2326 lda #$86
2327 sta $74
2328 lda #$52
2329 sta $75
2330 jsr move_projectile_after_unplot
2332 jsr move_projectile
2334 clc
2335 rts
2337 emerge_type: ; returns A=type
2338 jsr unlimited_values
2339 lda $7d
2340 and #7
2341 cmp #5
2342 bmi emerge_type_ok
2344 sec
2345 sbc #5
2346 clc
2348 emerge_type_ok:
2349 cmp $5781 ; only allow the appropriate enemies for this level
2350 bmi emerge_type_exit
2351 beq emerge_type_reduce
2353 sec
2354 sbc #1
2356 emerge_type_reduce:
2357 sec
2358 sbc $5781
2359 clc
2361 emerge_type_exit:
2362 asl
2363 asl
2364 asl
2365 asl
2366 clc
2367 rts
2369 emerge_character: ; $74,$75=character address
2371 lda #63
2372 sta $578f
2374 jsr unlimited_values
2375 and #$0f
2376 tax
2377 lda $0ee0,x
2378 cmp #0 ; check for an invalid value and exit if found
2379 beq emerge_character_exit
2381 sta $80 ; temporary
2382 lda $0ef0,x
2383 tax
2385 ; Add an emerging enemy.
2387 ldy #0
2388 lda #3 ; emerge/explosion
2389 sta ($74),y
2391 jsr emerge_type ; obtain an enemy type
2392 iny
2393 sta ($74),y
2395 txa
2396 iny
2397 sta ($74),y ; store the y position
2398 lda #1
2399 iny
2400 sta ($74),y ; store the dy offset
2402 lda $80
2403 iny
2404 sta ($74),y ; store the x position
2405 lda #0
2406 iny
2407 sta ($74),y ; store the dx offset
2409 jsr plot_character
2411 ldx #5
2412 jsr play_sound
2414 emerge_character_exit:
2415 clc
2416 rts
2418 emerge_explode: ; $74,$75=character address
2420 jsr unplot_character
2422 ldy #1
2423 lda ($74),y ; direction/animation
2424 tax
2425 adc #1 ; update the counter
2426 and #3 ; mask off everything else
2427 sta $80 ; store the masked counter value
2428 bne move_characters_explosion_not_finished
2430 txa
2431 and #4
2432 bne move_characters_remove_character
2434 ; For emerges, convert into an enemy.
2435 txa
2436 and #$70 ; only keep bits 4,5,6
2437 ora #8 ; make this an enemy
2439 ldy #0
2440 sta ($74),y ; update the type (>= 8)
2441 iny
2442 lda $7d ; prepare the direction and animation offset
2443 and #$0c
2444 sta ($74),y
2446 jsr plot_character
2447 jmp emerge_explode_exit
2449 move_characters_remove_character:
2451 ; For finished explosions, just write 0 into the character array.
2452 lda #0
2453 ldy #0
2454 sta ($74),y
2455 jmp emerge_explode_exit
2457 move_characters_explosion_not_finished:
2458 txa
2459 and #$fc
2460 ora $80
2462 ldy #1
2463 sta ($74),y
2465 jsr plot_character
2467 emerge_explode_exit:
2468 clc
2469 rts
2471 animate_enemy_left: ; $74,$75=character address
2473 ; Set the direction and toggle the animation bit.
2475 ldy #1
2476 lda ($74),y
2477 and #$fb ; keep vertical direction bit and animation bits
2478 sta ($74),y ; left (horizontal directional bit is 0)
2480 rts
2482 move_enemy_left: ; $74,$75=character address
2484 ldy #5
2485 lda ($74),y ; read dx
2486 cmp #0
2487 beq move_enemy_left_check_x
2489 sec
2490 sbc #1
2491 ldy #5
2492 sta ($74),y ; dx
2493 clc
2494 jmp animate_enemy_left ; optimise away the rts
2496 move_enemy_left_check_x:
2498 ; Check the x offset.
2500 ldy #4
2501 lda ($74),y ; x
2502 cmp #0
2503 beq move_enemy_left_exit
2505 sec
2506 sbc #1 ; x - 1
2507 sta $81 ; temporary
2508 ldy #2
2509 lda ($74),y ; load the y offset
2510 tax ; as an index
2511 lda room_row_offsets_low,x ; read the address of the row
2512 sta $70
2513 lda #$57
2514 sta $71
2515 ldy $81 ; temporary (x - 1)
2516 lda ($70),y ; load the tile to the left
2518 cmp #0
2519 bne move_enemy_left_exit
2521 ldy #3
2522 lda ($74),y ; dy
2523 cmp #2
2524 bmi move_enemy_allow_left
2526 clc
2527 lda $70 ; dy > 1 so we need to check another tile
2528 adc #10
2529 sta $70
2530 ldy $81 ; temporary (x - 1)
2531 lda ($70),y ; load the tile below and to the left
2533 cmp #0
2534 bne move_enemy_left_exit
2536 move_enemy_allow_left:
2537 lda $81
2538 ldy #4
2539 sta ($74),y ; store the new room x offset
2540 lda #3
2541 ldy #5
2542 sta ($74),y ; dx = 3
2543 clc
2544 jmp animate_enemy_left ; optimise away the rts
2546 move_enemy_left_exit:
2547 sec
2548 rts
2550 animate_enemy_right: ; $74,$75=character address
2552 ; Set the direction and toggle the animation bit.
2554 ldy #1
2555 lda ($74),y
2556 ora #$04 ; right (keep vertical direction bit and animation bits)
2557 sta ($74),y
2559 rts
2561 move_enemy_right: ; $74,$75=character_address
2563 ldy #5
2564 lda ($74),y ; read dx
2565 cmp #0
2566 beq move_enemy_right_check_x
2567 cmp #3
2568 beq move_enemy_right_tile
2570 clc
2571 adc #1
2572 ldy #5
2573 sta ($74),y
2574 jmp animate_enemy_right ; optimise away the rts
2576 move_enemy_right_check_x: ; Check the x offset.
2578 ldy #4
2579 lda ($74),y ; x
2580 cmp #9
2581 beq move_enemy_right_exit
2583 clc
2584 adc #1 ; x + 1
2585 sta $81 ; temporary (x + 1)
2586 ldy #2
2587 lda ($74),y ; load the y offset
2588 tax ; as an index
2589 lda room_row_offsets_low,x ; read the address of the row
2590 sta $70
2591 lda #$57
2592 sta $71
2593 ldy $81 ; temporary (x + 1)
2594 lda ($70),y ; load the tile to the right
2596 cmp #0
2597 bne move_enemy_right_exit
2599 ldy #3
2600 lda ($74),y ; dy
2601 cmp #2
2602 bmi move_enemy_allow_right
2604 clc ; dy > 1 so we need to check another tile
2605 lda $70
2606 adc #10
2607 sta $70
2608 ldy $81 ; temporary (x + 1)
2609 lda ($70),y ; load the tile below and to the right
2611 cmp #0
2612 bne move_enemy_right_exit
2614 move_enemy_allow_right:
2615 clc
2617 ldy #5
2618 lda ($74),y ; dx
2619 adc #1
2620 sta ($74),y ; update dx
2621 clc
2622 jmp animate_enemy_right ; optimise away the rts
2624 move_enemy_right_tile:
2625 clc
2627 ldy #4
2628 lda ($74),y ; x
2629 adc #1
2630 sta ($74),y ; store the new room x offset
2631 lda #0
2632 iny
2633 sta ($74),y ; dx = 0
2634 clc
2635 jmp animate_enemy_right ; optimise away the rts
2637 move_enemy_right_exit:
2638 sec
2639 rts
2641 animate_enemy_up: ; $74,$75=character address
2643 ; Set the direction and toggle the animation bit.
2645 ldy #1
2646 lda ($74),y
2647 and #$f7 ; keep horizontal direction bit and animation bits
2648 sta ($74),y
2650 rts
2652 move_enemy_up: ; $74,$75=character address
2654 ldy #3
2655 lda ($74),y ; read dy
2656 cmp #0
2657 beq move_enemy_up_check_y
2659 sec
2660 sbc #1
2661 ldy #3
2662 sta ($74),y ; dy
2663 clc
2664 jmp animate_enemy_up ; optimise away the rts
2666 move_enemy_up_check_y:
2668 ; Check the y offset.
2670 ldy #2
2671 lda ($74),y ; y
2672 cmp #0
2673 beq move_enemy_up_exit
2675 tax ; use the y offset as an index
2676 dex ; y - 1
2677 ldy #4
2678 lda ($74),y ; load the x offset
2679 sta $81 ; temporary (x)
2680 tay
2681 lda room_row_offsets_low,x ; read the address of the row
2682 sta $70
2683 lda #$57
2684 sta $71
2685 lda ($70),y ; load the tile above
2687 cmp #0
2688 bne move_enemy_up_exit
2690 ldy #5
2691 lda ($74),y ; dx
2692 cmp #0
2693 beq move_enemy_allow_up
2695 clc ; dx != 0 so we need to check another tile
2696 ldy $81
2697 iny
2698 lda ($70),y ; load the tile above and to the right
2700 cmp #0
2701 bne move_enemy_up_exit
2703 move_enemy_allow_up:
2704 txa
2705 ldy #2
2706 sta ($74),y ; store the new room y offset
2707 lda #3
2708 iny
2709 sta ($74),y ; dy = 3
2710 clc
2711 jmp animate_enemy_up ; optimise away the rts
2713 move_enemy_up_exit:
2714 sec
2715 rts
2717 animate_enemy_down: ; $74,$75=character address
2719 ; Set the direction and toggle the animation bit.
2721 ldy #1
2722 lda ($74),y
2723 ora #$08 ; down
2724 sta ($74),y
2726 rts
2728 move_enemy_down: ; $74,$75=character address
2730 ldy #3
2731 lda ($74),y ; dy
2732 cmp #1
2733 beq move_enemy_down_check_y
2734 cmp #3
2735 beq move_enemy_down_tile
2737 adc #1
2738 ldy #3
2739 sta ($74),y ; dy
2740 clc
2741 jmp animate_enemy_down ; optimise away the rts
2743 move_enemy_down_check_y:
2745 ; Check the y offset.
2747 ldy #2
2748 lda ($74),y
2749 cmp #9
2750 beq move_enemy_down_exit
2752 clc
2753 adc #1 ; y + 1
2754 tax
2755 ldy #4
2756 lda ($74),y ; load the x offset
2757 sta $81 ; temporary
2758 tay
2759 lda room_row_offsets_low,x ; read the address of the row
2760 sta $70
2761 lda #$57
2762 sta $71
2763 lda ($70),y ; load the tile below
2765 cmp #0
2766 bne move_enemy_down_exit
2768 ldy #5
2769 lda ($74),y ; dx
2770 cmp #0
2771 beq move_enemy_allow_down
2773 clc ; dx != 0 so we need to check another tile
2774 ldy $81 ; x
2775 iny
2776 lda ($70),y ; load the tile below and to the right
2778 cmp #0
2779 bne move_enemy_down_exit
2781 move_enemy_allow_down:
2782 clc
2784 ldy #3
2785 lda ($74),y ; dy
2786 adc #1
2787 sta ($74),y ; update dy
2788 clc
2789 jmp animate_enemy_down ; optimise away the rts
2791 move_enemy_down_tile:
2792 clc
2794 ldy #2
2795 lda ($74),y ; y
2796 adc #1
2797 sta ($74),y ; store the new room y offset
2798 lda #0
2799 iny
2800 sta ($74),y ; dy = 0
2801 clc
2802 jmp animate_enemy_down ; optimise away the rts
2804 move_enemy_down_exit:
2805 sec
2806 rts
2808 move_enemy_animate: ; $74,$75=character address
2810 ldy #1
2811 lda ($74),y ; direction/animation
2812 sta $81
2813 and #$03
2814 adc #1
2815 and #$03 ; keep animation bits
2816 sta $8f
2817 lda $81
2818 and #$fc ; mask off the animation bits
2819 ora $8f
2820 sta ($74),y
2821 rts
2823 move_enemy_next_direction: .byte $04, $0c, $00, $08
2825 move_enemy: ; $74,$75=character address
2827 lda #0
2828 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2829 lda #0
2830 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2832 lda ($74),y ; read the enemy number (Y should be zero)
2833 and #$10
2834 beq move_enemy_homing
2835 clc
2837 ; This enemy is a non-homing enemy.
2839 jsr unplot_character ; unplot now before we change the sprite used
2841 ldy #1
2842 lda ($74),y
2843 and #$f0
2844 cmp #$f0
2845 bne move_enemy_set_direction
2846 clc
2848 ldy #1
2849 lda ($74),y
2850 and #$0c
2851 ror
2852 ror
2853 tax
2854 lda move_enemy_next_direction,x
2855 sta ($74),y
2857 move_enemy_set_direction:
2858 clc
2860 ldy #1
2861 lda ($74),y
2862 sta $7b
2864 adc #$10
2865 sta ($74),y
2866 clc
2868 lda $7b
2869 and #$04
2870 ror
2871 ror
2872 adc #1
2873 sta $8e
2875 lda $7b
2876 and #$08
2877 ror
2878 ror
2879 ror
2880 adc #1
2881 sta $8d
2883 jmp move_enemy_with_direction
2885 move_enemy_homing:
2887 ldy #2
2888 lda ($74),y ; y
2889 cmp $5282 ; player y
2890 bmi move_enemy_downwards
2891 bne move_enemy_upwards
2893 ldy #3
2894 lda ($74),y ; dy
2895 cmp $5283 ; player y
2896 beq move_enemy_horizontally
2897 bpl move_enemy_upwards
2899 move_enemy_downwards:
2900 lda #2
2901 sta $8d
2902 jmp move_enemy_horizontally
2904 move_enemy_upwards:
2905 lda #1
2906 sta $8d
2907 ;jmp move_enemy_horizontally
2909 move_enemy_horizontally:
2910 ldy #4
2911 lda ($74),y ; x
2912 cmp $5284 ; player x
2913 bmi move_enemy_rightwards
2914 bne move_enemy_leftwards
2916 ldy #5
2917 lda ($74),y ; dx
2918 cmp #0
2919 beq move_enemy_with_direction_unplot
2920 bpl move_enemy_leftwards
2922 move_enemy_rightwards:
2923 lda #2
2924 sta $8e
2925 jmp move_enemy_with_direction_unplot
2927 move_enemy_leftwards:
2928 lda #1
2929 sta $8e
2931 move_enemy_with_direction_unplot:
2932 clc
2934 jsr unplot_character
2936 move_enemy_with_direction:
2937 clc
2939 lda $8e
2940 cmp #1
2941 bne move_enemy_not_left
2942 jsr move_enemy_left
2943 clc
2944 jmp move_enemy_not_right
2946 move_enemy_not_left:
2947 lda $8e
2948 cmp #2
2949 bne move_enemy_not_right
2950 jsr move_enemy_right
2951 clc
2953 move_enemy_not_right:
2954 lda $8d
2955 cmp #1
2956 bne move_enemy_not_up
2957 jsr move_enemy_up
2958 clc
2959 jmp move_enemy_toggle
2961 move_enemy_not_up:
2962 lda $8d
2963 cmp #2
2964 bne move_enemy_toggle
2965 jsr move_enemy_down
2967 move_enemy_toggle:
2968 clc
2969 jsr move_enemy_animate
2970 jmp plot_character ; optimise away the rts
2972 move_enemy_exit:
2973 clc
2974 rts
2976 create_explosion: ; X=y, Y=x
2978 lda #3
2979 sta $52a4
2980 lda #4
2981 sta $52a5
2982 txa
2983 sta $52a6
2984 lda #1
2985 sta $52a7
2986 tya
2987 sta $52a8
2988 lda #0
2989 sta $52a9
2990 rts
2992 move_projectile_left:
2994 lda $528b
2995 cmp #0
2996 beq move_projectile_left_check_x
2998 dec $528b
2999 clc
3000 rts
3002 move_projectile_left_check_x:
3004 lda $528a
3005 cmp #0
3006 bne move_projectile_left_in_room
3007 jmp move_projectile_left_exit
3009 move_projectile_left_in_room:
3010 tay
3011 dey ; x - 1
3012 ldx $5288 ; y
3013 lda room_row_offsets_low,x ; read the address of the row
3014 sta $70
3015 lda #$57
3016 sta $71
3017 lda ($70),y ; load the tile to the left
3019 cmp #0
3020 bne move_projectile_left_wall
3022 lda $5289 ; dy
3023 cmp #3
3024 bmi move_projectile_allow_left
3026 clc ; dy > 2 so we need to check another tile
3027 lda $70
3028 adc #10
3029 sta $70
3030 lda ($70),y ; load the tile below and to the left
3031 inx ; y += 1
3033 cmp #0
3034 bne move_projectile_left_wall
3036 move_projectile_allow_left:
3038 sty $528a ; x
3039 lda #3
3040 sta $528b ; dx = 3
3042 clc
3043 rts
3045 move_projectile_left_wall: ; the projectile hit a wall
3046 clc
3048 lda $5287 ; type 2 can pass through walls
3049 and #$06
3050 cmp #4
3051 beq move_projectile_allow_left
3053 cmp #2
3054 bne move_projectile_left_not_boomerang
3056 lda $5287
3057 and #$0f
3058 cmp #8
3059 bpl move_projectile_left_exit
3061 ldx $577f ; weapon counter
3062 ora boomerang_horizontal,x
3063 sta $5287
3064 clc
3065 rts ; exit without moving or registering a collision
3067 move_projectile_left_not_boomerang:
3069 cmp #6 ; type 3 can destroy certain walls
3070 bne move_projectile_left_exit
3072 lda ($70),y ; load the tile to the left
3073 cmp #1 ; decoration can be destroyed
3074 bne move_projectile_left_exit
3075 clc
3077 lda #0
3078 sta ($70),y
3080 ; X=y, Y=x
3081 jsr create_explosion
3082 jsr plot_blank_xy ; corrupted X
3084 lda #$a4
3085 sta $74
3086 lda #$52
3087 sta $75
3088 jsr plot_character
3090 ldx #0
3091 jsr play_sound
3093 lda #16 ; prevent the player from firing a new
3094 sta $578d ; projectile until the explosion has finished
3096 move_projectile_left_exit:
3097 sec
3098 rts
3100 boomerang_horizontal: .byte $28, $38
3102 move_projectile_right:
3104 ; Fire right.
3106 lda $528b
3107 cmp #2
3108 beq move_projectile_right_check_x
3109 cmp #3
3110 beq move_projectile_right_tile
3112 inc $528b
3113 clc
3114 rts
3116 move_projectile_right_check_x:
3118 lda $528a ; x
3119 cmp #9
3120 bne move_projectile_right_not_edge
3121 jmp move_projectile_right_exit
3123 move_projectile_right_not_edge:
3124 clc
3125 tay
3126 iny ; x + 1
3127 ldx $5288 ; y
3128 lda room_row_offsets_low,x ; read the address of the row
3129 sta $70
3130 lda #$57
3131 sta $71
3132 lda ($70),y ; load the tile to the right
3134 cmp #0
3135 bne move_projectile_right_wall
3137 lda $5289 ; dy
3138 cmp #3
3139 bmi move_projectile_allow_right
3141 clc ; dy > 2 so we need to check another tile
3142 lda $70
3143 adc #10
3144 sta $70
3145 lda ($70),y ; load the tile below and to the right
3146 inx ; y += 1
3148 cmp #0
3149 bne move_projectile_right_wall
3151 move_projectile_allow_right:
3153 inc $528b ; dx
3154 clc
3155 rts
3157 move_projectile_right_tile:
3159 inc $528a ; x
3160 lda #0
3161 sta $528b ; dx
3162 clc
3163 rts
3165 move_projectile_right_wall: ; the projectile hit a wall
3166 clc
3168 lda $5287 ; type 2 can pass through walls
3169 and #$06
3170 cmp #4
3171 beq move_projectile_allow_right
3173 cmp #2
3174 bne move_projectile_right_not_boomerang
3176 lda $5287
3177 and #$0f
3178 cmp #8
3179 bpl move_projectile_right_exit
3181 ldx $577f ; weapon counter
3182 ora boomerang_horizontal,x
3183 sta $5287
3184 clc
3185 rts ; exit without moving or registering a collision
3187 move_projectile_right_not_boomerang:
3189 cmp #6 ; type 3 can destroy certain walls
3190 bne move_projectile_right_exit
3192 lda ($70),y ; load the tile to the right
3193 cmp #1 ; decoration can be destroyed
3194 bne move_projectile_right_exit
3195 clc
3197 lda #0
3198 sta ($70),y
3200 ; X=y, Y=x
3201 jsr create_explosion
3202 jsr plot_blank_xy ; corrupted X
3204 lda #$a4
3205 sta $74
3206 lda #$52
3207 sta $75
3208 jsr plot_character
3210 ldx #0
3211 jsr play_sound
3213 lda #16 ; prevent the player from firing a new
3214 sta $578d ; projectile until the explosion has finished
3216 move_projectile_right_exit:
3217 sec
3218 rts
3220 move_projectile_up:
3222 lda $5289 ; read dy
3223 cmp #0
3224 beq move_projectile_up_check_y
3226 dec $5289
3227 clc
3228 rts
3230 move_projectile_up_check_y: ; Check the y offset.
3232 lda $5288
3233 cmp #0
3234 bne move_projectile_up_not_edge
3235 jmp move_projectile_up_exit
3237 move_projectile_up_not_edge:
3238 tax ; use the y offset as an index
3239 dex ; y - 1
3240 ldy $528a ; load the x offset
3241 lda room_row_offsets_low,x ; read the address of the row
3242 sta $70
3243 lda #$57
3244 sta $71
3245 lda ($70),y ; load the tile above
3247 cmp #0
3248 bne move_projectile_up_wall
3250 lda $528b ; dx
3251 cmp #3
3252 bmi move_projectile_allow_up
3254 clc ; dx > 2 so we need to check another tile
3255 iny
3256 lda ($70),y ; load the tile above and to the right
3258 cmp #0
3259 bne move_projectile_up_wall
3261 move_projectile_allow_up:
3262 txa
3263 sta $5288 ; store the new room y offset
3264 lda #3
3265 sta $5289 ; dy = 3
3267 clc
3268 rts
3270 move_projectile_up_wall: ; the projectile hit a wall
3271 clc
3273 lda $5287 ; type 2 can pass through walls
3274 and #$06
3275 cmp #4
3276 beq move_projectile_allow_up
3278 cmp #2
3279 bne move_projectile_up_not_boomerang
3281 lda $5287
3282 and #$0f
3283 cmp #8
3284 bpl move_projectile_up_exit
3286 ldx $577f ; weapon counter
3287 ora boomerang_vertical,x
3288 sta $5287
3289 clc
3290 rts ; exit without moving or registering a collision
3292 move_projectile_up_not_boomerang:
3294 cmp #6 ; type 3 can destroy certain walls
3295 bne move_projectile_up_exit
3297 lda ($70),y ; load the tile above
3298 cmp #1 ; decoration can be destroyed
3299 bne move_projectile_up_exit
3300 clc
3302 lda #0
3303 sta ($70),y
3305 ; X=y, Y=x
3306 jsr create_explosion
3307 jsr plot_blank_xy ; corrupted X
3309 lda #$a4
3310 sta $74
3311 lda #$52
3312 sta $75
3313 jsr plot_character
3315 ldx #0
3316 jsr play_sound
3318 lda #16 ; prevent the player from firing a new
3319 sta $578d ; projectile until the explosion has finished
3321 move_projectile_up_exit:
3322 sec
3323 rts
3325 boomerang_vertical: .byte $08, $18
3327 move_projectile_down:
3329 lda $5289 ; read dy
3330 cmp #2
3331 beq move_projectile_down_check_y
3332 cmp #3
3333 beq move_projectile_down_tile
3335 inc $5289 ; 0 <= dy < 3
3336 clc
3337 rts
3339 move_projectile_down_check_y: ; Check the y offset.
3341 lda $5288
3342 cmp #9
3343 bne move_projectile_down_in_room
3344 jmp move_projectile_down_exit
3346 move_projectile_down_in_room:
3347 clc
3348 tax
3349 inx ; y + 1
3350 ldy $528a ; load the x offset
3351 lda room_row_offsets_low,x ; read the address of the row
3352 sta $70
3353 lda #$57
3354 sta $71
3355 lda ($70),y ; load the tile below
3357 cmp #0
3358 bne move_projectile_down_wall
3360 lda $528b ; dx
3361 cmp #3
3362 bmi move_projectile_allow_down
3364 clc ; dx > 2 so we need to check another tile
3365 iny
3366 lda ($70),y ; load the tile below and to the right
3368 cmp #0
3369 bne move_projectile_down_wall
3371 move_projectile_allow_down:
3373 inc $5289 ; update dy
3374 clc
3375 rts
3377 move_projectile_down_tile:
3379 inc $5288 ; store the new room y offset
3380 lda #0
3381 sta $5289 ; dy = 0
3382 clc
3383 rts
3385 move_projectile_down_wall: ; the projectile hit a wall
3386 clc
3388 lda $5287 ; type 2 can pass through walls
3389 and #$06
3390 cmp #4
3391 beq move_projectile_allow_down
3393 cmp #2
3394 bne move_projectile_down_not_boomerang
3396 lda $5287
3397 and #$0f
3398 cmp #8
3399 bpl move_projectile_down_exit
3401 ldx $577f ; weapon counter
3402 ora boomerang_vertical,x
3403 sta $5287
3404 clc
3405 rts ; exit without moving or registering a collision
3407 move_projectile_down_not_boomerang:
3409 cmp #6 ; type 3 can destroy certain walls
3410 bne move_projectile_down_exit
3412 lda ($70),y ; load the tile below
3413 cmp #1 ; decoration can be destroyed
3414 bne move_projectile_down_exit
3415 clc
3417 lda #0
3418 sta ($70),y
3420 ; X=y, Y=x
3421 jsr create_explosion
3422 jsr plot_blank_xy ; corrupted X
3424 lda #$a4
3425 sta $74
3426 lda #$52
3427 sta $75
3428 jsr plot_character
3430 ldx #0
3431 jsr play_sound
3433 lda #16 ; prevent the player from firing a new
3434 sta $578d ; projectile until the explosion has finished
3436 move_projectile_down_exit:
3437 sec
3438 rts
3440 move_projectile_animate:
3442 lda $5287
3443 eor #1
3444 sta $5287
3445 rts
3447 move_projectile:
3449 lda $5286
3450 cmp #0
3451 bne move_projectile_move
3452 jmp move_projectile_exit
3454 move_projectile_move:
3455 clc
3457 lda #$86
3458 sta $74
3459 lda #$52
3460 sta $75
3461 jsr unplot_character
3463 move_projectile_after_unplot:
3465 lda $5287
3466 and #$30 ; direction
3468 cmp #0
3469 bne move_projectile_not_left
3471 jsr move_projectile_left
3472 bcc move_projectile_toggle
3473 bcs move_projectile_destroy
3475 move_projectile_not_left:
3476 cmp #$10
3477 bne move_projectile_not_right
3479 jsr move_projectile_right
3480 bcc move_projectile_toggle
3481 bcs move_projectile_destroy
3483 move_projectile_not_right:
3484 cmp #$20
3485 bne move_projectile_not_up
3487 jsr move_projectile_up
3488 bcc move_projectile_toggle
3489 bcs move_projectile_destroy
3491 move_projectile_not_up:
3492 cmp #$30
3493 bne move_projectile_toggle
3495 jsr move_projectile_down
3496 bcs move_projectile_destroy
3498 move_projectile_toggle:
3500 jsr projectile_collide
3501 bcs move_projectile_destroy
3503 jsr move_projectile_animate
3505 lda #$86
3506 sta $74
3507 lda #$52
3508 sta $75
3509 jmp plot_character ; optimise away the rts
3511 move_projectile_destroy:
3512 clc
3514 ldy #0
3515 lda ($74),y ; type
3516 cmp #8
3517 bmi move_projectile_no_enemy_collision
3519 and #$70 ; increase the player's score
3520 lsr
3521 lsr
3522 lsr
3523 adc #2
3524 sta $70
3525 jsr add_score
3526 jmp move_projectile_create_explosion
3528 move_projectile_no_enemy_collision:
3530 cmp #4 ; items can be destroyed as well
3531 bne move_projectile_no_item_collision
3533 ldy #1 ; but not keys
3534 lda ($74),y
3535 cmp #4 ; even the mace is stopped by a key
3536 beq move_projectile_remove_projectile
3537 clc
3539 jsr remove_room_item
3541 move_projectile_create_explosion:
3543 ; Unplot the item/enemy and replace it with an explosion.
3545 jsr unplot_character
3547 lda #3 ; explosion
3548 ldy #0
3549 sta ($74),y
3551 lda #4
3552 ldy #1
3553 sta ($74),y
3555 jsr plot_character
3557 ; Play a sound.
3558 ldx #0
3559 jsr play_sound
3561 move_projectile_no_item_collision:
3563 lda $5287 ; type 2 projectiles pass through everything
3564 and #$06
3565 cmp #4
3566 bne move_projectile_remove_projectile
3568 ; Ideally, we would have recorded if the projectile left the screen so
3569 ; that we don't perform these checks again here, but it would just add
3570 ; overhead to the normal movement routines for the other weapons.
3572 lda $5288 ; y
3573 cmp #0
3574 beq move_projectile_remove_projectile
3575 cmp #9
3576 beq move_projectile_remove_projectile
3578 lda $528a ; x
3579 cmp #0
3580 beq move_projectile_remove_projectile
3581 cmp #9
3582 beq move_projectile_remove_projectile
3584 clc
3585 lda #$86
3586 sta $74
3587 lda #$52
3588 sta $75
3590 jsr plot_character
3591 jmp move_projectile_exit
3593 move_projectile_remove_projectile:
3595 lda #0 ; remove the projectile from the character list
3596 sta $5286
3598 move_projectile_exit:
3599 clc
3600 rts
3602 emerge_characters:
3604 lda #$8c ; set the character address
3605 sta $74
3606 lda #$52
3607 sta $75
3609 emerge_characters_loop:
3611 ldy #0
3612 lda ($74),y
3613 cmp #0
3614 bne emerge_characters_next
3616 jmp emerge_character ; optimise away the rts
3618 emerge_characters_next:
3619 clc
3621 ; Examine the next character.
3622 lda $74
3623 adc #6
3625 cmp #$a4
3626 bpl emerge_characters_exit
3627 sta $74
3628 jmp emerge_characters_loop
3630 emerge_characters_exit:
3631 clc
3632 rts
3634 enemy_slots: .byte 0, 6, 12, 18
3636 move_characters:
3638 lda #$8c ; set the character address
3639 sta $74
3640 lda #$52
3641 sta $75
3643 lda $578e ; read a value from 0 to 3 from the motion counter
3644 and #3
3645 tax
3646 lda enemy_slots,x ; look up the corresponding slot in the character list
3647 adc $74
3648 sta $74 ; update the character address
3650 move_characters_loop:
3652 ldy #0
3653 lda ($74),y
3654 cmp #3
3655 bne move_characters_not_emerge_explode
3657 jsr emerge_explode
3658 jmp move_characters_next
3660 move_characters_not_emerge_explode:
3661 cmp #8
3662 bmi move_characters_next
3664 jsr move_enemy
3666 move_characters_next:
3667 clc
3669 lda $74 ; for the last enemy, check the next slot
3670 cmp #$9e ; for the presence of an explosion
3671 bne move_characters_endloop ; otherwise leave the loop (only performing
3672 clc ; one iteration)
3674 adc #6
3675 sta $74
3676 jmp move_characters_loop
3678 move_characters_endloop:
3679 clc
3681 ; Check collisions with the player.
3683 jsr player_collide
3684 bcs move_characters_collisions
3685 jmp move_characters_exit
3687 move_characters_collisions:
3688 clc
3690 ldy #0
3691 lda ($74),y ; type
3692 cmp #8
3693 bpl move_character_destroy_enemy
3695 ; Unplot the item.
3696 jsr unplot_character
3698 ; Remove it from the item table.
3699 jsr remove_room_item
3701 lda #0 ; remove the item from the character list
3702 ldy #0
3703 sta ($74),y
3705 iny
3706 lda ($74),y ; get the item type
3708 sta $8d ; temporarily store A and increase the score
3709 tax
3710 lda item_scores,x
3711 sta $70
3712 jsr add_score
3713 lda $8d
3715 ; Check the item type.
3716 cmp #8
3717 bmi move_characters_not_health
3719 lda #20
3720 sta $70
3721 jsr add_strength
3722 clc
3724 ldx #2
3725 jsr play_sound
3727 rts
3729 move_characters_not_health:
3730 cmp #5
3731 bmi move_characters_not_treasure
3733 ldx #2
3734 jsr play_sound
3736 clc
3737 rts
3739 move_characters_not_treasure:
3740 cmp #4
3741 bmi move_characters_not_key
3743 ; Key - update the item/player flags byte.
3744 lda $5780
3745 ora #$01
3746 sta $5780
3747 clc
3749 ldx #3
3750 jsr play_sound
3752 rts
3754 move_characters_not_key:
3756 ; Update the player's weapon.
3757 asl
3758 sta $5789
3759 clc
3761 ldx #2
3762 jsr play_sound
3764 rts
3766 move_character_destroy_enemy:
3768 ; Unplot the enemy and replace it with an explosion.
3770 jsr unplot_character
3772 lda #3 ; explosion
3773 ldy #0
3774 sta ($74),y
3776 lda #4
3777 ldy #1
3778 sta ($74),y
3780 jsr plot_character
3782 ; Reduce the player's strength.
3784 ldx #1
3785 jsr play_sound
3787 lda #1
3788 sta $70
3789 jmp reduce_strength ; optimise away the rts
3791 move_characters_exit:
3792 clc
3793 rts
3795 remove_room_item:
3797 ldx $5782 ; current room row number
3798 lda eleven_times_table,x
3799 adc $5783 ; current room column number
3800 tax
3801 lda #$80 ; store a value with the top bit set instead of zero because we
3802 sta $5200,x ; have visited this room if we can collect the object within it
3803 clc
3804 rts
3806 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3807 score_vdu_bytes: .byte 1,1,31 ; reversed
3808 score_digits: .byte "0123456789"
3810 add_score: ; $70=score to add
3812 sed
3813 lda $5786
3814 adc $70
3815 sta $5786
3816 lda $5787
3817 adc #0
3818 sta $5787
3819 lda $5788
3820 adc #0
3821 sta $5788
3822 cld
3824 write_score:
3826 lda #$86
3827 sta $70
3828 lda #$57
3829 sta $71
3831 ldx #2
3832 write_score_vdu_bytes:
3833 lda score_vdu_bytes,x
3834 jsr $ffee
3835 dex
3836 bpl write_score_vdu_bytes
3838 write_score_digits: ; $70,$71=address of score bytes
3840 ldy #2
3841 write_score_loop:
3843 lda ($70),y
3844 lsr
3845 lsr
3846 lsr
3847 lsr
3848 tax
3849 lda score_digits,x
3850 jsr $ffee
3852 lda ($70),y
3853 and #$0f
3854 tax
3855 lda score_digits,x
3856 jsr $ffee
3858 dey
3859 bpl write_score_loop
3861 clc
3862 rts
3864 strength_units: .byte $00,$88,$cc,$ee
3866 add_strength: ; $70=strength to add
3868 ; Divide the initial strength by 4 to determine which half character to
3869 ; start plotting at, and multiply by 8 to get the address. The net result
3870 ; is to mask off the bottom two bits and shift left once.
3871 lda $5784
3872 and #$fc
3873 sta $71 ; strength rounded down to a multiple of four units
3874 asl
3875 clc
3876 tay
3878 lda $5784
3879 adc $70
3880 cmp #65
3881 bmi add_strength_update
3883 lda #64
3885 add_strength_update:
3886 clc
3887 sta $5784 ; the final strength
3889 sec
3890 sbc $71
3891 clc
3892 tax ; the number of units to add between the rounded original
3893 ; strength and the final strength
3895 lda #$f3 ; the start of the strength bar
3896 sta $72
3897 lda #$59
3898 sta $73
3900 cpx #4
3901 bmi add_strength_loop_extra
3903 add_strength_loop:
3905 clc
3906 lda #$ff
3907 sta ($72),y
3909 tya
3910 adc #8
3911 tay
3913 txa
3914 sec
3915 sbc #4
3916 clc
3917 tax
3919 cmp #4
3920 bpl add_strength_loop
3922 add_strength_loop_extra:
3923 cpx #0
3924 beq add_strength_exit
3926 ; For any remaining units in excess of the multiples of four units, plot
3927 ; the appropriate byte.
3928 lda $5784
3929 and #3
3930 tax
3932 lda strength_units,x
3933 sta ($72),y
3935 add_strength_exit:
3936 clc
3937 rts
3939 reduce_strength: ; $70=strength to remove
3941 lda $5784
3942 tax
3943 sec
3944 sbc $70
3945 bpl reduce_strength_update
3947 lda #0
3949 reduce_strength_update:
3950 clc
3951 sta $5784
3953 ; Divide the final strength by 4 to determine which half character to
3954 ; plot, and multiply by 8 to get the address. The net result is to mask off
3955 ; the bottom two bits and shift left once.
3956 and #$fc
3957 asl
3958 tay
3960 lda #$f3 ; the start of the strength bar
3961 sta $70
3962 lda #$59
3963 sta $71
3965 lda $5784
3966 and #3
3967 tax
3968 lda strength_units,x
3969 sta ($70),y
3971 lda $5784
3972 cmp #0
3973 bne reduce_strength_exit
3975 lda $5780 ; the player ran out of strength
3976 ora #$40
3977 sta $5780
3979 lda #64 ; reset the delay counter
3980 sta $5785
3982 lda #$80 ; unplot the player
3983 sta $74
3984 lda #$52
3985 sta $75
3987 jsr unplot_character
3989 lda #8 ; change the player's direction to the demise animation
3990 sta $5281
3992 jsr plot_character
3993 jmp destroy_enemies ; optimise away the rts
3995 reduce_strength_exit:
3996 clc
3997 rts
3999 destroy_enemies:
4001 lda #$8c
4002 sta $74
4003 lda #$52
4004 sta $75
4006 destroy_enemies_loop:
4008 ldy #0
4009 lda ($74),y
4010 cmp #8
4011 bmi destroy_enemies_not_enemy
4013 jsr unplot_character
4015 lda #3 ; emerge/explosion
4016 ldy #0
4017 sta ($74),y
4019 iny
4020 lda #4 ; explosion
4021 sta ($74),y
4023 jsr plot_character
4024 jmp destroy_enemies_not_emerging_enemy
4026 destroy_enemies_not_enemy:
4027 cmp #3
4028 bne destroy_enemies_not_emerging_enemy
4030 jsr unplot_character
4032 iny ; whether emerging or exploding, ensure that the enemy
4033 lda ($74),y ; is now exploding
4034 ora #4
4035 sta ($74),y
4037 jsr plot_character
4039 destroy_enemies_not_emerging_enemy:
4040 clc
4041 lda $74
4042 adc #6
4043 sta $74
4044 cmp #$a4
4045 bmi destroy_enemies_loop
4047 clc
4048 rts
4050 remove_characters:
4052 ; Clear the character table.
4054 ldx #6
4055 remove_characters_loop:
4056 lda #0
4057 sta $5280,x
4058 txa
4059 adc #6
4060 tax
4061 cpx #$2a
4062 bmi remove_characters_loop
4064 rts
4066 ; The player collision masks use bits to represent where the player is in a
4067 ; tile. See the collisions.txt file for more information.
4069 ; Player is above, enemy is below, checking the overlap in the lower tile.
4070 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4072 projectile_collision_mask_above: .byte $00, $00, $00, $80
4074 ; Player and enemy share the same tile or player is on the tile below.
4075 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4077 projectile_collision_mask_below: .byte $e0, $38, $0e, $03
4079 ; Player is above or on the same tile, enemy is below, checking the overlap in
4080 ; the lower tile.
4081 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4083 ; Enemy is above, player is below, checking the overlap in the lower tile.
4084 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4086 ; Player is to the left, enemy is to the right, checking the overlap in the
4087 ; right hand tile.
4088 player_collision_mask_left:
4089 projectile_collision_mask_left: .byte $00, $00, $00, $08
4091 ; Player and enemy share the same tile or player is on the tile to the right.
4092 player_collision_mask_right:
4093 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4095 ; Player is to the left, enemy is to the right or on the same tile, checking
4096 ; the overlap in the right hand tile.
4097 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4099 ; Enemy is to the left, player is to the right, checking the overlap in the
4100 ; right hand tile.
4101 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4103 player_collide:
4105 lda $5282 ; player y
4106 sta $8a
4107 lda $5284 ; player x
4108 sta $8b
4110 ldx $5283 ; player dy
4111 lda player_collision_mask_above,x
4112 sta $86
4113 lda player_collision_mask_below,x
4114 sta $88
4115 ldx $5285 ; player dx
4116 lda player_collision_mask_left,x
4117 sta $87
4118 lda player_collision_mask_right,x
4119 sta $89
4121 jmp collide ; optimise away the rts
4123 projectile_collide:
4125 lda $5288 ; projectile y
4126 sta $8a
4127 lda $528a ; projectile x
4128 sta $8b
4130 ldx $5289 ; projectile dy
4131 lda projectile_collision_mask_above,x
4132 sta $86
4133 lda projectile_collision_mask_below,x
4134 sta $88
4135 ldx $528b ; projectile dx
4136 lda projectile_collision_mask_left,x
4137 sta $87
4138 lda projectile_collision_mask_right,x
4139 sta $89
4141 ; Run on into the next routine.
4143 collide:
4145 lda #$8c ; set the character address
4146 sta $74
4147 lda #$52
4148 sta $75
4150 collide_loop:
4152 ldy #0
4153 lda ($74),y ; type
4154 cmp #4
4155 bpl collide_check
4157 jmp collide_next
4159 collide_check:
4161 ldy #2
4162 lda ($74),y ; y
4163 sec
4164 sbc $8a ; y - player/projectile y
4165 beq check_collide_y_equal
4166 cmp #1
4167 beq check_collide_y_greater
4168 cmp #255
4169 beq check_collide_y_less
4171 jmp collide_next
4173 check_collide_y_equal:
4174 ; The enemy is on the same tile as the player/projectile so look at the
4175 ; collision on their common tile.
4176 ldy #3
4177 lda ($74),y ; dy
4178 tax
4179 lda enemy_collision_mask_above,x
4180 and $88 ; player/projectile mask below
4181 bne check_collide_x
4183 jmp collide_next
4185 check_collide_y_greater:
4186 ; The enemy is on the tile below the player/projectile so look at the
4187 ; collision on the enemy's tile.
4188 ldy #3
4189 lda ($74),y ; dy
4190 tax
4191 lda enemy_collision_mask_above,x
4192 and $86 ; player mask above
4193 bne check_collide_x
4195 jmp collide_next
4197 check_collide_y_less:
4198 ; The enemy is on the tile above the player/projectile so look at the
4199 ; collision on the player's tile.
4200 ldy #3
4201 lda ($74),y ; dy
4202 tax
4203 lda enemy_collision_mask_below,x
4204 and $88 ; player mask below
4205 bne check_collide_x
4207 jmp collide_next
4209 check_collide_x:
4210 ldy #4
4211 lda ($74),y ; x
4212 sec
4213 sbc $8b ; x - player/projectile x
4214 beq check_collide_x_equal
4215 cmp #1
4216 beq check_collide_x_greater
4217 cmp #255
4218 beq check_collide_x_less
4220 jmp collide_next
4222 check_collide_x_equal:
4223 ; The enemy is on the same tile as the player/projectile so look at the
4224 ; collision on their common tile.
4225 ldy #5
4226 lda ($74),y ; dx
4227 tax
4228 lda enemy_collision_mask_left,x
4229 and $89 ; player mask right
4230 bne check_collide_destroy
4232 jmp collide_next
4234 check_collide_x_greater:
4235 ; The enemy is the tile to the right of the player/projectile so look
4236 ; at the collision on the enemy's tile.
4237 ldy #5
4238 lda ($74),y ; dx
4239 tax
4240 lda enemy_collision_mask_left,x
4241 and $87 ; player mask left
4242 bne check_collide_destroy
4244 jmp collide_next
4246 check_collide_x_less:
4247 ; The enemy is the tile to the left of the player/projectile so look at
4248 ; the collision on the player's tile.
4249 ldy #5
4250 lda ($74),y ; dx
4251 tax
4252 lda enemy_collision_mask_right,x
4253 and $89 ; player mask right
4254 bne check_collide_destroy
4256 collide_next:
4257 clc
4259 ; Examine the next character.
4260 lda $74
4261 adc #6
4263 cmp #$a4
4264 bpl collide_exit
4265 sta $74
4266 jmp collide_loop
4268 check_collide_destroy:
4270 sec ; set the carry flag to inform the caller that the
4271 rts ; player/projectile should be destroyed
4273 collide_exit:
4274 clc
4275 rts
4277 blank_screen:
4278 lda #1
4279 sta $70
4280 lda #0
4281 sta $71
4282 jsr set_palette
4283 lda #2
4284 sta $70
4285 lda #0
4286 sta $71
4287 jsr set_palette
4288 lda #3
4289 sta $70
4290 lda #0
4291 sta $71
4292 ; Run on into set_palette.
4294 set_palette:
4295 ; $70=logical colour
4296 ; $71=physical colour
4297 lda $70
4298 sta $578b
4299 lda $71
4300 sta $578c
4301 lda #0
4302 sta $578d
4303 sta $578e
4304 sta $578f
4306 lda #$c
4307 ldx #$8b
4308 ldy #$57
4309 jsr $fff1
4310 rts
4312 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4313 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4315 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4316 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4317 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4318 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4319 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4321 .alias note_sound $5760
4322 .alias note_pitch $5764
4323 .alias note_duration $5766
4325 play_note: ; A=pitch, Y=duration
4327 sta note_pitch
4328 sty note_duration
4329 ldx #4
4330 ; Run on into the next routine.
4332 play_sound: ; X=sound number
4334 lda sounds_high,x
4335 tay
4336 lda sounds_low,x
4337 tax
4338 lda #7
4339 jsr $fff1
4341 rts
4343 copy_title_up:
4345 lda #$00
4346 sta $70
4347 lda #$18
4348 sta $71
4350 lda #$a0
4351 sta $72
4352 lda #$5a
4353 sta $73
4355 ldx #5
4356 ; Run on into the next routine.
4358 copy_title:
4360 copy_title_loop1:
4362 ldy #0
4363 copy_title_loop2:
4365 lda ($70),y
4366 sta ($72),y
4367 iny
4368 cpy #0
4369 bne copy_title_loop2
4371 clc
4372 lda $72
4373 adc #$40
4374 sta $72
4375 lda $73
4376 adc #$01
4377 sta $73
4378 clc
4380 lda $71
4381 adc #$01
4382 sta $71
4383 clc
4385 dex
4386 bpl copy_title_loop1
4388 rts
4390 copy_completed_screen_up:
4392 lda #$00
4393 sta $70
4394 lda #$0f
4395 sta $71
4397 lda #$60
4398 sta $72
4399 lda #$5e
4400 sta $73
4402 ldx #8
4403 jmp copy_title ; optimise away the rts
4405 init:
4406 ; Set up note data.
4407 ldx #7
4408 set_up_note_loop:
4409 lda note_data,x
4410 sta $5760,x
4411 dex
4412 bpl set_up_note_loop
4414 jsr cls ; clear the text window
4416 lda #26 ; unset the text window
4417 jsr $ffee
4419 ; Define the default high scores.
4420 ldy #0
4421 lda #$80
4422 sta $70
4423 lda #$51
4424 sta $71
4425 lda #$16
4426 sta $72
4428 ldx #0
4429 init_define_high_scores_loop:
4431 lda #0
4432 sta ($70),y
4433 iny
4434 lda $72
4435 sta ($70),y
4436 iny
4437 lda #0
4438 sta ($70),y
4440 iny
4441 init_define_high_score_name_loop:
4443 lda high_score_default_name1,x
4444 sta ($70),y
4445 iny
4446 inx
4447 cpx #9
4448 beq init_define_high_scores_next
4449 cpx #18
4450 bne init_define_high_score_name_loop
4452 ldx #0
4453 init_define_high_scores_next:
4455 sed
4456 lda $72
4457 sec
4458 sbc #2
4459 sta $72
4460 cld
4461 clc
4463 cpy #96
4464 bne init_define_high_scores_loop
4466 ; Disable joystick support.
4467 lda #0
4468 sta $577e
4470 rts
4472 note_data: .byte $13,0, 241,255, 0,0, 4,0
4474 high_score_default_name1: .byte "RETRO "
4475 high_score_default_name2: .byte " SOFTWARE"
4477 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4478 input_message: .byte 17,2, 31,2,27, "Press SPACE/FIRE"
4479 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4480 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4481 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4482 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4484 set_standard_palette:
4486 lda #1
4487 sta $70
4488 lda #1
4489 sta $71
4490 jsr set_palette
4492 jmp set_core_palette ; optimise away the rts
4494 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4496 set_complete_palette:
4498 lda #0
4499 sta $80
4500 lda #25
4501 sta $81
4503 set_complete_palette_loop:
4505 jsr wait_for_vsync
4507 dec $81
4508 lda $81
4509 cmp #0
4510 bne set_complete_palette_loop
4512 lda #25
4513 sta $81
4515 ldx $80
4516 lda complete_palette_bytes,x
4517 sta $70
4518 inx
4519 lda complete_palette_bytes,x
4520 sta $71
4521 inx
4522 stx $80
4523 jsr set_palette
4525 lda $80
4526 cmp #10
4527 bne set_complete_palette_loop
4529 rts
4531 set_hidden_palette:
4533 lda #1
4534 sta $70
4535 lda #0
4536 sta $71
4537 jsr set_palette
4539 ; Run on into the next routine.
4541 set_core_palette:
4543 lda #2
4544 sta $70
4545 lda #2
4546 sta $71
4547 jsr set_palette
4549 lda #3
4550 sta $70
4551 lda #3
4552 sta $71
4553 jsr set_palette
4555 rts
4557 show_title:
4559 jsr set_standard_palette
4561 ldx #0
4562 write_title_text_loop:
4563 lda title_vdu_bytes,x
4564 jsr $ffee
4565 inx
4566 cpx #12
4567 bmi write_title_text_loop
4569 jsr show_input_message
4571 ; Show the title.
4572 jsr copy_title_up
4574 ; Show the high scores.
4576 jsr colour1
4578 lda #$80
4579 sta $70
4580 lda #$51
4581 sta $71
4583 lda #8
4584 sta $80
4586 show_title_high_scores_loop:
4588 lda #31
4589 jsr $ffee
4590 lda #2
4591 jsr $ffee
4592 lda $80
4593 adc #2
4594 sta $80
4595 clc
4596 jsr $ffee
4598 jsr write_score_digits
4600 lda #32
4601 jsr $ffee
4603 ldx #8
4604 ldy #3
4605 show_title_high_scores_vdu_loop2:
4607 lda ($70),y
4608 cmp #32
4609 bmi ignore_char
4610 cmp #123
4611 bpl ignore_char
4612 jsr $ffee
4614 ignore_char:
4615 iny
4616 dex
4617 bpl show_title_high_scores_vdu_loop2
4619 lda $70
4620 adc #12
4621 sta $70
4622 cmp #$e0
4623 bne show_title_high_scores_loop
4625 lda #0 ; message counter
4626 sta $72
4628 show_title_wait_loop:
4630 lda #150
4631 sta $5785
4633 ldx $72
4634 ldy #22
4635 show_title_wait_message_loop:
4637 lda title_vdu_bytes1,x
4638 jsr $ffee
4639 inx
4640 dey
4641 bpl show_title_wait_message_loop
4643 cpx #92
4644 beq show_title_wait_reset_offset
4646 txa
4647 sta $72
4648 jmp show_title_wait_inner_loop
4650 show_title_wait_reset_offset:
4651 lda #0
4652 sta $72
4654 show_title_wait_inner_loop:
4655 jsr wait_for_vsync
4657 dec $5785
4658 beq show_title_wait_loop
4660 show_title_wait_loop_no_update:
4661 lda #128
4662 ldx #0
4663 jsr $fff4
4664 cpx #0 ; fire button pressed?
4665 beq show_title_no_joystick
4667 lda #1 ; enable joystick support
4668 sta $577e
4669 jmp show_title_exit
4671 show_title_no_joystick:
4672 ldx #157 ; SPACE
4673 jsr check_key
4674 cpy #255
4675 bne show_title_wait_inner_loop
4677 lda #0 ; disable joystick support
4678 sta $577e
4680 show_title_exit:
4681 clc
4682 rts
4684 show_input_message:
4686 ldx #0
4687 show_input_message_loop:
4689 lda input_message,x
4690 jsr $ffee
4691 inx
4692 cpx #21
4693 bne show_input_message_loop
4695 rts
4697 wait_for_vsync:
4699 lda #19
4700 jmp $fff4 ; optimise away the rts
4702 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4704 delay:
4706 delay_loop:
4708 jsr wait_for_vsync
4709 dec $5785
4710 bne delay_loop
4712 rts
4714 show_game_over:
4716 lda #128
4717 sta $5785
4718 jsr delay
4720 ldx #0
4721 write_game_over_text_loop:
4722 lda game_over_vdu_bytes,x
4723 jsr $ffee
4724 inx
4725 cpx #33
4726 bmi write_game_over_text_loop
4728 lda #192
4729 sta $5785
4730 jsr delay
4732 rts
4734 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4735 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4737 show_end_of_level_screen:
4739 ; Draw a decorative room.
4741 jsr make_empty_room
4743 ldx #5
4744 end_of_level_h_walls_loop:
4746 lda #3
4747 sta $57b2,x
4748 sta $57e4,x
4749 dex
4750 bpl end_of_level_h_walls_loop
4752 ldx #30
4753 end_of_level_v_walls_loop:
4755 lda #3
4756 sta $57bc,x
4757 sta $57c1,x
4758 txa
4759 sec
4760 sbc #10
4761 tax
4762 bpl end_of_level_v_walls_loop
4764 jsr plot_room_tiles
4765 jsr set_standard_palette
4767 ldx #0
4768 end_of_level_text_loop1:
4770 lda end_of_level_bytes1,x
4771 jsr $ffee
4772 inx
4773 cpx #28
4774 bne end_of_level_text_loop1
4776 ; Count the number of rooms explored.
4777 ldx #0
4778 lda #0
4779 sta $8d
4780 sta $8e
4781 end_of_level_room_count_loop:
4783 lda $5200,x
4784 and #$80
4785 beq end_of_level_room_count_loop_next
4787 sed
4788 lda $8d
4789 adc #1
4790 sta $8d
4791 lda $8e
4792 adc #0
4793 sta $8e
4794 cld
4795 clc
4797 end_of_level_room_count_loop_next:
4798 inx
4799 cpx #121
4800 bne end_of_level_room_count_loop
4802 ; Position the player so that we can perform an animation.
4803 jsr position_player_set_up_plotting
4805 lda $8d
4806 sta $70
4807 lda $8e
4808 sta $71
4809 jsr write_bonus
4811 lda #0 ; reset motion counter
4812 sta $578e
4814 show_end_of_level_bonus_loop:
4816 jsr wait_for_vsync
4818 clc
4819 lda $578e
4820 and #15
4821 bne end_of_level_no_animation
4823 ; Animate the player.
4825 jsr reset_unplot_buffer
4826 jsr reset_plot_buffer
4828 ; $74,$75 should be unchanged
4829 jsr unplot_character
4831 lda $5281
4832 eor #1
4833 sta $5281
4834 jsr plot_character
4836 jsr plot_buffer
4838 end_of_level_no_animation:
4839 clc
4840 lda $578e
4841 and #3
4842 bne end_of_level_no_countdown
4844 ; Transfer the bonus to the score.
4846 sed
4847 sec
4848 lda $8d
4849 sbc #1
4850 sta $8d
4851 sta $70
4852 lda $8e
4853 sbc #0
4854 sta $8e
4855 sta $71
4856 cld
4857 clc
4859 jsr write_bonus
4861 lda #9
4862 sta $70
4863 jsr add_score
4865 lda $8d
4866 and #$3f
4867 asl
4868 ldy #1
4869 jsr play_note
4871 end_of_level_no_countdown:
4872 inc $578e ; update motion counter
4873 clc
4875 lda $8d
4876 cmp #0
4877 bne show_end_of_level_bonus_loop
4879 lda $8e
4880 cmp #0
4881 bne show_end_of_level_bonus_loop
4883 lda #64 ; initialise delay counter
4884 sta $5785
4885 jsr delay
4887 ldx #0
4888 end_of_level_text_loop2:
4890 lda end_of_level_bytes2,x
4891 jsr $ffee
4892 inx
4893 cpx #25
4894 bne end_of_level_text_loop2
4896 lda $578a
4897 cmp #3
4898 bpl show_end_of_level_screen_exit
4900 lda #192 ; initialise delay counter
4901 sta $5785
4902 jsr delay
4904 show_end_of_level_screen_exit:
4905 rts
4907 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4909 write_bonus: ; $70,$71=value
4910 ; $72,$73=address of VDU codes
4912 ldx #4
4913 write_bonus_vdu_bytes:
4915 lda level_bonus_vdu_bytes,x
4916 jsr $ffee
4917 dex
4918 bpl write_bonus_vdu_bytes
4920 ldy #1
4921 write_bonus_loop:
4923 tya
4924 tax ; temporary
4926 lda $70,x
4927 sta $80
4928 lsr
4929 lsr
4930 lsr
4931 lsr
4932 tax
4933 lda score_digits,x
4934 jsr $ffee
4936 lda $80
4937 and #$0f
4938 tax
4939 lda score_digits,x
4940 jsr $ffee
4942 dey
4943 bpl write_bonus_loop
4945 clc
4946 rts
4948 position_player_set_up_plotting:
4950 jsr reset_player_position
4951 jsr remove_characters
4953 jsr reset_unplot_buffer
4954 jsr reset_plot_buffer
4956 ; Run on into the next routine.
4958 plot_the_player:
4960 lda #$80 ; plot the player
4961 sta $74
4962 lda #$52
4963 sta $75
4964 jsr plot_character
4966 jsr plot_buffer
4967 rts
4969 complete_game_vdu_bytes1: .byte 12
4970 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4971 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4972 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4974 show_complete_game:
4976 jsr blank_screen
4978 ldx #0
4979 show_complete_game_vdu_loop:
4981 lda complete_game_vdu_bytes1,x
4982 jsr $ffee
4983 inx
4984 cpx #68
4985 bne show_complete_game_vdu_loop
4987 jsr copy_completed_screen_up
4989 jsr set_complete_palette
4991 lda #255
4992 sta $5785
4994 show_complete_game_delay_loop:
4996 jsr wait_for_vsync
4998 dec $5785
4999 bne show_complete_game_no_message
5001 jsr colour1
5002 jsr show_input_message
5004 show_complete_game_no_message:
5006 lda #128
5007 ldx #0
5008 jsr $fff4
5009 cpx #0 ; fire button pressed?
5010 beq show_complete_game_no_joystick
5011 jmp show_complete_game_exit
5013 show_complete_game_no_joystick:
5015 ldx #157
5016 jsr check_key
5017 cpy #255
5018 bne show_complete_game_delay_loop
5020 show_complete_game_exit:
5021 clc
5022 rts
5024 check_high_scores:
5026 ; Start at the bottom of the table, moving scores down as necessary, and
5027 ; write in the current score at the appropriate place.
5029 lda #$86 ; current score
5030 sta $70
5031 lda #$57
5032 sta $71
5034 lda #$80
5035 sta $72
5036 lda #$51
5037 sta $73
5039 check_high_scores_loop:
5041 ldy #2
5042 check_high_scores_digits_loop:
5044 lda ($72),y
5045 cmp ($70),y ; existing score less than current score?
5046 bcc check_high_scores_move_down
5047 beq check_high_scores_digits_next ; keep checking digits if equal
5048 jmp check_high_scores_next
5050 check_high_scores_digits_next:
5051 dey
5052 bpl check_high_scores_digits_loop
5054 check_high_scores_next:
5055 clc
5056 lda $72
5057 adc #12
5058 sta $72
5059 cmp #$e0
5060 bne check_high_scores_loop
5062 ; The player's score didn't make it into the high score table.
5063 rts
5065 check_high_scores_move_down: ; $70,$71=pointer to current score
5066 ; $72,$73=pointer to old score
5068 ; The current score exceeded the existing entry. Make a note of the
5069 ; position in the high score table, insert the player's score, and take
5070 ; the old score
5072 lda $72 ; Record the position in the high score table of the
5073 sta $8d ; player's score.
5074 lda $73
5075 sta $8e
5077 lda #$e0
5078 sta $74
5079 lda #$51
5080 sta $75
5082 ldy #0
5083 insert_blank_player_name_loop:
5085 cpy #3
5086 bpl insert_blank_player_name_score_only
5088 lda ($70),y
5089 jmp insert_blank_player_name_store
5091 insert_blank_player_name_score_only:
5092 lda #32
5094 insert_blank_player_name_store:
5095 sta ($74),y
5096 iny
5097 cpy #12
5098 bne insert_blank_player_name_loop
5100 check_high_scores_move_down_loop:
5102 ldy #0
5103 check_high_scores_copy_score_and_name:
5105 lda ($72),y ; swap the current score with the score in the table
5106 tax
5107 lda ($74),y
5108 sta ($72),y
5109 txa
5110 sta ($74),y
5111 iny
5112 cpy #12
5113 bne check_high_scores_copy_score_and_name
5115 clc
5116 lda $72
5117 adc #12
5118 sta $72
5119 cmp #$e0
5120 bne check_high_scores_move_down_loop
5122 ; Draw a decorative room.
5124 jsr set_hidden_palette
5126 jsr make_empty_room
5128 lda #3
5129 sta $76
5130 sta $77
5131 jsr draw_top_line
5132 jsr draw_bottom_line
5133 jsr draw_left_line
5135 lda #0
5136 sta $77
5137 jsr draw_right_line
5139 jsr plot_room_tiles
5141 ; Add text characters to the room.
5142 jsr colour3
5144 lda #3 ; x
5145 sta $70
5146 lda #6 ; y
5147 sta $71
5149 lda #65
5150 sta $72
5152 ldx #3
5153 plot_text_characters_loop:
5155 jsr print_xy
5157 lda $70
5158 adc #4
5159 sta $70
5161 dex
5162 bpl plot_text_characters_next
5164 lda #3
5165 sta $70
5166 lda $71
5167 adc #3
5168 sta $71
5170 ldx #3
5172 plot_text_characters_next:
5174 inc $72
5175 lda $72
5176 cmp #91
5177 bne plot_text_characters_loop
5179 lda #11
5180 sta $70
5181 lda #95 ; _ representing a space
5182 sta $72
5183 jsr print_xy
5185 lda #15
5186 sta $70
5187 lda #60 ; < representing delete
5188 sta $72
5189 jsr print_xy
5191 ; Put the player in the centre of the room.
5192 jsr position_player_set_up_plotting
5194 lda #0 ; reset motion counter
5195 sta $578e
5197 lda #0 ; not on a character
5198 sta $578d
5200 lda #0 ; reset the level number so that the correct tiles are used
5201 sta $578a
5203 lda #3 ; cursor position in the high score entry held in $8d,$8e
5204 sta $8f
5206 jsr set_standard_palette
5208 ldx #0
5209 high_score_vdu_loop:
5211 lda high_score_vdu_bytes,x
5212 jsr $ffee
5213 inx
5214 cpx #39
5215 bne high_score_vdu_loop
5217 high_score_entry_loop:
5219 jsr reset_unplot_buffer
5220 jsr reset_plot_buffer
5222 jsr move_player
5223 ; Check if the player leaves the room.
5224 bcc high_score_entry_check_position
5225 jmp high_score_entry_after_loop
5227 high_score_entry_check_position:
5229 lda $5285 ; dx
5230 cmp #2
5231 beq high_score_entry_maybe_aligned
5232 jmp high_score_entry_not_aligned
5234 high_score_entry_maybe_aligned:
5236 lda $5282 ; y
5237 tay
5238 cmp #8
5239 bpl high_score_entry_not_aligned
5241 lda $5284 ; x
5242 tax
5243 cmp #9
5244 beq high_score_entry_not_aligned
5245 and #1
5246 beq high_score_entry_not_aligned
5248 lda $5283 ; dy
5249 cmp #2
5250 bmi high_score_entry_aligned
5251 jmp high_score_entry_not_aligned
5253 lda $5282 ; y again (don't apply the touching rule to the bottom
5254 cmp #7 ; row of characters)
5255 beq high_score_entry_not_aligned
5257 iny ; we are really touching the character below
5259 high_score_entry_aligned:
5261 lda $578d
5262 cmp #1
5263 beq high_score_entry_next
5265 ; The player is aligned with a letter.
5266 txa
5267 sec
5268 sbc #1
5269 lsr
5270 sta $7e ; record (x - 1) / 2
5272 tya ; recall y
5273 sec
5274 sbc #1
5275 asl
5276 asl ; (y - 1) * 4
5277 clc
5279 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5280 adc #65
5281 sta $7e ; record the ASCII code
5283 cmp #91
5284 bmi insert_character
5286 cmp #92
5287 beq delete_character
5289 ; Insert a space.
5290 lda #32
5291 sta $7e
5293 insert_character:
5294 lda $8f
5295 cmp #12
5296 bpl high_score_entry_pressed
5298 tay ; insert the character
5299 lda $7e
5300 sta ($8d),y
5301 jsr print_high_score_character
5303 inc $8f
5304 jmp high_score_entry_pressed
5306 delete_character:
5307 lda $8f
5308 cmp #4
5309 bmi high_score_entry_pressed
5311 cmp #12
5312 beq high_score_delete_previous_character
5314 tay
5315 lda #32 ; insert a space
5316 sta ($8d),y
5317 jsr print_high_score_character
5319 high_score_delete_previous_character:
5320 dec $8f
5321 lda $8f
5322 tay ; insert a space
5323 lda #32
5324 sta ($8d),y
5325 jsr print_high_score_character
5327 high_score_entry_pressed:
5328 lda #1
5329 sta $578d
5330 jmp high_score_entry_next
5332 high_score_entry_not_aligned:
5333 lda #0
5334 sta $578d
5336 high_score_entry_next:
5338 jsr wait_for_vsync
5339 jsr wait_for_vsync
5340 jsr plot_buffer
5342 jmp high_score_entry_loop
5344 inc $578e
5345 clc
5347 high_score_entry_after_loop:
5348 clc
5350 jsr cls
5351 jsr set_hidden_palette
5353 rts
5355 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5357 cls:
5358 lda #12
5359 jsr $ffee
5360 rts
5362 colour1:
5363 lda #17
5364 jsr $ffee
5365 lda #1
5366 jsr $ffee
5367 rts
5369 colour3:
5370 lda #17
5371 jsr $ffee
5372 lda #3
5373 jsr $ffee
5374 rts
5376 print_high_score_character: ; A=ASCII code
5378 clc
5379 sta $72 ; store the character
5380 lda $8f
5381 adc #3
5382 sta $70 ; store the x position of the character
5383 lda #30
5384 sta $71
5385 ; Run on into the next routine.
5387 print_xy:
5389 lda #31
5390 jsr $ffee
5391 lda $70
5392 jsr $ffee
5393 lda $71
5394 jsr $ffee
5395 lda $72
5396 jsr $ffee
5397 rts
5399 disable_sound: ; X=1 (disable); X=0 (enable)
5401 lda #210
5402 ldy #0
5403 jmp $fff4 ; optimise away the rts
5405 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5406 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5408 start_new_game:
5410 ; Clear the screen.
5411 jsr cls
5413 ; Set the level.
5414 lda #0
5415 sta $578a
5417 ; Set the score.
5418 lda #0
5419 sta $5786
5420 lda #0
5421 sta $5787
5422 lda #0
5423 sta $5788
5425 ; Blank the screen now because it will be blanked before the room is shown
5426 ; and otherwise the strength bar will show briefly.
5427 jsr blank_screen
5429 ; Set the player's strength.
5430 lda #0
5431 sta $5784
5432 lda #64
5433 sta $70
5434 jsr add_strength
5436 ; Set the projectile type.
5437 lda #0
5438 sta $5789
5440 rts
5442 reset_player_position:
5444 lda #1 ; player
5445 sta $5280
5446 lda #6 ; down (first frame)
5447 sta $5281
5448 lda #4 ; y=4
5449 sta $5282
5450 lda #2 ; dy=2
5451 sta $5283
5452 lda #4 ; x=4
5453 sta $5284
5454 lda #3 ; dx=3
5455 sta $5285
5457 rts
5459 start_level:
5461 ; Clear the item/player flags.
5462 lda #0
5463 sta $5780
5465 ; Set current room.
5467 ldx $578a
5468 lda start_rooms_y,x
5469 sta $5782
5470 lda start_rooms_x,x
5471 sta $5783
5473 ; Set the player's position.
5475 jsr reset_player_position
5477 ; Reset the weapon counter.
5478 lda #0
5479 sta $577f
5481 ; Fill the treasure table with objects.
5482 ldx $578a ; level
5483 lda key_rooms,x
5484 sta $80
5486 ldx $578a ; level
5487 lda seeds,x
5488 adc #1
5489 and #31
5490 sta $7c
5491 clc
5492 lda seeds,x
5493 adc #2
5494 and #31
5495 sta $7d
5496 clc
5498 lda $578a ; create an upper limit on the weapon type found in this level
5499 adc #2
5500 sta $5781
5501 clc
5503 lda #$00
5504 sta $8e
5505 lda #$52
5506 sta $8f
5508 ldy #0
5509 start_level_add_treasure_loop:
5511 cpy $80 ; check for the key room
5512 bne start_level_add_treasure_item
5514 lda #5 ; the value to store is type + 1
5515 jmp start_level_add_treasure_store
5517 start_level_add_treasure_item:
5518 clc
5519 jsr unlimited_values
5520 and #$0f
5521 cmp #0
5522 beq start_level_add_treasure_none
5524 clc
5525 sta $8c
5526 tya
5527 adc $8c
5528 and #31
5529 clc
5530 tax
5531 lda treasure_table,x
5533 cmp #4
5534 bmi start_level_add_treasure_weapon
5536 clc
5537 adc #1
5538 jmp start_level_add_treasure_store
5540 start_level_add_treasure_weapon:
5542 ; Only add weapons with types that equal the level number or exceed it
5543 ; by one.
5544 cmp $5781
5545 bcs start_level_add_treasure_none
5547 clc
5548 adc #1 ; store values 0-8 as values 1-9
5549 jmp start_level_add_treasure_store
5551 start_level_add_treasure_none:
5552 clc
5553 lda #0 ; do not put treasure in this room
5555 start_level_add_treasure_store:
5556 clc
5557 sta ($8e),y ; add the item to the table
5559 iny
5560 cpy #121
5561 bmi start_level_add_treasure_loop
5563 ; Write the status text.
5564 ldx #0
5565 write_status_text_loop:
5566 lda status_vdu_bytes,x
5567 jsr $ffee
5568 inx
5569 cpx #25
5570 bmi write_status_text_loop
5572 jsr write_score
5574 clc
5575 rts
5577 main:
5578 jsr init
5580 main_loop:
5582 jsr show_title
5584 jsr start_new_game
5586 level_loop:
5588 jsr start_level
5590 game_loop:
5592 jsr remove_characters
5594 jsr reset_unplot_buffer
5595 jsr reset_plot_buffer
5597 lda $5782 ; current room (y)
5598 sta $78
5599 lda $5783 ; current room (x)
5600 sta $79
5601 jsr plot_room
5602 jsr set_room_palette
5603 jsr create_enemy_positions
5604 jsr add_treasure
5606 jsr plot_the_player
5608 lda #0 ; reset projectile counter
5609 sta $578d
5611 lda #0 ; reset motion counter
5612 sta $578e
5614 lda #63 ; reset generation counter
5615 sta $578f
5617 room_loop:
5618 jsr reset_unplot_buffer
5619 jsr reset_plot_buffer
5621 jsr move_characters
5622 jsr move_projectile
5624 lda $5780 ; is player out of strength ($40), leaving the
5625 and #$c2 ; level (0x80) or completing the game (0x02)?
5626 beq room_loop_player_move
5627 clc
5629 dec $5785 ; leave the loop when the delay
5630 bne room_loop_delay_next
5631 jmp after_room_loop ; counter is about to reset
5633 room_loop_delay_next:
5635 lda $5281 ; leave the loop when the player demise
5636 cmp #11 ; animation has finished
5637 beq room_loop_after_player_move
5638 clc
5640 lda $578e
5641 and #7
5642 bne room_loop_after_player_move
5644 lda $5780 ; skip the animation if leaving the level or
5645 and #$82 ; completing the game
5646 bne room_loop_after_player_move
5648 ; Show the demise animation when appropriate.
5650 lda #$80
5651 sta $74
5652 lda #$52
5653 sta $75
5655 jsr unplot_character
5657 inc $5281
5658 jsr plot_character
5659 jmp room_loop_after_player_move
5661 room_loop_player_move:
5663 ; See if it is time to generate a new enemy.
5664 lda $578f
5665 cmp #0
5666 bne no_emerge_characters
5667 jsr emerge_characters
5669 no_emerge_characters:
5670 clc
5672 jsr check_fire_key
5673 jsr move_player
5674 bcs after_room_loop ; check if we are leaving the level
5676 room_loop_after_player_move:
5677 clc
5679 lda #19
5680 jsr $fff4
5681 jsr plot_buffer
5683 ldx #143 ; Escape key check
5684 jsr check_key
5685 cpy #255
5686 beq main_loop_play_again
5688 ldx #174 ; S key check
5689 jsr check_key
5690 cpy #255
5691 bne no_set_sound
5693 ldx #0
5694 jsr disable_sound
5695 jmp after_sound_checks
5697 no_set_sound:
5699 ldx #239 ; Q key check
5700 jsr check_key
5701 cpy #255
5702 bne after_sound_checks
5704 ldx #1
5705 jsr disable_sound
5707 after_sound_checks:
5709 ldx #200 ; P key check
5710 jsr check_key
5711 cpy #255
5712 bne no_pause
5714 pause_loop:
5716 ldx #201 ; O key check
5717 jsr check_key
5718 cpy #255
5719 bne pause_loop
5721 no_pause:
5722 clc
5724 lda $578d
5725 cmp #0
5726 beq room_loop_no_update_projectile_counter
5728 dec $578d
5730 room_loop_no_update_projectile_counter:
5732 dec $578f ; update generation counter
5734 inc $578e ; update motion counter
5735 clc
5736 jmp room_loop
5738 after_room_loop:
5739 clc
5741 lda $5780
5742 and #$80
5743 bne exit_level
5745 lda $5780
5746 and #$40
5747 bne game_over
5749 lda $5780
5750 and #$02
5751 bne complete_game
5753 jmp game_loop
5755 exit_level:
5757 jsr show_end_of_level_screen
5759 inc $578a
5760 clc
5761 jmp level_loop
5763 game_over:
5764 jsr show_game_over
5765 jmp main_loop_play_again
5767 complete_game:
5768 jsr show_end_of_level_screen
5769 jsr show_complete_game
5770 jmp main_loop_play_again
5772 main_loop_play_again:
5773 jsr cls
5775 ; Check the score against the high scores.
5776 jsr check_high_scores
5778 jmp main_loop
5780 exit:
5781 clc
5782 rts