junglejourney

view mapcode.oph @ 192:e1a1513fde16

Modified the joystick checks, hopefully with improved results.
author David Boddie <david@boddie.org.uk>
date Thu Sep 29 00:42:43 2011 +0200
parents a3e62b843f69
children 5502cf6e30cb
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 .org $1e00
17 jmp main
19 seeds: .byte 100, 239, 183, 144 ; $ef, $b7, $90, $d6, $89
20 start_rooms_x: .byte 5, 3, 5, 10
21 start_rooms_y: .byte 5, 8, 1, 8
22 exit_rooms_x: .byte 7, 9, 3, 0
23 exit_rooms_y: .byte 0, 0, 9, 10
25 ; These values need to be kept in sync - the room numbers must match their
26 ; positions in the room array.
27 key_rooms_x: .byte 1, 5, 10, 1
28 key_rooms_y: .byte 0, 2, 6, 4
29 key_rooms: .byte 1, 27, 76, 45 ; ky*11 + kx
31 treasure_table: .byte 6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7
32 treasure_table_: .byte 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0
34 unlimited_values: ; $7c,$7d=first,second
35 ; Add $7c and $7d, store the result in $7d and the original
36 ; $7d value in $7c, returning the sum in the accumulator.
37 lda $7c
38 sta $7b
39 lda $7d
40 sta $7c
41 adc $7b
42 sta $7d
43 clc
44 rts
46 mod9: ; A = value
47 divide_loop:
48 cmp #9
49 bcc after_divide_loop ; bmi should work here, I think, but it doesn't
50 sec
51 sbc #9
52 jmp divide_loop
54 after_divide_loop:
55 clc
56 rts ; A % 9
58 tile_values_map: .byte 0,1,0,0,0,0,2,3
60 next_value: ; no argument
61 jsr unlimited_values
62 lda $7d
63 jsr mod9
64 and #7 ; (next value % 9) & 7
65 tax
66 lda tile_values_map,x
67 sta $7b
68 rts
70 ; Room filling routines, writing to 0x579c to 0x57ff.
72 draw_top_line: ; $76=tile number for exit/wall
73 ldx #9
74 lda #2
76 draw_top_line_loop0:
77 sta $579c,x
78 dex
79 bpl draw_top_line_loop0
81 ldx #3 ; draw the exit or wall
82 lda $76
83 draw_top_line_loop1:
84 sta $579f,x
85 dex
86 bpl draw_top_line_loop1
87 clc
88 rts
90 draw_left_line: ; $77=tile number for exit/wall
91 ldx #90
92 draw_left_line_loop0:
93 lda #2
94 sta $579c,x
95 txa
96 sec
97 sbc #10
98 tax
99 bpl draw_left_line_loop0
101 ldx #30
102 draw_left_line_loop1:
103 lda $77
104 sta $57ba,x
105 txa
106 sec
107 sbc #10
108 tax
109 bpl draw_left_line_loop1
110 clc
111 rts
113 draw_bottom_line: ; $76=tile number for exit/wall
114 ldx #9
115 lda #2
116 draw_bottom_line_loop0:
117 sta $57f6,x
118 dex
119 bpl draw_bottom_line_loop0
121 ldx #3
122 lda $76
123 draw_bottom_line_loop1:
124 sta $57f9,x
125 dex
126 bpl draw_bottom_line_loop1
127 clc
128 rts
130 draw_right_line: ; $77=tile number for exit/wall
131 ldx #99
132 draw_right_line_loop0:
133 lda #2
134 sta $579c,x
135 txa
136 sec
137 sbc #10
138 tax
139 bpl draw_right_line_loop0
141 ldx #30
142 draw_right_line_loop1:
143 lda $77
144 sta $57c3,x
145 txa
146 sec
147 sbc #10
148 tax
149 bpl draw_right_line_loop1
150 clc
151 rts
153 make_empty_room:
155 ldx #99
156 make_empty_room_loop:
157 lda #0
158 sta $579c,x
159 dex
160 bpl make_empty_room_loop
162 rts
164 make_room: ; $78,$79=i,j
166 ; Fills the room array at 579c with values.
167 ; Tiles 0,1,2,3 are map tiles that will be shown by the plot_tile routine.
168 ; Other tiles are plotted separately:
169 ; 4 = exit
170 ; 5 = final exit
171 ; 6 = weapon (bits 3,4 are type)
172 ; 7 = treasure (bits 3,4 are type)
174 ; Fill the room with empty space.
176 jsr make_empty_room
178 ; Determine if there is a top exit.
180 lda #0
181 sta $76
183 lda $78 ; i == 0
184 cmp #0
185 bne not_top_screen
186 lda #2
187 sta $76
188 jmp do_top_exit
190 not_top_screen:
191 clc
193 lda $78
194 and #7 ; i & 7
195 sta $70 ; temporary result
196 lda $79
197 and #7 ; j & 7
198 cmp $70
199 beq do_top_exit
200 clc
202 lda $78
203 eor $79 ; i ^ j
204 adc $78 ; + i
205 clc
206 cmp $79 ; (i ^ j) + i == j
207 bne do_top_exit
208 lda #2
209 sta $76 ; top exit
211 do_top_exit:
212 jsr draw_top_line
214 ; Determine if there is a left exit.
215 lda #0
216 sta $77
218 lda $79
219 cmp #0
220 bne not_left_screen
221 lda #2
222 sta $77
223 jmp do_left_exit
225 not_left_screen:
226 clc
228 lda $78
229 and #3 ; i & 3
230 sta $70 ; temporary result
231 lda $79
232 and #3 ; j & 3
233 cmp $70
234 beq do_left_exit
235 clc
237 lda $78
238 ora $79 ; i | j
239 eor $79 ; ^ j
240 cmp $78 ; (i | j) ^ j == i
241 bne do_left_exit
242 lda #2
243 sta $77 ; left exit
245 do_left_exit:
246 jsr draw_left_line
248 ; Determine if there is a right exit.
249 lda #0
250 sta $77
252 lda $79
253 cmp #10
254 bne not_right_screen
255 lda #2
256 sta $77
257 jmp do_right_exit
259 not_right_screen:
260 clc
262 lda $78
263 and #3 ; i & 3
264 sta $70 ; temporary result
265 lda $79
266 adc #1
267 and #3 ; j & 3
268 cmp $70
269 beq do_right_exit
270 clc
272 lda $79
273 adc #1
274 sta $70
276 lda $78
277 ora $70 ; i | j
278 eor $70 ; ^ j
279 cmp $78 ; (i | j) ^ j == i
280 bne do_right_exit
281 lda #2
282 sta $77 ; right exit
284 do_right_exit:
285 jsr draw_right_line
287 ; Determine if there is a bottom exit.
288 lda #0
289 sta $76
291 lda $78
292 cmp #10
293 bne not_bottom_screen
294 lda #2
295 sta $76
296 jmp do_bottom_exit
298 not_bottom_screen:
299 clc
301 lda $78
302 adc #1
303 and #7 ; i & 7
304 sta $70 ; temporary result
305 lda $79
306 and #7 ; j & 7
307 cmp $70
308 beq do_bottom_exit
309 clc
311 lda $78
312 adc #1
313 sta $70
315 eor $79 ; i ^ j
316 adc $70 ; + i
317 cmp $79 ; (i ^ j) + i == j
318 bne do_bottom_exit
319 lda #2
320 sta $76 ; bottom exit
322 do_bottom_exit:
323 jsr draw_bottom_line
325 ; Add the final exit.
327 lda $578a
328 cmp #3
329 bmi make_room_no_final_exit
331 lda $78
332 cmp #0
333 bne make_room_no_final_exit
335 lda $79
336 cmp #2
337 bne make_room_no_final_exit
339 lda #6
340 sta $57a0
341 lda #7
342 sta $57a1
344 make_room_no_final_exit:
346 ; Make sure that the starting, exit, key rooms are empty.
348 ldx $578a ; level number
349 lda start_rooms_y,x
350 cmp $78
351 bne make_room_not_starting_room
352 lda start_rooms_x,x
353 cmp $79
354 bne make_room_not_starting_room
356 lda #3
357 sta $70
358 jmp add_room_decoration ; optimise away the rts
360 make_room_not_starting_room:
362 lda exit_rooms_y,x
363 cmp $78
364 bne make_room_not_exit_room
365 lda exit_rooms_x,x
366 cmp $79
367 bne make_room_not_exit_room
369 ; Add an exit to the room.
370 lda $78
371 eor $79
372 and #15
373 tax
374 lda exit_room_offsets,x
375 tax
376 lda $5780
377 and #1
378 beq exit_not_open
380 lda #5
381 sta $579c,x
382 jmp exit_decoration
384 exit_not_open:
385 clc
386 lda #4
387 sta $579c,x
389 exit_decoration:
390 lda #3
391 sta $70
392 jmp add_room_decoration ; optimise away the rts
394 make_room_not_exit_room:
396 lda key_rooms_y,x
397 cmp $78
398 bne make_room_not_key_room
399 lda key_rooms_x,x
400 cmp $79
401 bne make_room_not_key_room
403 lda #1
404 sta $70
405 jmp add_room_decoration ; optimise away the rts
407 make_room_not_key_room:
408 clc
410 ; Fill in the room details.
412 lda $79
413 sta $7c
414 sec
415 ldx $578a
416 lda seeds,x
417 sbc $78
418 sec
419 sta $7d
420 clc
422 ; Discard the first ten values.
424 ldy #10
425 make_room_loop0:
426 jsr unlimited_values
427 dey
428 bne make_room_loop0
430 ; Fill the room array with values.
432 lda #$a7
433 sta $70
434 lda #$57
435 sta $71
437 ldy #0
438 make_room_loop1:
440 jsr next_value
441 sta ($70),y
442 iny
443 cpy #8
444 bne make_room_loop1 ; continue the same row
446 lda $70
447 cmp #$ed
448 beq make_room_loop1_exit ; exit after the last row
450 adc #10
451 sta $70
452 ldy #0 ; reset the row counter
453 jmp make_room_loop1
455 make_room_loop1_exit:
456 rts
458 decoration_offsets: .byte 11,18,81,88
460 add_room_decoration:
462 lda #$9c
463 sta $8e
464 lda #$57
465 sta $8f
467 ldx #3
468 add_room_decoration_loop:
470 lda decoration_offsets,x
471 tay
472 lda $70
473 sta ($8e),y
474 dex
475 bpl add_room_decoration_loop
477 clc
478 rts
480 exit_room_offsets: .byte 35,66,63,56,34,44,64,33,36,55,65,53,45,46,54,43
481 treasure_x: .byte 3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6
482 treasure_y: .byte 1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2
484 eleven_times_table: .byte 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110
486 add_treasure: ; $78,$79 = i,j
488 lda $78
489 tax
490 lda eleven_times_table,x
491 adc $79
492 tax
494 lda $5200,x
495 ora #$80
496 sta $5200,x ; set the top bit (room visited)
497 and #$7f ; mask off the top bit to obtain the item number + 1
498 cmp #0
499 beq add_treasure_exit
501 sec
502 sbc #1
503 sta $528d ; store weapon/treasure type
504 clc
506 lda $78
507 eor $79
508 adc $528d
509 and #15
510 sta $70
512 lda #15
513 sta $8c
514 ldy #0
515 add_treasure_loop:
517 clc
519 ldx $70
520 lda treasure_y,x ; y
521 sta $8d
522 tax
523 lda room_row_offsets_low,x
524 sta $80
526 ldx $70
527 lda treasure_x,x ; x
528 sta $8e
529 adc $80
530 sta $80
532 lda #$57
533 adc #0
534 sta $81
535 clc
537 lda ($80),y ; tile
538 cmp #0
539 bne add_treasure_loop_next
541 lda #4 ; type (weapon/treasure)
542 sta $528c
543 lda $8d ; y
544 sta $528e
545 lda #1 ; dy
546 sta $528f
547 lda $8e ; x
548 sta $5290
549 lda #0 ; dx
550 sta $5291
552 lda #$8c
553 sta $74
554 lda #$52
555 sta $75
556 jmp plot_character ; optimise away the rts
558 add_treasure_loop_next:
559 dec $8c
560 bmi add_treasure_exit
562 dec $70
563 bpl add_treasure_loop
565 lda #15
566 sta $70
567 jmp add_treasure_loop
569 add_treasure_exit:
570 clc
571 rts
573 create_enemy_positions:
575 lda #31 ; counter
576 sta $7e
578 lda #1 ; x
579 sta $70
581 lda #1 ; y
582 sta $71
584 lda #$a7
585 sta $72
586 lda #$57
587 sta $73
589 ldx #15 ; offset into position areas
590 ldy #0
592 create_enemy_positions_loop:
594 jsr unlimited_values
595 and #7
596 sta $80 ; store temporarily
598 lda $72
599 adc $80
600 sta $72 ; update the offset into the room data
601 clc
603 lda $70
604 adc $80 ; update x
605 cmp #10
606 bpl create_enemy_positions_next_row
608 sta $70 ; store x
609 jmp create_enemy_positions_check_tile
611 create_enemy_positions_next_row:
613 sec
614 sbc #10
615 sta $70 ; store the x position on the next row
616 clc
618 lda $71
619 adc #1 ; update the y position
620 cmp #10
621 bpl create_enemy_positions_to_top
623 sta $71 ; store the y position for the next row
624 jmp create_enemy_positions_check_tile
626 create_enemy_positions_to_top:
628 lda #1 ; reset the x, y and offset values
629 sta $70
630 sta $71
631 lda #$a7
632 sta $72
634 create_enemy_positions_check_tile:
636 lda ($72),y
637 cmp #0
638 bne create_enemy_positions_next
640 lda $70
641 sta $0ee0,x ; store the x value
643 lda $71
644 sta $0ef0,x ; store the y value
646 dex
647 bmi create_enemy_positions_exit
649 create_enemy_positions_next:
650 clc
651 dec $7e
652 bpl create_enemy_positions_loop
654 ; The position areas were not filled. Write invalid values into the
655 ; first area for the emerge routine to find.
657 lda #0
658 create_enemy_positions_fill_loop:
660 sta $0ee0,x
661 dex
662 bpl create_enemy_positions_fill_loop
664 create_enemy_positions_exit:
665 clc
666 rts
668 plot: ; $70,$71=source address
669 ; $72,$73=destination address
670 ldy #$1f
671 plotloop0:
672 lda ($70),y
673 sta ($72),y
674 dey
675 bpl plotloop0
677 lda $72
678 adc #$20
679 sta $72
680 lda $73
681 adc #$01
682 sta $73 ; next line minus 0x20
683 clc
685 ldy #$3f
686 plotloop1:
687 lda ($70),y
688 sta ($72),y
689 dey
690 cpy #$20
691 bpl plotloop1
693 lda $72
694 adc #$20
695 sta $72
696 lda $73
697 adc #$01
698 sta $73 ; next line minus 0x20
699 clc
701 ldy #$5f
702 plotloop2:
703 lda ($70),y
704 sta ($72),y
705 dey
706 cpy #$40
707 bpl plotloop2
709 sec
710 lda $72
711 sbc #$20
712 sta $72
713 lda $73
714 sbc #$02
715 sta $73 ; back two lines minus 0x20
716 clc
718 rts
722 plot_blank_xy: ; X=y, Y=x
724 lda screen_rows_low,x
725 sta $72
726 lda screen_rows_high,x
727 sta $73
729 tya
730 tax
731 lda screen_columns_low,x
732 adc $72
733 sta $72
734 lda screen_columns_high,x
735 adc $73
736 sta $73
737 clc
738 ; run on into plot_blank
740 plot_blank: ; $72,$73=destination address
742 ldy #$1f
743 lda #0
744 plot_blank_loop0:
745 sta ($72),y
746 dey
747 bpl plot_blank_loop0
749 lda $72
750 adc #$20
751 sta $72
752 lda $73
753 adc #$01
754 sta $73 ; next line minus 0x20
755 clc
757 ldy #$3f
758 lda #0
759 plot_blank_loop1:
760 sta ($72),y
761 dey
762 cpy #$20
763 bpl plot_blank_loop1
765 lda $72
766 adc #$20
767 sta $72
768 lda $73
769 adc #$01
770 sta $73 ; next line minus 0x20
771 clc
773 ldy #$5f
774 lda #0
775 plot_blank_loop2:
776 sta ($72),y
777 dey
778 cpy #$40
779 bpl plot_blank_loop2
781 sec
782 lda $72
783 sbc #$20
784 sta $72
785 lda $73
786 sbc #$02
787 sta $73 ; back two lines minus 0x20
788 clc
790 rts
792 tile_addresses_low: .byte $00, $60, $c0, $00, $60, $c0, $20
793 tile_addresses_high: .byte $54, $54, $54, $50, $50, $50, $51
795 plot_tile: ; $7b=tile number
796 ; 1 = flowers/decoration
797 ; 2 = trees/wall
798 ; 3 = trees
799 ; 4 = exit
800 ; 5 = open exit
801 ; 6 = final exit (left)
802 ; 7 = final exit (right)
803 ; $72,$73=screen position
805 lda $7b
806 cmp #0
807 bne plot_tile_sprite
808 clc
809 jmp plot_blank ; optimise away the rts
811 plot_tile_sprite:
812 clc
813 tax
814 dex
815 lda tile_addresses_low,x
816 sta $70
817 lda tile_addresses_high,x
818 sta $71
820 lda $7b
821 cmp #4
822 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
824 clc
825 lda $578a
826 and #3 ; change the tile set for later levels
827 tax
829 plot_not_blank_add_loop:
831 cpx #2
832 bne plot_not_blank_not_2
833 dex
834 jmp plot_not_blank_not_0
836 plot_not_blank_not_2:
837 beq plot_not_blank_add_loop
838 cpx #0
840 plot_not_blank_not_0:
841 beq plot_not_blank_after_add_loop
842 clc
843 lda $70
844 adc #$20
845 sta $70
846 lda $71
847 adc #$01
848 sta $71
849 dex
850 jmp plot_not_blank_add_loop
852 plot_not_blank_after_add_loop:
853 clc
854 jsr plot
855 rts
857 plot_room: ; $78,$79 = i,j (from $5782,$5783)
858 jsr blank_screen
860 lda $5782
861 sta $78
862 lda $5783
863 sta $79
865 jsr make_room
866 ; Run on into the next piece of code.
868 plot_room_tiles:
870 lda #$80
871 sta $72
872 lda #$5a
873 sta $73 ; $72,$73 = screen position
875 lda #0
876 sta $7a
877 row_loop:
879 lda #9
880 sta $76
882 column_loop:
883 lda $7a
884 tax
885 lda $579c,x
886 sta $7b
887 jsr plot_tile
889 inc $7a
890 lda $76
891 sec
892 sbc #1
893 sta $76
894 clc
895 cmp #0
896 bpl column_loop
898 clc
900 lda $72
901 adc #$80
902 sta $72
903 lda $73
904 adc #$02
905 sta $73
906 clc
907 cmp #$80
908 beq end_rows
910 jmp row_loop
912 end_rows:
913 rts
915 set_room_palette: ; $78=i; $79=j
917 lda #1
918 sta $70
919 lda $78
920 eor $79
921 and #3
922 tax
923 lda room_palettes,x
924 sta $71
925 jsr set_palette
927 jsr set_core_palette
928 rts
930 room_palettes: .byte 1, 6, 5, 7
932 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
934 plot8x24_y0: ; $70,$71=source address
935 ; $72,$73=destination address
937 ldx #2
939 plot8x24_y0_loop:
941 ldy #15
943 plotloop8x24_y0_0:
944 lda ($70),y
945 eor ($72),y
946 sta ($72),y
947 dey
948 bpl plotloop8x24_y0_0
950 dex
951 bmi plot8x24_y0_exit
953 lda $72
954 adc #$40
955 sta $72
956 lda $73
957 adc #$01
958 sta $73
959 clc
961 lda $70
962 adc #16
963 sta $70
964 lda $71
965 adc #0
966 sta $71
967 clc
969 jmp plot8x24_y0_loop
971 plot8x24_y0_exit:
972 clc
973 jmp plot_buffer_loop_next
976 plot8x8_y1: ; $70,$71=source address
977 ; $72,$73=destination address
978 lda #2
979 sta $7e
980 lda #10
981 sta $7f
983 lda #0 ; plotting 1 8x8 piece
984 sta $8a
986 jmp plot8x24_y123 ; optimise away the rts
988 plot8x24_y1: ; $70,$71=source address
989 ; $72,$73=destination address
990 lda #2
991 sta $7e
992 lda #10
993 sta $7f
995 lda #2 ; plotting 3 8x8 pieces
996 sta $8a
998 jmp plot8x24_y123 ; optimise away the rts
1000 plot8x8_y2: ; $70,$71=source address
1001 ; $72,$73=destination address
1002 lda #4
1003 sta $7e
1004 lda #12
1005 sta $7f
1007 lda #0 ; plotting 1 8x8 piece
1008 sta $8a
1010 jmp plot8x24_y123 ; optimise away the rts
1012 plot8x24_y2: ; $70,$71=source address
1013 ; $72,$73=destination address
1014 lda #4
1015 sta $7e
1016 lda #12
1017 sta $7f
1019 lda #2 ; plotting 3 8x8 pieces
1020 sta $8a
1022 jmp plot8x24_y123 ; optimise away the rts
1024 plot8x8_y3: ; $70,$71=source address
1025 ; $72,$73=destination address
1026 lda #6
1027 sta $7e
1028 lda #14
1029 sta $7f
1031 lda #0 ; plotting 1 8x8 piece
1032 sta $8a
1034 jmp plot8x24_y123 ; optimise away the rts
1036 plot8x24_y3: ; $70,$71=source address
1037 ; $72,$73=destination address
1038 lda #6
1039 sta $7e
1040 lda #14
1041 sta $7f
1043 lda #2 ; plotting 3 8x8 pieces
1044 sta $8a
1046 ; Run on into the next routine.
1048 plot8x24_y123: ; $70,$71=source address
1049 ; $72,$73=destination address
1050 ; $7e=offset into source data for first column
1051 ; $7f=offset into source data for second column
1053 plot8x24_y123_loop:
1055 ldx #0
1056 plot8x24_y123_upper_loop_outer:
1058 ldy $7e,x
1059 lda plot_upper_offsets,x
1060 sta $89
1062 plot8x24_y123_upper_loop_inner: ; plot the first column until
1063 dey ; we reach the start
1064 cpy $89
1065 bmi plot8x24_y123_upper_loop_inner_endloop
1066 lda ($70),y
1067 eor ($72),y
1068 sta ($72),y
1069 jmp plot8x24_y123_upper_loop_inner
1071 plot8x24_y123_upper_loop_inner_endloop:
1072 clc
1074 inx
1075 cpx #2
1076 bne plot8x24_y123_upper_loop_outer
1078 clc
1079 lda $72 ; move the destination pointer to refer to the next line
1080 adc #$38
1081 sta $72
1082 lda $73
1083 adc #$01
1084 sta $73
1085 clc
1087 ldx #0
1088 plot8x24_y123_lower_loop_outer:
1090 lda plot_lower_offsets,x
1091 tay
1092 lda $7e,x
1093 sta $89
1095 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1096 lda ($70),y ; offset for the column
1097 eor ($72),y
1098 sta ($72),y
1099 dey
1100 cpy $89
1101 bpl plot8x24_y123_lower_loop_inner
1103 inx
1104 cpx #2
1105 bne plot8x24_y123_lower_loop_outer
1107 dec $8a
1108 bmi plot8x24_y123_exit
1110 clc
1111 lda $70 ; update the source pointer to refer to the next piece
1112 adc #16 ; of sprite data
1113 sta $70
1114 lda $71
1115 adc #0
1116 sta $71
1117 clc
1119 lda $72 ; update the destination pointer to point to the next
1120 adc #8 ; space
1121 sta $72
1122 lda $73
1123 adc #0
1124 sta $73
1125 clc
1127 jmp plot8x24_y123_loop
1129 plot8x24_y123_exit:
1130 clc
1131 jmp plot_buffer_loop_next
1133 plot16x16_y0: ; $70,$71=source address
1134 ; $72,$73=destination address
1135 ldy #31
1137 plotloop16x16_y0_0:
1138 lda ($70),y
1139 eor ($72),y
1140 sta ($72),y
1141 dey
1142 bpl plotloop16x16_y0_0
1143 clc
1145 lda $72
1146 adc #$20
1147 sta $72
1148 lda $73
1149 adc #$01
1150 sta $73 ; 0x140 - 32
1151 clc
1153 ldy #63
1155 plotloop16x16_y0_1:
1156 lda ($70),y
1157 eor ($72),y
1158 sta ($72),y
1159 dey
1160 cpy #32
1161 bpl plotloop16x16_y0_1
1162 clc
1164 jmp plot_buffer_loop_next
1166 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1168 plot16x16_y1: ; $70,$71=source address
1169 ; $72,$73=destination address
1171 lda #2
1172 sta $7e
1173 lda #10
1174 sta $7f
1175 lda #18
1176 sta $80
1177 lda #26
1178 sta $81
1179 jmp plot16x16_y123 ; optimise away the rts
1181 plot16x16_y2: ; $70,$71=source address
1182 ; $72,$73=destination address
1184 lda #4
1185 sta $7e
1186 lda #12
1187 sta $7f
1188 lda #20
1189 sta $80
1190 lda #28
1191 sta $81
1192 jmp plot16x16_y123 ; optimise away the rts
1194 plot16x16_y3: ; $70,$71=source address
1195 ; $72,$73=destination address
1197 lda #6
1198 sta $7e
1199 lda #14
1200 sta $7f
1201 lda #22
1202 sta $80
1203 lda #30
1204 sta $81
1205 ; Run on into the next routine.
1207 plot16x16_y123: ; $70,$71=source address
1208 ; $72,$73=destination address
1209 ; $7e=offset into source data for first column
1210 ; $7f=offset into source data for second column
1211 ; $80=offset into source data for third column
1212 ; $81=offset into source data for fourth column
1214 lda #1
1215 sta $8a
1217 plot16x16_y123_loop:
1219 ldx #0
1220 plot16x16_y123_upper_loop_outer:
1222 ldy $7e,x
1223 lda plot_upper_offsets,x
1224 sta $89
1226 plot16x16_y123_upper_loop_inner:
1228 dey
1229 cpy $89
1230 bmi plot16x16_y123_upper_loop_inner_endloop
1231 lda ($70),y
1232 eor ($72),y
1233 sta ($72),y
1234 jmp plot16x16_y123_upper_loop_inner
1236 plot16x16_y123_upper_loop_inner_endloop:
1237 clc
1239 inx
1240 cpx #4
1241 bne plot16x16_y123_upper_loop_outer
1243 clc
1244 lda $72 ; move the destination pointer to refer to the next line
1245 adc #$38
1246 sta $72
1247 lda $73
1248 adc #$01
1249 sta $73
1250 clc
1252 ldx #0
1253 plot16x16_y123_lower_loop_outer:
1255 lda plot_lower_offsets,x
1256 tay
1257 lda $7e,x
1258 sta $89
1260 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1261 lda ($70),y ; for the column
1262 eor ($72),y
1263 sta ($72),y
1264 dey
1265 cpy $89
1266 bpl plot16x16_y123_lower_loop_inner
1268 inx
1269 cpx #4
1270 bne plot16x16_y123_lower_loop_outer
1272 dec $8a
1273 bmi plot16x16_y123_exit
1275 clc
1276 lda $70 ; update the source pointer to refer to the next piece
1277 adc #32 ; of sprite data
1278 sta $70
1279 lda $71
1280 adc #0
1281 sta $71
1282 clc
1284 lda $72 ; update the destination pointer to point to the next
1285 adc #8 ; space
1286 sta $72
1287 lda $73
1288 adc #0
1289 sta $73
1290 clc
1292 jmp plot16x16_y123_loop
1294 plot16x16_y123_exit:
1295 clc
1296 jmp plot_buffer_loop_next
1298 plot_upper_offsets: .byte 0, 8, 16, 24
1299 plot_lower_offsets: .byte 7, 15, 23, 31
1301 plot8x8_y0: ; $70,$71=source address
1302 ; $72,$73=destination address
1303 ldy #15
1305 plotloop8x8_y0_0:
1306 lda ($70),y
1307 eor ($72),y
1308 sta ($72),y
1309 dey
1310 bpl plotloop8x8_y0_0
1311 clc
1313 jmp plot_buffer_loop_next
1316 check_key: ; x=key code
1317 lda #129 ; returns y=255 or 0
1318 ldy #255
1319 jsr $fff4
1320 rts
1322 player_direction_chars_low: .byte $00,$30,$60,$90,$c0,$f0,$20,$50, $80,$b0,$e0,$10
1323 player_direction_chars_high: .byte $3f,$3f,$3f,$3f,$3f,$3f,$40,$40, $40,$40,$40,$41
1325 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1326 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1327 screen_subrows_low: .byte $00,$06,$44,$82
1328 screen_subrows_high: .byte $00,$00,$01,$02
1330 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1331 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1332 screen_subcolumns_low: .byte $00,$08,$10,$18
1334 enemy_direction_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1335 enemy_direction_chars_high: .byte $41,$42,$42,$42,$42,$43,$43,$43
1337 emerge_explode_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1338 emerge_explode_chars_high: .byte $4b,$4c,$4c,$4c,$4c,$4d,$4d,$4d
1340 item_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80,$c0
1341 item_chars_high: .byte $4d,$4e,$4e,$4e,$4e,$4f,$4f,$4f,$4f
1343 projectile_chars_low: .byte $40,$50,$60,$70,$80,$90,$a0,$b0
1345 unplot_character: ; $74,$75=character address
1347 lda $82 ; store the unplot buffer address in $78,$79
1348 sta $78
1349 lda $83
1350 sta $79
1351 jsr plot_character_sprite
1352 lda $78
1353 sta $82 ; update the latest space in the unplot buffer
1354 rts
1356 plot_character: ; $74,$75=character address
1358 lda $84 ; store the plot buffer address in $78,$79
1359 sta $78
1360 lda $85
1361 sta $79
1362 jsr plot_character_sprite
1363 lda $78
1364 sta $84 ; update the latest space in the plot buffer
1365 rts
1367 plot_character_sprite: ; $74,$75=character address
1368 ; $78,$79=unplot/plot buffer address
1370 ldy #0
1371 lda ($74),y
1372 cmp #0
1373 bne plot_characters_read_character
1374 jmp plot_characters_next
1376 plot_characters_read_character:
1377 clc
1379 sta $77 ; temporarily store the object type
1381 ; Use lookup tables to load the offsets into the sprite.
1383 ; Direction
1384 iny
1385 lda ($74),y
1386 sta $80 ; temporarily store the direction
1388 ; y
1389 iny
1390 lda ($74),y
1391 tax
1392 lda screen_rows_low,x
1393 sta $72
1394 lda screen_rows_high,x
1395 sta $73
1396 clc
1398 ; dy
1399 iny
1400 lda ($74),y
1401 sta $76
1402 tax
1403 lda screen_subrows_low,x
1404 adc $72
1405 sta $72
1406 lda screen_subrows_high,x
1407 adc $73
1408 sta $73
1409 clc
1411 ; x
1412 iny
1413 lda ($74),y
1414 tax
1415 lda screen_columns_low,x
1416 adc $72
1417 sta $72
1418 lda screen_columns_high,x
1419 adc $73
1420 sta $73
1421 clc
1423 ; dx
1424 iny
1425 lda ($74),y
1426 tax
1427 lda screen_subcolumns_low,x
1428 adc $72
1429 sta $72
1430 clc
1432 lda $77
1433 cmp #1
1434 bne plot_characters_loop_not_player
1436 ; Plot 8x24 sprites (player)
1438 ldx $80
1439 lda player_direction_chars_low,x
1440 sta $70
1441 lda player_direction_chars_high,x
1442 sta $71
1444 ; Use the dy value to determine which plotting routine to use.
1446 ldy #0
1447 ldx $76
1448 lda plot_routine_indices_8x24,x
1450 sta ($78),y
1451 jmp plot_characters_stored
1454 plot_characters_loop_not_player:
1455 cmp #2
1456 bne plot_characters_loop_not_projectile
1458 ; Plot 8x8 sprites (projectiles)
1460 lda $80
1461 and #7
1462 tax
1463 lda projectile_chars_low,x
1464 sta $70
1465 lda #$41
1466 sta $71
1468 ; Use the dy value to determine which plotting routine to use.
1470 ldy #0
1471 ldx $76
1472 lda plot_routine_indices_8x8,x
1474 sta ($78),y
1475 jmp plot_characters_stored
1478 plot_characters_loop_not_projectile:
1479 cmp #3
1480 bne plot_characters_loop_not_explosion
1482 ; Plot 16x16 sprites (emerging, explosions)
1484 ; Select the sprites to use.
1486 lda $80
1487 and #7 ; only keep the bits required to find the correct sprite
1488 clc
1489 tax
1490 lda emerge_explode_chars_low,x
1491 sta $70
1492 lda emerge_explode_chars_high,x
1493 sta $71
1495 jmp plot_characters_16x16
1497 plot_characters_loop_not_explosion:
1498 cmp #4
1499 bne plot_characters_loop_not_item
1501 ; Plot 16x16 sprites (items)
1503 ; Select the sprites to use.
1505 lda $80
1506 and #$0f ; only keep the bits required to find the correct sprite
1507 clc
1508 tax
1509 lda item_chars_low,x
1510 sta $70
1511 lda item_chars_high,x
1512 sta $71
1514 jmp plot_characters_16x16
1516 plot_characters_loop_not_item:
1517 cmp #8
1518 bmi plot_characters_loop_not_enemy
1520 ; Plot 16x16 sprites (enemies)
1522 ; Select the set of sprites to use.
1524 and #$70
1525 lsr
1526 lsr
1527 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1528 clc
1529 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1531 lda $80
1532 and #7 ; keep the animation bits
1533 tax
1534 lda enemy_direction_chars_low,x
1535 sta $70
1536 lda enemy_direction_chars_high,x
1537 adc $71
1538 sta $71
1540 plot_characters_16x16:
1542 ; Use the dy value to determine which plotting routine to use.
1544 ldy #0
1545 ldx $76
1546 lda plot_routine_indices_16x16,x
1548 sta ($78),y
1550 plot_characters_stored:
1552 iny
1553 lda $70
1554 sta ($78),y
1555 iny
1556 lda $71
1557 sta ($78),y
1558 iny
1559 lda $72
1560 sta ($78),y
1561 iny
1562 lda $73
1563 sta ($78),y
1565 clc
1566 lda $78
1567 adc #12
1568 sta $78
1570 plot_characters_loop_not_enemy:
1572 plot_characters_next:
1574 lda #255 ; terminate this stream of entries in the plot buffer
1575 ldy #0
1576 sta ($78),y
1577 clc
1578 rts
1580 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1581 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1582 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1584 reset_plot_buffer:
1585 lda #$06 ; reset the index into the plot buffer
1586 sta $84
1587 lda #$53
1588 sta $85
1590 lda #255 ; terminate the plot list
1591 ldy #0
1592 sta ($84),y
1593 rts
1595 reset_unplot_buffer:
1596 lda #$00 ; reset the index into the plot buffer
1597 sta $82
1598 lda #$53
1599 sta $83
1601 lda #255 ; terminate the unplot list
1602 ldy #0
1603 sta ($82),y
1604 rts
1606 plot_buffer_types_low: .byte <plot_buffer_loop_next
1607 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1608 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1609 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1611 plot_buffer_types_high: .byte >plot_buffer_loop_next
1612 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1613 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1614 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1616 plot_buffer:
1618 lda #$00
1619 sta $84
1620 lda #$53
1621 sta $85
1623 lda #6
1624 sta $88
1626 plot_buffer_loop:
1628 ldy #0
1629 lda ($84),y
1630 cmp #255
1631 beq plot_buffer_loop_skip
1633 clc
1634 tax
1635 lda plot_buffer_types_low,x
1636 sta $86
1637 lda plot_buffer_types_high,x
1638 sta $87
1640 iny
1641 lda ($84),y
1642 sta $70
1644 iny
1645 lda ($84),y
1646 sta $71
1648 iny
1649 lda ($84),y
1650 sta $72
1652 iny
1653 lda ($84),y
1654 sta $73
1656 jmp ($86) ; returns to plot_buffer_loop_next
1658 plot_buffer_loop_skip:
1660 lda $88
1661 cmp #12
1662 beq plot_buffer_exit ; both unplot and plot lists have terminated
1664 lda #12
1665 sta $88
1666 lda $84
1667 adc #6
1668 sta $84
1669 jmp plot_buffer_loop
1671 plot_buffer_loop_next:
1672 clc
1674 lda $84
1675 adc $88
1676 sta $84
1677 jmp plot_buffer_loop
1679 plot_buffer_exit:
1680 clc
1681 rts
1683 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1685 animate_player_left:
1687 ; Set the direction and toggle the animation bit.
1689 lda $5281
1690 and #1
1691 eor #1 ; toggle animation flag
1692 sta $5281 ; left (directional bits are 0)
1694 jsr plot_character
1695 rts
1697 animate_player_right:
1699 ; Set the direction and toggle the animation bit.
1701 lda $5281
1702 and #1 ; remove direction information (result is 0)
1703 eor #1 ; toggle animation flag
1704 ora #2 ; right
1705 sta $5281
1707 jsr plot_character
1708 rts
1710 animate_player_up:
1712 ; Set the direction and toggle the animation bit.
1714 lda $5281
1715 and #1 ; remove direction information (result is 0)
1716 eor #1 ; toggle animation flag
1717 ora #4 ; up
1718 sta $5281
1720 jsr plot_character
1721 rts
1723 animate_player_down:
1725 ; Set the direction and toggle the animation bit.
1727 lda $5281
1728 and #1 ; remove direction information (result is 0)
1729 eor #1 ; toggle animation flag
1730 ora #6 ; down
1731 sta $5281
1733 jsr plot_character
1734 rts
1736 move_player:
1738 lda $578e
1739 and #1
1740 beq move_player_allowed
1742 clc
1743 rts
1745 move_player_allowed:
1747 lda #$80 ; set up the address of the player character
1748 sta $74
1749 lda #$52
1750 sta $75
1752 ; Handle joystick
1754 lda $577e
1755 cmp #0
1756 beq move_player_handle_left_key
1758 lda #128
1759 ldx #1
1760 jsr $fff4
1761 cpy #16
1762 bmi move_player_joystick_left_check
1763 jmp move_player_right
1765 move_player_joystick_left_check:
1766 cpy #240
1767 bpl move_player_handle_joystick_up_down
1768 jmp move_player_left
1770 move_player_handle_joystick_up_down:
1772 lda #128
1773 ldx #2
1774 jsr $fff4
1775 cpy #16
1776 bmi move_player_joystick_down_check
1777 jmp move_player_up
1779 move_player_joystick_down_check:
1780 cpy #240
1781 bpl move_player_handle_left_key
1782 jmp move_player_down
1784 move_player_handle_left_key:
1786 ; Handle the left key.
1788 ldx #158 ; (Z)
1789 jsr check_key
1790 cpy #255
1791 bne move_player_not_left_key
1793 move_player_left:
1795 lda $5285 ; read dx
1796 cmp #0
1797 beq move_player_left_check_x
1799 jsr unplot_character ; unplot the player character
1800 dec $5285
1801 clc
1802 jmp animate_player_left ; optimise away the rts
1804 move_player_left_check_x: ; Check the x offset.
1806 lda $5284
1807 cmp #0
1808 beq move_player_leave_room_left
1810 clc
1811 tay
1812 dey ; x - 1
1813 lda $5282 ; load the y offset
1814 tax ; as an index
1815 lda room_row_offsets_low,x ; read the address of the row
1816 sta $70
1817 lda #$57
1818 sta $71
1819 lda ($70),y ; load the tile to the left
1821 cmp #5 ; check for the open exit or final exit
1822 bmi move_player_not_left_exit1
1823 jmp try_to_exit_level ; optimise away the rts
1825 move_player_not_left_exit1:
1826 cmp #0
1827 bne move_player_not_left_key
1829 lda $5283 ; dy
1830 cmp #0
1831 beq move_player_allow_left
1833 clc
1834 lda $70 ; dy > 0 so we need to check another tile
1835 adc #10
1836 sta $70
1837 lda ($70),y ; load the tile below and to the left
1839 cmp #5 ; check for the open exit or final exit
1840 bmi move_player_not_left_exit2
1841 jmp try_to_exit_level ; optimise away the rts
1843 move_player_not_left_exit2:
1844 cmp #0
1845 bne move_player_not_left_key
1847 move_player_allow_left:
1848 tya
1849 sta $81 ; temporary
1850 jsr unplot_character ; unplot the player character
1851 lda $81
1852 sta $5284 ; store the new room x offset
1853 lda #3
1854 sta $5285 ; dx = 3
1855 clc
1856 jmp animate_player_left ; optimise away the rts
1858 move_player_leave_room_left:
1859 sec
1860 lda $5783
1861 sbc #1
1862 sta $5783
1863 clc
1865 ; Set the player's position on the right of the screen.
1867 ; No need to unplot.
1869 lda #9 ; x = 9
1870 sta $5284
1871 lda #2 ; dx = 2
1872 sta $5285
1874 jsr animate_player_left
1875 sec ; indicate to the calling routine that the player
1876 rts ; has left the room
1878 move_player_not_left_key:
1880 ; Handle the right key.
1882 ldx #189 ; (X)
1883 jsr check_key
1884 cpy #255
1885 beq move_player_right
1886 jmp move_player_not_right_key
1888 move_player_right:
1890 lda $5285 ; read dx
1891 cmp #2
1892 beq move_player_right_check_x
1893 cmp #3
1894 beq move_player_right_tile
1896 jsr unplot_character ; unplot the player character
1897 inc $5285
1898 clc
1899 jmp animate_player_right ; optimise away the rts
1901 move_player_right_check_x: ; Check the x offset.
1903 lda $5284
1904 cmp #9
1905 beq move_player_leave_room_right
1907 clc
1908 tay
1909 iny ; x + 1
1910 lda $5282 ; load the y offset
1911 tax ; as an index
1912 lda room_row_offsets_low,x ; read the address of the row
1913 sta $70
1914 lda #$57
1915 sta $71
1916 lda ($70),y ; load the tile to the right
1918 cmp #5 ; check for the open exit or final exit
1919 bmi move_player_not_right_exit1
1920 jmp try_to_exit_level ; optimise away the rts
1922 move_player_not_right_exit1:
1923 cmp #0
1924 bne move_player_not_right_key
1926 lda $5283 ; dy
1927 cmp #0
1928 beq move_player_allow_right
1930 clc ; dy > 0 so we need to check another tile
1931 lda $70
1932 adc #10
1933 sta $70
1934 lda ($70),y ; load the tile below and to the right
1936 cmp #5 ; check for the open exit or final exit
1937 bmi move_player_not_right_exit2
1938 jmp try_to_exit_level ; optimise away the rts
1940 move_player_not_right_exit2:
1941 cmp #0
1942 bne move_player_not_right_key
1944 move_player_allow_right:
1946 jsr unplot_character ; unplot the player character
1947 inc $5285 ; update dx
1948 clc
1949 jmp animate_player_right ; optimise away the rts
1951 move_player_right_tile:
1953 jsr unplot_character ; unplot the player character
1954 inc $5284 ; store the new room x offset
1955 lda #0
1956 sta $5285 ; dx = 0
1957 clc
1958 jmp animate_player_right ; optimise away the rts
1960 move_player_leave_room_right:
1961 clc
1962 inc $5783
1963 clc
1965 ; Set the player's position on the left of the screen.
1967 ; No need to unplot.
1969 lda #0 ; x = 0
1970 sta $5284
1971 lda #0 ; dx = 0
1972 sta $5285
1974 jsr animate_player_right
1975 sec ; indicate to the calling routine that the
1976 rts ; player has left the room
1978 move_player_not_right_key:
1980 ; Handle the up key.
1982 ldx #183 ; (:)
1983 jsr check_key
1984 cpy #255
1985 bne move_player_not_up_key
1987 move_player_up:
1989 lda $5283 ; read dy
1990 cmp #0
1991 beq move_player_up_check_y
1993 jsr unplot_character ; unplot the player character
1994 dec $5283
1995 clc
1996 jmp animate_player_up ; optimise away the rts
1998 move_player_up_check_y: ; Check the y offset.
2000 lda $5282
2001 cmp #0
2002 beq move_player_leave_room_up
2004 tax ; use the y offset as an index
2005 dex ; y - 1
2006 ldy $5284 ; load the x offset
2007 lda room_row_offsets_low,x ; read the address of the row
2008 sta $70
2009 lda #$57
2010 sta $71
2011 lda ($70),y ; load the tile above
2013 cmp #5 ; check for the open exit or final exit
2014 bmi move_player_not_up_exit1
2015 jmp try_to_exit_level ; optimise away the rts
2017 move_player_not_up_exit1:
2018 cmp #0
2019 bne move_player_not_up_key
2021 lda $5285 ; dx
2022 cmp #3
2023 bmi move_player_allow_up
2025 clc ; dx > 2 so we need to check another tile
2026 iny
2027 lda ($70),y ; load the tile above and to the right
2029 cmp #5 ; check for the open exit or final exit
2030 bmi move_player_not_up_exit2
2031 jmp try_to_exit_level ; optimise away the rts
2033 move_player_not_up_exit2:
2034 cmp #0
2035 bne move_player_not_up_key
2037 move_player_allow_up:
2038 txa
2039 sta $81 ; temporary
2040 jsr unplot_character ; unplot the player character
2041 lda $81
2042 sta $5282 ; store the new room y offset
2043 lda #3
2044 sta $5283 ; dy = 3
2045 clc
2046 jmp animate_player_up ; optimise away the rts
2048 move_player_leave_room_up:
2049 sec
2050 lda $5782
2051 sbc #1
2052 sta $5782
2053 clc
2055 ; Set the player's position on the bottom of the screen.
2057 ; No need to unplot.
2059 lda #9 ; y = 9
2060 sta $5282
2061 lda #0 ; dy = 0
2062 sta $5283
2064 jsr animate_player_up
2065 sec ; indicate to the calling routine that the player
2066 rts ; has left the room
2068 move_player_not_up_key:
2070 ; Handle the down key.
2072 ldx #151 ; (/)
2073 jsr check_key
2074 cpy #255
2075 beq move_player_down
2076 jmp move_player_not_down_key
2078 move_player_down:
2080 lda $5283 ; read dy
2081 cmp #0
2082 beq move_player_down_check_y
2083 cmp #3
2084 beq move_player_down_tile
2086 jsr unplot_character ; unplot the player character
2087 inc $5283 ; 0 <= dy < 3
2088 clc
2089 jmp animate_player_down ; optimise away the rts
2091 move_player_down_check_y: ; Check the y offset.
2093 lda $5282
2094 cmp #9
2095 beq move_player_leave_room_down
2097 clc
2098 tax
2099 inx ; y + 1
2100 ldy $5284 ; load the x offset
2101 lda room_row_offsets_low,x ; read the address of the row
2102 sta $70
2103 lda #$57
2104 sta $71
2105 lda ($70),y ; load the tile below
2107 cmp #5 ; check for the open exit or final exit
2108 bmi move_player_not_down_exit1
2109 jmp try_to_exit_level ; optimise away the rts
2111 move_player_not_down_exit1:
2112 cmp #0
2113 bne move_player_not_down_key
2115 lda $5285 ; dx
2116 cmp #3
2117 bmi move_player_allow_down
2119 clc ; dx > 2 so we need to check another tile
2120 iny
2121 lda ($70),y ; load the tile below and to the right
2123 cmp #5 ; check for the open exit or final exit
2124 bmi move_player_not_down_exit2
2125 jmp try_to_exit_level ; optimise away the rts
2127 move_player_not_down_exit2:
2128 cmp #0
2129 bne move_player_not_down_key
2131 move_player_allow_down:
2133 jsr unplot_character ; unplot the player character
2134 inc $5283 ; update dy
2135 clc
2136 jmp animate_player_down ; optimise away the rts
2138 move_player_down_tile:
2140 jsr unplot_character ; unplot the player character
2141 inc $5282 ; store the new room y offset
2142 lda #0
2143 sta $5283 ; dy = 0
2144 clc
2145 jmp animate_player_down ; optimise away the rts
2147 move_player_leave_room_down:
2148 inc $5782
2149 clc
2151 ; Set the player's position on the top of the screen.
2153 ; No need to unplot.
2155 lda #0 ; y = 0
2156 sta $5282
2157 lda #0 ; dy = 0
2158 sta $5283
2160 jsr animate_player_down
2161 sec ; indicate to the calling routine that the
2162 rts ; player has left the room
2164 move_player_not_down_key:
2165 clc
2166 rts
2168 try_to_exit_level:
2170 cmp #6
2171 bmi just_exit_level
2173 lda $5780 ; set the complete game flag
2174 ora #$02
2175 jmp try_to_exit_level_exit
2177 just_exit_level:
2178 lda $5780 ; set the exit level flag
2179 ora #$80
2181 try_to_exit_level_exit:
2182 sta $5780
2184 lda #$80
2185 sta $74
2186 lda #$52
2187 sta $75
2188 jsr unplot_character ; remove the player sprite
2189 jmp destroy_enemies ; optimise away the rts
2191 check_fire_key:
2193 lda $578d
2194 bne check_fire_key_exit
2196 lda $577e
2197 beq check_fire_key_no_joystick
2199 lda #128
2200 ldx #0
2201 jsr $fff4
2202 cpx #0
2203 bne check_fire_key_fire
2205 check_fire_key_no_joystick:
2207 ldx #182 ; (Return)
2208 jsr check_key
2209 cpy #255
2210 bne check_fire_key_exit
2212 check_fire_key_fire:
2214 lda $5286
2215 cmp #0
2216 bne check_fire_key_exit
2218 lda #16
2219 sta $578d
2221 jmp create_projectile ; optimise away the rts
2223 check_fire_key_exit:
2224 clc
2225 rts
2227 create_projectile:
2229 lda #2
2230 sta $5286
2232 lda $5281
2233 and #$06 ; copy the direction information
2234 asl
2235 asl
2236 asl
2237 ora $5789 ; apply the projectile type
2238 sta $5287
2240 lda $5283 ; player dy
2241 adc $577f ; add the weapon counter
2242 adc #1
2243 cmp #4 ; if dy > 3, create the projectile on the tile below
2244 bpl create_projectile_below
2246 clc
2247 sta $5289 ; dy + weapon counter + 1
2248 lda $5282 ; y
2249 sta $5288
2250 jmp create_projectile_continue
2252 create_projectile_below:
2253 sec
2254 sbc #4
2255 sta $5289 ; dy + weapon counter + 1 - 4
2256 clc
2257 lda $5282 ; y
2258 adc #1
2259 sta $5288
2261 create_projectile_continue:
2262 lda $5284 ; x
2263 sta $528a
2265 lda $5285 ; dx
2266 sta $528b
2268 lda $577f ; toggle the weapon counter
2269 eor #1
2270 sta $577f
2272 ; Move the projectile away from the player.
2274 jsr move_projectile_after_unplot
2275 jsr move_projectile
2277 clc
2278 rts
2280 emerge_type: ; returns A=type
2281 jsr unlimited_values
2282 lda $7d
2283 and #7
2284 cmp #4
2285 bmi emerge_type_ok
2287 sec
2288 sbc #4
2289 clc
2291 emerge_type_ok:
2292 cmp $5781 ; only allow the appropriate enemies for this level
2293 bmi emerge_type_exit
2295 sec
2296 sbc $5781
2297 clc
2299 emerge_type_exit:
2300 asl
2301 asl
2302 asl
2303 asl
2304 clc
2305 rts
2307 emerge_character: ; $74,$75=character address
2309 lda #63
2310 sta $578f
2312 jsr unlimited_values
2313 and #$0f
2314 tax
2315 lda $0ee0,x
2316 cmp #0 ; check for an invalid value and exit if found
2317 beq emerge_character_exit
2319 sta $80 ; temporary
2320 lda $0ef0,x
2321 tax
2323 ; Add an emerging enemy.
2325 ldy #0
2326 lda #3 ; emerge/explosion
2327 sta ($74),y
2329 jsr emerge_type ; obtain an enemy type
2330 iny
2331 sta ($74),y
2333 txa
2334 iny
2335 sta ($74),y ; store the y position
2336 lda #1
2337 iny
2338 sta ($74),y ; store the dy offset
2340 lda $80
2341 iny
2342 sta ($74),y ; store the x position
2343 lda #0
2344 iny
2345 sta ($74),y ; store the dx offset
2347 jsr plot_character
2349 ldx #5
2350 jsr play_sound
2352 emerge_character_exit:
2353 clc
2354 rts
2356 emerge_explode: ; $74,$75=character address
2358 jsr unplot_character
2360 ldy #1
2361 lda ($74),y ; direction/animation
2362 tax
2363 adc #1 ; update the counter
2364 and #3 ; mask off everything else
2365 sta $80 ; store the masked counter value
2366 bne move_characters_explosion_not_finished
2368 txa
2369 and #4
2370 bne move_characters_remove_character
2372 ; For emerges, convert into an enemy.
2373 txa
2374 and #$70 ; only keep bits 4,5,6
2375 ora #8 ; make this an enemy
2377 ldy #0
2378 sta ($74),y ; update the type (>= 8)
2379 iny
2380 lda $7d ; prepare the direction and animation offset
2381 and #$0c
2382 sta ($74),y
2384 jsr plot_character
2385 jmp emerge_explode_exit
2387 move_characters_remove_character:
2389 ; For finished explosions, just write 0 into the character array.
2390 lda #0
2391 ldy #0
2392 sta ($74),y
2393 jmp emerge_explode_exit
2395 move_characters_explosion_not_finished:
2396 txa
2397 and #$fc
2398 ora $80
2400 ldy #1
2401 sta ($74),y
2403 jsr plot_character
2405 emerge_explode_exit:
2406 clc
2407 rts
2409 animate_enemy_left: ; $74,$75=character address
2411 ; Set the direction and toggle the animation bit.
2413 ldy #1
2414 lda ($74),y
2415 and #$fb ; keep vertical direction bit and animation bits
2416 sta ($74),y ; left (horizontal directional bit is 0)
2418 rts
2420 move_enemy_left: ; $74,$75=character address
2422 ldy #5
2423 lda ($74),y ; read dx
2424 cmp #0
2425 beq move_enemy_left_check_x
2427 sec
2428 sbc #1
2429 ldy #5
2430 sta ($74),y ; dx
2431 clc
2432 jmp animate_enemy_left ; optimise away the rts
2434 move_enemy_left_check_x:
2436 ; Check the x offset.
2438 ldy #4
2439 lda ($74),y ; x
2440 cmp #0
2441 beq move_enemy_left_exit
2443 sec
2444 sbc #1 ; x - 1
2445 sta $81 ; temporary
2446 ldy #2
2447 lda ($74),y ; load the y offset
2448 tax ; as an index
2449 lda room_row_offsets_low,x ; read the address of the row
2450 sta $70
2451 lda #$57
2452 sta $71
2453 ldy $81 ; temporary (x - 1)
2454 lda ($70),y ; load the tile to the left
2456 cmp #0
2457 bne move_enemy_left_exit
2459 ldy #3
2460 lda ($74),y ; dy
2461 cmp #2
2462 bmi move_enemy_allow_left
2464 clc
2465 lda $70 ; dy > 1 so we need to check another tile
2466 adc #10
2467 sta $70
2468 ldy $81 ; temporary (x - 1)
2469 lda ($70),y ; load the tile below and to the left
2471 cmp #0
2472 bne move_enemy_left_exit
2474 move_enemy_allow_left:
2475 lda $81
2476 ldy #4
2477 sta ($74),y ; store the new room x offset
2478 lda #3
2479 ldy #5
2480 sta ($74),y ; dx = 3
2481 clc
2482 jmp animate_enemy_left ; optimise away the rts
2484 move_enemy_left_exit:
2485 sec
2486 rts
2488 animate_enemy_right: ; $74,$75=character address
2490 ; Set the direction and toggle the animation bit.
2492 ldy #1
2493 lda ($74),y
2494 ora #$04 ; right (keep vertical direction bit and animation bits)
2495 sta ($74),y
2497 rts
2499 move_enemy_right: ; $74,$75=character_address
2501 ldy #5
2502 lda ($74),y ; read dx
2503 cmp #0
2504 beq move_enemy_right_check_x
2505 cmp #3
2506 beq move_enemy_right_tile
2508 clc
2509 adc #1
2510 ldy #5
2511 sta ($74),y
2512 jmp animate_enemy_right ; optimise away the rts
2514 move_enemy_right_check_x: ; Check the x offset.
2516 ldy #4
2517 lda ($74),y ; x
2518 cmp #9
2519 beq move_enemy_right_exit
2521 clc
2522 adc #1 ; x + 1
2523 sta $81 ; temporary (x + 1)
2524 ldy #2
2525 lda ($74),y ; load the y offset
2526 tax ; as an index
2527 lda room_row_offsets_low,x ; read the address of the row
2528 sta $70
2529 lda #$57
2530 sta $71
2531 ldy $81 ; temporary (x + 1)
2532 lda ($70),y ; load the tile to the right
2534 cmp #0
2535 bne move_enemy_right_exit
2537 ldy #3
2538 lda ($74),y ; dy
2539 cmp #2
2540 bmi move_enemy_allow_right
2542 clc ; dy > 1 so we need to check another tile
2543 lda $70
2544 adc #10
2545 sta $70
2546 ldy $81 ; temporary (x + 1)
2547 lda ($70),y ; load the tile below and to the right
2549 cmp #0
2550 bne move_enemy_right_exit
2552 move_enemy_allow_right:
2553 clc
2555 ldy #5
2556 lda ($74),y ; dx
2557 adc #1
2558 sta ($74),y ; update dx
2559 clc
2560 jmp animate_enemy_right ; optimise away the rts
2562 move_enemy_right_tile:
2563 clc
2565 ldy #4
2566 lda ($74),y ; x
2567 adc #1
2568 sta ($74),y ; store the new room x offset
2569 lda #0
2570 iny
2571 sta ($74),y ; dx = 0
2572 clc
2573 jmp animate_enemy_right ; optimise away the rts
2575 move_enemy_right_exit:
2576 sec
2577 rts
2579 animate_enemy_up: ; $74,$75=character address
2581 ; Set the direction and toggle the animation bit.
2583 ldy #1
2584 lda ($74),y
2585 and #$f7 ; keep horizontal direction bit and animation bits
2586 sta ($74),y
2588 rts
2590 move_enemy_up: ; $74,$75=character address
2592 ldy #3
2593 lda ($74),y ; read dy
2594 cmp #0
2595 beq move_enemy_up_check_y
2597 sec
2598 sbc #1
2599 ldy #3
2600 sta ($74),y ; dy
2601 clc
2602 jmp animate_enemy_up ; optimise away the rts
2604 move_enemy_up_check_y:
2606 ; Check the y offset.
2608 ldy #2
2609 lda ($74),y ; y
2610 cmp #0
2611 beq move_enemy_up_exit
2613 tax ; use the y offset as an index
2614 dex ; y - 1
2615 ldy #4
2616 lda ($74),y ; load the x offset
2617 sta $81 ; temporary (x)
2618 tay
2619 lda room_row_offsets_low,x ; read the address of the row
2620 sta $70
2621 lda #$57
2622 sta $71
2623 lda ($70),y ; load the tile above
2625 cmp #0
2626 bne move_enemy_up_exit
2628 ldy #5
2629 lda ($74),y ; dx
2630 cmp #0
2631 beq move_enemy_allow_up
2633 clc ; dx != 0 so we need to check another tile
2634 ldy $81
2635 iny
2636 lda ($70),y ; load the tile above and to the right
2638 cmp #0
2639 bne move_enemy_up_exit
2641 move_enemy_allow_up:
2642 txa
2643 ldy #2
2644 sta ($74),y ; store the new room y offset
2645 lda #3
2646 iny
2647 sta ($74),y ; dy = 3
2648 clc
2649 jmp animate_enemy_up ; optimise away the rts
2651 move_enemy_up_exit:
2652 sec
2653 rts
2655 animate_enemy_down: ; $74,$75=character address
2657 ; Set the direction and toggle the animation bit.
2659 ldy #1
2660 lda ($74),y
2661 ora #$08 ; down
2662 sta ($74),y
2664 rts
2666 move_enemy_down: ; $74,$75=character address
2668 ldy #3
2669 lda ($74),y ; dy
2670 cmp #1
2671 beq move_enemy_down_check_y
2672 cmp #3
2673 beq move_enemy_down_tile
2675 adc #1
2676 ldy #3
2677 sta ($74),y ; dy
2678 clc
2679 jmp animate_enemy_down ; optimise away the rts
2681 move_enemy_down_check_y:
2683 ; Check the y offset.
2685 ldy #2
2686 lda ($74),y
2687 cmp #9
2688 beq move_enemy_down_exit
2690 clc
2691 adc #1 ; y + 1
2692 tax
2693 ldy #4
2694 lda ($74),y ; load the x offset
2695 sta $81 ; temporary
2696 tay
2697 lda room_row_offsets_low,x ; read the address of the row
2698 sta $70
2699 lda #$57
2700 sta $71
2701 lda ($70),y ; load the tile below
2703 cmp #0
2704 bne move_enemy_down_exit
2706 ldy #5
2707 lda ($74),y ; dx
2708 cmp #0
2709 beq move_enemy_allow_down
2711 clc ; dx != 0 so we need to check another tile
2712 ldy $81 ; x
2713 iny
2714 lda ($70),y ; load the tile below and to the right
2716 cmp #0
2717 bne move_enemy_down_exit
2719 move_enemy_allow_down:
2720 clc
2722 ldy #3
2723 lda ($74),y ; dy
2724 adc #1
2725 sta ($74),y ; update dy
2726 clc
2727 jmp animate_enemy_down ; optimise away the rts
2729 move_enemy_down_tile:
2730 clc
2732 ldy #2
2733 lda ($74),y ; y
2734 adc #1
2735 sta ($74),y ; store the new room y offset
2736 lda #0
2737 iny
2738 sta ($74),y ; dy = 0
2739 clc
2740 jmp animate_enemy_down ; optimise away the rts
2742 move_enemy_down_exit:
2743 sec
2744 rts
2746 move_enemy_animate: ; $74,$75=character address
2748 ldy #1
2749 lda ($74),y ; direction/animation
2750 sta $81
2751 and #$03
2752 adc #1
2753 and #$03 ; keep animation bits
2754 sta $8f
2755 lda $81
2756 and #$fc ; mask off the animation bits
2757 ora $8f
2758 sta ($74),y
2759 rts
2761 move_enemy_next_direction: .byte $04, $0c, $00, $08
2763 move_enemy: ; $74,$75=character address
2765 lda #0
2766 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2767 lda #0
2768 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2770 lda ($74),y ; read the enemy number (Y should be zero)
2771 and #$10
2772 beq move_enemy_homing
2773 clc
2775 ; This enemy is a non-homing enemy.
2777 jsr unplot_character ; unplot now before we change the sprite used
2779 ldy #1
2780 lda ($74),y
2781 and #$f0
2782 cmp #$f0
2783 bne move_enemy_set_direction
2784 clc
2786 ldy #1
2787 lda ($74),y
2788 and #$0c
2789 ror
2790 ror
2791 tax
2792 lda move_enemy_next_direction,x
2793 sta ($74),y
2795 move_enemy_set_direction:
2796 clc
2798 ldy #1
2799 lda ($74),y
2800 sta $7b
2802 adc #$10
2803 sta ($74),y
2804 clc
2806 lda $7b
2807 and #$04
2808 ror
2809 ror
2810 adc #1
2811 sta $8e
2813 lda $7b
2814 and #$08
2815 ror
2816 ror
2817 ror
2818 adc #1
2819 sta $8d
2821 jmp move_enemy_with_direction
2823 move_enemy_homing:
2825 ldy #2
2826 lda ($74),y ; y
2827 cmp $5282 ; player y
2828 bmi move_enemy_downwards
2829 bne move_enemy_upwards
2831 ldy #3
2832 lda ($74),y ; dy
2833 cmp $5283 ; player y
2834 beq move_enemy_horizontally
2835 bpl move_enemy_upwards
2837 move_enemy_downwards:
2838 lda #2
2839 sta $8d
2840 jmp move_enemy_horizontally
2842 move_enemy_upwards:
2843 lda #1
2844 sta $8d
2845 ;jmp move_enemy_horizontally
2847 move_enemy_horizontally:
2848 ldy #4
2849 lda ($74),y ; x
2850 cmp $5284 ; player x
2851 bmi move_enemy_rightwards
2852 bne move_enemy_leftwards
2854 ldy #5
2855 lda ($74),y ; dx
2856 cmp #0
2857 beq move_enemy_with_direction_unplot
2858 bpl move_enemy_leftwards
2860 move_enemy_rightwards:
2861 lda #2
2862 sta $8e
2863 jmp move_enemy_with_direction_unplot
2865 move_enemy_leftwards:
2866 lda #1
2867 sta $8e
2869 move_enemy_with_direction_unplot:
2870 clc
2872 jsr unplot_character
2874 move_enemy_with_direction:
2875 clc
2877 lda $8e
2878 cmp #1
2879 bne move_enemy_not_left
2880 jsr move_enemy_left
2881 clc
2882 jmp move_enemy_not_right
2884 move_enemy_not_left:
2885 lda $8e
2886 cmp #2
2887 bne move_enemy_not_right
2888 jsr move_enemy_right
2889 clc
2891 move_enemy_not_right:
2892 lda $8d
2893 cmp #1
2894 bne move_enemy_not_up
2895 jsr move_enemy_up
2896 clc
2897 jmp move_enemy_toggle
2899 move_enemy_not_up:
2900 lda $8d
2901 cmp #2
2902 bne move_enemy_toggle
2903 jsr move_enemy_down
2905 move_enemy_toggle:
2906 clc
2907 jsr move_enemy_animate
2908 jmp plot_character ; optimise away the rts
2910 move_enemy_exit:
2911 clc
2912 rts
2914 create_explosion: ; X=y, Y=x
2916 lda #3
2917 sta $52a4
2918 lda #4
2919 sta $52a5
2920 txa
2921 sta $52a6
2922 lda #1
2923 sta $52a7
2924 tya
2925 sta $52a8
2926 lda #0
2927 sta $52a9
2928 rts
2930 move_projectile_left:
2932 lda $528b
2933 cmp #0
2934 beq move_projectile_left_check_x
2936 dec $528b
2937 clc
2938 rts
2940 move_projectile_left_check_x:
2942 lda $528a
2943 cmp #0
2944 bne move_projectile_left_in_room
2945 jmp move_projectile_left_exit
2947 move_projectile_left_in_room:
2948 tay
2949 dey ; x - 1
2950 ldx $5288 ; y
2951 lda room_row_offsets_low,x ; read the address of the row
2952 sta $70
2953 lda #$57
2954 sta $71
2955 lda ($70),y ; load the tile to the left
2957 cmp #0
2958 bne move_projectile_left_wall
2960 lda $5289 ; dy
2961 cmp #3
2962 bmi move_projectile_allow_left
2964 clc ; dy > 2 so we need to check another tile
2965 lda $70
2966 adc #10
2967 sta $70
2968 lda ($70),y ; load the tile below and to the left
2969 inx ; y += 1
2971 cmp #0
2972 bne move_projectile_left_wall
2974 move_projectile_allow_left:
2976 sty $528a ; x
2977 lda #3
2978 sta $528b ; dx = 3
2980 clc
2981 rts
2983 move_projectile_left_wall: ; the projectile hit a wall
2984 clc
2986 lda $5287 ; type 2 can pass through walls
2987 and #$06
2988 cmp #4
2989 beq move_projectile_allow_left
2991 cmp #2
2992 bne move_projectile_left_not_boomerang
2994 lda $5287
2995 and #$0f
2996 cmp #8
2997 bpl move_projectile_left_exit
2999 ldx $577f ; weapon counter
3000 ora boomerang_horizontal,x
3001 sta $5287
3002 clc
3003 rts ; exit without moving or registering a collision
3005 move_projectile_left_not_boomerang:
3007 cmp #6 ; type 3 can destroy certain walls
3008 bne move_projectile_left_exit
3010 lda ($70),y ; load the tile to the left
3011 cmp #1 ; decoration can be destroyed
3012 bne move_projectile_left_exit
3013 clc
3015 lda #0
3016 sta ($70),y
3018 ; X=y, Y=x
3019 jsr create_explosion
3020 jsr plot_blank_xy ; corrupted X
3022 lda #$a4
3023 sta $74
3024 lda #$52
3025 sta $75
3026 jsr plot_character
3028 ldx #0
3029 jsr play_sound
3031 lda #16 ; prevent the player from firing a new
3032 sta $578d ; projectile until the explosion has finished
3034 move_projectile_left_exit:
3035 sec
3036 rts
3038 boomerang_horizontal: .byte $28, $38
3040 move_projectile_right:
3042 ; Fire right.
3044 lda $528b
3045 cmp #2
3046 beq move_projectile_right_check_x
3047 cmp #3
3048 beq move_projectile_right_tile
3050 inc $528b
3051 clc
3052 rts
3054 move_projectile_right_check_x:
3056 lda $528a ; x
3057 cmp #9
3058 bne move_projectile_right_not_edge
3059 jmp move_projectile_right_exit
3061 move_projectile_right_not_edge:
3062 clc
3063 tay
3064 iny ; x + 1
3065 ldx $5288 ; y
3066 lda room_row_offsets_low,x ; read the address of the row
3067 sta $70
3068 lda #$57
3069 sta $71
3070 lda ($70),y ; load the tile to the right
3072 cmp #0
3073 bne move_projectile_right_wall
3075 lda $5289 ; dy
3076 cmp #3
3077 bmi move_projectile_allow_right
3079 clc ; dy > 2 so we need to check another tile
3080 lda $70
3081 adc #10
3082 sta $70
3083 lda ($70),y ; load the tile below and to the right
3084 inx ; y += 1
3086 cmp #0
3087 bne move_projectile_right_wall
3089 move_projectile_allow_right:
3091 inc $528b ; dx
3092 clc
3093 rts
3095 move_projectile_right_tile:
3097 inc $528a ; x
3098 lda #0
3099 sta $528b ; dx
3100 clc
3101 rts
3103 move_projectile_right_wall: ; the projectile hit a wall
3104 clc
3106 lda $5287 ; type 2 can pass through walls
3107 and #$06
3108 cmp #4
3109 beq move_projectile_allow_right
3111 cmp #2
3112 bne move_projectile_right_not_boomerang
3114 lda $5287
3115 and #$0f
3116 cmp #8
3117 bpl move_projectile_right_exit
3119 ldx $577f ; weapon counter
3120 ora boomerang_horizontal,x
3121 sta $5287
3122 clc
3123 rts ; exit without moving or registering a collision
3125 move_projectile_right_not_boomerang:
3127 cmp #6 ; type 3 can destroy certain walls
3128 bne move_projectile_right_exit
3130 lda ($70),y ; load the tile to the right
3131 cmp #1 ; decoration can be destroyed
3132 bne move_projectile_right_exit
3133 clc
3135 lda #0
3136 sta ($70),y
3138 ; X=y, Y=x
3139 jsr create_explosion
3140 jsr plot_blank_xy ; corrupted X
3142 lda #$a4
3143 sta $74
3144 lda #$52
3145 sta $75
3146 jsr plot_character
3148 ldx #0
3149 jsr play_sound
3151 lda #16 ; prevent the player from firing a new
3152 sta $578d ; projectile until the explosion has finished
3154 move_projectile_right_exit:
3155 sec
3156 rts
3158 move_projectile_up:
3160 lda $5289 ; read dy
3161 cmp #0
3162 beq move_projectile_up_check_y
3164 dec $5289
3165 clc
3166 rts
3168 move_projectile_up_check_y: ; Check the y offset.
3170 lda $5288
3171 cmp #0
3172 bne move_projectile_up_not_edge
3173 jmp move_projectile_up_exit
3175 move_projectile_up_not_edge:
3176 tax ; use the y offset as an index
3177 dex ; y - 1
3178 ldy $528a ; load the x offset
3179 lda room_row_offsets_low,x ; read the address of the row
3180 sta $70
3181 lda #$57
3182 sta $71
3183 lda ($70),y ; load the tile above
3185 cmp #0
3186 bne move_projectile_up_wall
3188 lda $528b ; dx
3189 cmp #3
3190 bmi move_projectile_allow_up
3192 clc ; dx > 2 so we need to check another tile
3193 iny
3194 lda ($70),y ; load the tile above and to the right
3196 cmp #0
3197 bne move_projectile_up_wall
3199 move_projectile_allow_up:
3200 txa
3201 sta $5288 ; store the new room y offset
3202 lda #3
3203 sta $5289 ; dy = 3
3205 clc
3206 rts
3208 move_projectile_up_wall: ; the projectile hit a wall
3209 clc
3211 lda $5287 ; type 2 can pass through walls
3212 and #$06
3213 cmp #4
3214 beq move_projectile_allow_up
3216 cmp #2
3217 bne move_projectile_up_not_boomerang
3219 lda $5287
3220 and #$0f
3221 cmp #8
3222 bpl move_projectile_up_exit
3224 ldx $577f ; weapon counter
3225 ora boomerang_vertical,x
3226 sta $5287
3227 clc
3228 rts ; exit without moving or registering a collision
3230 move_projectile_up_not_boomerang:
3232 cmp #6 ; type 3 can destroy certain walls
3233 bne move_projectile_up_exit
3235 lda ($70),y ; load the tile above
3236 cmp #1 ; decoration can be destroyed
3237 bne move_projectile_up_exit
3238 clc
3240 lda #0
3241 sta ($70),y
3243 ; X=y, Y=x
3244 jsr create_explosion
3245 jsr plot_blank_xy ; corrupted X
3247 lda #$a4
3248 sta $74
3249 lda #$52
3250 sta $75
3251 jsr plot_character
3253 ldx #0
3254 jsr play_sound
3256 lda #16 ; prevent the player from firing a new
3257 sta $578d ; projectile until the explosion has finished
3259 move_projectile_up_exit:
3260 sec
3261 rts
3263 boomerang_vertical: .byte $08, $18
3265 move_projectile_down:
3267 lda $5289 ; read dy
3268 cmp #2
3269 beq move_projectile_down_check_y
3270 cmp #3
3271 beq move_projectile_down_tile
3273 inc $5289 ; 0 <= dy < 3
3274 clc
3275 rts
3277 move_projectile_down_check_y: ; Check the y offset.
3279 lda $5288
3280 cmp #9
3281 bne move_projectile_down_in_room
3282 jmp move_projectile_down_exit
3284 move_projectile_down_in_room:
3285 clc
3286 tax
3287 inx ; y + 1
3288 ldy $528a ; load the x offset
3289 lda room_row_offsets_low,x ; read the address of the row
3290 sta $70
3291 lda #$57
3292 sta $71
3293 lda ($70),y ; load the tile below
3295 cmp #0
3296 bne move_projectile_down_wall
3298 lda $528b ; dx
3299 cmp #3
3300 bmi move_projectile_allow_down
3302 clc ; dx > 2 so we need to check another tile
3303 iny
3304 lda ($70),y ; load the tile below and to the right
3306 cmp #0
3307 bne move_projectile_down_wall
3309 move_projectile_allow_down:
3311 inc $5289 ; update dy
3312 clc
3313 rts
3315 move_projectile_down_tile:
3317 inc $5288 ; store the new room y offset
3318 lda #0
3319 sta $5289 ; dy = 0
3320 clc
3321 rts
3323 move_projectile_down_wall: ; the projectile hit a wall
3324 clc
3326 lda $5287 ; type 2 can pass through walls
3327 and #$06
3328 cmp #4
3329 beq move_projectile_allow_down
3331 cmp #2
3332 bne move_projectile_down_not_boomerang
3334 lda $5287
3335 and #$0f
3336 cmp #8
3337 bpl move_projectile_down_exit
3339 ldx $577f ; weapon counter
3340 ora boomerang_vertical,x
3341 sta $5287
3342 clc
3343 rts ; exit without moving or registering a collision
3345 move_projectile_down_not_boomerang:
3347 cmp #6 ; type 3 can destroy certain walls
3348 bne move_projectile_down_exit
3350 lda ($70),y ; load the tile below
3351 cmp #1 ; decoration can be destroyed
3352 bne move_projectile_down_exit
3353 clc
3355 lda #0
3356 sta ($70),y
3358 ; X=y, Y=x
3359 jsr create_explosion
3360 jsr plot_blank_xy ; corrupted X
3362 lda #$a4
3363 sta $74
3364 lda #$52
3365 sta $75
3366 jsr plot_character
3368 ldx #0
3369 jsr play_sound
3371 lda #16 ; prevent the player from firing a new
3372 sta $578d ; projectile until the explosion has finished
3374 move_projectile_down_exit:
3375 sec
3376 rts
3378 move_projectile_animate:
3380 lda $5287
3381 eor #1
3382 sta $5287
3383 rts
3385 move_projectile:
3387 lda $5286
3388 cmp #0
3389 bne move_projectile_move
3390 jmp move_projectile_exit
3392 move_projectile_move:
3393 clc
3395 lda #$86
3396 sta $74
3397 lda #$52
3398 sta $75
3399 jsr unplot_character
3401 move_projectile_after_unplot:
3403 lda $5287
3404 and #$30 ; direction
3406 cmp #0
3407 bne move_projectile_not_left
3409 jsr move_projectile_left
3410 bcc move_projectile_toggle
3411 bcs move_projectile_destroy
3413 move_projectile_not_left:
3414 cmp #$10
3415 bne move_projectile_not_right
3417 jsr move_projectile_right
3418 bcc move_projectile_toggle
3419 bcs move_projectile_destroy
3421 move_projectile_not_right:
3422 cmp #$20
3423 bne move_projectile_not_up
3425 jsr move_projectile_up
3426 bcc move_projectile_toggle
3427 bcs move_projectile_destroy
3429 move_projectile_not_up:
3430 cmp #$30
3431 bne move_projectile_toggle
3433 jsr move_projectile_down
3434 bcs move_projectile_destroy
3436 move_projectile_toggle:
3438 jsr projectile_collide
3439 bcs move_projectile_destroy
3441 jsr move_projectile_animate
3443 lda #$86
3444 sta $74
3445 lda #$52
3446 sta $75
3447 jmp plot_character ; optimise away the rts
3449 move_projectile_destroy:
3450 clc
3452 ldy #0
3453 lda ($74),y ; type
3454 cmp #8
3455 bmi move_projectile_no_enemy_collision
3457 and #$70 ; increase the player's score
3458 lsr
3459 lsr
3460 lsr
3461 adc #2
3462 sta $70
3463 jsr add_score
3464 jmp move_projectile_create_explosion
3466 move_projectile_no_enemy_collision:
3468 cmp #4 ; items can be destroyed as well
3469 bne move_projectile_no_item_collision
3471 ldy #1 ; but not keys
3472 lda ($74),y
3473 cmp #4 ; even the mace is stopped by a key
3474 beq move_projectile_remove_projectile
3475 clc
3477 jsr remove_room_item
3479 move_projectile_create_explosion:
3481 ; Unplot the item/enemy and replace it with an explosion.
3483 jsr unplot_character
3485 lda #3 ; explosion
3486 ldy #0
3487 sta ($74),y
3489 lda #4
3490 ldy #1
3491 sta ($74),y
3493 jsr plot_character
3495 ; Play a sound.
3496 ldx #0
3497 jsr play_sound
3499 move_projectile_no_item_collision:
3501 lda $5287 ; type 2 projectiles pass through everything
3502 and #$06
3503 cmp #4
3504 bne move_projectile_remove_projectile
3506 ; Ideally, we would have recorded if the projectile left the screen so
3507 ; that we don't perform these checks again here, but it would just add
3508 ; overhead to the normal movement routines for the other weapons.
3510 lda $5288 ; y
3511 cmp #0
3512 beq move_projectile_remove_projectile
3513 cmp #9
3514 beq move_projectile_remove_projectile
3516 lda $528a ; x
3517 cmp #0
3518 beq move_projectile_remove_projectile
3519 cmp #9
3520 beq move_projectile_remove_projectile
3522 clc
3523 lda #$86
3524 sta $74
3525 lda #$52
3526 sta $75
3528 jsr plot_character
3529 jmp move_projectile_exit
3531 move_projectile_remove_projectile:
3533 lda #0 ; remove the projectile from the character list
3534 sta $5286
3536 move_projectile_exit:
3537 clc
3538 rts
3540 emerge_characters:
3542 lda #$8c ; set the character address
3543 sta $74
3544 lda #$52
3545 sta $75
3547 emerge_characters_loop:
3549 ldy #0
3550 lda ($74),y
3551 cmp #0
3552 bne emerge_characters_next
3554 jmp emerge_character ; optimise away the rts
3556 emerge_characters_next:
3557 clc
3559 ; Examine the next character.
3560 lda $74
3561 adc #6
3563 cmp #$a4
3564 bpl emerge_characters_exit
3565 sta $74
3566 jmp emerge_characters_loop
3568 emerge_characters_exit:
3569 clc
3570 rts
3572 enemy_slots: .byte 0, 6, 12, 18
3574 move_characters:
3576 lda #$8c ; set the character address
3577 sta $74
3578 lda #$52
3579 sta $75
3581 lda $578e ; read a value from 0 to 3 from the motion counter
3582 and #3
3583 tax
3584 lda enemy_slots,x ; look up the corresponding slot in the character list
3585 adc $74
3586 sta $74 ; update the character address
3588 move_characters_loop:
3590 ldy #0
3591 lda ($74),y
3592 cmp #3
3593 bne move_characters_not_emerge_explode
3595 jsr emerge_explode
3596 jmp move_characters_next
3598 move_characters_not_emerge_explode:
3599 cmp #8
3600 bmi move_characters_next
3602 jsr move_enemy
3604 move_characters_next:
3605 clc
3607 lda $74 ; for the last enemy, check the next slot
3608 cmp #$9e ; for the presence of an explosion
3609 bne move_characters_endloop ; otherwise leave the loop (only performing
3610 clc ; one iteration)
3612 adc #6
3613 sta $74
3614 jmp move_characters_loop
3616 move_characters_endloop:
3617 clc
3619 ; Check collisions with the player.
3621 jsr player_collide
3622 bcs move_characters_collisions
3623 jmp move_characters_exit
3625 move_characters_collisions:
3626 clc
3628 ldy #0
3629 lda ($74),y ; type
3630 cmp #8
3631 bpl move_character_destroy_enemy
3633 ; Unplot the item.
3634 jsr unplot_character
3636 ; Remove it from the item table.
3637 jsr remove_room_item
3639 lda #0 ; remove the item from the character list
3640 ldy #0
3641 sta ($74),y
3643 iny
3644 lda ($74),y ; get the item type
3646 sta $8d ; temporarily store A and increase the score
3647 tax
3648 lda item_scores,x
3649 sta $70
3650 jsr add_score
3651 lda $8d
3653 ; Check the item type.
3654 cmp #8
3655 bmi move_characters_not_health
3657 lda #20
3658 sta $70
3659 jsr add_strength
3660 clc
3662 ldx #2
3663 jsr play_sound
3665 rts
3667 move_characters_not_health:
3668 cmp #5
3669 bmi move_characters_not_treasure
3671 ldx #2
3672 jsr play_sound
3674 clc
3675 rts
3677 move_characters_not_treasure:
3678 cmp #4
3679 bmi move_characters_not_key
3681 ; Key - update the item/player flags byte.
3682 lda $5780
3683 ora #$01
3684 sta $5780
3685 clc
3687 ldx #3
3688 jsr play_sound
3690 rts
3692 move_characters_not_key:
3694 ; Update the player's weapon.
3695 asl
3696 sta $5789
3697 clc
3699 ldx #2
3700 jsr play_sound
3702 rts
3704 move_character_destroy_enemy:
3706 ; Unplot the enemy and replace it with an explosion.
3708 jsr unplot_character
3710 lda #3 ; explosion
3711 ldy #0
3712 sta ($74),y
3714 lda #4
3715 ldy #1
3716 sta ($74),y
3718 jsr plot_character
3720 ; Reduce the player's strength.
3722 ldx #1
3723 jsr play_sound
3725 lda #1
3726 sta $70
3727 jmp reduce_strength ; optimise away the rts
3729 move_characters_exit:
3730 clc
3731 rts
3733 remove_room_item:
3735 ldx $5782 ; current room row number
3736 lda eleven_times_table,x
3737 adc $5783 ; current room column number
3738 tax
3739 lda #$80 ; store a value with the top bit set instead of zero because we
3740 sta $5200,x ; have visited this room if we can collect the object within it
3741 clc
3742 rts
3744 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3745 score_vdu_bytes: .byte 1,1,31 ; reversed
3746 score_digits: .byte "0123456789"
3748 add_score: ; $70=score to add
3750 sed
3751 lda $5786
3752 adc $70
3753 sta $5786
3754 lda $5787
3755 adc #0
3756 sta $5787
3757 lda $5788
3758 adc #0
3759 sta $5788
3760 cld
3762 write_score:
3764 lda #$86
3765 sta $70
3766 lda #$57
3767 sta $71
3769 ldx #2
3770 write_score_vdu_bytes:
3771 lda score_vdu_bytes,x
3772 jsr $ffee
3773 dex
3774 bpl write_score_vdu_bytes
3776 write_score_digits: ; $70,$71=address of score bytes
3778 ldy #2
3779 write_score_loop:
3781 lda ($70),y
3782 lsr
3783 lsr
3784 lsr
3785 lsr
3786 tax
3787 lda score_digits,x
3788 jsr $ffee
3790 lda ($70),y
3791 and #$0f
3792 tax
3793 lda score_digits,x
3794 jsr $ffee
3796 dey
3797 bpl write_score_loop
3799 clc
3800 rts
3802 strength_units: .byte $00,$88,$cc,$ee
3804 add_strength: ; $70=strength to add
3806 ; Divide the initial strength by 4 to determine which half character to
3807 ; start plotting at, and multiply by 8 to get the address. The net result
3808 ; is to mask off the bottom two bits and shift left once.
3809 lda $5784
3810 and #$fc
3811 sta $71 ; strength rounded down to a multiple of four units
3812 asl
3813 clc
3814 tay
3816 lda $5784
3817 adc $70
3818 cmp #65
3819 bmi add_strength_update
3821 lda #64
3823 add_strength_update:
3824 clc
3825 sta $5784 ; the final strength
3827 sec
3828 sbc $71
3829 clc
3830 tax ; the number of units to add between the rounded original
3831 ; strength and the final strength
3833 lda #$f3 ; the start of the strength bar
3834 sta $72
3835 lda #$59
3836 sta $73
3838 cpx #4
3839 bmi add_strength_loop_extra
3841 add_strength_loop:
3843 clc
3844 lda #$ff
3845 sta ($72),y
3847 tya
3848 adc #8
3849 tay
3851 txa
3852 sec
3853 sbc #4
3854 clc
3855 tax
3857 cmp #4
3858 bpl add_strength_loop
3860 add_strength_loop_extra:
3861 cpx #0
3862 beq add_strength_exit
3864 ; For any remaining units in excess of the multiples of four units, plot
3865 ; the appropriate byte.
3866 lda $5784
3867 and #3
3868 tax
3870 lda strength_units,x
3871 sta ($72),y
3873 add_strength_exit:
3874 clc
3875 rts
3877 reduce_strength: ; $70=strength to remove
3879 lda $5784
3880 tax
3881 sec
3882 sbc $70
3883 bpl reduce_strength_update
3885 lda #0
3887 reduce_strength_update:
3888 clc
3889 sta $5784
3891 ; Divide the final strength by 4 to determine which half character to
3892 ; plot, and multiply by 8 to get the address. The net result is to mask off
3893 ; the bottom two bits and shift left once.
3894 and #$fc
3895 asl
3896 tay
3898 lda #$f3 ; the start of the strength bar
3899 sta $70
3900 lda #$59
3901 sta $71
3903 lda $5784
3904 and #3
3905 tax
3906 lda strength_units,x
3907 sta ($70),y
3909 lda $5784
3910 cmp #0
3911 bne reduce_strength_exit
3913 lda $5780 ; the player ran out of strength
3914 ora #$40
3915 sta $5780
3917 lda #64 ; reset the delay counter
3918 sta $5785
3920 lda #$80 ; unplot the player
3921 sta $74
3922 lda #$52
3923 sta $75
3925 jsr unplot_character
3927 lda #8 ; change the player's direction to the demise animation
3928 sta $5281
3930 jsr plot_character
3931 jmp destroy_enemies ; optimise away the rts
3933 reduce_strength_exit:
3934 clc
3935 rts
3937 destroy_enemies:
3939 lda #$8c
3940 sta $74
3941 lda #$52
3942 sta $75
3944 destroy_enemies_loop:
3946 ldy #0
3947 lda ($74),y
3948 cmp #8
3949 bmi destroy_enemies_not_enemy
3951 jsr unplot_character
3953 lda #3 ; emerge/explosion
3954 ldy #0
3955 sta ($74),y
3957 iny
3958 lda #4 ; explosion
3959 sta ($74),y
3961 jsr plot_character
3962 jmp destroy_enemies_not_emerging_enemy
3964 destroy_enemies_not_enemy:
3965 cmp #3
3966 bne destroy_enemies_not_emerging_enemy
3968 jsr unplot_character
3970 iny ; whether emerging or exploding, ensure that the enemy
3971 lda ($74),y ; is now exploding
3972 ora #4
3973 sta ($74),y
3975 jsr plot_character
3977 destroy_enemies_not_emerging_enemy:
3978 clc
3979 lda $74
3980 adc #6
3981 sta $74
3982 cmp #$a4
3983 bmi destroy_enemies_loop
3985 clc
3986 rts
3988 remove_characters:
3990 ; Clear the character table.
3992 ldx #6
3993 remove_characters_loop:
3994 lda #0
3995 sta $5280,x
3996 txa
3997 adc #6
3998 tax
3999 cpx #$2a
4000 bmi remove_characters_loop
4002 rts
4004 ; The player collision masks use bits to represent where the player is in a
4005 ; tile. See the collisions.txt file for more information.
4007 ; Player is above, enemy is below, checking the overlap in the lower tile.
4008 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4010 projectile_collision_mask_above: .byte $00, $00, $00, $80
4012 ; Player and enemy share the same tile or player is on the tile below.
4013 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4015 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4017 ; Player is above or on the same tile, enemy is below, checking the overlap in
4018 ; the lower tile.
4019 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4021 ; Enemy is above, player is below, checking the overlap in the lower tile.
4022 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4024 ; Player is to the left, enemy is to the right, checking the overlap in the
4025 ; right hand tile.
4026 player_collision_mask_left:
4027 projectile_collision_mask_left: .byte $00, $00, $00, $08
4029 ; Player and enemy share the same tile or player is on the tile to the right.
4030 player_collision_mask_right:
4031 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4033 ; Player is to the left, enemy is to the right or on the same tile, checking
4034 ; the overlap in the right hand tile.
4035 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4037 ; Enemy is to the left, player is to the right, checking the overlap in the
4038 ; right hand tile.
4039 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4041 player_collide:
4043 lda $5282 ; player y
4044 sta $8a
4045 lda $5284 ; player x
4046 sta $8b
4048 ldx $5283 ; player dy
4049 lda player_collision_mask_above,x
4050 sta $86
4051 lda player_collision_mask_below,x
4052 sta $88
4053 ldx $5285 ; player dx
4054 lda player_collision_mask_left,x
4055 sta $87
4056 lda player_collision_mask_right,x
4057 sta $89
4059 jmp collide ; optimise away the rts
4061 projectile_collide:
4063 lda $5288 ; projectile y
4064 sta $8a
4065 lda $528a ; projectile x
4066 sta $8b
4068 ldx $5289 ; projectile dy
4069 lda projectile_collision_mask_above,x
4070 sta $86
4071 lda projectile_collision_mask_below,x
4072 sta $88
4073 ldx $528b ; projectile dx
4074 lda projectile_collision_mask_left,x
4075 sta $87
4076 lda projectile_collision_mask_right,x
4077 sta $89
4079 ; Run on into the next routine.
4081 collide:
4083 lda #$8c ; set the character address
4084 sta $74
4085 lda #$52
4086 sta $75
4088 collide_loop:
4090 ldy #0
4091 lda ($74),y ; type
4092 cmp #4
4093 bpl collide_check
4095 jmp collide_next
4097 collide_check:
4099 ldy #2
4100 lda ($74),y ; y
4101 sec
4102 sbc $8a ; y - player/projectile y
4103 beq check_collide_y_equal
4104 cmp #1
4105 beq check_collide_y_greater
4106 cmp #255
4107 beq check_collide_y_less
4109 jmp collide_next
4111 check_collide_y_equal:
4112 ; The enemy is on the same tile as the player/projectile so look at the
4113 ; collision on their common tile.
4114 ldy #3
4115 lda ($74),y ; dy
4116 tax
4117 lda enemy_collision_mask_above,x
4118 and $88 ; player/projectile mask below
4119 bne check_collide_x
4121 jmp collide_next
4123 check_collide_y_greater:
4124 ; The enemy is on the tile below the player/projectile so look at the
4125 ; collision on the enemy's tile.
4126 ldy #3
4127 lda ($74),y ; dy
4128 tax
4129 lda enemy_collision_mask_above,x
4130 and $86 ; player mask above
4131 bne check_collide_x
4133 jmp collide_next
4135 check_collide_y_less:
4136 ; The enemy is on the tile above the player/projectile so look at the
4137 ; collision on the player's tile.
4138 ldy #3
4139 lda ($74),y ; dy
4140 tax
4141 lda enemy_collision_mask_below,x
4142 and $88 ; player mask below
4143 bne check_collide_x
4145 jmp collide_next
4147 check_collide_x:
4148 ldy #4
4149 lda ($74),y ; x
4150 sec
4151 sbc $8b ; x - player/projectile x
4152 beq check_collide_x_equal
4153 cmp #1
4154 beq check_collide_x_greater
4155 cmp #255
4156 beq check_collide_x_less
4158 jmp collide_next
4160 check_collide_x_equal:
4161 ; The enemy is on the same tile as the player/projectile so look at the
4162 ; collision on their common tile.
4163 ldy #5
4164 lda ($74),y ; dx
4165 tax
4166 lda enemy_collision_mask_left,x
4167 and $89 ; player mask right
4168 bne check_collide_destroy
4170 jmp collide_next
4172 check_collide_x_greater:
4173 ; The enemy is the tile to the right of the player/projectile so look
4174 ; at the collision on the enemy's tile.
4175 ldy #5
4176 lda ($74),y ; dx
4177 tax
4178 lda enemy_collision_mask_left,x
4179 and $87 ; player mask left
4180 bne check_collide_destroy
4182 jmp collide_next
4184 check_collide_x_less:
4185 ; The enemy is the tile to the left of the player/projectile so look at
4186 ; the collision on the player's tile.
4187 ldy #5
4188 lda ($74),y ; dx
4189 tax
4190 lda enemy_collision_mask_right,x
4191 and $89 ; player mask right
4192 bne check_collide_destroy
4194 collide_next:
4195 clc
4197 ; Examine the next character.
4198 lda $74
4199 adc #6
4201 cmp #$a4
4202 bpl collide_exit
4203 sta $74
4204 jmp collide_loop
4206 check_collide_destroy:
4208 sec ; set the carry flag to inform the caller that the
4209 rts ; player/projectile should be destroyed
4211 collide_exit:
4212 clc
4213 rts
4215 blank_screen:
4216 lda #1
4217 sta $70
4218 lda #0
4219 sta $71
4220 jsr set_palette
4221 lda #2
4222 sta $70
4223 lda #0
4224 sta $71
4225 jsr set_palette
4226 lda #3
4227 sta $70
4228 lda #0
4229 sta $71
4230 ; Run on into set_palette.
4232 set_palette:
4233 ; $70=logical colour
4234 ; $71=physical colour
4235 lda $70
4236 sta $578b
4237 lda $71
4238 sta $578c
4239 lda #0
4240 sta $578d
4241 sta $578e
4242 sta $578f
4244 lda #$c
4245 ldx #$8b
4246 ldy #$57
4247 jsr $fff1
4248 rts
4250 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4251 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4253 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4254 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4255 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4256 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4257 note_sound: .byte $13,0, 241,255
4258 note_pitch: .byte 0,0
4259 note_duration: .byte 4,0
4260 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4262 play_note: ; A=pitch, Y=duration
4264 sta note_pitch
4265 sty note_duration
4266 ldx #4
4267 ; Run on into the next routine.
4269 play_sound: ; X=sound number
4271 lda sounds_high,x
4272 tay
4273 lda sounds_low,x
4274 tax
4275 lda #7
4276 jsr $fff1
4278 rts
4280 copy_title_up:
4282 lda #$00
4283 sta $70
4284 lda #$18
4285 sta $71
4287 lda #$a0
4288 sta $72
4289 lda #$5a
4290 sta $73
4292 ldx #5
4293 ; Run on into the next routine.
4295 copy_title:
4297 copy_title_loop1:
4299 ldy #0
4300 copy_title_loop2:
4302 lda ($70),y
4303 sta ($72),y
4304 iny
4305 cpy #0
4306 bne copy_title_loop2
4308 clc
4309 lda $72
4310 adc #$40
4311 sta $72
4312 lda $73
4313 adc #$01
4314 sta $73
4315 clc
4317 lda $71
4318 adc #$01
4319 sta $71
4320 clc
4322 dex
4323 bpl copy_title_loop1
4325 rts
4327 copy_completed_screen_up:
4329 lda #$00
4330 sta $70
4331 lda #$0f
4332 sta $71
4334 lda #$60
4335 sta $72
4336 lda #$5e
4337 sta $73
4339 ldx #8
4340 jmp copy_title ; optimise away the rts
4342 init:
4343 jsr cls ; clear the text window
4345 lda #26 ; unset the text window
4346 jsr $ffee
4348 ; Define the default high scores.
4349 ldy #0
4350 lda #$80
4351 sta $70
4352 lda #$51
4353 sta $71
4354 lda #$16
4355 sta $72
4357 ldx #0
4358 init_define_high_scores_loop:
4360 lda #0
4361 sta ($70),y
4362 iny
4363 lda $72
4364 sta ($70),y
4365 iny
4366 lda #0
4367 sta ($70),y
4369 iny
4370 init_define_high_score_name_loop:
4372 lda high_score_default_name1,x
4373 sta ($70),y
4374 iny
4375 inx
4376 cpx #9
4377 beq init_define_high_scores_next
4378 cpx #18
4379 bne init_define_high_score_name_loop
4381 ldx #0
4382 init_define_high_scores_next:
4384 sed
4385 lda $72
4386 sec
4387 sbc #2
4388 sta $72
4389 cld
4390 clc
4392 cpy #96
4393 bne init_define_high_scores_loop
4395 ; Disable joystick support.
4396 lda #0
4397 sta $577e
4399 rts
4401 high_score_default_name1: .byte "RETRO "
4402 high_score_default_name2: .byte " SOFTWARE"
4404 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4405 input_message: .byte 17,2, 31,1,27, "Press SPACE / FIRE"
4406 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4407 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4408 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4409 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4411 set_standard_palette:
4413 lda #1
4414 sta $70
4415 lda #1
4416 sta $71
4417 jsr set_palette
4419 jmp set_core_palette ; optimise away the rts
4421 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4423 set_complete_palette:
4425 lda #0
4426 sta $80
4427 lda #25
4428 sta $81
4430 set_complete_palette_loop:
4432 jsr wait_for_vsync
4434 dec $81
4435 lda $81
4436 cmp #0
4437 bne set_complete_palette_loop
4439 lda #25
4440 sta $81
4442 ldx $80
4443 lda complete_palette_bytes,x
4444 sta $70
4445 inx
4446 lda complete_palette_bytes,x
4447 sta $71
4448 inx
4449 stx $80
4450 jsr set_palette
4452 lda $80
4453 cmp #10
4454 bne set_complete_palette_loop
4456 rts
4458 set_hidden_palette:
4460 lda #1
4461 sta $70
4462 lda #0
4463 sta $71
4464 jsr set_palette
4466 ; Run on into the next routine.
4468 set_core_palette:
4470 lda #2
4471 sta $70
4472 lda #2
4473 sta $71
4474 jsr set_palette
4476 lda #3
4477 sta $70
4478 lda #3
4479 sta $71
4480 jsr set_palette
4482 rts
4484 show_title:
4486 jsr set_standard_palette
4488 ldx #0
4489 write_title_text_loop:
4490 lda title_vdu_bytes,x
4491 jsr $ffee
4492 inx
4493 cpx #12
4494 bmi write_title_text_loop
4496 jsr show_input_message
4498 ; Show the title.
4499 jsr copy_title_up
4501 ; Show the high scores.
4503 jsr colour1
4505 lda #$80
4506 sta $70
4507 lda #$51
4508 sta $71
4510 lda #8
4511 sta $80
4513 show_title_high_scores_loop:
4515 lda #31
4516 jsr $ffee
4517 lda #2
4518 jsr $ffee
4519 lda $80
4520 adc #2
4521 sta $80
4522 clc
4523 jsr $ffee
4525 jsr write_score_digits
4527 lda #32
4528 jsr $ffee
4530 ldx #8
4531 ldy #3
4532 show_title_high_scores_vdu_loop2:
4534 lda ($70),y
4535 cmp #32
4536 bmi ignore_char
4537 cmp #123
4538 bpl ignore_char
4539 jsr $ffee
4541 ignore_char:
4542 iny
4543 dex
4544 bpl show_title_high_scores_vdu_loop2
4546 lda $70
4547 adc #12
4548 sta $70
4549 cmp #$e0
4550 bne show_title_high_scores_loop
4552 lda #0 ; message counter
4553 sta $72
4555 show_title_wait_loop:
4557 lda #150
4558 sta $5785
4560 ldx $72
4561 ldy #22
4562 show_title_wait_message_loop:
4564 lda title_vdu_bytes1,x
4565 jsr $ffee
4566 inx
4567 dey
4568 bpl show_title_wait_message_loop
4570 cpx #92
4571 beq show_title_wait_reset_offset
4573 txa
4574 sta $72
4575 jmp show_title_wait_inner_loop
4577 show_title_wait_reset_offset:
4578 lda #0
4579 sta $72
4581 show_title_wait_inner_loop:
4582 jsr wait_for_vsync
4584 dec $5785
4585 beq show_title_wait_loop
4587 show_title_wait_loop_no_update:
4588 lda #128
4589 ldx #0
4590 jsr $fff4
4591 cpx #0 ; fire button pressed?
4592 beq show_title_no_joystick
4594 lda #1 ; enable joystick support
4595 sta $577e
4596 jmp show_title_exit
4598 show_title_no_joystick:
4599 ldx #157 ; SPACE
4600 jsr check_key
4601 cpy #255
4602 bne show_title_wait_inner_loop
4604 lda #0 ; disable joystick support
4605 sta $577e
4607 show_title_exit:
4608 clc
4609 rts
4611 show_input_message:
4613 ldx #0
4614 show_input_message_loop:
4616 lda input_message,x
4617 jsr $ffee
4618 inx
4619 cpx #23
4620 bne show_input_message_loop
4622 rts
4624 wait_for_vsync:
4626 lda #19
4627 jmp $fff4 ; optimise away the rts
4629 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4631 delay:
4633 delay_loop:
4635 jsr wait_for_vsync
4636 dec $5785
4637 bne delay_loop
4639 rts
4641 show_game_over:
4643 lda #128
4644 sta $5785
4645 jsr delay
4647 ldx #0
4648 write_game_over_text_loop:
4649 lda game_over_vdu_bytes,x
4650 jsr $ffee
4651 inx
4652 cpx #33
4653 bmi write_game_over_text_loop
4655 lda #192
4656 sta $5785
4657 jsr delay
4659 rts
4661 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4662 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4664 show_end_of_level_screen:
4666 ; Draw a decorative room.
4668 jsr make_empty_room
4670 ldx #5
4671 end_of_level_h_walls_loop:
4673 lda #3
4674 sta $57b2,x
4675 sta $57e4,x
4676 dex
4677 bpl end_of_level_h_walls_loop
4679 ldx #30
4680 end_of_level_v_walls_loop:
4682 lda #3
4683 sta $57bc,x
4684 sta $57c1,x
4685 txa
4686 sec
4687 sbc #10
4688 tax
4689 bpl end_of_level_v_walls_loop
4691 jsr plot_room_tiles
4692 jsr set_standard_palette
4694 ldx #0
4695 end_of_level_text_loop1:
4697 lda end_of_level_bytes1,x
4698 jsr $ffee
4699 inx
4700 cpx #28
4701 bne end_of_level_text_loop1
4703 ; Count the number of rooms explored.
4704 ldx #0
4705 lda #0
4706 sta $8d
4707 sta $8e
4708 end_of_level_room_count_loop:
4710 lda $5200,x
4711 and #$80
4712 beq end_of_level_room_count_loop_next
4714 sed
4715 lda $8d
4716 adc #1
4717 sta $8d
4718 lda $8e
4719 adc #0
4720 sta $8e
4721 cld
4722 clc
4724 end_of_level_room_count_loop_next:
4725 inx
4726 cpx #121
4727 bne end_of_level_room_count_loop
4729 ; Position the player so that we can perform an animation.
4730 jsr position_player_set_up_plotting
4732 lda $8d
4733 sta $70
4734 lda $8e
4735 sta $71
4736 jsr write_bonus
4738 lda #0 ; reset motion counter
4739 sta $578e
4741 show_end_of_level_bonus_loop:
4743 jsr wait_for_vsync
4745 clc
4746 lda $578e
4747 and #15
4748 bne end_of_level_no_animation
4750 ; Animate the player.
4752 jsr reset_unplot_buffer
4753 jsr reset_plot_buffer
4755 ; $74,$75 should be unchanged
4756 jsr unplot_character
4758 lda $5281
4759 eor #1
4760 sta $5281
4761 jsr plot_character
4763 jsr plot_buffer
4765 end_of_level_no_animation:
4766 clc
4767 lda $578e
4768 and #3
4769 bne end_of_level_no_countdown
4771 ; Transfer the bonus to the score.
4773 sed
4774 sec
4775 lda $8d
4776 sbc #1
4777 sta $8d
4778 sta $70
4779 lda $8e
4780 sbc #0
4781 sta $8e
4782 sta $71
4783 cld
4784 clc
4786 jsr write_bonus
4788 lda #9
4789 sta $70
4790 jsr add_score
4792 lda $8d
4793 and #$3f
4794 asl
4795 ldy #1
4796 jsr play_note
4798 end_of_level_no_countdown:
4799 inc $578e ; update motion counter
4800 clc
4802 lda $8d
4803 cmp #0
4804 bne show_end_of_level_bonus_loop
4806 lda $8e
4807 cmp #0
4808 bne show_end_of_level_bonus_loop
4810 lda #64 ; initialise delay counter
4811 sta $5785
4812 jsr delay
4814 ldx #0
4815 end_of_level_text_loop2:
4817 lda end_of_level_bytes2,x
4818 jsr $ffee
4819 inx
4820 cpx #25
4821 bne end_of_level_text_loop2
4823 lda $578a
4824 cmp #3
4825 bpl show_end_of_level_screen_exit
4827 lda #192 ; initialise delay counter
4828 sta $5785
4829 jsr delay
4831 show_end_of_level_screen_exit:
4832 rts
4834 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4836 write_bonus: ; $70,$71=value
4837 ; $72,$73=address of VDU codes
4839 ldx #4
4840 write_bonus_vdu_bytes:
4842 lda level_bonus_vdu_bytes,x
4843 jsr $ffee
4844 dex
4845 bpl write_bonus_vdu_bytes
4847 ldy #1
4848 write_bonus_loop:
4850 tya
4851 tax ; temporary
4853 lda $70,x
4854 sta $80
4855 lsr
4856 lsr
4857 lsr
4858 lsr
4859 tax
4860 lda score_digits,x
4861 jsr $ffee
4863 lda $80
4864 and #$0f
4865 tax
4866 lda score_digits,x
4867 jsr $ffee
4869 dey
4870 bpl write_bonus_loop
4872 clc
4873 rts
4875 position_player_set_up_plotting:
4877 jsr reset_player_position
4878 jsr remove_characters
4880 jsr reset_unplot_buffer
4881 jsr reset_plot_buffer
4883 ; Run on into the next routine.
4885 plot_the_player:
4887 lda #$80 ; plot the player
4888 sta $74
4889 lda #$52
4890 sta $75
4891 jsr plot_character
4893 jsr plot_buffer
4894 rts
4896 complete_game_vdu_bytes1: .byte 12
4897 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4898 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4899 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4901 show_complete_game:
4903 jsr blank_screen
4905 ldx #0
4906 show_complete_game_vdu_loop:
4908 lda complete_game_vdu_bytes1,x
4909 jsr $ffee
4910 inx
4911 cpx #68
4912 bne show_complete_game_vdu_loop
4914 jsr copy_completed_screen_up
4916 jsr set_complete_palette
4918 lda #255
4919 sta $5785
4921 show_complete_game_delay_loop:
4923 jsr wait_for_vsync
4925 dec $5785
4926 bne show_complete_game_no_message
4928 jsr colour1
4929 jsr show_input_message
4931 show_complete_game_no_message:
4933 lda #128
4934 ldx #0
4935 jsr $fff4
4936 cpx #0 ; fire button pressed?
4937 beq show_complete_game_no_joystick
4938 jmp show_complete_game_exit
4940 show_complete_game_no_joystick:
4942 ldx #157
4943 jsr check_key
4944 cpy #255
4945 bne show_complete_game_delay_loop
4947 show_complete_game_exit:
4948 clc
4949 rts
4951 check_high_scores:
4953 ; Start at the bottom of the table, moving scores down as necessary, and
4954 ; write in the current score at the appropriate place.
4956 lda #$86 ; current score
4957 sta $70
4958 lda #$57
4959 sta $71
4961 lda #$80
4962 sta $72
4963 lda #$51
4964 sta $73
4966 check_high_scores_loop:
4968 ldy #2
4969 check_high_scores_digits_loop:
4971 lda ($72),y
4972 cmp ($70),y ; existing score less than current score?
4973 bmi check_high_scores_move_down
4974 beq check_high_scores_digits_next ; keep checking digits if equal
4975 jmp check_high_scores_next
4977 check_high_scores_digits_next:
4978 dey
4979 bpl check_high_scores_digits_loop
4981 check_high_scores_next:
4982 clc
4983 lda $72
4984 adc #12
4985 sta $72
4986 cmp #$e0
4987 bne check_high_scores_loop
4989 ; The player's score didn't make it into the high score table.
4990 rts
4992 check_high_scores_move_down: ; $70,$71=pointer to current score
4993 ; $72,$73=pointer to old score
4995 ; The current score exceeded the existing entry. Make a note of the
4996 ; position in the high score table, insert the player's score, and take
4997 ; the old score
4999 lda $72 ; Record the position in the high score table of the
5000 sta $8d ; player's score.
5001 lda $73
5002 sta $8e
5004 lda #$e0
5005 sta $74
5006 lda #$51
5007 sta $75
5009 ldy #0
5010 insert_blank_player_name_loop:
5012 cpy #3
5013 bpl insert_blank_player_name_score_only
5015 lda ($70),y
5016 jmp insert_blank_player_name_store
5018 insert_blank_player_name_score_only:
5019 lda #32
5021 insert_blank_player_name_store:
5022 sta ($74),y
5023 iny
5024 cpy #12
5025 bne insert_blank_player_name_loop
5027 check_high_scores_move_down_loop:
5029 ldy #0
5030 check_high_scores_copy_score_and_name:
5032 lda ($72),y ; swap the current score with the score in the table
5033 tax
5034 lda ($74),y
5035 sta ($72),y
5036 txa
5037 sta ($74),y
5038 iny
5039 cpy #12
5040 bne check_high_scores_copy_score_and_name
5042 clc
5043 lda $72
5044 adc #12
5045 sta $72
5046 cmp #$e0
5047 bne check_high_scores_move_down_loop
5049 ; Draw a decorative room.
5051 jsr set_hidden_palette
5053 jsr make_empty_room
5055 lda #3
5056 sta $76
5057 sta $77
5058 jsr draw_top_line
5059 jsr draw_bottom_line
5060 jsr draw_left_line
5062 lda #0
5063 sta $77
5064 jsr draw_right_line
5066 jsr plot_room_tiles
5068 ; Add text characters to the room.
5069 jsr colour3
5071 lda #3 ; x
5072 sta $70
5073 lda #6 ; y
5074 sta $71
5076 lda #65
5077 sta $72
5079 ldx #3
5080 plot_text_characters_loop:
5082 jsr print_xy
5084 lda $70
5085 adc #4
5086 sta $70
5088 dex
5089 bpl plot_text_characters_next
5091 lda #3
5092 sta $70
5093 lda $71
5094 adc #3
5095 sta $71
5097 ldx #3
5099 plot_text_characters_next:
5101 inc $72
5102 lda $72
5103 cmp #91
5104 bne plot_text_characters_loop
5106 lda #11
5107 sta $70
5108 lda #95 ; _ representing a space
5109 sta $72
5110 jsr print_xy
5112 lda #15
5113 sta $70
5114 lda #60 ; < representing delete
5115 sta $72
5116 jsr print_xy
5118 ; Put the player in the centre of the room.
5119 jsr position_player_set_up_plotting
5121 lda #0 ; reset motion counter
5122 sta $578e
5124 lda #0 ; not on a character
5125 sta $578d
5127 lda #0 ; reset the level number so that the correct tiles are used
5128 sta $578a
5130 lda #3 ; cursor position in the high score entry held in $8d,$8e
5131 sta $8f
5133 jsr set_standard_palette
5135 ldx #0
5136 high_score_vdu_loop:
5138 lda high_score_vdu_bytes,x
5139 jsr $ffee
5140 inx
5141 cpx #39
5142 bne high_score_vdu_loop
5144 high_score_entry_loop:
5146 jsr reset_unplot_buffer
5147 jsr reset_plot_buffer
5149 jsr move_player
5150 ; Check if the player leaves the room.
5151 bcc high_score_entry_check_position
5152 jmp high_score_entry_after_loop
5154 high_score_entry_check_position:
5156 lda $5285 ; dx
5157 cmp #2
5158 beq high_score_entry_maybe_aligned
5159 jmp high_score_entry_not_aligned
5161 high_score_entry_maybe_aligned:
5163 lda $5282 ; y
5164 tay
5165 cmp #8
5166 bpl high_score_entry_not_aligned
5168 lda $5284 ; x
5169 tax
5170 cmp #9
5171 beq high_score_entry_not_aligned
5172 and #1
5173 beq high_score_entry_not_aligned
5175 lda $5283 ; dy
5176 cmp #2
5177 bmi high_score_entry_aligned
5178 jmp high_score_entry_not_aligned
5180 lda $5282 ; y again (don't apply the touching rule to the bottom
5181 cmp #7 ; row of characters)
5182 beq high_score_entry_not_aligned
5184 iny ; we are really touching the character below
5186 high_score_entry_aligned:
5188 lda $578d
5189 cmp #1
5190 beq high_score_entry_next
5192 ; The player is aligned with a letter.
5193 txa
5194 sec
5195 sbc #1
5196 lsr
5197 sta $7e ; record (x - 1) / 2
5199 tya ; recall y
5200 sec
5201 sbc #1
5202 asl
5203 asl ; (y - 1) * 4
5204 clc
5206 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5207 adc #65
5208 sta $7e ; record the ASCII code
5210 cmp #91
5211 bmi insert_character
5213 cmp #92
5214 beq delete_character
5216 ; Insert a space.
5217 lda #32
5218 sta $7e
5220 insert_character:
5221 lda $8f
5222 cmp #12
5223 bpl high_score_entry_pressed
5225 tay ; insert the character
5226 lda $7e
5227 sta ($8d),y
5228 jsr print_high_score_character
5230 inc $8f
5231 jmp high_score_entry_pressed
5233 delete_character:
5234 lda $8f
5235 cmp #4
5236 bmi high_score_entry_pressed
5238 cmp #12
5239 beq high_score_delete_previous_character
5241 tay
5242 lda #32 ; insert a space
5243 sta ($8d),y
5244 jsr print_high_score_character
5246 high_score_delete_previous_character:
5247 dec $8f
5248 lda $8f
5249 tay ; insert a space
5250 lda #32
5251 sta ($8d),y
5252 jsr print_high_score_character
5254 high_score_entry_pressed:
5255 lda #1
5256 sta $578d
5257 jmp high_score_entry_next
5259 high_score_entry_not_aligned:
5260 lda #0
5261 sta $578d
5263 high_score_entry_next:
5265 jsr wait_for_vsync
5266 jsr plot_buffer
5268 jmp high_score_entry_loop
5270 inc $578e
5271 clc
5273 high_score_entry_after_loop:
5274 clc
5276 jsr cls
5277 jsr set_hidden_palette
5279 rts
5281 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5283 cls:
5284 lda #12
5285 jsr $ffee
5286 rts
5288 colour1:
5289 lda #17
5290 jsr $ffee
5291 lda #1
5292 jsr $ffee
5293 rts
5295 colour3:
5296 lda #17
5297 jsr $ffee
5298 lda #3
5299 jsr $ffee
5300 rts
5302 print_high_score_character: ; A=ASCII code
5304 clc
5305 sta $72 ; store the character
5306 lda $8f
5307 adc #3
5308 sta $70 ; store the x position of the character
5309 lda #30
5310 sta $71
5311 ; Run on into the next routine.
5313 print_xy:
5315 lda #31
5316 jsr $ffee
5317 lda $70
5318 jsr $ffee
5319 lda $71
5320 jsr $ffee
5321 lda $72
5322 jsr $ffee
5323 rts
5325 disable_sound: ; X=1 (disable); X=0 (enable)
5327 lda #210
5328 ldy #0
5329 jmp $fff4 ; optimise away the rts
5331 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5332 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5334 start_new_game:
5336 ; Clear the screen.
5337 jsr cls
5339 ; Set the level.
5340 lda #0
5341 sta $578a
5343 ; Set the score.
5344 lda #0
5345 sta $5786
5346 lda #0
5347 sta $5787
5348 lda #0
5349 sta $5788
5351 ; Blank the screen now because it will be blanked before the room is shown
5352 ; and otherwise the strength bar will show briefly.
5353 jsr blank_screen
5355 ; Set the player's strength.
5356 lda #0
5357 sta $5784
5358 lda #64
5359 sta $70
5360 jsr add_strength
5362 ; Set the projectile type.
5363 lda #0
5364 sta $5789
5366 rts
5368 reset_player_position:
5370 lda #1 ; player
5371 sta $5280
5372 lda #6 ; down (first frame)
5373 sta $5281
5374 lda #4 ; y=4
5375 sta $5282
5376 lda #2 ; dy=2
5377 sta $5283
5378 lda #4 ; x=4
5379 sta $5284
5380 lda #3 ; dx=3
5381 sta $5285
5383 rts
5385 start_level:
5387 ; Clear the item/player flags.
5388 lda #0
5389 sta $5780
5391 ; Set current room.
5393 ldx $578a
5394 lda start_rooms_y,x
5395 sta $5782
5396 lda start_rooms_x,x
5397 sta $5783
5399 ; Set the player's position.
5401 jsr reset_player_position
5403 ; Reset the weapon counter.
5404 lda #0
5405 sta $577f
5407 ; Fill the treasure table with objects.
5408 ldx $578a ; level
5409 lda key_rooms,x
5410 sta $80
5412 ldx $578a ; level
5413 lda seeds,x
5414 adc #1
5415 and #31
5416 sta $7c
5417 clc
5418 lda seeds,x
5419 adc #2
5420 and #31
5421 sta $7d
5422 clc
5424 lda $578a ; create an upper limit on the weapon type found in this level
5425 adc #2
5426 sta $5781
5427 clc
5429 lda #$00
5430 sta $8e
5431 lda #$52
5432 sta $8f
5434 ldy #0
5435 start_level_add_treasure_loop:
5437 cpy $80 ; check for the key room
5438 bne start_level_add_treasure_item
5440 lda #5 ; the value to store is type + 1
5441 jmp start_level_add_treasure_store
5443 start_level_add_treasure_item:
5444 clc
5445 jsr unlimited_values
5446 and #$0f
5447 cmp #0
5448 beq start_level_add_treasure_none
5450 clc
5451 sta $8c
5452 tya
5453 adc $8c
5454 and #31
5455 clc
5456 tax
5457 lda treasure_table,x
5459 cmp #4
5460 bmi start_level_add_treasure_weapon
5462 clc
5463 adc #1
5464 jmp start_level_add_treasure_store
5466 start_level_add_treasure_weapon:
5468 ; Only add weapons with types that equal the level number or exceed it
5469 ; by one.
5470 cmp $5781
5471 bcs start_level_add_treasure_none
5473 clc
5474 adc #1 ; store values 0-8 as values 1-9
5475 jmp start_level_add_treasure_store
5477 start_level_add_treasure_none:
5478 clc
5479 lda #0 ; do not put treasure in this room
5481 start_level_add_treasure_store:
5482 clc
5483 sta ($8e),y ; add the item to the table
5485 iny
5486 cpy #121
5487 bmi start_level_add_treasure_loop
5489 ; Write the status text.
5490 ldx #0
5491 write_status_text_loop:
5492 lda status_vdu_bytes,x
5493 jsr $ffee
5494 inx
5495 cpx #25
5496 bmi write_status_text_loop
5498 jsr write_score
5500 clc
5501 rts
5503 main:
5504 jsr init
5506 main_loop:
5508 jsr show_title
5510 jsr start_new_game
5512 level_loop:
5514 jsr start_level
5516 game_loop:
5518 jsr remove_characters
5520 jsr reset_unplot_buffer
5521 jsr reset_plot_buffer
5523 lda $5782 ; current room (y)
5524 sta $78
5525 lda $5783 ; current room (x)
5526 sta $79
5527 jsr plot_room
5528 jsr set_room_palette
5529 jsr create_enemy_positions
5530 jsr add_treasure
5532 jsr plot_the_player
5534 lda #0 ; reset projectile counter
5535 sta $578d
5537 lda #0 ; reset motion counter
5538 sta $578e
5540 lda #63 ; reset generation counter
5541 sta $578f
5543 room_loop:
5544 jsr reset_unplot_buffer
5545 jsr reset_plot_buffer
5547 jsr move_characters
5548 jsr move_projectile
5550 lda $5780 ; is player out of strength ($40), leaving the
5551 and #$c2 ; level (0x80) or completing the game (0x02)?
5552 beq room_loop_player_move
5553 clc
5555 dec $5785 ; leave the loop when the delay
5556 bne room_loop_delay_next
5557 jmp after_room_loop ; counter is about to reset
5559 room_loop_delay_next:
5561 lda $5281 ; leave the loop when the player demise
5562 cmp #11 ; animation has finished
5563 beq room_loop_after_player_move
5564 clc
5566 lda $578e
5567 and #7
5568 bne room_loop_after_player_move
5570 lda $5780 ; skip the animation if leaving the level or
5571 and #$82 ; completing the game
5572 bne room_loop_after_player_move
5574 ; Show the demise animation when appropriate.
5576 lda #$80
5577 sta $74
5578 lda #$52
5579 sta $75
5581 jsr unplot_character
5583 inc $5281
5584 jsr plot_character
5585 jmp room_loop_after_player_move
5587 room_loop_player_move:
5589 ; See if it is time to generate a new enemy.
5590 lda $578f
5591 cmp #0
5592 bne no_emerge_characters
5593 jsr emerge_characters
5595 no_emerge_characters:
5596 clc
5598 jsr check_fire_key
5599 jsr move_player
5600 bcs after_room_loop ; check if we are leaving the level
5602 room_loop_after_player_move:
5603 clc
5605 lda #19
5606 jsr $fff4
5607 jsr plot_buffer
5609 ldx #143 ; Escape key check
5610 jsr check_key
5611 cpy #255
5612 beq main_loop_play_again
5614 ldx #174 ; S key check
5615 jsr check_key
5616 cpy #255
5617 bne no_set_sound
5619 ldx #0
5620 jsr disable_sound
5621 jmp after_sound_checks
5623 no_set_sound:
5625 ldx #239 ; Q key check
5626 jsr check_key
5627 cpy #255
5628 bne after_sound_checks
5630 ldx #1
5631 jsr disable_sound
5633 after_sound_checks:
5635 ldx #200 ; P key check
5636 jsr check_key
5637 cpy #255
5638 bne no_pause
5640 pause_loop:
5642 ldx #201 ; O key check
5643 jsr check_key
5644 cpy #255
5645 bne pause_loop
5647 no_pause:
5648 clc
5650 lda $578d
5651 cmp #0
5652 beq room_loop_no_update_projectile_counter
5654 dec $578d
5656 room_loop_no_update_projectile_counter:
5658 dec $578f ; update generation counter
5660 inc $578e ; update motion counter
5661 clc
5662 jmp room_loop
5664 after_room_loop:
5665 clc
5667 lda $5780
5668 and #$80
5669 bne exit_level
5671 lda $5780
5672 and #$40
5673 bne game_over
5675 lda $5780
5676 and #$02
5677 bne complete_game
5679 jmp game_loop
5681 exit_level:
5683 jsr show_end_of_level_screen
5685 inc $578a
5686 clc
5687 jmp level_loop
5689 game_over:
5690 jsr show_game_over
5691 jmp main_loop_play_again
5693 complete_game:
5694 jsr show_end_of_level_screen
5695 jsr show_complete_game
5696 jmp main_loop_play_again
5698 main_loop_play_again:
5699 jsr cls
5701 ; Check the score against the high scores.
5702 jsr check_high_scores
5704 jmp main_loop
5706 exit:
5707 clc
5708 rts