junglejourney
view mapcode.oph @ 197:8ff47d1667f7
Only allow the fire button on the first joystick to be used.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sat Oct 01 13:18:15 2011 +0200 |
| parents | 095ccf30c42a |
| children | aa9f05624182 |
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 #112 ; <= -16
1762 bcs move_player_check_joystick_left
1763 jmp move_player_right
1765 move_player_check_joystick_left:
1766 cpy #144 ; >= 16
1767 bcc 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 #112 ; <= -16
1776 bcs move_player_check_joystick_up
1777 jmp move_player_down
1779 move_player_check_joystick_up:
1780 cpy #144
1781 bcc move_player_handle_left_key
1782 jmp move_player_up ; >= 16
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 txa
2203 and #1
2204 bne check_fire_key_fire
2206 check_fire_key_no_joystick:
2208 ldx #182 ; (Return)
2209 jsr check_key
2210 cpy #255
2211 bne check_fire_key_exit
2213 check_fire_key_fire:
2215 lda $5286
2216 cmp #0
2217 bne check_fire_key_exit
2219 lda #16
2220 sta $578d
2222 jmp create_projectile ; optimise away the rts
2224 check_fire_key_exit:
2225 clc
2226 rts
2228 create_projectile:
2230 lda #2
2231 sta $5286
2233 lda $5281
2234 and #$06 ; copy the direction information
2235 asl
2236 asl
2237 asl
2238 ora $5789 ; apply the projectile type
2239 sta $5287
2241 lda $5283 ; player dy
2242 adc $577f ; add the weapon counter
2243 adc #1
2244 cmp #4 ; if dy > 3, create the projectile on the tile below
2245 bpl create_projectile_below
2247 clc
2248 sta $5289 ; dy + weapon counter + 1
2249 lda $5282 ; y
2250 sta $5288
2251 jmp create_projectile_continue
2253 create_projectile_below:
2254 sec
2255 sbc #4
2256 sta $5289 ; dy + weapon counter + 1 - 4
2257 clc
2258 lda $5282 ; y
2259 adc #1
2260 sta $5288
2262 create_projectile_continue:
2263 lda $5284 ; x
2264 sta $528a
2266 lda $5285 ; dx
2267 sta $528b
2269 lda $577f ; toggle the weapon counter
2270 eor #1
2271 sta $577f
2273 ; Move the projectile away from the player.
2275 jsr move_projectile_after_unplot
2276 jsr move_projectile
2278 clc
2279 rts
2281 emerge_type: ; returns A=type
2282 jsr unlimited_values
2283 lda $7d
2284 and #7
2285 cmp #4
2286 bmi emerge_type_ok
2288 sec
2289 sbc #4
2290 clc
2292 emerge_type_ok:
2293 cmp $5781 ; only allow the appropriate enemies for this level
2294 bmi emerge_type_exit
2296 sec
2297 sbc $5781
2298 clc
2300 emerge_type_exit:
2301 asl
2302 asl
2303 asl
2304 asl
2305 clc
2306 rts
2308 emerge_character: ; $74,$75=character address
2310 lda #63
2311 sta $578f
2313 jsr unlimited_values
2314 and #$0f
2315 tax
2316 lda $0ee0,x
2317 cmp #0 ; check for an invalid value and exit if found
2318 beq emerge_character_exit
2320 sta $80 ; temporary
2321 lda $0ef0,x
2322 tax
2324 ; Add an emerging enemy.
2326 ldy #0
2327 lda #3 ; emerge/explosion
2328 sta ($74),y
2330 jsr emerge_type ; obtain an enemy type
2331 iny
2332 sta ($74),y
2334 txa
2335 iny
2336 sta ($74),y ; store the y position
2337 lda #1
2338 iny
2339 sta ($74),y ; store the dy offset
2341 lda $80
2342 iny
2343 sta ($74),y ; store the x position
2344 lda #0
2345 iny
2346 sta ($74),y ; store the dx offset
2348 jsr plot_character
2350 ldx #5
2351 jsr play_sound
2353 emerge_character_exit:
2354 clc
2355 rts
2357 emerge_explode: ; $74,$75=character address
2359 jsr unplot_character
2361 ldy #1
2362 lda ($74),y ; direction/animation
2363 tax
2364 adc #1 ; update the counter
2365 and #3 ; mask off everything else
2366 sta $80 ; store the masked counter value
2367 bne move_characters_explosion_not_finished
2369 txa
2370 and #4
2371 bne move_characters_remove_character
2373 ; For emerges, convert into an enemy.
2374 txa
2375 and #$70 ; only keep bits 4,5,6
2376 ora #8 ; make this an enemy
2378 ldy #0
2379 sta ($74),y ; update the type (>= 8)
2380 iny
2381 lda $7d ; prepare the direction and animation offset
2382 and #$0c
2383 sta ($74),y
2385 jsr plot_character
2386 jmp emerge_explode_exit
2388 move_characters_remove_character:
2390 ; For finished explosions, just write 0 into the character array.
2391 lda #0
2392 ldy #0
2393 sta ($74),y
2394 jmp emerge_explode_exit
2396 move_characters_explosion_not_finished:
2397 txa
2398 and #$fc
2399 ora $80
2401 ldy #1
2402 sta ($74),y
2404 jsr plot_character
2406 emerge_explode_exit:
2407 clc
2408 rts
2410 animate_enemy_left: ; $74,$75=character address
2412 ; Set the direction and toggle the animation bit.
2414 ldy #1
2415 lda ($74),y
2416 and #$fb ; keep vertical direction bit and animation bits
2417 sta ($74),y ; left (horizontal directional bit is 0)
2419 rts
2421 move_enemy_left: ; $74,$75=character address
2423 ldy #5
2424 lda ($74),y ; read dx
2425 cmp #0
2426 beq move_enemy_left_check_x
2428 sec
2429 sbc #1
2430 ldy #5
2431 sta ($74),y ; dx
2432 clc
2433 jmp animate_enemy_left ; optimise away the rts
2435 move_enemy_left_check_x:
2437 ; Check the x offset.
2439 ldy #4
2440 lda ($74),y ; x
2441 cmp #0
2442 beq move_enemy_left_exit
2444 sec
2445 sbc #1 ; x - 1
2446 sta $81 ; temporary
2447 ldy #2
2448 lda ($74),y ; load the y offset
2449 tax ; as an index
2450 lda room_row_offsets_low,x ; read the address of the row
2451 sta $70
2452 lda #$57
2453 sta $71
2454 ldy $81 ; temporary (x - 1)
2455 lda ($70),y ; load the tile to the left
2457 cmp #0
2458 bne move_enemy_left_exit
2460 ldy #3
2461 lda ($74),y ; dy
2462 cmp #2
2463 bmi move_enemy_allow_left
2465 clc
2466 lda $70 ; dy > 1 so we need to check another tile
2467 adc #10
2468 sta $70
2469 ldy $81 ; temporary (x - 1)
2470 lda ($70),y ; load the tile below and to the left
2472 cmp #0
2473 bne move_enemy_left_exit
2475 move_enemy_allow_left:
2476 lda $81
2477 ldy #4
2478 sta ($74),y ; store the new room x offset
2479 lda #3
2480 ldy #5
2481 sta ($74),y ; dx = 3
2482 clc
2483 jmp animate_enemy_left ; optimise away the rts
2485 move_enemy_left_exit:
2486 sec
2487 rts
2489 animate_enemy_right: ; $74,$75=character address
2491 ; Set the direction and toggle the animation bit.
2493 ldy #1
2494 lda ($74),y
2495 ora #$04 ; right (keep vertical direction bit and animation bits)
2496 sta ($74),y
2498 rts
2500 move_enemy_right: ; $74,$75=character_address
2502 ldy #5
2503 lda ($74),y ; read dx
2504 cmp #0
2505 beq move_enemy_right_check_x
2506 cmp #3
2507 beq move_enemy_right_tile
2509 clc
2510 adc #1
2511 ldy #5
2512 sta ($74),y
2513 jmp animate_enemy_right ; optimise away the rts
2515 move_enemy_right_check_x: ; Check the x offset.
2517 ldy #4
2518 lda ($74),y ; x
2519 cmp #9
2520 beq move_enemy_right_exit
2522 clc
2523 adc #1 ; x + 1
2524 sta $81 ; temporary (x + 1)
2525 ldy #2
2526 lda ($74),y ; load the y offset
2527 tax ; as an index
2528 lda room_row_offsets_low,x ; read the address of the row
2529 sta $70
2530 lda #$57
2531 sta $71
2532 ldy $81 ; temporary (x + 1)
2533 lda ($70),y ; load the tile to the right
2535 cmp #0
2536 bne move_enemy_right_exit
2538 ldy #3
2539 lda ($74),y ; dy
2540 cmp #2
2541 bmi move_enemy_allow_right
2543 clc ; dy > 1 so we need to check another tile
2544 lda $70
2545 adc #10
2546 sta $70
2547 ldy $81 ; temporary (x + 1)
2548 lda ($70),y ; load the tile below and to the right
2550 cmp #0
2551 bne move_enemy_right_exit
2553 move_enemy_allow_right:
2554 clc
2556 ldy #5
2557 lda ($74),y ; dx
2558 adc #1
2559 sta ($74),y ; update dx
2560 clc
2561 jmp animate_enemy_right ; optimise away the rts
2563 move_enemy_right_tile:
2564 clc
2566 ldy #4
2567 lda ($74),y ; x
2568 adc #1
2569 sta ($74),y ; store the new room x offset
2570 lda #0
2571 iny
2572 sta ($74),y ; dx = 0
2573 clc
2574 jmp animate_enemy_right ; optimise away the rts
2576 move_enemy_right_exit:
2577 sec
2578 rts
2580 animate_enemy_up: ; $74,$75=character address
2582 ; Set the direction and toggle the animation bit.
2584 ldy #1
2585 lda ($74),y
2586 and #$f7 ; keep horizontal direction bit and animation bits
2587 sta ($74),y
2589 rts
2591 move_enemy_up: ; $74,$75=character address
2593 ldy #3
2594 lda ($74),y ; read dy
2595 cmp #0
2596 beq move_enemy_up_check_y
2598 sec
2599 sbc #1
2600 ldy #3
2601 sta ($74),y ; dy
2602 clc
2603 jmp animate_enemy_up ; optimise away the rts
2605 move_enemy_up_check_y:
2607 ; Check the y offset.
2609 ldy #2
2610 lda ($74),y ; y
2611 cmp #0
2612 beq move_enemy_up_exit
2614 tax ; use the y offset as an index
2615 dex ; y - 1
2616 ldy #4
2617 lda ($74),y ; load the x offset
2618 sta $81 ; temporary (x)
2619 tay
2620 lda room_row_offsets_low,x ; read the address of the row
2621 sta $70
2622 lda #$57
2623 sta $71
2624 lda ($70),y ; load the tile above
2626 cmp #0
2627 bne move_enemy_up_exit
2629 ldy #5
2630 lda ($74),y ; dx
2631 cmp #0
2632 beq move_enemy_allow_up
2634 clc ; dx != 0 so we need to check another tile
2635 ldy $81
2636 iny
2637 lda ($70),y ; load the tile above and to the right
2639 cmp #0
2640 bne move_enemy_up_exit
2642 move_enemy_allow_up:
2643 txa
2644 ldy #2
2645 sta ($74),y ; store the new room y offset
2646 lda #3
2647 iny
2648 sta ($74),y ; dy = 3
2649 clc
2650 jmp animate_enemy_up ; optimise away the rts
2652 move_enemy_up_exit:
2653 sec
2654 rts
2656 animate_enemy_down: ; $74,$75=character address
2658 ; Set the direction and toggle the animation bit.
2660 ldy #1
2661 lda ($74),y
2662 ora #$08 ; down
2663 sta ($74),y
2665 rts
2667 move_enemy_down: ; $74,$75=character address
2669 ldy #3
2670 lda ($74),y ; dy
2671 cmp #1
2672 beq move_enemy_down_check_y
2673 cmp #3
2674 beq move_enemy_down_tile
2676 adc #1
2677 ldy #3
2678 sta ($74),y ; dy
2679 clc
2680 jmp animate_enemy_down ; optimise away the rts
2682 move_enemy_down_check_y:
2684 ; Check the y offset.
2686 ldy #2
2687 lda ($74),y
2688 cmp #9
2689 beq move_enemy_down_exit
2691 clc
2692 adc #1 ; y + 1
2693 tax
2694 ldy #4
2695 lda ($74),y ; load the x offset
2696 sta $81 ; temporary
2697 tay
2698 lda room_row_offsets_low,x ; read the address of the row
2699 sta $70
2700 lda #$57
2701 sta $71
2702 lda ($70),y ; load the tile below
2704 cmp #0
2705 bne move_enemy_down_exit
2707 ldy #5
2708 lda ($74),y ; dx
2709 cmp #0
2710 beq move_enemy_allow_down
2712 clc ; dx != 0 so we need to check another tile
2713 ldy $81 ; x
2714 iny
2715 lda ($70),y ; load the tile below and to the right
2717 cmp #0
2718 bne move_enemy_down_exit
2720 move_enemy_allow_down:
2721 clc
2723 ldy #3
2724 lda ($74),y ; dy
2725 adc #1
2726 sta ($74),y ; update dy
2727 clc
2728 jmp animate_enemy_down ; optimise away the rts
2730 move_enemy_down_tile:
2731 clc
2733 ldy #2
2734 lda ($74),y ; y
2735 adc #1
2736 sta ($74),y ; store the new room y offset
2737 lda #0
2738 iny
2739 sta ($74),y ; dy = 0
2740 clc
2741 jmp animate_enemy_down ; optimise away the rts
2743 move_enemy_down_exit:
2744 sec
2745 rts
2747 move_enemy_animate: ; $74,$75=character address
2749 ldy #1
2750 lda ($74),y ; direction/animation
2751 sta $81
2752 and #$03
2753 adc #1
2754 and #$03 ; keep animation bits
2755 sta $8f
2756 lda $81
2757 and #$fc ; mask off the animation bits
2758 ora $8f
2759 sta ($74),y
2760 rts
2762 move_enemy_next_direction: .byte $04, $0c, $00, $08
2764 move_enemy: ; $74,$75=character address
2766 lda #0
2767 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2768 lda #0
2769 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2771 lda ($74),y ; read the enemy number (Y should be zero)
2772 and #$10
2773 beq move_enemy_homing
2774 clc
2776 ; This enemy is a non-homing enemy.
2778 jsr unplot_character ; unplot now before we change the sprite used
2780 ldy #1
2781 lda ($74),y
2782 and #$f0
2783 cmp #$f0
2784 bne move_enemy_set_direction
2785 clc
2787 ldy #1
2788 lda ($74),y
2789 and #$0c
2790 ror
2791 ror
2792 tax
2793 lda move_enemy_next_direction,x
2794 sta ($74),y
2796 move_enemy_set_direction:
2797 clc
2799 ldy #1
2800 lda ($74),y
2801 sta $7b
2803 adc #$10
2804 sta ($74),y
2805 clc
2807 lda $7b
2808 and #$04
2809 ror
2810 ror
2811 adc #1
2812 sta $8e
2814 lda $7b
2815 and #$08
2816 ror
2817 ror
2818 ror
2819 adc #1
2820 sta $8d
2822 jmp move_enemy_with_direction
2824 move_enemy_homing:
2826 ldy #2
2827 lda ($74),y ; y
2828 cmp $5282 ; player y
2829 bmi move_enemy_downwards
2830 bne move_enemy_upwards
2832 ldy #3
2833 lda ($74),y ; dy
2834 cmp $5283 ; player y
2835 beq move_enemy_horizontally
2836 bpl move_enemy_upwards
2838 move_enemy_downwards:
2839 lda #2
2840 sta $8d
2841 jmp move_enemy_horizontally
2843 move_enemy_upwards:
2844 lda #1
2845 sta $8d
2846 ;jmp move_enemy_horizontally
2848 move_enemy_horizontally:
2849 ldy #4
2850 lda ($74),y ; x
2851 cmp $5284 ; player x
2852 bmi move_enemy_rightwards
2853 bne move_enemy_leftwards
2855 ldy #5
2856 lda ($74),y ; dx
2857 cmp #0
2858 beq move_enemy_with_direction_unplot
2859 bpl move_enemy_leftwards
2861 move_enemy_rightwards:
2862 lda #2
2863 sta $8e
2864 jmp move_enemy_with_direction_unplot
2866 move_enemy_leftwards:
2867 lda #1
2868 sta $8e
2870 move_enemy_with_direction_unplot:
2871 clc
2873 jsr unplot_character
2875 move_enemy_with_direction:
2876 clc
2878 lda $8e
2879 cmp #1
2880 bne move_enemy_not_left
2881 jsr move_enemy_left
2882 clc
2883 jmp move_enemy_not_right
2885 move_enemy_not_left:
2886 lda $8e
2887 cmp #2
2888 bne move_enemy_not_right
2889 jsr move_enemy_right
2890 clc
2892 move_enemy_not_right:
2893 lda $8d
2894 cmp #1
2895 bne move_enemy_not_up
2896 jsr move_enemy_up
2897 clc
2898 jmp move_enemy_toggle
2900 move_enemy_not_up:
2901 lda $8d
2902 cmp #2
2903 bne move_enemy_toggle
2904 jsr move_enemy_down
2906 move_enemy_toggle:
2907 clc
2908 jsr move_enemy_animate
2909 jmp plot_character ; optimise away the rts
2911 move_enemy_exit:
2912 clc
2913 rts
2915 create_explosion: ; X=y, Y=x
2917 lda #3
2918 sta $52a4
2919 lda #4
2920 sta $52a5
2921 txa
2922 sta $52a6
2923 lda #1
2924 sta $52a7
2925 tya
2926 sta $52a8
2927 lda #0
2928 sta $52a9
2929 rts
2931 move_projectile_left:
2933 lda $528b
2934 cmp #0
2935 beq move_projectile_left_check_x
2937 dec $528b
2938 clc
2939 rts
2941 move_projectile_left_check_x:
2943 lda $528a
2944 cmp #0
2945 bne move_projectile_left_in_room
2946 jmp move_projectile_left_exit
2948 move_projectile_left_in_room:
2949 tay
2950 dey ; x - 1
2951 ldx $5288 ; y
2952 lda room_row_offsets_low,x ; read the address of the row
2953 sta $70
2954 lda #$57
2955 sta $71
2956 lda ($70),y ; load the tile to the left
2958 cmp #0
2959 bne move_projectile_left_wall
2961 lda $5289 ; dy
2962 cmp #3
2963 bmi move_projectile_allow_left
2965 clc ; dy > 2 so we need to check another tile
2966 lda $70
2967 adc #10
2968 sta $70
2969 lda ($70),y ; load the tile below and to the left
2970 inx ; y += 1
2972 cmp #0
2973 bne move_projectile_left_wall
2975 move_projectile_allow_left:
2977 sty $528a ; x
2978 lda #3
2979 sta $528b ; dx = 3
2981 clc
2982 rts
2984 move_projectile_left_wall: ; the projectile hit a wall
2985 clc
2987 lda $5287 ; type 2 can pass through walls
2988 and #$06
2989 cmp #4
2990 beq move_projectile_allow_left
2992 cmp #2
2993 bne move_projectile_left_not_boomerang
2995 lda $5287
2996 and #$0f
2997 cmp #8
2998 bpl move_projectile_left_exit
3000 ldx $577f ; weapon counter
3001 ora boomerang_horizontal,x
3002 sta $5287
3003 clc
3004 rts ; exit without moving or registering a collision
3006 move_projectile_left_not_boomerang:
3008 cmp #6 ; type 3 can destroy certain walls
3009 bne move_projectile_left_exit
3011 lda ($70),y ; load the tile to the left
3012 cmp #1 ; decoration can be destroyed
3013 bne move_projectile_left_exit
3014 clc
3016 lda #0
3017 sta ($70),y
3019 ; X=y, Y=x
3020 jsr create_explosion
3021 jsr plot_blank_xy ; corrupted X
3023 lda #$a4
3024 sta $74
3025 lda #$52
3026 sta $75
3027 jsr plot_character
3029 ldx #0
3030 jsr play_sound
3032 lda #16 ; prevent the player from firing a new
3033 sta $578d ; projectile until the explosion has finished
3035 move_projectile_left_exit:
3036 sec
3037 rts
3039 boomerang_horizontal: .byte $28, $38
3041 move_projectile_right:
3043 ; Fire right.
3045 lda $528b
3046 cmp #2
3047 beq move_projectile_right_check_x
3048 cmp #3
3049 beq move_projectile_right_tile
3051 inc $528b
3052 clc
3053 rts
3055 move_projectile_right_check_x:
3057 lda $528a ; x
3058 cmp #9
3059 bne move_projectile_right_not_edge
3060 jmp move_projectile_right_exit
3062 move_projectile_right_not_edge:
3063 clc
3064 tay
3065 iny ; x + 1
3066 ldx $5288 ; y
3067 lda room_row_offsets_low,x ; read the address of the row
3068 sta $70
3069 lda #$57
3070 sta $71
3071 lda ($70),y ; load the tile to the right
3073 cmp #0
3074 bne move_projectile_right_wall
3076 lda $5289 ; dy
3077 cmp #3
3078 bmi move_projectile_allow_right
3080 clc ; dy > 2 so we need to check another tile
3081 lda $70
3082 adc #10
3083 sta $70
3084 lda ($70),y ; load the tile below and to the right
3085 inx ; y += 1
3087 cmp #0
3088 bne move_projectile_right_wall
3090 move_projectile_allow_right:
3092 inc $528b ; dx
3093 clc
3094 rts
3096 move_projectile_right_tile:
3098 inc $528a ; x
3099 lda #0
3100 sta $528b ; dx
3101 clc
3102 rts
3104 move_projectile_right_wall: ; the projectile hit a wall
3105 clc
3107 lda $5287 ; type 2 can pass through walls
3108 and #$06
3109 cmp #4
3110 beq move_projectile_allow_right
3112 cmp #2
3113 bne move_projectile_right_not_boomerang
3115 lda $5287
3116 and #$0f
3117 cmp #8
3118 bpl move_projectile_right_exit
3120 ldx $577f ; weapon counter
3121 ora boomerang_horizontal,x
3122 sta $5287
3123 clc
3124 rts ; exit without moving or registering a collision
3126 move_projectile_right_not_boomerang:
3128 cmp #6 ; type 3 can destroy certain walls
3129 bne move_projectile_right_exit
3131 lda ($70),y ; load the tile to the right
3132 cmp #1 ; decoration can be destroyed
3133 bne move_projectile_right_exit
3134 clc
3136 lda #0
3137 sta ($70),y
3139 ; X=y, Y=x
3140 jsr create_explosion
3141 jsr plot_blank_xy ; corrupted X
3143 lda #$a4
3144 sta $74
3145 lda #$52
3146 sta $75
3147 jsr plot_character
3149 ldx #0
3150 jsr play_sound
3152 lda #16 ; prevent the player from firing a new
3153 sta $578d ; projectile until the explosion has finished
3155 move_projectile_right_exit:
3156 sec
3157 rts
3159 move_projectile_up:
3161 lda $5289 ; read dy
3162 cmp #0
3163 beq move_projectile_up_check_y
3165 dec $5289
3166 clc
3167 rts
3169 move_projectile_up_check_y: ; Check the y offset.
3171 lda $5288
3172 cmp #0
3173 bne move_projectile_up_not_edge
3174 jmp move_projectile_up_exit
3176 move_projectile_up_not_edge:
3177 tax ; use the y offset as an index
3178 dex ; y - 1
3179 ldy $528a ; load the x offset
3180 lda room_row_offsets_low,x ; read the address of the row
3181 sta $70
3182 lda #$57
3183 sta $71
3184 lda ($70),y ; load the tile above
3186 cmp #0
3187 bne move_projectile_up_wall
3189 lda $528b ; dx
3190 cmp #3
3191 bmi move_projectile_allow_up
3193 clc ; dx > 2 so we need to check another tile
3194 iny
3195 lda ($70),y ; load the tile above and to the right
3197 cmp #0
3198 bne move_projectile_up_wall
3200 move_projectile_allow_up:
3201 txa
3202 sta $5288 ; store the new room y offset
3203 lda #3
3204 sta $5289 ; dy = 3
3206 clc
3207 rts
3209 move_projectile_up_wall: ; the projectile hit a wall
3210 clc
3212 lda $5287 ; type 2 can pass through walls
3213 and #$06
3214 cmp #4
3215 beq move_projectile_allow_up
3217 cmp #2
3218 bne move_projectile_up_not_boomerang
3220 lda $5287
3221 and #$0f
3222 cmp #8
3223 bpl move_projectile_up_exit
3225 ldx $577f ; weapon counter
3226 ora boomerang_vertical,x
3227 sta $5287
3228 clc
3229 rts ; exit without moving or registering a collision
3231 move_projectile_up_not_boomerang:
3233 cmp #6 ; type 3 can destroy certain walls
3234 bne move_projectile_up_exit
3236 lda ($70),y ; load the tile above
3237 cmp #1 ; decoration can be destroyed
3238 bne move_projectile_up_exit
3239 clc
3241 lda #0
3242 sta ($70),y
3244 ; X=y, Y=x
3245 jsr create_explosion
3246 jsr plot_blank_xy ; corrupted X
3248 lda #$a4
3249 sta $74
3250 lda #$52
3251 sta $75
3252 jsr plot_character
3254 ldx #0
3255 jsr play_sound
3257 lda #16 ; prevent the player from firing a new
3258 sta $578d ; projectile until the explosion has finished
3260 move_projectile_up_exit:
3261 sec
3262 rts
3264 boomerang_vertical: .byte $08, $18
3266 move_projectile_down:
3268 lda $5289 ; read dy
3269 cmp #2
3270 beq move_projectile_down_check_y
3271 cmp #3
3272 beq move_projectile_down_tile
3274 inc $5289 ; 0 <= dy < 3
3275 clc
3276 rts
3278 move_projectile_down_check_y: ; Check the y offset.
3280 lda $5288
3281 cmp #9
3282 bne move_projectile_down_in_room
3283 jmp move_projectile_down_exit
3285 move_projectile_down_in_room:
3286 clc
3287 tax
3288 inx ; y + 1
3289 ldy $528a ; load the x offset
3290 lda room_row_offsets_low,x ; read the address of the row
3291 sta $70
3292 lda #$57
3293 sta $71
3294 lda ($70),y ; load the tile below
3296 cmp #0
3297 bne move_projectile_down_wall
3299 lda $528b ; dx
3300 cmp #3
3301 bmi move_projectile_allow_down
3303 clc ; dx > 2 so we need to check another tile
3304 iny
3305 lda ($70),y ; load the tile below and to the right
3307 cmp #0
3308 bne move_projectile_down_wall
3310 move_projectile_allow_down:
3312 inc $5289 ; update dy
3313 clc
3314 rts
3316 move_projectile_down_tile:
3318 inc $5288 ; store the new room y offset
3319 lda #0
3320 sta $5289 ; dy = 0
3321 clc
3322 rts
3324 move_projectile_down_wall: ; the projectile hit a wall
3325 clc
3327 lda $5287 ; type 2 can pass through walls
3328 and #$06
3329 cmp #4
3330 beq move_projectile_allow_down
3332 cmp #2
3333 bne move_projectile_down_not_boomerang
3335 lda $5287
3336 and #$0f
3337 cmp #8
3338 bpl move_projectile_down_exit
3340 ldx $577f ; weapon counter
3341 ora boomerang_vertical,x
3342 sta $5287
3343 clc
3344 rts ; exit without moving or registering a collision
3346 move_projectile_down_not_boomerang:
3348 cmp #6 ; type 3 can destroy certain walls
3349 bne move_projectile_down_exit
3351 lda ($70),y ; load the tile below
3352 cmp #1 ; decoration can be destroyed
3353 bne move_projectile_down_exit
3354 clc
3356 lda #0
3357 sta ($70),y
3359 ; X=y, Y=x
3360 jsr create_explosion
3361 jsr plot_blank_xy ; corrupted X
3363 lda #$a4
3364 sta $74
3365 lda #$52
3366 sta $75
3367 jsr plot_character
3369 ldx #0
3370 jsr play_sound
3372 lda #16 ; prevent the player from firing a new
3373 sta $578d ; projectile until the explosion has finished
3375 move_projectile_down_exit:
3376 sec
3377 rts
3379 move_projectile_animate:
3381 lda $5287
3382 eor #1
3383 sta $5287
3384 rts
3386 move_projectile:
3388 lda $5286
3389 cmp #0
3390 bne move_projectile_move
3391 jmp move_projectile_exit
3393 move_projectile_move:
3394 clc
3396 lda #$86
3397 sta $74
3398 lda #$52
3399 sta $75
3400 jsr unplot_character
3402 move_projectile_after_unplot:
3404 lda $5287
3405 and #$30 ; direction
3407 cmp #0
3408 bne move_projectile_not_left
3410 jsr move_projectile_left
3411 bcc move_projectile_toggle
3412 bcs move_projectile_destroy
3414 move_projectile_not_left:
3415 cmp #$10
3416 bne move_projectile_not_right
3418 jsr move_projectile_right
3419 bcc move_projectile_toggle
3420 bcs move_projectile_destroy
3422 move_projectile_not_right:
3423 cmp #$20
3424 bne move_projectile_not_up
3426 jsr move_projectile_up
3427 bcc move_projectile_toggle
3428 bcs move_projectile_destroy
3430 move_projectile_not_up:
3431 cmp #$30
3432 bne move_projectile_toggle
3434 jsr move_projectile_down
3435 bcs move_projectile_destroy
3437 move_projectile_toggle:
3439 jsr projectile_collide
3440 bcs move_projectile_destroy
3442 jsr move_projectile_animate
3444 lda #$86
3445 sta $74
3446 lda #$52
3447 sta $75
3448 jmp plot_character ; optimise away the rts
3450 move_projectile_destroy:
3451 clc
3453 ldy #0
3454 lda ($74),y ; type
3455 cmp #8
3456 bmi move_projectile_no_enemy_collision
3458 and #$70 ; increase the player's score
3459 lsr
3460 lsr
3461 lsr
3462 adc #2
3463 sta $70
3464 jsr add_score
3465 jmp move_projectile_create_explosion
3467 move_projectile_no_enemy_collision:
3469 cmp #4 ; items can be destroyed as well
3470 bne move_projectile_no_item_collision
3472 ldy #1 ; but not keys
3473 lda ($74),y
3474 cmp #4 ; even the mace is stopped by a key
3475 beq move_projectile_remove_projectile
3476 clc
3478 jsr remove_room_item
3480 move_projectile_create_explosion:
3482 ; Unplot the item/enemy and replace it with an explosion.
3484 jsr unplot_character
3486 lda #3 ; explosion
3487 ldy #0
3488 sta ($74),y
3490 lda #4
3491 ldy #1
3492 sta ($74),y
3494 jsr plot_character
3496 ; Play a sound.
3497 ldx #0
3498 jsr play_sound
3500 move_projectile_no_item_collision:
3502 lda $5287 ; type 2 projectiles pass through everything
3503 and #$06
3504 cmp #4
3505 bne move_projectile_remove_projectile
3507 ; Ideally, we would have recorded if the projectile left the screen so
3508 ; that we don't perform these checks again here, but it would just add
3509 ; overhead to the normal movement routines for the other weapons.
3511 lda $5288 ; y
3512 cmp #0
3513 beq move_projectile_remove_projectile
3514 cmp #9
3515 beq move_projectile_remove_projectile
3517 lda $528a ; x
3518 cmp #0
3519 beq move_projectile_remove_projectile
3520 cmp #9
3521 beq move_projectile_remove_projectile
3523 clc
3524 lda #$86
3525 sta $74
3526 lda #$52
3527 sta $75
3529 jsr plot_character
3530 jmp move_projectile_exit
3532 move_projectile_remove_projectile:
3534 lda #0 ; remove the projectile from the character list
3535 sta $5286
3537 move_projectile_exit:
3538 clc
3539 rts
3541 emerge_characters:
3543 lda #$8c ; set the character address
3544 sta $74
3545 lda #$52
3546 sta $75
3548 emerge_characters_loop:
3550 ldy #0
3551 lda ($74),y
3552 cmp #0
3553 bne emerge_characters_next
3555 jmp emerge_character ; optimise away the rts
3557 emerge_characters_next:
3558 clc
3560 ; Examine the next character.
3561 lda $74
3562 adc #6
3564 cmp #$a4
3565 bpl emerge_characters_exit
3566 sta $74
3567 jmp emerge_characters_loop
3569 emerge_characters_exit:
3570 clc
3571 rts
3573 enemy_slots: .byte 0, 6, 12, 18
3575 move_characters:
3577 lda #$8c ; set the character address
3578 sta $74
3579 lda #$52
3580 sta $75
3582 lda $578e ; read a value from 0 to 3 from the motion counter
3583 and #3
3584 tax
3585 lda enemy_slots,x ; look up the corresponding slot in the character list
3586 adc $74
3587 sta $74 ; update the character address
3589 move_characters_loop:
3591 ldy #0
3592 lda ($74),y
3593 cmp #3
3594 bne move_characters_not_emerge_explode
3596 jsr emerge_explode
3597 jmp move_characters_next
3599 move_characters_not_emerge_explode:
3600 cmp #8
3601 bmi move_characters_next
3603 jsr move_enemy
3605 move_characters_next:
3606 clc
3608 lda $74 ; for the last enemy, check the next slot
3609 cmp #$9e ; for the presence of an explosion
3610 bne move_characters_endloop ; otherwise leave the loop (only performing
3611 clc ; one iteration)
3613 adc #6
3614 sta $74
3615 jmp move_characters_loop
3617 move_characters_endloop:
3618 clc
3620 ; Check collisions with the player.
3622 jsr player_collide
3623 bcs move_characters_collisions
3624 jmp move_characters_exit
3626 move_characters_collisions:
3627 clc
3629 ldy #0
3630 lda ($74),y ; type
3631 cmp #8
3632 bpl move_character_destroy_enemy
3634 ; Unplot the item.
3635 jsr unplot_character
3637 ; Remove it from the item table.
3638 jsr remove_room_item
3640 lda #0 ; remove the item from the character list
3641 ldy #0
3642 sta ($74),y
3644 iny
3645 lda ($74),y ; get the item type
3647 sta $8d ; temporarily store A and increase the score
3648 tax
3649 lda item_scores,x
3650 sta $70
3651 jsr add_score
3652 lda $8d
3654 ; Check the item type.
3655 cmp #8
3656 bmi move_characters_not_health
3658 lda #20
3659 sta $70
3660 jsr add_strength
3661 clc
3663 ldx #2
3664 jsr play_sound
3666 rts
3668 move_characters_not_health:
3669 cmp #5
3670 bmi move_characters_not_treasure
3672 ldx #2
3673 jsr play_sound
3675 clc
3676 rts
3678 move_characters_not_treasure:
3679 cmp #4
3680 bmi move_characters_not_key
3682 ; Key - update the item/player flags byte.
3683 lda $5780
3684 ora #$01
3685 sta $5780
3686 clc
3688 ldx #3
3689 jsr play_sound
3691 rts
3693 move_characters_not_key:
3695 ; Update the player's weapon.
3696 asl
3697 sta $5789
3698 clc
3700 ldx #2
3701 jsr play_sound
3703 rts
3705 move_character_destroy_enemy:
3707 ; Unplot the enemy and replace it with an explosion.
3709 jsr unplot_character
3711 lda #3 ; explosion
3712 ldy #0
3713 sta ($74),y
3715 lda #4
3716 ldy #1
3717 sta ($74),y
3719 jsr plot_character
3721 ; Reduce the player's strength.
3723 ldx #1
3724 jsr play_sound
3726 lda #1
3727 sta $70
3728 jmp reduce_strength ; optimise away the rts
3730 move_characters_exit:
3731 clc
3732 rts
3734 remove_room_item:
3736 ldx $5782 ; current room row number
3737 lda eleven_times_table,x
3738 adc $5783 ; current room column number
3739 tax
3740 lda #$80 ; store a value with the top bit set instead of zero because we
3741 sta $5200,x ; have visited this room if we can collect the object within it
3742 clc
3743 rts
3745 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3746 score_vdu_bytes: .byte 1,1,31 ; reversed
3747 score_digits: .byte "0123456789"
3749 add_score: ; $70=score to add
3751 sed
3752 lda $5786
3753 adc $70
3754 sta $5786
3755 lda $5787
3756 adc #0
3757 sta $5787
3758 lda $5788
3759 adc #0
3760 sta $5788
3761 cld
3763 write_score:
3765 lda #$86
3766 sta $70
3767 lda #$57
3768 sta $71
3770 ldx #2
3771 write_score_vdu_bytes:
3772 lda score_vdu_bytes,x
3773 jsr $ffee
3774 dex
3775 bpl write_score_vdu_bytes
3777 write_score_digits: ; $70,$71=address of score bytes
3779 ldy #2
3780 write_score_loop:
3782 lda ($70),y
3783 lsr
3784 lsr
3785 lsr
3786 lsr
3787 tax
3788 lda score_digits,x
3789 jsr $ffee
3791 lda ($70),y
3792 and #$0f
3793 tax
3794 lda score_digits,x
3795 jsr $ffee
3797 dey
3798 bpl write_score_loop
3800 clc
3801 rts
3803 strength_units: .byte $00,$88,$cc,$ee
3805 add_strength: ; $70=strength to add
3807 ; Divide the initial strength by 4 to determine which half character to
3808 ; start plotting at, and multiply by 8 to get the address. The net result
3809 ; is to mask off the bottom two bits and shift left once.
3810 lda $5784
3811 and #$fc
3812 sta $71 ; strength rounded down to a multiple of four units
3813 asl
3814 clc
3815 tay
3817 lda $5784
3818 adc $70
3819 cmp #65
3820 bmi add_strength_update
3822 lda #64
3824 add_strength_update:
3825 clc
3826 sta $5784 ; the final strength
3828 sec
3829 sbc $71
3830 clc
3831 tax ; the number of units to add between the rounded original
3832 ; strength and the final strength
3834 lda #$f3 ; the start of the strength bar
3835 sta $72
3836 lda #$59
3837 sta $73
3839 cpx #4
3840 bmi add_strength_loop_extra
3842 add_strength_loop:
3844 clc
3845 lda #$ff
3846 sta ($72),y
3848 tya
3849 adc #8
3850 tay
3852 txa
3853 sec
3854 sbc #4
3855 clc
3856 tax
3858 cmp #4
3859 bpl add_strength_loop
3861 add_strength_loop_extra:
3862 cpx #0
3863 beq add_strength_exit
3865 ; For any remaining units in excess of the multiples of four units, plot
3866 ; the appropriate byte.
3867 lda $5784
3868 and #3
3869 tax
3871 lda strength_units,x
3872 sta ($72),y
3874 add_strength_exit:
3875 clc
3876 rts
3878 reduce_strength: ; $70=strength to remove
3880 lda $5784
3881 tax
3882 sec
3883 sbc $70
3884 bpl reduce_strength_update
3886 lda #0
3888 reduce_strength_update:
3889 clc
3890 sta $5784
3892 ; Divide the final strength by 4 to determine which half character to
3893 ; plot, and multiply by 8 to get the address. The net result is to mask off
3894 ; the bottom two bits and shift left once.
3895 and #$fc
3896 asl
3897 tay
3899 lda #$f3 ; the start of the strength bar
3900 sta $70
3901 lda #$59
3902 sta $71
3904 lda $5784
3905 and #3
3906 tax
3907 lda strength_units,x
3908 sta ($70),y
3910 lda $5784
3911 cmp #0
3912 bne reduce_strength_exit
3914 lda $5780 ; the player ran out of strength
3915 ora #$40
3916 sta $5780
3918 lda #64 ; reset the delay counter
3919 sta $5785
3921 lda #$80 ; unplot the player
3922 sta $74
3923 lda #$52
3924 sta $75
3926 jsr unplot_character
3928 lda #8 ; change the player's direction to the demise animation
3929 sta $5281
3931 jsr plot_character
3932 jmp destroy_enemies ; optimise away the rts
3934 reduce_strength_exit:
3935 clc
3936 rts
3938 destroy_enemies:
3940 lda #$8c
3941 sta $74
3942 lda #$52
3943 sta $75
3945 destroy_enemies_loop:
3947 ldy #0
3948 lda ($74),y
3949 cmp #8
3950 bmi destroy_enemies_not_enemy
3952 jsr unplot_character
3954 lda #3 ; emerge/explosion
3955 ldy #0
3956 sta ($74),y
3958 iny
3959 lda #4 ; explosion
3960 sta ($74),y
3962 jsr plot_character
3963 jmp destroy_enemies_not_emerging_enemy
3965 destroy_enemies_not_enemy:
3966 cmp #3
3967 bne destroy_enemies_not_emerging_enemy
3969 jsr unplot_character
3971 iny ; whether emerging or exploding, ensure that the enemy
3972 lda ($74),y ; is now exploding
3973 ora #4
3974 sta ($74),y
3976 jsr plot_character
3978 destroy_enemies_not_emerging_enemy:
3979 clc
3980 lda $74
3981 adc #6
3982 sta $74
3983 cmp #$a4
3984 bmi destroy_enemies_loop
3986 clc
3987 rts
3989 remove_characters:
3991 ; Clear the character table.
3993 ldx #6
3994 remove_characters_loop:
3995 lda #0
3996 sta $5280,x
3997 txa
3998 adc #6
3999 tax
4000 cpx #$2a
4001 bmi remove_characters_loop
4003 rts
4005 ; The player collision masks use bits to represent where the player is in a
4006 ; tile. See the collisions.txt file for more information.
4008 ; Player is above, enemy is below, checking the overlap in the lower tile.
4009 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4011 projectile_collision_mask_above: .byte $00, $00, $00, $80
4013 ; Player and enemy share the same tile or player is on the tile below.
4014 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4016 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4018 ; Player is above or on the same tile, enemy is below, checking the overlap in
4019 ; the lower tile.
4020 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4022 ; Enemy is above, player is below, checking the overlap in the lower tile.
4023 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4025 ; Player is to the left, enemy is to the right, checking the overlap in the
4026 ; right hand tile.
4027 player_collision_mask_left:
4028 projectile_collision_mask_left: .byte $00, $00, $00, $08
4030 ; Player and enemy share the same tile or player is on the tile to the right.
4031 player_collision_mask_right:
4032 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4034 ; Player is to the left, enemy is to the right or on the same tile, checking
4035 ; the overlap in the right hand tile.
4036 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4038 ; Enemy is to the left, player is to the right, checking the overlap in the
4039 ; right hand tile.
4040 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4042 player_collide:
4044 lda $5282 ; player y
4045 sta $8a
4046 lda $5284 ; player x
4047 sta $8b
4049 ldx $5283 ; player dy
4050 lda player_collision_mask_above,x
4051 sta $86
4052 lda player_collision_mask_below,x
4053 sta $88
4054 ldx $5285 ; player dx
4055 lda player_collision_mask_left,x
4056 sta $87
4057 lda player_collision_mask_right,x
4058 sta $89
4060 jmp collide ; optimise away the rts
4062 projectile_collide:
4064 lda $5288 ; projectile y
4065 sta $8a
4066 lda $528a ; projectile x
4067 sta $8b
4069 ldx $5289 ; projectile dy
4070 lda projectile_collision_mask_above,x
4071 sta $86
4072 lda projectile_collision_mask_below,x
4073 sta $88
4074 ldx $528b ; projectile dx
4075 lda projectile_collision_mask_left,x
4076 sta $87
4077 lda projectile_collision_mask_right,x
4078 sta $89
4080 ; Run on into the next routine.
4082 collide:
4084 lda #$8c ; set the character address
4085 sta $74
4086 lda #$52
4087 sta $75
4089 collide_loop:
4091 ldy #0
4092 lda ($74),y ; type
4093 cmp #4
4094 bpl collide_check
4096 jmp collide_next
4098 collide_check:
4100 ldy #2
4101 lda ($74),y ; y
4102 sec
4103 sbc $8a ; y - player/projectile y
4104 beq check_collide_y_equal
4105 cmp #1
4106 beq check_collide_y_greater
4107 cmp #255
4108 beq check_collide_y_less
4110 jmp collide_next
4112 check_collide_y_equal:
4113 ; The enemy is on the same tile as the player/projectile so look at the
4114 ; collision on their common tile.
4115 ldy #3
4116 lda ($74),y ; dy
4117 tax
4118 lda enemy_collision_mask_above,x
4119 and $88 ; player/projectile mask below
4120 bne check_collide_x
4122 jmp collide_next
4124 check_collide_y_greater:
4125 ; The enemy is on the tile below the player/projectile so look at the
4126 ; collision on the enemy's tile.
4127 ldy #3
4128 lda ($74),y ; dy
4129 tax
4130 lda enemy_collision_mask_above,x
4131 and $86 ; player mask above
4132 bne check_collide_x
4134 jmp collide_next
4136 check_collide_y_less:
4137 ; The enemy is on the tile above the player/projectile so look at the
4138 ; collision on the player's tile.
4139 ldy #3
4140 lda ($74),y ; dy
4141 tax
4142 lda enemy_collision_mask_below,x
4143 and $88 ; player mask below
4144 bne check_collide_x
4146 jmp collide_next
4148 check_collide_x:
4149 ldy #4
4150 lda ($74),y ; x
4151 sec
4152 sbc $8b ; x - player/projectile x
4153 beq check_collide_x_equal
4154 cmp #1
4155 beq check_collide_x_greater
4156 cmp #255
4157 beq check_collide_x_less
4159 jmp collide_next
4161 check_collide_x_equal:
4162 ; The enemy is on the same tile as the player/projectile so look at the
4163 ; collision on their common tile.
4164 ldy #5
4165 lda ($74),y ; dx
4166 tax
4167 lda enemy_collision_mask_left,x
4168 and $89 ; player mask right
4169 bne check_collide_destroy
4171 jmp collide_next
4173 check_collide_x_greater:
4174 ; The enemy is the tile to the right of the player/projectile so look
4175 ; at the collision on the enemy's tile.
4176 ldy #5
4177 lda ($74),y ; dx
4178 tax
4179 lda enemy_collision_mask_left,x
4180 and $87 ; player mask left
4181 bne check_collide_destroy
4183 jmp collide_next
4185 check_collide_x_less:
4186 ; The enemy is the tile to the left of the player/projectile so look at
4187 ; the collision on the player's tile.
4188 ldy #5
4189 lda ($74),y ; dx
4190 tax
4191 lda enemy_collision_mask_right,x
4192 and $89 ; player mask right
4193 bne check_collide_destroy
4195 collide_next:
4196 clc
4198 ; Examine the next character.
4199 lda $74
4200 adc #6
4202 cmp #$a4
4203 bpl collide_exit
4204 sta $74
4205 jmp collide_loop
4207 check_collide_destroy:
4209 sec ; set the carry flag to inform the caller that the
4210 rts ; player/projectile should be destroyed
4212 collide_exit:
4213 clc
4214 rts
4216 blank_screen:
4217 lda #1
4218 sta $70
4219 lda #0
4220 sta $71
4221 jsr set_palette
4222 lda #2
4223 sta $70
4224 lda #0
4225 sta $71
4226 jsr set_palette
4227 lda #3
4228 sta $70
4229 lda #0
4230 sta $71
4231 ; Run on into set_palette.
4233 set_palette:
4234 ; $70=logical colour
4235 ; $71=physical colour
4236 lda $70
4237 sta $578b
4238 lda $71
4239 sta $578c
4240 lda #0
4241 sta $578d
4242 sta $578e
4243 sta $578f
4245 lda #$c
4246 ldx #$8b
4247 ldy #$57
4248 jsr $fff1
4249 rts
4251 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4252 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4254 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4255 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4256 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4257 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4258 note_sound: .byte $13,0, 241,255
4259 note_pitch: .byte 0,0
4260 note_duration: .byte 4,0
4261 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4263 play_note: ; A=pitch, Y=duration
4265 sta note_pitch
4266 sty note_duration
4267 ldx #4
4268 ; Run on into the next routine.
4270 play_sound: ; X=sound number
4272 lda sounds_high,x
4273 tay
4274 lda sounds_low,x
4275 tax
4276 lda #7
4277 jsr $fff1
4279 rts
4281 copy_title_up:
4283 lda #$00
4284 sta $70
4285 lda #$18
4286 sta $71
4288 lda #$a0
4289 sta $72
4290 lda #$5a
4291 sta $73
4293 ldx #5
4294 ; Run on into the next routine.
4296 copy_title:
4298 copy_title_loop1:
4300 ldy #0
4301 copy_title_loop2:
4303 lda ($70),y
4304 sta ($72),y
4305 iny
4306 cpy #0
4307 bne copy_title_loop2
4309 clc
4310 lda $72
4311 adc #$40
4312 sta $72
4313 lda $73
4314 adc #$01
4315 sta $73
4316 clc
4318 lda $71
4319 adc #$01
4320 sta $71
4321 clc
4323 dex
4324 bpl copy_title_loop1
4326 rts
4328 copy_completed_screen_up:
4330 lda #$00
4331 sta $70
4332 lda #$0f
4333 sta $71
4335 lda #$60
4336 sta $72
4337 lda #$5e
4338 sta $73
4340 ldx #8
4341 jmp copy_title ; optimise away the rts
4343 init:
4344 jsr cls ; clear the text window
4346 lda #26 ; unset the text window
4347 jsr $ffee
4349 ; Define the default high scores.
4350 ldy #0
4351 lda #$80
4352 sta $70
4353 lda #$51
4354 sta $71
4355 lda #$16
4356 sta $72
4358 ldx #0
4359 init_define_high_scores_loop:
4361 lda #0
4362 sta ($70),y
4363 iny
4364 lda $72
4365 sta ($70),y
4366 iny
4367 lda #0
4368 sta ($70),y
4370 iny
4371 init_define_high_score_name_loop:
4373 lda high_score_default_name1,x
4374 sta ($70),y
4375 iny
4376 inx
4377 cpx #9
4378 beq init_define_high_scores_next
4379 cpx #18
4380 bne init_define_high_score_name_loop
4382 ldx #0
4383 init_define_high_scores_next:
4385 sed
4386 lda $72
4387 sec
4388 sbc #2
4389 sta $72
4390 cld
4391 clc
4393 cpy #96
4394 bne init_define_high_scores_loop
4396 ; Disable joystick support.
4397 lda #0
4398 sta $577e
4400 rts
4402 high_score_default_name1: .byte "RETRO "
4403 high_score_default_name2: .byte " SOFTWARE"
4405 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4406 input_message: .byte 17,2, 31,1,27, "Press SPACE / FIRE"
4407 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4408 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4409 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4410 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4412 set_standard_palette:
4414 lda #1
4415 sta $70
4416 lda #1
4417 sta $71
4418 jsr set_palette
4420 jmp set_core_palette ; optimise away the rts
4422 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4424 set_complete_palette:
4426 lda #0
4427 sta $80
4428 lda #25
4429 sta $81
4431 set_complete_palette_loop:
4433 jsr wait_for_vsync
4435 dec $81
4436 lda $81
4437 cmp #0
4438 bne set_complete_palette_loop
4440 lda #25
4441 sta $81
4443 ldx $80
4444 lda complete_palette_bytes,x
4445 sta $70
4446 inx
4447 lda complete_palette_bytes,x
4448 sta $71
4449 inx
4450 stx $80
4451 jsr set_palette
4453 lda $80
4454 cmp #10
4455 bne set_complete_palette_loop
4457 rts
4459 set_hidden_palette:
4461 lda #1
4462 sta $70
4463 lda #0
4464 sta $71
4465 jsr set_palette
4467 ; Run on into the next routine.
4469 set_core_palette:
4471 lda #2
4472 sta $70
4473 lda #2
4474 sta $71
4475 jsr set_palette
4477 lda #3
4478 sta $70
4479 lda #3
4480 sta $71
4481 jsr set_palette
4483 rts
4485 show_title:
4487 jsr set_standard_palette
4489 ldx #0
4490 write_title_text_loop:
4491 lda title_vdu_bytes,x
4492 jsr $ffee
4493 inx
4494 cpx #12
4495 bmi write_title_text_loop
4497 jsr show_input_message
4499 ; Show the title.
4500 jsr copy_title_up
4502 ; Show the high scores.
4504 jsr colour1
4506 lda #$80
4507 sta $70
4508 lda #$51
4509 sta $71
4511 lda #8
4512 sta $80
4514 show_title_high_scores_loop:
4516 lda #31
4517 jsr $ffee
4518 lda #2
4519 jsr $ffee
4520 lda $80
4521 adc #2
4522 sta $80
4523 clc
4524 jsr $ffee
4526 jsr write_score_digits
4528 lda #32
4529 jsr $ffee
4531 ldx #8
4532 ldy #3
4533 show_title_high_scores_vdu_loop2:
4535 lda ($70),y
4536 cmp #32
4537 bmi ignore_char
4538 cmp #123
4539 bpl ignore_char
4540 jsr $ffee
4542 ignore_char:
4543 iny
4544 dex
4545 bpl show_title_high_scores_vdu_loop2
4547 lda $70
4548 adc #12
4549 sta $70
4550 cmp #$e0
4551 bne show_title_high_scores_loop
4553 lda #0 ; message counter
4554 sta $72
4556 show_title_wait_loop:
4558 lda #150
4559 sta $5785
4561 ldx $72
4562 ldy #22
4563 show_title_wait_message_loop:
4565 lda title_vdu_bytes1,x
4566 jsr $ffee
4567 inx
4568 dey
4569 bpl show_title_wait_message_loop
4571 cpx #92
4572 beq show_title_wait_reset_offset
4574 txa
4575 sta $72
4576 jmp show_title_wait_inner_loop
4578 show_title_wait_reset_offset:
4579 lda #0
4580 sta $72
4582 show_title_wait_inner_loop:
4583 jsr wait_for_vsync
4585 dec $5785
4586 beq show_title_wait_loop
4588 show_title_wait_loop_no_update:
4589 lda #128
4590 ldx #0
4591 jsr $fff4
4592 cpx #0 ; fire button pressed?
4593 beq show_title_no_joystick
4595 lda #1 ; enable joystick support
4596 sta $577e
4597 jmp show_title_exit
4599 show_title_no_joystick:
4600 ldx #157 ; SPACE
4601 jsr check_key
4602 cpy #255
4603 bne show_title_wait_inner_loop
4605 lda #0 ; disable joystick support
4606 sta $577e
4608 show_title_exit:
4609 clc
4610 rts
4612 show_input_message:
4614 ldx #0
4615 show_input_message_loop:
4617 lda input_message,x
4618 jsr $ffee
4619 inx
4620 cpx #23
4621 bne show_input_message_loop
4623 rts
4625 wait_for_vsync:
4627 lda #19
4628 jmp $fff4 ; optimise away the rts
4630 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4632 delay:
4634 delay_loop:
4636 jsr wait_for_vsync
4637 dec $5785
4638 bne delay_loop
4640 rts
4642 show_game_over:
4644 lda #128
4645 sta $5785
4646 jsr delay
4648 ldx #0
4649 write_game_over_text_loop:
4650 lda game_over_vdu_bytes,x
4651 jsr $ffee
4652 inx
4653 cpx #33
4654 bmi write_game_over_text_loop
4656 lda #192
4657 sta $5785
4658 jsr delay
4660 rts
4662 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4663 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4665 show_end_of_level_screen:
4667 ; Draw a decorative room.
4669 jsr make_empty_room
4671 ldx #5
4672 end_of_level_h_walls_loop:
4674 lda #3
4675 sta $57b2,x
4676 sta $57e4,x
4677 dex
4678 bpl end_of_level_h_walls_loop
4680 ldx #30
4681 end_of_level_v_walls_loop:
4683 lda #3
4684 sta $57bc,x
4685 sta $57c1,x
4686 txa
4687 sec
4688 sbc #10
4689 tax
4690 bpl end_of_level_v_walls_loop
4692 jsr plot_room_tiles
4693 jsr set_standard_palette
4695 ldx #0
4696 end_of_level_text_loop1:
4698 lda end_of_level_bytes1,x
4699 jsr $ffee
4700 inx
4701 cpx #28
4702 bne end_of_level_text_loop1
4704 ; Count the number of rooms explored.
4705 ldx #0
4706 lda #0
4707 sta $8d
4708 sta $8e
4709 end_of_level_room_count_loop:
4711 lda $5200,x
4712 and #$80
4713 beq end_of_level_room_count_loop_next
4715 sed
4716 lda $8d
4717 adc #1
4718 sta $8d
4719 lda $8e
4720 adc #0
4721 sta $8e
4722 cld
4723 clc
4725 end_of_level_room_count_loop_next:
4726 inx
4727 cpx #121
4728 bne end_of_level_room_count_loop
4730 ; Position the player so that we can perform an animation.
4731 jsr position_player_set_up_plotting
4733 lda $8d
4734 sta $70
4735 lda $8e
4736 sta $71
4737 jsr write_bonus
4739 lda #0 ; reset motion counter
4740 sta $578e
4742 show_end_of_level_bonus_loop:
4744 jsr wait_for_vsync
4746 clc
4747 lda $578e
4748 and #15
4749 bne end_of_level_no_animation
4751 ; Animate the player.
4753 jsr reset_unplot_buffer
4754 jsr reset_plot_buffer
4756 ; $74,$75 should be unchanged
4757 jsr unplot_character
4759 lda $5281
4760 eor #1
4761 sta $5281
4762 jsr plot_character
4764 jsr plot_buffer
4766 end_of_level_no_animation:
4767 clc
4768 lda $578e
4769 and #3
4770 bne end_of_level_no_countdown
4772 ; Transfer the bonus to the score.
4774 sed
4775 sec
4776 lda $8d
4777 sbc #1
4778 sta $8d
4779 sta $70
4780 lda $8e
4781 sbc #0
4782 sta $8e
4783 sta $71
4784 cld
4785 clc
4787 jsr write_bonus
4789 lda #9
4790 sta $70
4791 jsr add_score
4793 lda $8d
4794 and #$3f
4795 asl
4796 ldy #1
4797 jsr play_note
4799 end_of_level_no_countdown:
4800 inc $578e ; update motion counter
4801 clc
4803 lda $8d
4804 cmp #0
4805 bne show_end_of_level_bonus_loop
4807 lda $8e
4808 cmp #0
4809 bne show_end_of_level_bonus_loop
4811 lda #64 ; initialise delay counter
4812 sta $5785
4813 jsr delay
4815 ldx #0
4816 end_of_level_text_loop2:
4818 lda end_of_level_bytes2,x
4819 jsr $ffee
4820 inx
4821 cpx #25
4822 bne end_of_level_text_loop2
4824 lda $578a
4825 cmp #3
4826 bpl show_end_of_level_screen_exit
4828 lda #192 ; initialise delay counter
4829 sta $5785
4830 jsr delay
4832 show_end_of_level_screen_exit:
4833 rts
4835 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4837 write_bonus: ; $70,$71=value
4838 ; $72,$73=address of VDU codes
4840 ldx #4
4841 write_bonus_vdu_bytes:
4843 lda level_bonus_vdu_bytes,x
4844 jsr $ffee
4845 dex
4846 bpl write_bonus_vdu_bytes
4848 ldy #1
4849 write_bonus_loop:
4851 tya
4852 tax ; temporary
4854 lda $70,x
4855 sta $80
4856 lsr
4857 lsr
4858 lsr
4859 lsr
4860 tax
4861 lda score_digits,x
4862 jsr $ffee
4864 lda $80
4865 and #$0f
4866 tax
4867 lda score_digits,x
4868 jsr $ffee
4870 dey
4871 bpl write_bonus_loop
4873 clc
4874 rts
4876 position_player_set_up_plotting:
4878 jsr reset_player_position
4879 jsr remove_characters
4881 jsr reset_unplot_buffer
4882 jsr reset_plot_buffer
4884 ; Run on into the next routine.
4886 plot_the_player:
4888 lda #$80 ; plot the player
4889 sta $74
4890 lda #$52
4891 sta $75
4892 jsr plot_character
4894 jsr plot_buffer
4895 rts
4897 complete_game_vdu_bytes1: .byte 12
4898 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4899 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4900 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4902 show_complete_game:
4904 jsr blank_screen
4906 ldx #0
4907 show_complete_game_vdu_loop:
4909 lda complete_game_vdu_bytes1,x
4910 jsr $ffee
4911 inx
4912 cpx #68
4913 bne show_complete_game_vdu_loop
4915 jsr copy_completed_screen_up
4917 jsr set_complete_palette
4919 lda #255
4920 sta $5785
4922 show_complete_game_delay_loop:
4924 jsr wait_for_vsync
4926 dec $5785
4927 bne show_complete_game_no_message
4929 jsr colour1
4930 jsr show_input_message
4932 show_complete_game_no_message:
4934 lda #128
4935 ldx #0
4936 jsr $fff4
4937 cpx #0 ; fire button pressed?
4938 beq show_complete_game_no_joystick
4939 jmp show_complete_game_exit
4941 show_complete_game_no_joystick:
4943 ldx #157
4944 jsr check_key
4945 cpy #255
4946 bne show_complete_game_delay_loop
4948 show_complete_game_exit:
4949 clc
4950 rts
4952 check_high_scores:
4954 ; Start at the bottom of the table, moving scores down as necessary, and
4955 ; write in the current score at the appropriate place.
4957 lda #$86 ; current score
4958 sta $70
4959 lda #$57
4960 sta $71
4962 lda #$80
4963 sta $72
4964 lda #$51
4965 sta $73
4967 check_high_scores_loop:
4969 ldy #2
4970 check_high_scores_digits_loop:
4972 lda ($72),y
4973 cmp ($70),y ; existing score less than current score?
4974 bmi check_high_scores_move_down
4975 beq check_high_scores_digits_next ; keep checking digits if equal
4976 jmp check_high_scores_next
4978 check_high_scores_digits_next:
4979 dey
4980 bpl check_high_scores_digits_loop
4982 check_high_scores_next:
4983 clc
4984 lda $72
4985 adc #12
4986 sta $72
4987 cmp #$e0
4988 bne check_high_scores_loop
4990 ; The player's score didn't make it into the high score table.
4991 rts
4993 check_high_scores_move_down: ; $70,$71=pointer to current score
4994 ; $72,$73=pointer to old score
4996 ; The current score exceeded the existing entry. Make a note of the
4997 ; position in the high score table, insert the player's score, and take
4998 ; the old score
5000 lda $72 ; Record the position in the high score table of the
5001 sta $8d ; player's score.
5002 lda $73
5003 sta $8e
5005 lda #$e0
5006 sta $74
5007 lda #$51
5008 sta $75
5010 ldy #0
5011 insert_blank_player_name_loop:
5013 cpy #3
5014 bpl insert_blank_player_name_score_only
5016 lda ($70),y
5017 jmp insert_blank_player_name_store
5019 insert_blank_player_name_score_only:
5020 lda #32
5022 insert_blank_player_name_store:
5023 sta ($74),y
5024 iny
5025 cpy #12
5026 bne insert_blank_player_name_loop
5028 check_high_scores_move_down_loop:
5030 ldy #0
5031 check_high_scores_copy_score_and_name:
5033 lda ($72),y ; swap the current score with the score in the table
5034 tax
5035 lda ($74),y
5036 sta ($72),y
5037 txa
5038 sta ($74),y
5039 iny
5040 cpy #12
5041 bne check_high_scores_copy_score_and_name
5043 clc
5044 lda $72
5045 adc #12
5046 sta $72
5047 cmp #$e0
5048 bne check_high_scores_move_down_loop
5050 ; Draw a decorative room.
5052 jsr set_hidden_palette
5054 jsr make_empty_room
5056 lda #3
5057 sta $76
5058 sta $77
5059 jsr draw_top_line
5060 jsr draw_bottom_line
5061 jsr draw_left_line
5063 lda #0
5064 sta $77
5065 jsr draw_right_line
5067 jsr plot_room_tiles
5069 ; Add text characters to the room.
5070 jsr colour3
5072 lda #3 ; x
5073 sta $70
5074 lda #6 ; y
5075 sta $71
5077 lda #65
5078 sta $72
5080 ldx #3
5081 plot_text_characters_loop:
5083 jsr print_xy
5085 lda $70
5086 adc #4
5087 sta $70
5089 dex
5090 bpl plot_text_characters_next
5092 lda #3
5093 sta $70
5094 lda $71
5095 adc #3
5096 sta $71
5098 ldx #3
5100 plot_text_characters_next:
5102 inc $72
5103 lda $72
5104 cmp #91
5105 bne plot_text_characters_loop
5107 lda #11
5108 sta $70
5109 lda #95 ; _ representing a space
5110 sta $72
5111 jsr print_xy
5113 lda #15
5114 sta $70
5115 lda #60 ; < representing delete
5116 sta $72
5117 jsr print_xy
5119 ; Put the player in the centre of the room.
5120 jsr position_player_set_up_plotting
5122 lda #0 ; reset motion counter
5123 sta $578e
5125 lda #0 ; not on a character
5126 sta $578d
5128 lda #0 ; reset the level number so that the correct tiles are used
5129 sta $578a
5131 lda #3 ; cursor position in the high score entry held in $8d,$8e
5132 sta $8f
5134 jsr set_standard_palette
5136 ldx #0
5137 high_score_vdu_loop:
5139 lda high_score_vdu_bytes,x
5140 jsr $ffee
5141 inx
5142 cpx #39
5143 bne high_score_vdu_loop
5145 high_score_entry_loop:
5147 jsr reset_unplot_buffer
5148 jsr reset_plot_buffer
5150 jsr move_player
5151 ; Check if the player leaves the room.
5152 bcc high_score_entry_check_position
5153 jmp high_score_entry_after_loop
5155 high_score_entry_check_position:
5157 lda $5285 ; dx
5158 cmp #2
5159 beq high_score_entry_maybe_aligned
5160 jmp high_score_entry_not_aligned
5162 high_score_entry_maybe_aligned:
5164 lda $5282 ; y
5165 tay
5166 cmp #8
5167 bpl high_score_entry_not_aligned
5169 lda $5284 ; x
5170 tax
5171 cmp #9
5172 beq high_score_entry_not_aligned
5173 and #1
5174 beq high_score_entry_not_aligned
5176 lda $5283 ; dy
5177 cmp #2
5178 bmi high_score_entry_aligned
5179 jmp high_score_entry_not_aligned
5181 lda $5282 ; y again (don't apply the touching rule to the bottom
5182 cmp #7 ; row of characters)
5183 beq high_score_entry_not_aligned
5185 iny ; we are really touching the character below
5187 high_score_entry_aligned:
5189 lda $578d
5190 cmp #1
5191 beq high_score_entry_next
5193 ; The player is aligned with a letter.
5194 txa
5195 sec
5196 sbc #1
5197 lsr
5198 sta $7e ; record (x - 1) / 2
5200 tya ; recall y
5201 sec
5202 sbc #1
5203 asl
5204 asl ; (y - 1) * 4
5205 clc
5207 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5208 adc #65
5209 sta $7e ; record the ASCII code
5211 cmp #91
5212 bmi insert_character
5214 cmp #92
5215 beq delete_character
5217 ; Insert a space.
5218 lda #32
5219 sta $7e
5221 insert_character:
5222 lda $8f
5223 cmp #12
5224 bpl high_score_entry_pressed
5226 tay ; insert the character
5227 lda $7e
5228 sta ($8d),y
5229 jsr print_high_score_character
5231 inc $8f
5232 jmp high_score_entry_pressed
5234 delete_character:
5235 lda $8f
5236 cmp #4
5237 bmi high_score_entry_pressed
5239 cmp #12
5240 beq high_score_delete_previous_character
5242 tay
5243 lda #32 ; insert a space
5244 sta ($8d),y
5245 jsr print_high_score_character
5247 high_score_delete_previous_character:
5248 dec $8f
5249 lda $8f
5250 tay ; insert a space
5251 lda #32
5252 sta ($8d),y
5253 jsr print_high_score_character
5255 high_score_entry_pressed:
5256 lda #1
5257 sta $578d
5258 jmp high_score_entry_next
5260 high_score_entry_not_aligned:
5261 lda #0
5262 sta $578d
5264 high_score_entry_next:
5266 jsr wait_for_vsync
5267 jsr plot_buffer
5269 jmp high_score_entry_loop
5271 inc $578e
5272 clc
5274 high_score_entry_after_loop:
5275 clc
5277 jsr cls
5278 jsr set_hidden_palette
5280 rts
5282 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5284 cls:
5285 lda #12
5286 jsr $ffee
5287 rts
5289 colour1:
5290 lda #17
5291 jsr $ffee
5292 lda #1
5293 jsr $ffee
5294 rts
5296 colour3:
5297 lda #17
5298 jsr $ffee
5299 lda #3
5300 jsr $ffee
5301 rts
5303 print_high_score_character: ; A=ASCII code
5305 clc
5306 sta $72 ; store the character
5307 lda $8f
5308 adc #3
5309 sta $70 ; store the x position of the character
5310 lda #30
5311 sta $71
5312 ; Run on into the next routine.
5314 print_xy:
5316 lda #31
5317 jsr $ffee
5318 lda $70
5319 jsr $ffee
5320 lda $71
5321 jsr $ffee
5322 lda $72
5323 jsr $ffee
5324 rts
5326 disable_sound: ; X=1 (disable); X=0 (enable)
5328 lda #210
5329 ldy #0
5330 jmp $fff4 ; optimise away the rts
5332 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5333 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5335 start_new_game:
5337 ; Clear the screen.
5338 jsr cls
5340 ; Set the level.
5341 lda #0
5342 sta $578a
5344 ; Set the score.
5345 lda #0
5346 sta $5786
5347 lda #0
5348 sta $5787
5349 lda #0
5350 sta $5788
5352 ; Blank the screen now because it will be blanked before the room is shown
5353 ; and otherwise the strength bar will show briefly.
5354 jsr blank_screen
5356 ; Set the player's strength.
5357 lda #0
5358 sta $5784
5359 lda #64
5360 sta $70
5361 jsr add_strength
5363 ; Set the projectile type.
5364 lda #0
5365 sta $5789
5367 rts
5369 reset_player_position:
5371 lda #1 ; player
5372 sta $5280
5373 lda #6 ; down (first frame)
5374 sta $5281
5375 lda #4 ; y=4
5376 sta $5282
5377 lda #2 ; dy=2
5378 sta $5283
5379 lda #4 ; x=4
5380 sta $5284
5381 lda #3 ; dx=3
5382 sta $5285
5384 rts
5386 start_level:
5388 ; Clear the item/player flags.
5389 lda #0
5390 sta $5780
5392 ; Set current room.
5394 ldx $578a
5395 lda start_rooms_y,x
5396 sta $5782
5397 lda start_rooms_x,x
5398 sta $5783
5400 ; Set the player's position.
5402 jsr reset_player_position
5404 ; Reset the weapon counter.
5405 lda #0
5406 sta $577f
5408 ; Fill the treasure table with objects.
5409 ldx $578a ; level
5410 lda key_rooms,x
5411 sta $80
5413 ldx $578a ; level
5414 lda seeds,x
5415 adc #1
5416 and #31
5417 sta $7c
5418 clc
5419 lda seeds,x
5420 adc #2
5421 and #31
5422 sta $7d
5423 clc
5425 lda $578a ; create an upper limit on the weapon type found in this level
5426 adc #2
5427 sta $5781
5428 clc
5430 lda #$00
5431 sta $8e
5432 lda #$52
5433 sta $8f
5435 ldy #0
5436 start_level_add_treasure_loop:
5438 cpy $80 ; check for the key room
5439 bne start_level_add_treasure_item
5441 lda #5 ; the value to store is type + 1
5442 jmp start_level_add_treasure_store
5444 start_level_add_treasure_item:
5445 clc
5446 jsr unlimited_values
5447 and #$0f
5448 cmp #0
5449 beq start_level_add_treasure_none
5451 clc
5452 sta $8c
5453 tya
5454 adc $8c
5455 and #31
5456 clc
5457 tax
5458 lda treasure_table,x
5460 cmp #4
5461 bmi start_level_add_treasure_weapon
5463 clc
5464 adc #1
5465 jmp start_level_add_treasure_store
5467 start_level_add_treasure_weapon:
5469 ; Only add weapons with types that equal the level number or exceed it
5470 ; by one.
5471 cmp $5781
5472 bcs start_level_add_treasure_none
5474 clc
5475 adc #1 ; store values 0-8 as values 1-9
5476 jmp start_level_add_treasure_store
5478 start_level_add_treasure_none:
5479 clc
5480 lda #0 ; do not put treasure in this room
5482 start_level_add_treasure_store:
5483 clc
5484 sta ($8e),y ; add the item to the table
5486 iny
5487 cpy #121
5488 bmi start_level_add_treasure_loop
5490 ; Write the status text.
5491 ldx #0
5492 write_status_text_loop:
5493 lda status_vdu_bytes,x
5494 jsr $ffee
5495 inx
5496 cpx #25
5497 bmi write_status_text_loop
5499 jsr write_score
5501 clc
5502 rts
5504 main:
5505 jsr init
5507 main_loop:
5509 jsr show_title
5511 jsr start_new_game
5513 level_loop:
5515 jsr start_level
5517 game_loop:
5519 jsr remove_characters
5521 jsr reset_unplot_buffer
5522 jsr reset_plot_buffer
5524 lda $5782 ; current room (y)
5525 sta $78
5526 lda $5783 ; current room (x)
5527 sta $79
5528 jsr plot_room
5529 jsr set_room_palette
5530 jsr create_enemy_positions
5531 jsr add_treasure
5533 jsr plot_the_player
5535 lda #0 ; reset projectile counter
5536 sta $578d
5538 lda #0 ; reset motion counter
5539 sta $578e
5541 lda #63 ; reset generation counter
5542 sta $578f
5544 room_loop:
5545 jsr reset_unplot_buffer
5546 jsr reset_plot_buffer
5548 jsr move_characters
5549 jsr move_projectile
5551 lda $5780 ; is player out of strength ($40), leaving the
5552 and #$c2 ; level (0x80) or completing the game (0x02)?
5553 beq room_loop_player_move
5554 clc
5556 dec $5785 ; leave the loop when the delay
5557 bne room_loop_delay_next
5558 jmp after_room_loop ; counter is about to reset
5560 room_loop_delay_next:
5562 lda $5281 ; leave the loop when the player demise
5563 cmp #11 ; animation has finished
5564 beq room_loop_after_player_move
5565 clc
5567 lda $578e
5568 and #7
5569 bne room_loop_after_player_move
5571 lda $5780 ; skip the animation if leaving the level or
5572 and #$82 ; completing the game
5573 bne room_loop_after_player_move
5575 ; Show the demise animation when appropriate.
5577 lda #$80
5578 sta $74
5579 lda #$52
5580 sta $75
5582 jsr unplot_character
5584 inc $5281
5585 jsr plot_character
5586 jmp room_loop_after_player_move
5588 room_loop_player_move:
5590 ; See if it is time to generate a new enemy.
5591 lda $578f
5592 cmp #0
5593 bne no_emerge_characters
5594 jsr emerge_characters
5596 no_emerge_characters:
5597 clc
5599 jsr check_fire_key
5600 jsr move_player
5601 bcs after_room_loop ; check if we are leaving the level
5603 room_loop_after_player_move:
5604 clc
5606 lda #19
5607 jsr $fff4
5608 jsr plot_buffer
5610 ldx #143 ; Escape key check
5611 jsr check_key
5612 cpy #255
5613 beq main_loop_play_again
5615 ldx #174 ; S key check
5616 jsr check_key
5617 cpy #255
5618 bne no_set_sound
5620 ldx #0
5621 jsr disable_sound
5622 jmp after_sound_checks
5624 no_set_sound:
5626 ldx #239 ; Q key check
5627 jsr check_key
5628 cpy #255
5629 bne after_sound_checks
5631 ldx #1
5632 jsr disable_sound
5634 after_sound_checks:
5636 ldx #200 ; P key check
5637 jsr check_key
5638 cpy #255
5639 bne no_pause
5641 pause_loop:
5643 ldx #201 ; O key check
5644 jsr check_key
5645 cpy #255
5646 bne pause_loop
5648 no_pause:
5649 clc
5651 lda $578d
5652 cmp #0
5653 beq room_loop_no_update_projectile_counter
5655 dec $578d
5657 room_loop_no_update_projectile_counter:
5659 dec $578f ; update generation counter
5661 inc $578e ; update motion counter
5662 clc
5663 jmp room_loop
5665 after_room_loop:
5666 clc
5668 lda $5780
5669 and #$80
5670 bne exit_level
5672 lda $5780
5673 and #$40
5674 bne game_over
5676 lda $5780
5677 and #$02
5678 bne complete_game
5680 jmp game_loop
5682 exit_level:
5684 jsr show_end_of_level_screen
5686 inc $578a
5687 clc
5688 jmp level_loop
5690 game_over:
5691 jsr show_game_over
5692 jmp main_loop_play_again
5694 complete_game:
5695 jsr show_end_of_level_screen
5696 jsr show_complete_game
5697 jmp main_loop_play_again
5699 main_loop_play_again:
5700 jsr cls
5702 ; Check the score against the high scores.
5703 jsr check_high_scores
5705 jmp main_loop
5707 exit:
5708 clc
5709 rts
