junglejourney

view mapcode.oph @ 193:5502cf6e30cb

Another attempt at joystick support.
author David Boddie <david@boddie.org.uk>
date Thu Sep 29 20:56:34 2011 +0200
parents e1a1513fde16
children d0b47e8eaed2
line source
1 ; Copyright (C) 2011 David Boddie <david@boddie.org.uk>
2 ;
3 ; This program is free software: you can redistribute it and/or modify
4 ; it under the terms of the GNU General Public License as published by
5 ; the Free Software Foundation, either version 3 of the License, or
6 ; (at your option) any later version.
7 ;
8 ; This program is distributed in the hope that it will be useful,
9 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ; GNU General Public License for more details.
12 ;
13 ; You should have received a copy of the GNU General Public License
14 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
16 .org $1e00
17 jmp main
19 seeds: .byte 100, 239, 183, 144 ; $ef, $b7, $90, $d6, $89
20 start_rooms_x: .byte 5, 3, 5, 10
21 start_rooms_y: .byte 5, 8, 1, 8
22 exit_rooms_x: .byte 7, 9, 3, 0
23 exit_rooms_y: .byte 0, 0, 9, 10
25 ; These values need to be kept in sync - the room numbers must match their
26 ; positions in the room array.
27 key_rooms_x: .byte 1, 5, 10, 1
28 key_rooms_y: .byte 0, 2, 6, 4
29 key_rooms: .byte 1, 27, 76, 45 ; ky*11 + kx
31 treasure_table: .byte 6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7
32 treasure_table_: .byte 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0
34 unlimited_values: ; $7c,$7d=first,second
35 ; Add $7c and $7d, store the result in $7d and the original
36 ; $7d value in $7c, returning the sum in the accumulator.
37 lda $7c
38 sta $7b
39 lda $7d
40 sta $7c
41 adc $7b
42 sta $7d
43 clc
44 rts
46 mod9: ; A = value
47 divide_loop:
48 cmp #9
49 bcc after_divide_loop ; bmi should work here, I think, but it doesn't
50 sec
51 sbc #9
52 jmp divide_loop
54 after_divide_loop:
55 clc
56 rts ; A % 9
58 tile_values_map: .byte 0,1,0,0,0,0,2,3
60 next_value: ; no argument
61 jsr unlimited_values
62 lda $7d
63 jsr mod9
64 and #7 ; (next value % 9) & 7
65 tax
66 lda tile_values_map,x
67 sta $7b
68 rts
70 ; Room filling routines, writing to 0x579c to 0x57ff.
72 draw_top_line: ; $76=tile number for exit/wall
73 ldx #9
74 lda #2
76 draw_top_line_loop0:
77 sta $579c,x
78 dex
79 bpl draw_top_line_loop0
81 ldx #3 ; draw the exit or wall
82 lda $76
83 draw_top_line_loop1:
84 sta $579f,x
85 dex
86 bpl draw_top_line_loop1
87 clc
88 rts
90 draw_left_line: ; $77=tile number for exit/wall
91 ldx #90
92 draw_left_line_loop0:
93 lda #2
94 sta $579c,x
95 txa
96 sec
97 sbc #10
98 tax
99 bpl draw_left_line_loop0
101 ldx #30
102 draw_left_line_loop1:
103 lda $77
104 sta $57ba,x
105 txa
106 sec
107 sbc #10
108 tax
109 bpl draw_left_line_loop1
110 clc
111 rts
113 draw_bottom_line: ; $76=tile number for exit/wall
114 ldx #9
115 lda #2
116 draw_bottom_line_loop0:
117 sta $57f6,x
118 dex
119 bpl draw_bottom_line_loop0
121 ldx #3
122 lda $76
123 draw_bottom_line_loop1:
124 sta $57f9,x
125 dex
126 bpl draw_bottom_line_loop1
127 clc
128 rts
130 draw_right_line: ; $77=tile number for exit/wall
131 ldx #99
132 draw_right_line_loop0:
133 lda #2
134 sta $579c,x
135 txa
136 sec
137 sbc #10
138 tax
139 bpl draw_right_line_loop0
141 ldx #30
142 draw_right_line_loop1:
143 lda $77
144 sta $57c3,x
145 txa
146 sec
147 sbc #10
148 tax
149 bpl draw_right_line_loop1
150 clc
151 rts
153 make_empty_room:
155 ldx #99
156 make_empty_room_loop:
157 lda #0
158 sta $579c,x
159 dex
160 bpl make_empty_room_loop
162 rts
164 make_room: ; $78,$79=i,j
166 ; Fills the room array at 579c with values.
167 ; Tiles 0,1,2,3 are map tiles that will be shown by the plot_tile routine.
168 ; Other tiles are plotted separately:
169 ; 4 = exit
170 ; 5 = final exit
171 ; 6 = weapon (bits 3,4 are type)
172 ; 7 = treasure (bits 3,4 are type)
174 ; Fill the room with empty space.
176 jsr make_empty_room
178 ; Determine if there is a top exit.
180 lda #0
181 sta $76
183 lda $78 ; i == 0
184 cmp #0
185 bne not_top_screen
186 lda #2
187 sta $76
188 jmp do_top_exit
190 not_top_screen:
191 clc
193 lda $78
194 and #7 ; i & 7
195 sta $70 ; temporary result
196 lda $79
197 and #7 ; j & 7
198 cmp $70
199 beq do_top_exit
200 clc
202 lda $78
203 eor $79 ; i ^ j
204 adc $78 ; + i
205 clc
206 cmp $79 ; (i ^ j) + i == j
207 bne do_top_exit
208 lda #2
209 sta $76 ; top exit
211 do_top_exit:
212 jsr draw_top_line
214 ; Determine if there is a left exit.
215 lda #0
216 sta $77
218 lda $79
219 cmp #0
220 bne not_left_screen
221 lda #2
222 sta $77
223 jmp do_left_exit
225 not_left_screen:
226 clc
228 lda $78
229 and #3 ; i & 3
230 sta $70 ; temporary result
231 lda $79
232 and #3 ; j & 3
233 cmp $70
234 beq do_left_exit
235 clc
237 lda $78
238 ora $79 ; i | j
239 eor $79 ; ^ j
240 cmp $78 ; (i | j) ^ j == i
241 bne do_left_exit
242 lda #2
243 sta $77 ; left exit
245 do_left_exit:
246 jsr draw_left_line
248 ; Determine if there is a right exit.
249 lda #0
250 sta $77
252 lda $79
253 cmp #10
254 bne not_right_screen
255 lda #2
256 sta $77
257 jmp do_right_exit
259 not_right_screen:
260 clc
262 lda $78
263 and #3 ; i & 3
264 sta $70 ; temporary result
265 lda $79
266 adc #1
267 and #3 ; j & 3
268 cmp $70
269 beq do_right_exit
270 clc
272 lda $79
273 adc #1
274 sta $70
276 lda $78
277 ora $70 ; i | j
278 eor $70 ; ^ j
279 cmp $78 ; (i | j) ^ j == i
280 bne do_right_exit
281 lda #2
282 sta $77 ; right exit
284 do_right_exit:
285 jsr draw_right_line
287 ; Determine if there is a bottom exit.
288 lda #0
289 sta $76
291 lda $78
292 cmp #10
293 bne not_bottom_screen
294 lda #2
295 sta $76
296 jmp do_bottom_exit
298 not_bottom_screen:
299 clc
301 lda $78
302 adc #1
303 and #7 ; i & 7
304 sta $70 ; temporary result
305 lda $79
306 and #7 ; j & 7
307 cmp $70
308 beq do_bottom_exit
309 clc
311 lda $78
312 adc #1
313 sta $70
315 eor $79 ; i ^ j
316 adc $70 ; + i
317 cmp $79 ; (i ^ j) + i == j
318 bne do_bottom_exit
319 lda #2
320 sta $76 ; bottom exit
322 do_bottom_exit:
323 jsr draw_bottom_line
325 ; Add the final exit.
327 lda $578a
328 cmp #3
329 bmi make_room_no_final_exit
331 lda $78
332 cmp #0
333 bne make_room_no_final_exit
335 lda $79
336 cmp #2
337 bne make_room_no_final_exit
339 lda #6
340 sta $57a0
341 lda #7
342 sta $57a1
344 make_room_no_final_exit:
346 ; Make sure that the starting, exit, key rooms are empty.
348 ldx $578a ; level number
349 lda start_rooms_y,x
350 cmp $78
351 bne make_room_not_starting_room
352 lda start_rooms_x,x
353 cmp $79
354 bne make_room_not_starting_room
356 lda #3
357 sta $70
358 jmp add_room_decoration ; optimise away the rts
360 make_room_not_starting_room:
362 lda exit_rooms_y,x
363 cmp $78
364 bne make_room_not_exit_room
365 lda exit_rooms_x,x
366 cmp $79
367 bne make_room_not_exit_room
369 ; Add an exit to the room.
370 lda $78
371 eor $79
372 and #15
373 tax
374 lda exit_room_offsets,x
375 tax
376 lda $5780
377 and #1
378 beq exit_not_open
380 lda #5
381 sta $579c,x
382 jmp exit_decoration
384 exit_not_open:
385 clc
386 lda #4
387 sta $579c,x
389 exit_decoration:
390 lda #3
391 sta $70
392 jmp add_room_decoration ; optimise away the rts
394 make_room_not_exit_room:
396 lda key_rooms_y,x
397 cmp $78
398 bne make_room_not_key_room
399 lda key_rooms_x,x
400 cmp $79
401 bne make_room_not_key_room
403 lda #1
404 sta $70
405 jmp add_room_decoration ; optimise away the rts
407 make_room_not_key_room:
408 clc
410 ; Fill in the room details.
412 lda $79
413 sta $7c
414 sec
415 ldx $578a
416 lda seeds,x
417 sbc $78
418 sec
419 sta $7d
420 clc
422 ; Discard the first ten values.
424 ldy #10
425 make_room_loop0:
426 jsr unlimited_values
427 dey
428 bne make_room_loop0
430 ; Fill the room array with values.
432 lda #$a7
433 sta $70
434 lda #$57
435 sta $71
437 ldy #0
438 make_room_loop1:
440 jsr next_value
441 sta ($70),y
442 iny
443 cpy #8
444 bne make_room_loop1 ; continue the same row
446 lda $70
447 cmp #$ed
448 beq make_room_loop1_exit ; exit after the last row
450 adc #10
451 sta $70
452 ldy #0 ; reset the row counter
453 jmp make_room_loop1
455 make_room_loop1_exit:
456 rts
458 decoration_offsets: .byte 11,18,81,88
460 add_room_decoration:
462 lda #$9c
463 sta $8e
464 lda #$57
465 sta $8f
467 ldx #3
468 add_room_decoration_loop:
470 lda decoration_offsets,x
471 tay
472 lda $70
473 sta ($8e),y
474 dex
475 bpl add_room_decoration_loop
477 clc
478 rts
480 exit_room_offsets: .byte 35,66,63,56,34,44,64,33,36,55,65,53,45,46,54,43
481 treasure_x: .byte 3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6
482 treasure_y: .byte 1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2
484 eleven_times_table: .byte 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110
486 add_treasure: ; $78,$79 = i,j
488 lda $78
489 tax
490 lda eleven_times_table,x
491 adc $79
492 tax
494 lda $5200,x
495 ora #$80
496 sta $5200,x ; set the top bit (room visited)
497 and #$7f ; mask off the top bit to obtain the item number + 1
498 cmp #0
499 beq add_treasure_exit
501 sec
502 sbc #1
503 sta $528d ; store weapon/treasure type
504 clc
506 lda $78
507 eor $79
508 adc $528d
509 and #15
510 sta $70
512 lda #15
513 sta $8c
514 ldy #0
515 add_treasure_loop:
517 clc
519 ldx $70
520 lda treasure_y,x ; y
521 sta $8d
522 tax
523 lda room_row_offsets_low,x
524 sta $80
526 ldx $70
527 lda treasure_x,x ; x
528 sta $8e
529 adc $80
530 sta $80
532 lda #$57
533 adc #0
534 sta $81
535 clc
537 lda ($80),y ; tile
538 cmp #0
539 bne add_treasure_loop_next
541 lda #4 ; type (weapon/treasure)
542 sta $528c
543 lda $8d ; y
544 sta $528e
545 lda #1 ; dy
546 sta $528f
547 lda $8e ; x
548 sta $5290
549 lda #0 ; dx
550 sta $5291
552 lda #$8c
553 sta $74
554 lda #$52
555 sta $75
556 jmp plot_character ; optimise away the rts
558 add_treasure_loop_next:
559 dec $8c
560 bmi add_treasure_exit
562 dec $70
563 bpl add_treasure_loop
565 lda #15
566 sta $70
567 jmp add_treasure_loop
569 add_treasure_exit:
570 clc
571 rts
573 create_enemy_positions:
575 lda #31 ; counter
576 sta $7e
578 lda #1 ; x
579 sta $70
581 lda #1 ; y
582 sta $71
584 lda #$a7
585 sta $72
586 lda #$57
587 sta $73
589 ldx #15 ; offset into position areas
590 ldy #0
592 create_enemy_positions_loop:
594 jsr unlimited_values
595 and #7
596 sta $80 ; store temporarily
598 lda $72
599 adc $80
600 sta $72 ; update the offset into the room data
601 clc
603 lda $70
604 adc $80 ; update x
605 cmp #10
606 bpl create_enemy_positions_next_row
608 sta $70 ; store x
609 jmp create_enemy_positions_check_tile
611 create_enemy_positions_next_row:
613 sec
614 sbc #10
615 sta $70 ; store the x position on the next row
616 clc
618 lda $71
619 adc #1 ; update the y position
620 cmp #10
621 bpl create_enemy_positions_to_top
623 sta $71 ; store the y position for the next row
624 jmp create_enemy_positions_check_tile
626 create_enemy_positions_to_top:
628 lda #1 ; reset the x, y and offset values
629 sta $70
630 sta $71
631 lda #$a7
632 sta $72
634 create_enemy_positions_check_tile:
636 lda ($72),y
637 cmp #0
638 bne create_enemy_positions_next
640 lda $70
641 sta $0ee0,x ; store the x value
643 lda $71
644 sta $0ef0,x ; store the y value
646 dex
647 bmi create_enemy_positions_exit
649 create_enemy_positions_next:
650 clc
651 dec $7e
652 bpl create_enemy_positions_loop
654 ; The position areas were not filled. Write invalid values into the
655 ; first area for the emerge routine to find.
657 lda #0
658 create_enemy_positions_fill_loop:
660 sta $0ee0,x
661 dex
662 bpl create_enemy_positions_fill_loop
664 create_enemy_positions_exit:
665 clc
666 rts
668 plot: ; $70,$71=source address
669 ; $72,$73=destination address
670 ldy #$1f
671 plotloop0:
672 lda ($70),y
673 sta ($72),y
674 dey
675 bpl plotloop0
677 lda $72
678 adc #$20
679 sta $72
680 lda $73
681 adc #$01
682 sta $73 ; next line minus 0x20
683 clc
685 ldy #$3f
686 plotloop1:
687 lda ($70),y
688 sta ($72),y
689 dey
690 cpy #$20
691 bpl plotloop1
693 lda $72
694 adc #$20
695 sta $72
696 lda $73
697 adc #$01
698 sta $73 ; next line minus 0x20
699 clc
701 ldy #$5f
702 plotloop2:
703 lda ($70),y
704 sta ($72),y
705 dey
706 cpy #$40
707 bpl plotloop2
709 sec
710 lda $72
711 sbc #$20
712 sta $72
713 lda $73
714 sbc #$02
715 sta $73 ; back two lines minus 0x20
716 clc
718 rts
722 plot_blank_xy: ; X=y, Y=x
724 lda screen_rows_low,x
725 sta $72
726 lda screen_rows_high,x
727 sta $73
729 tya
730 tax
731 lda screen_columns_low,x
732 adc $72
733 sta $72
734 lda screen_columns_high,x
735 adc $73
736 sta $73
737 clc
738 ; run on into plot_blank
740 plot_blank: ; $72,$73=destination address
742 ldy #$1f
743 lda #0
744 plot_blank_loop0:
745 sta ($72),y
746 dey
747 bpl plot_blank_loop0
749 lda $72
750 adc #$20
751 sta $72
752 lda $73
753 adc #$01
754 sta $73 ; next line minus 0x20
755 clc
757 ldy #$3f
758 lda #0
759 plot_blank_loop1:
760 sta ($72),y
761 dey
762 cpy #$20
763 bpl plot_blank_loop1
765 lda $72
766 adc #$20
767 sta $72
768 lda $73
769 adc #$01
770 sta $73 ; next line minus 0x20
771 clc
773 ldy #$5f
774 lda #0
775 plot_blank_loop2:
776 sta ($72),y
777 dey
778 cpy #$40
779 bpl plot_blank_loop2
781 sec
782 lda $72
783 sbc #$20
784 sta $72
785 lda $73
786 sbc #$02
787 sta $73 ; back two lines minus 0x20
788 clc
790 rts
792 tile_addresses_low: .byte $00, $60, $c0, $00, $60, $c0, $20
793 tile_addresses_high: .byte $54, $54, $54, $50, $50, $50, $51
795 plot_tile: ; $7b=tile number
796 ; 1 = flowers/decoration
797 ; 2 = trees/wall
798 ; 3 = trees
799 ; 4 = exit
800 ; 5 = open exit
801 ; 6 = final exit (left)
802 ; 7 = final exit (right)
803 ; $72,$73=screen position
805 lda $7b
806 cmp #0
807 bne plot_tile_sprite
808 clc
809 jmp plot_blank ; optimise away the rts
811 plot_tile_sprite:
812 clc
813 tax
814 dex
815 lda tile_addresses_low,x
816 sta $70
817 lda tile_addresses_high,x
818 sta $71
820 lda $7b
821 cmp #4
822 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
824 clc
825 lda $578a
826 and #3 ; change the tile set for later levels
827 tax
829 plot_not_blank_add_loop:
831 cpx #2
832 bne plot_not_blank_not_2
833 dex
834 jmp plot_not_blank_not_0
836 plot_not_blank_not_2:
837 beq plot_not_blank_add_loop
838 cpx #0
840 plot_not_blank_not_0:
841 beq plot_not_blank_after_add_loop
842 clc
843 lda $70
844 adc #$20
845 sta $70
846 lda $71
847 adc #$01
848 sta $71
849 dex
850 jmp plot_not_blank_add_loop
852 plot_not_blank_after_add_loop:
853 clc
854 jsr plot
855 rts
857 plot_room: ; $78,$79 = i,j (from $5782,$5783)
858 jsr blank_screen
860 lda $5782
861 sta $78
862 lda $5783
863 sta $79
865 jsr make_room
866 ; Run on into the next piece of code.
868 plot_room_tiles:
870 lda #$80
871 sta $72
872 lda #$5a
873 sta $73 ; $72,$73 = screen position
875 lda #0
876 sta $7a
877 row_loop:
879 lda #9
880 sta $76
882 column_loop:
883 lda $7a
884 tax
885 lda $579c,x
886 sta $7b
887 jsr plot_tile
889 inc $7a
890 lda $76
891 sec
892 sbc #1
893 sta $76
894 clc
895 cmp #0
896 bpl column_loop
898 clc
900 lda $72
901 adc #$80
902 sta $72
903 lda $73
904 adc #$02
905 sta $73
906 clc
907 cmp #$80
908 beq end_rows
910 jmp row_loop
912 end_rows:
913 rts
915 set_room_palette: ; $78=i; $79=j
917 lda #1
918 sta $70
919 lda $78
920 eor $79
921 and #3
922 tax
923 lda room_palettes,x
924 sta $71
925 jsr set_palette
927 jsr set_core_palette
928 rts
930 room_palettes: .byte 1, 6, 5, 7
932 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
934 plot8x24_y0: ; $70,$71=source address
935 ; $72,$73=destination address
937 ldx #2
939 plot8x24_y0_loop:
941 ldy #15
943 plotloop8x24_y0_0:
944 lda ($70),y
945 eor ($72),y
946 sta ($72),y
947 dey
948 bpl plotloop8x24_y0_0
950 dex
951 bmi plot8x24_y0_exit
953 lda $72
954 adc #$40
955 sta $72
956 lda $73
957 adc #$01
958 sta $73
959 clc
961 lda $70
962 adc #16
963 sta $70
964 lda $71
965 adc #0
966 sta $71
967 clc
969 jmp plot8x24_y0_loop
971 plot8x24_y0_exit:
972 clc
973 jmp plot_buffer_loop_next
976 plot8x8_y1: ; $70,$71=source address
977 ; $72,$73=destination address
978 lda #2
979 sta $7e
980 lda #10
981 sta $7f
983 lda #0 ; plotting 1 8x8 piece
984 sta $8a
986 jmp plot8x24_y123 ; optimise away the rts
988 plot8x24_y1: ; $70,$71=source address
989 ; $72,$73=destination address
990 lda #2
991 sta $7e
992 lda #10
993 sta $7f
995 lda #2 ; plotting 3 8x8 pieces
996 sta $8a
998 jmp plot8x24_y123 ; optimise away the rts
1000 plot8x8_y2: ; $70,$71=source address
1001 ; $72,$73=destination address
1002 lda #4
1003 sta $7e
1004 lda #12
1005 sta $7f
1007 lda #0 ; plotting 1 8x8 piece
1008 sta $8a
1010 jmp plot8x24_y123 ; optimise away the rts
1012 plot8x24_y2: ; $70,$71=source address
1013 ; $72,$73=destination address
1014 lda #4
1015 sta $7e
1016 lda #12
1017 sta $7f
1019 lda #2 ; plotting 3 8x8 pieces
1020 sta $8a
1022 jmp plot8x24_y123 ; optimise away the rts
1024 plot8x8_y3: ; $70,$71=source address
1025 ; $72,$73=destination address
1026 lda #6
1027 sta $7e
1028 lda #14
1029 sta $7f
1031 lda #0 ; plotting 1 8x8 piece
1032 sta $8a
1034 jmp plot8x24_y123 ; optimise away the rts
1036 plot8x24_y3: ; $70,$71=source address
1037 ; $72,$73=destination address
1038 lda #6
1039 sta $7e
1040 lda #14
1041 sta $7f
1043 lda #2 ; plotting 3 8x8 pieces
1044 sta $8a
1046 ; Run on into the next routine.
1048 plot8x24_y123: ; $70,$71=source address
1049 ; $72,$73=destination address
1050 ; $7e=offset into source data for first column
1051 ; $7f=offset into source data for second column
1053 plot8x24_y123_loop:
1055 ldx #0
1056 plot8x24_y123_upper_loop_outer:
1058 ldy $7e,x
1059 lda plot_upper_offsets,x
1060 sta $89
1062 plot8x24_y123_upper_loop_inner: ; plot the first column until
1063 dey ; we reach the start
1064 cpy $89
1065 bmi plot8x24_y123_upper_loop_inner_endloop
1066 lda ($70),y
1067 eor ($72),y
1068 sta ($72),y
1069 jmp plot8x24_y123_upper_loop_inner
1071 plot8x24_y123_upper_loop_inner_endloop:
1072 clc
1074 inx
1075 cpx #2
1076 bne plot8x24_y123_upper_loop_outer
1078 clc
1079 lda $72 ; move the destination pointer to refer to the next line
1080 adc #$38
1081 sta $72
1082 lda $73
1083 adc #$01
1084 sta $73
1085 clc
1087 ldx #0
1088 plot8x24_y123_lower_loop_outer:
1090 lda plot_lower_offsets,x
1091 tay
1092 lda $7e,x
1093 sta $89
1095 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1096 lda ($70),y ; offset for the column
1097 eor ($72),y
1098 sta ($72),y
1099 dey
1100 cpy $89
1101 bpl plot8x24_y123_lower_loop_inner
1103 inx
1104 cpx #2
1105 bne plot8x24_y123_lower_loop_outer
1107 dec $8a
1108 bmi plot8x24_y123_exit
1110 clc
1111 lda $70 ; update the source pointer to refer to the next piece
1112 adc #16 ; of sprite data
1113 sta $70
1114 lda $71
1115 adc #0
1116 sta $71
1117 clc
1119 lda $72 ; update the destination pointer to point to the next
1120 adc #8 ; space
1121 sta $72
1122 lda $73
1123 adc #0
1124 sta $73
1125 clc
1127 jmp plot8x24_y123_loop
1129 plot8x24_y123_exit:
1130 clc
1131 jmp plot_buffer_loop_next
1133 plot16x16_y0: ; $70,$71=source address
1134 ; $72,$73=destination address
1135 ldy #31
1137 plotloop16x16_y0_0:
1138 lda ($70),y
1139 eor ($72),y
1140 sta ($72),y
1141 dey
1142 bpl plotloop16x16_y0_0
1143 clc
1145 lda $72
1146 adc #$20
1147 sta $72
1148 lda $73
1149 adc #$01
1150 sta $73 ; 0x140 - 32
1151 clc
1153 ldy #63
1155 plotloop16x16_y0_1:
1156 lda ($70),y
1157 eor ($72),y
1158 sta ($72),y
1159 dey
1160 cpy #32
1161 bpl plotloop16x16_y0_1
1162 clc
1164 jmp plot_buffer_loop_next
1166 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1168 plot16x16_y1: ; $70,$71=source address
1169 ; $72,$73=destination address
1171 lda #2
1172 sta $7e
1173 lda #10
1174 sta $7f
1175 lda #18
1176 sta $80
1177 lda #26
1178 sta $81
1179 jmp plot16x16_y123 ; optimise away the rts
1181 plot16x16_y2: ; $70,$71=source address
1182 ; $72,$73=destination address
1184 lda #4
1185 sta $7e
1186 lda #12
1187 sta $7f
1188 lda #20
1189 sta $80
1190 lda #28
1191 sta $81
1192 jmp plot16x16_y123 ; optimise away the rts
1194 plot16x16_y3: ; $70,$71=source address
1195 ; $72,$73=destination address
1197 lda #6
1198 sta $7e
1199 lda #14
1200 sta $7f
1201 lda #22
1202 sta $80
1203 lda #30
1204 sta $81
1205 ; Run on into the next routine.
1207 plot16x16_y123: ; $70,$71=source address
1208 ; $72,$73=destination address
1209 ; $7e=offset into source data for first column
1210 ; $7f=offset into source data for second column
1211 ; $80=offset into source data for third column
1212 ; $81=offset into source data for fourth column
1214 lda #1
1215 sta $8a
1217 plot16x16_y123_loop:
1219 ldx #0
1220 plot16x16_y123_upper_loop_outer:
1222 ldy $7e,x
1223 lda plot_upper_offsets,x
1224 sta $89
1226 plot16x16_y123_upper_loop_inner:
1228 dey
1229 cpy $89
1230 bmi plot16x16_y123_upper_loop_inner_endloop
1231 lda ($70),y
1232 eor ($72),y
1233 sta ($72),y
1234 jmp plot16x16_y123_upper_loop_inner
1236 plot16x16_y123_upper_loop_inner_endloop:
1237 clc
1239 inx
1240 cpx #4
1241 bne plot16x16_y123_upper_loop_outer
1243 clc
1244 lda $72 ; move the destination pointer to refer to the next line
1245 adc #$38
1246 sta $72
1247 lda $73
1248 adc #$01
1249 sta $73
1250 clc
1252 ldx #0
1253 plot16x16_y123_lower_loop_outer:
1255 lda plot_lower_offsets,x
1256 tay
1257 lda $7e,x
1258 sta $89
1260 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1261 lda ($70),y ; for the column
1262 eor ($72),y
1263 sta ($72),y
1264 dey
1265 cpy $89
1266 bpl plot16x16_y123_lower_loop_inner
1268 inx
1269 cpx #4
1270 bne plot16x16_y123_lower_loop_outer
1272 dec $8a
1273 bmi plot16x16_y123_exit
1275 clc
1276 lda $70 ; update the source pointer to refer to the next piece
1277 adc #32 ; of sprite data
1278 sta $70
1279 lda $71
1280 adc #0
1281 sta $71
1282 clc
1284 lda $72 ; update the destination pointer to point to the next
1285 adc #8 ; space
1286 sta $72
1287 lda $73
1288 adc #0
1289 sta $73
1290 clc
1292 jmp plot16x16_y123_loop
1294 plot16x16_y123_exit:
1295 clc
1296 jmp plot_buffer_loop_next
1298 plot_upper_offsets: .byte 0, 8, 16, 24
1299 plot_lower_offsets: .byte 7, 15, 23, 31
1301 plot8x8_y0: ; $70,$71=source address
1302 ; $72,$73=destination address
1303 ldy #15
1305 plotloop8x8_y0_0:
1306 lda ($70),y
1307 eor ($72),y
1308 sta ($72),y
1309 dey
1310 bpl plotloop8x8_y0_0
1311 clc
1313 jmp plot_buffer_loop_next
1316 check_key: ; x=key code
1317 lda #129 ; returns y=255 or 0
1318 ldy #255
1319 jsr $fff4
1320 rts
1322 player_direction_chars_low: .byte $00,$30,$60,$90,$c0,$f0,$20,$50, $80,$b0,$e0,$10
1323 player_direction_chars_high: .byte $3f,$3f,$3f,$3f,$3f,$3f,$40,$40, $40,$40,$40,$41
1325 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1326 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1327 screen_subrows_low: .byte $00,$06,$44,$82
1328 screen_subrows_high: .byte $00,$00,$01,$02
1330 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1331 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1332 screen_subcolumns_low: .byte $00,$08,$10,$18
1334 enemy_direction_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1335 enemy_direction_chars_high: .byte $41,$42,$42,$42,$42,$43,$43,$43
1337 emerge_explode_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1338 emerge_explode_chars_high: .byte $4b,$4c,$4c,$4c,$4c,$4d,$4d,$4d
1340 item_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80,$c0
1341 item_chars_high: .byte $4d,$4e,$4e,$4e,$4e,$4f,$4f,$4f,$4f
1343 projectile_chars_low: .byte $40,$50,$60,$70,$80,$90,$a0,$b0
1345 unplot_character: ; $74,$75=character address
1347 lda $82 ; store the unplot buffer address in $78,$79
1348 sta $78
1349 lda $83
1350 sta $79
1351 jsr plot_character_sprite
1352 lda $78
1353 sta $82 ; update the latest space in the unplot buffer
1354 rts
1356 plot_character: ; $74,$75=character address
1358 lda $84 ; store the plot buffer address in $78,$79
1359 sta $78
1360 lda $85
1361 sta $79
1362 jsr plot_character_sprite
1363 lda $78
1364 sta $84 ; update the latest space in the plot buffer
1365 rts
1367 plot_character_sprite: ; $74,$75=character address
1368 ; $78,$79=unplot/plot buffer address
1370 ldy #0
1371 lda ($74),y
1372 cmp #0
1373 bne plot_characters_read_character
1374 jmp plot_characters_next
1376 plot_characters_read_character:
1377 clc
1379 sta $77 ; temporarily store the object type
1381 ; Use lookup tables to load the offsets into the sprite.
1383 ; Direction
1384 iny
1385 lda ($74),y
1386 sta $80 ; temporarily store the direction
1388 ; y
1389 iny
1390 lda ($74),y
1391 tax
1392 lda screen_rows_low,x
1393 sta $72
1394 lda screen_rows_high,x
1395 sta $73
1396 clc
1398 ; dy
1399 iny
1400 lda ($74),y
1401 sta $76
1402 tax
1403 lda screen_subrows_low,x
1404 adc $72
1405 sta $72
1406 lda screen_subrows_high,x
1407 adc $73
1408 sta $73
1409 clc
1411 ; x
1412 iny
1413 lda ($74),y
1414 tax
1415 lda screen_columns_low,x
1416 adc $72
1417 sta $72
1418 lda screen_columns_high,x
1419 adc $73
1420 sta $73
1421 clc
1423 ; dx
1424 iny
1425 lda ($74),y
1426 tax
1427 lda screen_subcolumns_low,x
1428 adc $72
1429 sta $72
1430 clc
1432 lda $77
1433 cmp #1
1434 bne plot_characters_loop_not_player
1436 ; Plot 8x24 sprites (player)
1438 ldx $80
1439 lda player_direction_chars_low,x
1440 sta $70
1441 lda player_direction_chars_high,x
1442 sta $71
1444 ; Use the dy value to determine which plotting routine to use.
1446 ldy #0
1447 ldx $76
1448 lda plot_routine_indices_8x24,x
1450 sta ($78),y
1451 jmp plot_characters_stored
1454 plot_characters_loop_not_player:
1455 cmp #2
1456 bne plot_characters_loop_not_projectile
1458 ; Plot 8x8 sprites (projectiles)
1460 lda $80
1461 and #7
1462 tax
1463 lda projectile_chars_low,x
1464 sta $70
1465 lda #$41
1466 sta $71
1468 ; Use the dy value to determine which plotting routine to use.
1470 ldy #0
1471 ldx $76
1472 lda plot_routine_indices_8x8,x
1474 sta ($78),y
1475 jmp plot_characters_stored
1478 plot_characters_loop_not_projectile:
1479 cmp #3
1480 bne plot_characters_loop_not_explosion
1482 ; Plot 16x16 sprites (emerging, explosions)
1484 ; Select the sprites to use.
1486 lda $80
1487 and #7 ; only keep the bits required to find the correct sprite
1488 clc
1489 tax
1490 lda emerge_explode_chars_low,x
1491 sta $70
1492 lda emerge_explode_chars_high,x
1493 sta $71
1495 jmp plot_characters_16x16
1497 plot_characters_loop_not_explosion:
1498 cmp #4
1499 bne plot_characters_loop_not_item
1501 ; Plot 16x16 sprites (items)
1503 ; Select the sprites to use.
1505 lda $80
1506 and #$0f ; only keep the bits required to find the correct sprite
1507 clc
1508 tax
1509 lda item_chars_low,x
1510 sta $70
1511 lda item_chars_high,x
1512 sta $71
1514 jmp plot_characters_16x16
1516 plot_characters_loop_not_item:
1517 cmp #8
1518 bmi plot_characters_loop_not_enemy
1520 ; Plot 16x16 sprites (enemies)
1522 ; Select the set of sprites to use.
1524 and #$70
1525 lsr
1526 lsr
1527 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1528 clc
1529 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1531 lda $80
1532 and #7 ; keep the animation bits
1533 tax
1534 lda enemy_direction_chars_low,x
1535 sta $70
1536 lda enemy_direction_chars_high,x
1537 adc $71
1538 sta $71
1540 plot_characters_16x16:
1542 ; Use the dy value to determine which plotting routine to use.
1544 ldy #0
1545 ldx $76
1546 lda plot_routine_indices_16x16,x
1548 sta ($78),y
1550 plot_characters_stored:
1552 iny
1553 lda $70
1554 sta ($78),y
1555 iny
1556 lda $71
1557 sta ($78),y
1558 iny
1559 lda $72
1560 sta ($78),y
1561 iny
1562 lda $73
1563 sta ($78),y
1565 clc
1566 lda $78
1567 adc #12
1568 sta $78
1570 plot_characters_loop_not_enemy:
1572 plot_characters_next:
1574 lda #255 ; terminate this stream of entries in the plot buffer
1575 ldy #0
1576 sta ($78),y
1577 clc
1578 rts
1580 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1581 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1582 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1584 reset_plot_buffer:
1585 lda #$06 ; reset the index into the plot buffer
1586 sta $84
1587 lda #$53
1588 sta $85
1590 lda #255 ; terminate the plot list
1591 ldy #0
1592 sta ($84),y
1593 rts
1595 reset_unplot_buffer:
1596 lda #$00 ; reset the index into the plot buffer
1597 sta $82
1598 lda #$53
1599 sta $83
1601 lda #255 ; terminate the unplot list
1602 ldy #0
1603 sta ($82),y
1604 rts
1606 plot_buffer_types_low: .byte <plot_buffer_loop_next
1607 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1608 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1609 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1611 plot_buffer_types_high: .byte >plot_buffer_loop_next
1612 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1613 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1614 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1616 plot_buffer:
1618 lda #$00
1619 sta $84
1620 lda #$53
1621 sta $85
1623 lda #6
1624 sta $88
1626 plot_buffer_loop:
1628 ldy #0
1629 lda ($84),y
1630 cmp #255
1631 beq plot_buffer_loop_skip
1633 clc
1634 tax
1635 lda plot_buffer_types_low,x
1636 sta $86
1637 lda plot_buffer_types_high,x
1638 sta $87
1640 iny
1641 lda ($84),y
1642 sta $70
1644 iny
1645 lda ($84),y
1646 sta $71
1648 iny
1649 lda ($84),y
1650 sta $72
1652 iny
1653 lda ($84),y
1654 sta $73
1656 jmp ($86) ; returns to plot_buffer_loop_next
1658 plot_buffer_loop_skip:
1660 lda $88
1661 cmp #12
1662 beq plot_buffer_exit ; both unplot and plot lists have terminated
1664 lda #12
1665 sta $88
1666 lda $84
1667 adc #6
1668 sta $84
1669 jmp plot_buffer_loop
1671 plot_buffer_loop_next:
1672 clc
1674 lda $84
1675 adc $88
1676 sta $84
1677 jmp plot_buffer_loop
1679 plot_buffer_exit:
1680 clc
1681 rts
1683 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1685 animate_player_left:
1687 ; Set the direction and toggle the animation bit.
1689 lda $5281
1690 and #1
1691 eor #1 ; toggle animation flag
1692 sta $5281 ; left (directional bits are 0)
1694 jsr plot_character
1695 rts
1697 animate_player_right:
1699 ; Set the direction and toggle the animation bit.
1701 lda $5281
1702 and #1 ; remove direction information (result is 0)
1703 eor #1 ; toggle animation flag
1704 ora #2 ; right
1705 sta $5281
1707 jsr plot_character
1708 rts
1710 animate_player_up:
1712 ; Set the direction and toggle the animation bit.
1714 lda $5281
1715 and #1 ; remove direction information (result is 0)
1716 eor #1 ; toggle animation flag
1717 ora #4 ; up
1718 sta $5281
1720 jsr plot_character
1721 rts
1723 animate_player_down:
1725 ; Set the direction and toggle the animation bit.
1727 lda $5281
1728 and #1 ; remove direction information (result is 0)
1729 eor #1 ; toggle animation flag
1730 ora #6 ; down
1731 sta $5281
1733 jsr plot_character
1734 rts
1736 move_player:
1738 lda $578e
1739 and #1
1740 beq move_player_allowed
1742 clc
1743 rts
1745 move_player_allowed:
1747 lda #$80 ; set up the address of the player character
1748 sta $74
1749 lda #$52
1750 sta $75
1752 ; Handle joystick
1754 lda $577e
1755 cmp #0
1756 beq move_player_handle_left_key
1758 lda #128
1759 ldx #1
1760 jsr $fff4
1761 cpy #16 ; >= 16 but could be -128 ... -1
1762 bcc move_player_handle_joystick_up_down
1764 move_player_joystick_right_or_negative:
1765 cmp #128
1766 bcs move_player_joystick_not_right
1767 jmp move_player_right ; 16 ... 255
1769 move_player_joystick_not_right:
1771 cmp #241
1772 bcs move_player_handle_joystick_up_down
1773 jmp move_player_left ; <= -16
1775 move_player_handle_joystick_up_down:
1777 lda #128
1778 ldx #2
1779 jsr $fff4
1780 cpy #16 ; >= 16 but could be -128 ... -1
1781 bcc move_player_handle_left_key
1783 move_player_joystick_up_or_negative:
1784 cmp #128
1785 bcs move_player_joystick_not_up
1786 jmp move_player_up ; 16 ... 255
1788 move_player_joystick_not_up:
1790 cmp #241
1791 bcs move_player_handle_left_key
1792 jmp move_player_down ; <= -16
1794 move_player_handle_left_key:
1796 ; Handle the left key.
1798 ldx #158 ; (Z)
1799 jsr check_key
1800 cpy #255
1801 bne move_player_not_left_key
1803 move_player_left:
1805 lda $5285 ; read dx
1806 cmp #0
1807 beq move_player_left_check_x
1809 jsr unplot_character ; unplot the player character
1810 dec $5285
1811 clc
1812 jmp animate_player_left ; optimise away the rts
1814 move_player_left_check_x: ; Check the x offset.
1816 lda $5284
1817 cmp #0
1818 beq move_player_leave_room_left
1820 clc
1821 tay
1822 dey ; x - 1
1823 lda $5282 ; load the y offset
1824 tax ; as an index
1825 lda room_row_offsets_low,x ; read the address of the row
1826 sta $70
1827 lda #$57
1828 sta $71
1829 lda ($70),y ; load the tile to the left
1831 cmp #5 ; check for the open exit or final exit
1832 bmi move_player_not_left_exit1
1833 jmp try_to_exit_level ; optimise away the rts
1835 move_player_not_left_exit1:
1836 cmp #0
1837 bne move_player_not_left_key
1839 lda $5283 ; dy
1840 cmp #0
1841 beq move_player_allow_left
1843 clc
1844 lda $70 ; dy > 0 so we need to check another tile
1845 adc #10
1846 sta $70
1847 lda ($70),y ; load the tile below and to the left
1849 cmp #5 ; check for the open exit or final exit
1850 bmi move_player_not_left_exit2
1851 jmp try_to_exit_level ; optimise away the rts
1853 move_player_not_left_exit2:
1854 cmp #0
1855 bne move_player_not_left_key
1857 move_player_allow_left:
1858 tya
1859 sta $81 ; temporary
1860 jsr unplot_character ; unplot the player character
1861 lda $81
1862 sta $5284 ; store the new room x offset
1863 lda #3
1864 sta $5285 ; dx = 3
1865 clc
1866 jmp animate_player_left ; optimise away the rts
1868 move_player_leave_room_left:
1869 sec
1870 lda $5783
1871 sbc #1
1872 sta $5783
1873 clc
1875 ; Set the player's position on the right of the screen.
1877 ; No need to unplot.
1879 lda #9 ; x = 9
1880 sta $5284
1881 lda #2 ; dx = 2
1882 sta $5285
1884 jsr animate_player_left
1885 sec ; indicate to the calling routine that the player
1886 rts ; has left the room
1888 move_player_not_left_key:
1890 ; Handle the right key.
1892 ldx #189 ; (X)
1893 jsr check_key
1894 cpy #255
1895 beq move_player_right
1896 jmp move_player_not_right_key
1898 move_player_right:
1900 lda $5285 ; read dx
1901 cmp #2
1902 beq move_player_right_check_x
1903 cmp #3
1904 beq move_player_right_tile
1906 jsr unplot_character ; unplot the player character
1907 inc $5285
1908 clc
1909 jmp animate_player_right ; optimise away the rts
1911 move_player_right_check_x: ; Check the x offset.
1913 lda $5284
1914 cmp #9
1915 beq move_player_leave_room_right
1917 clc
1918 tay
1919 iny ; x + 1
1920 lda $5282 ; load the y offset
1921 tax ; as an index
1922 lda room_row_offsets_low,x ; read the address of the row
1923 sta $70
1924 lda #$57
1925 sta $71
1926 lda ($70),y ; load the tile to the right
1928 cmp #5 ; check for the open exit or final exit
1929 bmi move_player_not_right_exit1
1930 jmp try_to_exit_level ; optimise away the rts
1932 move_player_not_right_exit1:
1933 cmp #0
1934 bne move_player_not_right_key
1936 lda $5283 ; dy
1937 cmp #0
1938 beq move_player_allow_right
1940 clc ; dy > 0 so we need to check another tile
1941 lda $70
1942 adc #10
1943 sta $70
1944 lda ($70),y ; load the tile below and to the right
1946 cmp #5 ; check for the open exit or final exit
1947 bmi move_player_not_right_exit2
1948 jmp try_to_exit_level ; optimise away the rts
1950 move_player_not_right_exit2:
1951 cmp #0
1952 bne move_player_not_right_key
1954 move_player_allow_right:
1956 jsr unplot_character ; unplot the player character
1957 inc $5285 ; update dx
1958 clc
1959 jmp animate_player_right ; optimise away the rts
1961 move_player_right_tile:
1963 jsr unplot_character ; unplot the player character
1964 inc $5284 ; store the new room x offset
1965 lda #0
1966 sta $5285 ; dx = 0
1967 clc
1968 jmp animate_player_right ; optimise away the rts
1970 move_player_leave_room_right:
1971 clc
1972 inc $5783
1973 clc
1975 ; Set the player's position on the left of the screen.
1977 ; No need to unplot.
1979 lda #0 ; x = 0
1980 sta $5284
1981 lda #0 ; dx = 0
1982 sta $5285
1984 jsr animate_player_right
1985 sec ; indicate to the calling routine that the
1986 rts ; player has left the room
1988 move_player_not_right_key:
1990 ; Handle the up key.
1992 ldx #183 ; (:)
1993 jsr check_key
1994 cpy #255
1995 bne move_player_not_up_key
1997 move_player_up:
1999 lda $5283 ; read dy
2000 cmp #0
2001 beq move_player_up_check_y
2003 jsr unplot_character ; unplot the player character
2004 dec $5283
2005 clc
2006 jmp animate_player_up ; optimise away the rts
2008 move_player_up_check_y: ; Check the y offset.
2010 lda $5282
2011 cmp #0
2012 beq move_player_leave_room_up
2014 tax ; use the y offset as an index
2015 dex ; y - 1
2016 ldy $5284 ; load the x offset
2017 lda room_row_offsets_low,x ; read the address of the row
2018 sta $70
2019 lda #$57
2020 sta $71
2021 lda ($70),y ; load the tile above
2023 cmp #5 ; check for the open exit or final exit
2024 bmi move_player_not_up_exit1
2025 jmp try_to_exit_level ; optimise away the rts
2027 move_player_not_up_exit1:
2028 cmp #0
2029 bne move_player_not_up_key
2031 lda $5285 ; dx
2032 cmp #3
2033 bmi move_player_allow_up
2035 clc ; dx > 2 so we need to check another tile
2036 iny
2037 lda ($70),y ; load the tile above and to the right
2039 cmp #5 ; check for the open exit or final exit
2040 bmi move_player_not_up_exit2
2041 jmp try_to_exit_level ; optimise away the rts
2043 move_player_not_up_exit2:
2044 cmp #0
2045 bne move_player_not_up_key
2047 move_player_allow_up:
2048 txa
2049 sta $81 ; temporary
2050 jsr unplot_character ; unplot the player character
2051 lda $81
2052 sta $5282 ; store the new room y offset
2053 lda #3
2054 sta $5283 ; dy = 3
2055 clc
2056 jmp animate_player_up ; optimise away the rts
2058 move_player_leave_room_up:
2059 sec
2060 lda $5782
2061 sbc #1
2062 sta $5782
2063 clc
2065 ; Set the player's position on the bottom of the screen.
2067 ; No need to unplot.
2069 lda #9 ; y = 9
2070 sta $5282
2071 lda #0 ; dy = 0
2072 sta $5283
2074 jsr animate_player_up
2075 sec ; indicate to the calling routine that the player
2076 rts ; has left the room
2078 move_player_not_up_key:
2080 ; Handle the down key.
2082 ldx #151 ; (/)
2083 jsr check_key
2084 cpy #255
2085 beq move_player_down
2086 jmp move_player_not_down_key
2088 move_player_down:
2090 lda $5283 ; read dy
2091 cmp #0
2092 beq move_player_down_check_y
2093 cmp #3
2094 beq move_player_down_tile
2096 jsr unplot_character ; unplot the player character
2097 inc $5283 ; 0 <= dy < 3
2098 clc
2099 jmp animate_player_down ; optimise away the rts
2101 move_player_down_check_y: ; Check the y offset.
2103 lda $5282
2104 cmp #9
2105 beq move_player_leave_room_down
2107 clc
2108 tax
2109 inx ; y + 1
2110 ldy $5284 ; load the x offset
2111 lda room_row_offsets_low,x ; read the address of the row
2112 sta $70
2113 lda #$57
2114 sta $71
2115 lda ($70),y ; load the tile below
2117 cmp #5 ; check for the open exit or final exit
2118 bmi move_player_not_down_exit1
2119 jmp try_to_exit_level ; optimise away the rts
2121 move_player_not_down_exit1:
2122 cmp #0
2123 bne move_player_not_down_key
2125 lda $5285 ; dx
2126 cmp #3
2127 bmi move_player_allow_down
2129 clc ; dx > 2 so we need to check another tile
2130 iny
2131 lda ($70),y ; load the tile below and to the right
2133 cmp #5 ; check for the open exit or final exit
2134 bmi move_player_not_down_exit2
2135 jmp try_to_exit_level ; optimise away the rts
2137 move_player_not_down_exit2:
2138 cmp #0
2139 bne move_player_not_down_key
2141 move_player_allow_down:
2143 jsr unplot_character ; unplot the player character
2144 inc $5283 ; update dy
2145 clc
2146 jmp animate_player_down ; optimise away the rts
2148 move_player_down_tile:
2150 jsr unplot_character ; unplot the player character
2151 inc $5282 ; store the new room y offset
2152 lda #0
2153 sta $5283 ; dy = 0
2154 clc
2155 jmp animate_player_down ; optimise away the rts
2157 move_player_leave_room_down:
2158 inc $5782
2159 clc
2161 ; Set the player's position on the top of the screen.
2163 ; No need to unplot.
2165 lda #0 ; y = 0
2166 sta $5282
2167 lda #0 ; dy = 0
2168 sta $5283
2170 jsr animate_player_down
2171 sec ; indicate to the calling routine that the
2172 rts ; player has left the room
2174 move_player_not_down_key:
2175 clc
2176 rts
2178 try_to_exit_level:
2180 cmp #6
2181 bmi just_exit_level
2183 lda $5780 ; set the complete game flag
2184 ora #$02
2185 jmp try_to_exit_level_exit
2187 just_exit_level:
2188 lda $5780 ; set the exit level flag
2189 ora #$80
2191 try_to_exit_level_exit:
2192 sta $5780
2194 lda #$80
2195 sta $74
2196 lda #$52
2197 sta $75
2198 jsr unplot_character ; remove the player sprite
2199 jmp destroy_enemies ; optimise away the rts
2201 check_fire_key:
2203 lda $578d
2204 bne check_fire_key_exit
2206 lda $577e
2207 beq check_fire_key_no_joystick
2209 lda #128
2210 ldx #0
2211 jsr $fff4
2212 cpx #0
2213 bne check_fire_key_fire
2215 check_fire_key_no_joystick:
2217 ldx #182 ; (Return)
2218 jsr check_key
2219 cpy #255
2220 bne check_fire_key_exit
2222 check_fire_key_fire:
2224 lda $5286
2225 cmp #0
2226 bne check_fire_key_exit
2228 lda #16
2229 sta $578d
2231 jmp create_projectile ; optimise away the rts
2233 check_fire_key_exit:
2234 clc
2235 rts
2237 create_projectile:
2239 lda #2
2240 sta $5286
2242 lda $5281
2243 and #$06 ; copy the direction information
2244 asl
2245 asl
2246 asl
2247 ora $5789 ; apply the projectile type
2248 sta $5287
2250 lda $5283 ; player dy
2251 adc $577f ; add the weapon counter
2252 adc #1
2253 cmp #4 ; if dy > 3, create the projectile on the tile below
2254 bpl create_projectile_below
2256 clc
2257 sta $5289 ; dy + weapon counter + 1
2258 lda $5282 ; y
2259 sta $5288
2260 jmp create_projectile_continue
2262 create_projectile_below:
2263 sec
2264 sbc #4
2265 sta $5289 ; dy + weapon counter + 1 - 4
2266 clc
2267 lda $5282 ; y
2268 adc #1
2269 sta $5288
2271 create_projectile_continue:
2272 lda $5284 ; x
2273 sta $528a
2275 lda $5285 ; dx
2276 sta $528b
2278 lda $577f ; toggle the weapon counter
2279 eor #1
2280 sta $577f
2282 ; Move the projectile away from the player.
2284 jsr move_projectile_after_unplot
2285 jsr move_projectile
2287 clc
2288 rts
2290 emerge_type: ; returns A=type
2291 jsr unlimited_values
2292 lda $7d
2293 and #7
2294 cmp #4
2295 bmi emerge_type_ok
2297 sec
2298 sbc #4
2299 clc
2301 emerge_type_ok:
2302 cmp $5781 ; only allow the appropriate enemies for this level
2303 bmi emerge_type_exit
2305 sec
2306 sbc $5781
2307 clc
2309 emerge_type_exit:
2310 asl
2311 asl
2312 asl
2313 asl
2314 clc
2315 rts
2317 emerge_character: ; $74,$75=character address
2319 lda #63
2320 sta $578f
2322 jsr unlimited_values
2323 and #$0f
2324 tax
2325 lda $0ee0,x
2326 cmp #0 ; check for an invalid value and exit if found
2327 beq emerge_character_exit
2329 sta $80 ; temporary
2330 lda $0ef0,x
2331 tax
2333 ; Add an emerging enemy.
2335 ldy #0
2336 lda #3 ; emerge/explosion
2337 sta ($74),y
2339 jsr emerge_type ; obtain an enemy type
2340 iny
2341 sta ($74),y
2343 txa
2344 iny
2345 sta ($74),y ; store the y position
2346 lda #1
2347 iny
2348 sta ($74),y ; store the dy offset
2350 lda $80
2351 iny
2352 sta ($74),y ; store the x position
2353 lda #0
2354 iny
2355 sta ($74),y ; store the dx offset
2357 jsr plot_character
2359 ldx #5
2360 jsr play_sound
2362 emerge_character_exit:
2363 clc
2364 rts
2366 emerge_explode: ; $74,$75=character address
2368 jsr unplot_character
2370 ldy #1
2371 lda ($74),y ; direction/animation
2372 tax
2373 adc #1 ; update the counter
2374 and #3 ; mask off everything else
2375 sta $80 ; store the masked counter value
2376 bne move_characters_explosion_not_finished
2378 txa
2379 and #4
2380 bne move_characters_remove_character
2382 ; For emerges, convert into an enemy.
2383 txa
2384 and #$70 ; only keep bits 4,5,6
2385 ora #8 ; make this an enemy
2387 ldy #0
2388 sta ($74),y ; update the type (>= 8)
2389 iny
2390 lda $7d ; prepare the direction and animation offset
2391 and #$0c
2392 sta ($74),y
2394 jsr plot_character
2395 jmp emerge_explode_exit
2397 move_characters_remove_character:
2399 ; For finished explosions, just write 0 into the character array.
2400 lda #0
2401 ldy #0
2402 sta ($74),y
2403 jmp emerge_explode_exit
2405 move_characters_explosion_not_finished:
2406 txa
2407 and #$fc
2408 ora $80
2410 ldy #1
2411 sta ($74),y
2413 jsr plot_character
2415 emerge_explode_exit:
2416 clc
2417 rts
2419 animate_enemy_left: ; $74,$75=character address
2421 ; Set the direction and toggle the animation bit.
2423 ldy #1
2424 lda ($74),y
2425 and #$fb ; keep vertical direction bit and animation bits
2426 sta ($74),y ; left (horizontal directional bit is 0)
2428 rts
2430 move_enemy_left: ; $74,$75=character address
2432 ldy #5
2433 lda ($74),y ; read dx
2434 cmp #0
2435 beq move_enemy_left_check_x
2437 sec
2438 sbc #1
2439 ldy #5
2440 sta ($74),y ; dx
2441 clc
2442 jmp animate_enemy_left ; optimise away the rts
2444 move_enemy_left_check_x:
2446 ; Check the x offset.
2448 ldy #4
2449 lda ($74),y ; x
2450 cmp #0
2451 beq move_enemy_left_exit
2453 sec
2454 sbc #1 ; x - 1
2455 sta $81 ; temporary
2456 ldy #2
2457 lda ($74),y ; load the y offset
2458 tax ; as an index
2459 lda room_row_offsets_low,x ; read the address of the row
2460 sta $70
2461 lda #$57
2462 sta $71
2463 ldy $81 ; temporary (x - 1)
2464 lda ($70),y ; load the tile to the left
2466 cmp #0
2467 bne move_enemy_left_exit
2469 ldy #3
2470 lda ($74),y ; dy
2471 cmp #2
2472 bmi move_enemy_allow_left
2474 clc
2475 lda $70 ; dy > 1 so we need to check another tile
2476 adc #10
2477 sta $70
2478 ldy $81 ; temporary (x - 1)
2479 lda ($70),y ; load the tile below and to the left
2481 cmp #0
2482 bne move_enemy_left_exit
2484 move_enemy_allow_left:
2485 lda $81
2486 ldy #4
2487 sta ($74),y ; store the new room x offset
2488 lda #3
2489 ldy #5
2490 sta ($74),y ; dx = 3
2491 clc
2492 jmp animate_enemy_left ; optimise away the rts
2494 move_enemy_left_exit:
2495 sec
2496 rts
2498 animate_enemy_right: ; $74,$75=character address
2500 ; Set the direction and toggle the animation bit.
2502 ldy #1
2503 lda ($74),y
2504 ora #$04 ; right (keep vertical direction bit and animation bits)
2505 sta ($74),y
2507 rts
2509 move_enemy_right: ; $74,$75=character_address
2511 ldy #5
2512 lda ($74),y ; read dx
2513 cmp #0
2514 beq move_enemy_right_check_x
2515 cmp #3
2516 beq move_enemy_right_tile
2518 clc
2519 adc #1
2520 ldy #5
2521 sta ($74),y
2522 jmp animate_enemy_right ; optimise away the rts
2524 move_enemy_right_check_x: ; Check the x offset.
2526 ldy #4
2527 lda ($74),y ; x
2528 cmp #9
2529 beq move_enemy_right_exit
2531 clc
2532 adc #1 ; x + 1
2533 sta $81 ; temporary (x + 1)
2534 ldy #2
2535 lda ($74),y ; load the y offset
2536 tax ; as an index
2537 lda room_row_offsets_low,x ; read the address of the row
2538 sta $70
2539 lda #$57
2540 sta $71
2541 ldy $81 ; temporary (x + 1)
2542 lda ($70),y ; load the tile to the right
2544 cmp #0
2545 bne move_enemy_right_exit
2547 ldy #3
2548 lda ($74),y ; dy
2549 cmp #2
2550 bmi move_enemy_allow_right
2552 clc ; dy > 1 so we need to check another tile
2553 lda $70
2554 adc #10
2555 sta $70
2556 ldy $81 ; temporary (x + 1)
2557 lda ($70),y ; load the tile below and to the right
2559 cmp #0
2560 bne move_enemy_right_exit
2562 move_enemy_allow_right:
2563 clc
2565 ldy #5
2566 lda ($74),y ; dx
2567 adc #1
2568 sta ($74),y ; update dx
2569 clc
2570 jmp animate_enemy_right ; optimise away the rts
2572 move_enemy_right_tile:
2573 clc
2575 ldy #4
2576 lda ($74),y ; x
2577 adc #1
2578 sta ($74),y ; store the new room x offset
2579 lda #0
2580 iny
2581 sta ($74),y ; dx = 0
2582 clc
2583 jmp animate_enemy_right ; optimise away the rts
2585 move_enemy_right_exit:
2586 sec
2587 rts
2589 animate_enemy_up: ; $74,$75=character address
2591 ; Set the direction and toggle the animation bit.
2593 ldy #1
2594 lda ($74),y
2595 and #$f7 ; keep horizontal direction bit and animation bits
2596 sta ($74),y
2598 rts
2600 move_enemy_up: ; $74,$75=character address
2602 ldy #3
2603 lda ($74),y ; read dy
2604 cmp #0
2605 beq move_enemy_up_check_y
2607 sec
2608 sbc #1
2609 ldy #3
2610 sta ($74),y ; dy
2611 clc
2612 jmp animate_enemy_up ; optimise away the rts
2614 move_enemy_up_check_y:
2616 ; Check the y offset.
2618 ldy #2
2619 lda ($74),y ; y
2620 cmp #0
2621 beq move_enemy_up_exit
2623 tax ; use the y offset as an index
2624 dex ; y - 1
2625 ldy #4
2626 lda ($74),y ; load the x offset
2627 sta $81 ; temporary (x)
2628 tay
2629 lda room_row_offsets_low,x ; read the address of the row
2630 sta $70
2631 lda #$57
2632 sta $71
2633 lda ($70),y ; load the tile above
2635 cmp #0
2636 bne move_enemy_up_exit
2638 ldy #5
2639 lda ($74),y ; dx
2640 cmp #0
2641 beq move_enemy_allow_up
2643 clc ; dx != 0 so we need to check another tile
2644 ldy $81
2645 iny
2646 lda ($70),y ; load the tile above and to the right
2648 cmp #0
2649 bne move_enemy_up_exit
2651 move_enemy_allow_up:
2652 txa
2653 ldy #2
2654 sta ($74),y ; store the new room y offset
2655 lda #3
2656 iny
2657 sta ($74),y ; dy = 3
2658 clc
2659 jmp animate_enemy_up ; optimise away the rts
2661 move_enemy_up_exit:
2662 sec
2663 rts
2665 animate_enemy_down: ; $74,$75=character address
2667 ; Set the direction and toggle the animation bit.
2669 ldy #1
2670 lda ($74),y
2671 ora #$08 ; down
2672 sta ($74),y
2674 rts
2676 move_enemy_down: ; $74,$75=character address
2678 ldy #3
2679 lda ($74),y ; dy
2680 cmp #1
2681 beq move_enemy_down_check_y
2682 cmp #3
2683 beq move_enemy_down_tile
2685 adc #1
2686 ldy #3
2687 sta ($74),y ; dy
2688 clc
2689 jmp animate_enemy_down ; optimise away the rts
2691 move_enemy_down_check_y:
2693 ; Check the y offset.
2695 ldy #2
2696 lda ($74),y
2697 cmp #9
2698 beq move_enemy_down_exit
2700 clc
2701 adc #1 ; y + 1
2702 tax
2703 ldy #4
2704 lda ($74),y ; load the x offset
2705 sta $81 ; temporary
2706 tay
2707 lda room_row_offsets_low,x ; read the address of the row
2708 sta $70
2709 lda #$57
2710 sta $71
2711 lda ($70),y ; load the tile below
2713 cmp #0
2714 bne move_enemy_down_exit
2716 ldy #5
2717 lda ($74),y ; dx
2718 cmp #0
2719 beq move_enemy_allow_down
2721 clc ; dx != 0 so we need to check another tile
2722 ldy $81 ; x
2723 iny
2724 lda ($70),y ; load the tile below and to the right
2726 cmp #0
2727 bne move_enemy_down_exit
2729 move_enemy_allow_down:
2730 clc
2732 ldy #3
2733 lda ($74),y ; dy
2734 adc #1
2735 sta ($74),y ; update dy
2736 clc
2737 jmp animate_enemy_down ; optimise away the rts
2739 move_enemy_down_tile:
2740 clc
2742 ldy #2
2743 lda ($74),y ; y
2744 adc #1
2745 sta ($74),y ; store the new room y offset
2746 lda #0
2747 iny
2748 sta ($74),y ; dy = 0
2749 clc
2750 jmp animate_enemy_down ; optimise away the rts
2752 move_enemy_down_exit:
2753 sec
2754 rts
2756 move_enemy_animate: ; $74,$75=character address
2758 ldy #1
2759 lda ($74),y ; direction/animation
2760 sta $81
2761 and #$03
2762 adc #1
2763 and #$03 ; keep animation bits
2764 sta $8f
2765 lda $81
2766 and #$fc ; mask off the animation bits
2767 ora $8f
2768 sta ($74),y
2769 rts
2771 move_enemy_next_direction: .byte $04, $0c, $00, $08
2773 move_enemy: ; $74,$75=character address
2775 lda #0
2776 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2777 lda #0
2778 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2780 lda ($74),y ; read the enemy number (Y should be zero)
2781 and #$10
2782 beq move_enemy_homing
2783 clc
2785 ; This enemy is a non-homing enemy.
2787 jsr unplot_character ; unplot now before we change the sprite used
2789 ldy #1
2790 lda ($74),y
2791 and #$f0
2792 cmp #$f0
2793 bne move_enemy_set_direction
2794 clc
2796 ldy #1
2797 lda ($74),y
2798 and #$0c
2799 ror
2800 ror
2801 tax
2802 lda move_enemy_next_direction,x
2803 sta ($74),y
2805 move_enemy_set_direction:
2806 clc
2808 ldy #1
2809 lda ($74),y
2810 sta $7b
2812 adc #$10
2813 sta ($74),y
2814 clc
2816 lda $7b
2817 and #$04
2818 ror
2819 ror
2820 adc #1
2821 sta $8e
2823 lda $7b
2824 and #$08
2825 ror
2826 ror
2827 ror
2828 adc #1
2829 sta $8d
2831 jmp move_enemy_with_direction
2833 move_enemy_homing:
2835 ldy #2
2836 lda ($74),y ; y
2837 cmp $5282 ; player y
2838 bmi move_enemy_downwards
2839 bne move_enemy_upwards
2841 ldy #3
2842 lda ($74),y ; dy
2843 cmp $5283 ; player y
2844 beq move_enemy_horizontally
2845 bpl move_enemy_upwards
2847 move_enemy_downwards:
2848 lda #2
2849 sta $8d
2850 jmp move_enemy_horizontally
2852 move_enemy_upwards:
2853 lda #1
2854 sta $8d
2855 ;jmp move_enemy_horizontally
2857 move_enemy_horizontally:
2858 ldy #4
2859 lda ($74),y ; x
2860 cmp $5284 ; player x
2861 bmi move_enemy_rightwards
2862 bne move_enemy_leftwards
2864 ldy #5
2865 lda ($74),y ; dx
2866 cmp #0
2867 beq move_enemy_with_direction_unplot
2868 bpl move_enemy_leftwards
2870 move_enemy_rightwards:
2871 lda #2
2872 sta $8e
2873 jmp move_enemy_with_direction_unplot
2875 move_enemy_leftwards:
2876 lda #1
2877 sta $8e
2879 move_enemy_with_direction_unplot:
2880 clc
2882 jsr unplot_character
2884 move_enemy_with_direction:
2885 clc
2887 lda $8e
2888 cmp #1
2889 bne move_enemy_not_left
2890 jsr move_enemy_left
2891 clc
2892 jmp move_enemy_not_right
2894 move_enemy_not_left:
2895 lda $8e
2896 cmp #2
2897 bne move_enemy_not_right
2898 jsr move_enemy_right
2899 clc
2901 move_enemy_not_right:
2902 lda $8d
2903 cmp #1
2904 bne move_enemy_not_up
2905 jsr move_enemy_up
2906 clc
2907 jmp move_enemy_toggle
2909 move_enemy_not_up:
2910 lda $8d
2911 cmp #2
2912 bne move_enemy_toggle
2913 jsr move_enemy_down
2915 move_enemy_toggle:
2916 clc
2917 jsr move_enemy_animate
2918 jmp plot_character ; optimise away the rts
2920 move_enemy_exit:
2921 clc
2922 rts
2924 create_explosion: ; X=y, Y=x
2926 lda #3
2927 sta $52a4
2928 lda #4
2929 sta $52a5
2930 txa
2931 sta $52a6
2932 lda #1
2933 sta $52a7
2934 tya
2935 sta $52a8
2936 lda #0
2937 sta $52a9
2938 rts
2940 move_projectile_left:
2942 lda $528b
2943 cmp #0
2944 beq move_projectile_left_check_x
2946 dec $528b
2947 clc
2948 rts
2950 move_projectile_left_check_x:
2952 lda $528a
2953 cmp #0
2954 bne move_projectile_left_in_room
2955 jmp move_projectile_left_exit
2957 move_projectile_left_in_room:
2958 tay
2959 dey ; x - 1
2960 ldx $5288 ; y
2961 lda room_row_offsets_low,x ; read the address of the row
2962 sta $70
2963 lda #$57
2964 sta $71
2965 lda ($70),y ; load the tile to the left
2967 cmp #0
2968 bne move_projectile_left_wall
2970 lda $5289 ; dy
2971 cmp #3
2972 bmi move_projectile_allow_left
2974 clc ; dy > 2 so we need to check another tile
2975 lda $70
2976 adc #10
2977 sta $70
2978 lda ($70),y ; load the tile below and to the left
2979 inx ; y += 1
2981 cmp #0
2982 bne move_projectile_left_wall
2984 move_projectile_allow_left:
2986 sty $528a ; x
2987 lda #3
2988 sta $528b ; dx = 3
2990 clc
2991 rts
2993 move_projectile_left_wall: ; the projectile hit a wall
2994 clc
2996 lda $5287 ; type 2 can pass through walls
2997 and #$06
2998 cmp #4
2999 beq move_projectile_allow_left
3001 cmp #2
3002 bne move_projectile_left_not_boomerang
3004 lda $5287
3005 and #$0f
3006 cmp #8
3007 bpl move_projectile_left_exit
3009 ldx $577f ; weapon counter
3010 ora boomerang_horizontal,x
3011 sta $5287
3012 clc
3013 rts ; exit without moving or registering a collision
3015 move_projectile_left_not_boomerang:
3017 cmp #6 ; type 3 can destroy certain walls
3018 bne move_projectile_left_exit
3020 lda ($70),y ; load the tile to the left
3021 cmp #1 ; decoration can be destroyed
3022 bne move_projectile_left_exit
3023 clc
3025 lda #0
3026 sta ($70),y
3028 ; X=y, Y=x
3029 jsr create_explosion
3030 jsr plot_blank_xy ; corrupted X
3032 lda #$a4
3033 sta $74
3034 lda #$52
3035 sta $75
3036 jsr plot_character
3038 ldx #0
3039 jsr play_sound
3041 lda #16 ; prevent the player from firing a new
3042 sta $578d ; projectile until the explosion has finished
3044 move_projectile_left_exit:
3045 sec
3046 rts
3048 boomerang_horizontal: .byte $28, $38
3050 move_projectile_right:
3052 ; Fire right.
3054 lda $528b
3055 cmp #2
3056 beq move_projectile_right_check_x
3057 cmp #3
3058 beq move_projectile_right_tile
3060 inc $528b
3061 clc
3062 rts
3064 move_projectile_right_check_x:
3066 lda $528a ; x
3067 cmp #9
3068 bne move_projectile_right_not_edge
3069 jmp move_projectile_right_exit
3071 move_projectile_right_not_edge:
3072 clc
3073 tay
3074 iny ; x + 1
3075 ldx $5288 ; y
3076 lda room_row_offsets_low,x ; read the address of the row
3077 sta $70
3078 lda #$57
3079 sta $71
3080 lda ($70),y ; load the tile to the right
3082 cmp #0
3083 bne move_projectile_right_wall
3085 lda $5289 ; dy
3086 cmp #3
3087 bmi move_projectile_allow_right
3089 clc ; dy > 2 so we need to check another tile
3090 lda $70
3091 adc #10
3092 sta $70
3093 lda ($70),y ; load the tile below and to the right
3094 inx ; y += 1
3096 cmp #0
3097 bne move_projectile_right_wall
3099 move_projectile_allow_right:
3101 inc $528b ; dx
3102 clc
3103 rts
3105 move_projectile_right_tile:
3107 inc $528a ; x
3108 lda #0
3109 sta $528b ; dx
3110 clc
3111 rts
3113 move_projectile_right_wall: ; the projectile hit a wall
3114 clc
3116 lda $5287 ; type 2 can pass through walls
3117 and #$06
3118 cmp #4
3119 beq move_projectile_allow_right
3121 cmp #2
3122 bne move_projectile_right_not_boomerang
3124 lda $5287
3125 and #$0f
3126 cmp #8
3127 bpl move_projectile_right_exit
3129 ldx $577f ; weapon counter
3130 ora boomerang_horizontal,x
3131 sta $5287
3132 clc
3133 rts ; exit without moving or registering a collision
3135 move_projectile_right_not_boomerang:
3137 cmp #6 ; type 3 can destroy certain walls
3138 bne move_projectile_right_exit
3140 lda ($70),y ; load the tile to the right
3141 cmp #1 ; decoration can be destroyed
3142 bne move_projectile_right_exit
3143 clc
3145 lda #0
3146 sta ($70),y
3148 ; X=y, Y=x
3149 jsr create_explosion
3150 jsr plot_blank_xy ; corrupted X
3152 lda #$a4
3153 sta $74
3154 lda #$52
3155 sta $75
3156 jsr plot_character
3158 ldx #0
3159 jsr play_sound
3161 lda #16 ; prevent the player from firing a new
3162 sta $578d ; projectile until the explosion has finished
3164 move_projectile_right_exit:
3165 sec
3166 rts
3168 move_projectile_up:
3170 lda $5289 ; read dy
3171 cmp #0
3172 beq move_projectile_up_check_y
3174 dec $5289
3175 clc
3176 rts
3178 move_projectile_up_check_y: ; Check the y offset.
3180 lda $5288
3181 cmp #0
3182 bne move_projectile_up_not_edge
3183 jmp move_projectile_up_exit
3185 move_projectile_up_not_edge:
3186 tax ; use the y offset as an index
3187 dex ; y - 1
3188 ldy $528a ; load the x offset
3189 lda room_row_offsets_low,x ; read the address of the row
3190 sta $70
3191 lda #$57
3192 sta $71
3193 lda ($70),y ; load the tile above
3195 cmp #0
3196 bne move_projectile_up_wall
3198 lda $528b ; dx
3199 cmp #3
3200 bmi move_projectile_allow_up
3202 clc ; dx > 2 so we need to check another tile
3203 iny
3204 lda ($70),y ; load the tile above and to the right
3206 cmp #0
3207 bne move_projectile_up_wall
3209 move_projectile_allow_up:
3210 txa
3211 sta $5288 ; store the new room y offset
3212 lda #3
3213 sta $5289 ; dy = 3
3215 clc
3216 rts
3218 move_projectile_up_wall: ; the projectile hit a wall
3219 clc
3221 lda $5287 ; type 2 can pass through walls
3222 and #$06
3223 cmp #4
3224 beq move_projectile_allow_up
3226 cmp #2
3227 bne move_projectile_up_not_boomerang
3229 lda $5287
3230 and #$0f
3231 cmp #8
3232 bpl move_projectile_up_exit
3234 ldx $577f ; weapon counter
3235 ora boomerang_vertical,x
3236 sta $5287
3237 clc
3238 rts ; exit without moving or registering a collision
3240 move_projectile_up_not_boomerang:
3242 cmp #6 ; type 3 can destroy certain walls
3243 bne move_projectile_up_exit
3245 lda ($70),y ; load the tile above
3246 cmp #1 ; decoration can be destroyed
3247 bne move_projectile_up_exit
3248 clc
3250 lda #0
3251 sta ($70),y
3253 ; X=y, Y=x
3254 jsr create_explosion
3255 jsr plot_blank_xy ; corrupted X
3257 lda #$a4
3258 sta $74
3259 lda #$52
3260 sta $75
3261 jsr plot_character
3263 ldx #0
3264 jsr play_sound
3266 lda #16 ; prevent the player from firing a new
3267 sta $578d ; projectile until the explosion has finished
3269 move_projectile_up_exit:
3270 sec
3271 rts
3273 boomerang_vertical: .byte $08, $18
3275 move_projectile_down:
3277 lda $5289 ; read dy
3278 cmp #2
3279 beq move_projectile_down_check_y
3280 cmp #3
3281 beq move_projectile_down_tile
3283 inc $5289 ; 0 <= dy < 3
3284 clc
3285 rts
3287 move_projectile_down_check_y: ; Check the y offset.
3289 lda $5288
3290 cmp #9
3291 bne move_projectile_down_in_room
3292 jmp move_projectile_down_exit
3294 move_projectile_down_in_room:
3295 clc
3296 tax
3297 inx ; y + 1
3298 ldy $528a ; load the x offset
3299 lda room_row_offsets_low,x ; read the address of the row
3300 sta $70
3301 lda #$57
3302 sta $71
3303 lda ($70),y ; load the tile below
3305 cmp #0
3306 bne move_projectile_down_wall
3308 lda $528b ; dx
3309 cmp #3
3310 bmi move_projectile_allow_down
3312 clc ; dx > 2 so we need to check another tile
3313 iny
3314 lda ($70),y ; load the tile below and to the right
3316 cmp #0
3317 bne move_projectile_down_wall
3319 move_projectile_allow_down:
3321 inc $5289 ; update dy
3322 clc
3323 rts
3325 move_projectile_down_tile:
3327 inc $5288 ; store the new room y offset
3328 lda #0
3329 sta $5289 ; dy = 0
3330 clc
3331 rts
3333 move_projectile_down_wall: ; the projectile hit a wall
3334 clc
3336 lda $5287 ; type 2 can pass through walls
3337 and #$06
3338 cmp #4
3339 beq move_projectile_allow_down
3341 cmp #2
3342 bne move_projectile_down_not_boomerang
3344 lda $5287
3345 and #$0f
3346 cmp #8
3347 bpl move_projectile_down_exit
3349 ldx $577f ; weapon counter
3350 ora boomerang_vertical,x
3351 sta $5287
3352 clc
3353 rts ; exit without moving or registering a collision
3355 move_projectile_down_not_boomerang:
3357 cmp #6 ; type 3 can destroy certain walls
3358 bne move_projectile_down_exit
3360 lda ($70),y ; load the tile below
3361 cmp #1 ; decoration can be destroyed
3362 bne move_projectile_down_exit
3363 clc
3365 lda #0
3366 sta ($70),y
3368 ; X=y, Y=x
3369 jsr create_explosion
3370 jsr plot_blank_xy ; corrupted X
3372 lda #$a4
3373 sta $74
3374 lda #$52
3375 sta $75
3376 jsr plot_character
3378 ldx #0
3379 jsr play_sound
3381 lda #16 ; prevent the player from firing a new
3382 sta $578d ; projectile until the explosion has finished
3384 move_projectile_down_exit:
3385 sec
3386 rts
3388 move_projectile_animate:
3390 lda $5287
3391 eor #1
3392 sta $5287
3393 rts
3395 move_projectile:
3397 lda $5286
3398 cmp #0
3399 bne move_projectile_move
3400 jmp move_projectile_exit
3402 move_projectile_move:
3403 clc
3405 lda #$86
3406 sta $74
3407 lda #$52
3408 sta $75
3409 jsr unplot_character
3411 move_projectile_after_unplot:
3413 lda $5287
3414 and #$30 ; direction
3416 cmp #0
3417 bne move_projectile_not_left
3419 jsr move_projectile_left
3420 bcc move_projectile_toggle
3421 bcs move_projectile_destroy
3423 move_projectile_not_left:
3424 cmp #$10
3425 bne move_projectile_not_right
3427 jsr move_projectile_right
3428 bcc move_projectile_toggle
3429 bcs move_projectile_destroy
3431 move_projectile_not_right:
3432 cmp #$20
3433 bne move_projectile_not_up
3435 jsr move_projectile_up
3436 bcc move_projectile_toggle
3437 bcs move_projectile_destroy
3439 move_projectile_not_up:
3440 cmp #$30
3441 bne move_projectile_toggle
3443 jsr move_projectile_down
3444 bcs move_projectile_destroy
3446 move_projectile_toggle:
3448 jsr projectile_collide
3449 bcs move_projectile_destroy
3451 jsr move_projectile_animate
3453 lda #$86
3454 sta $74
3455 lda #$52
3456 sta $75
3457 jmp plot_character ; optimise away the rts
3459 move_projectile_destroy:
3460 clc
3462 ldy #0
3463 lda ($74),y ; type
3464 cmp #8
3465 bmi move_projectile_no_enemy_collision
3467 and #$70 ; increase the player's score
3468 lsr
3469 lsr
3470 lsr
3471 adc #2
3472 sta $70
3473 jsr add_score
3474 jmp move_projectile_create_explosion
3476 move_projectile_no_enemy_collision:
3478 cmp #4 ; items can be destroyed as well
3479 bne move_projectile_no_item_collision
3481 ldy #1 ; but not keys
3482 lda ($74),y
3483 cmp #4 ; even the mace is stopped by a key
3484 beq move_projectile_remove_projectile
3485 clc
3487 jsr remove_room_item
3489 move_projectile_create_explosion:
3491 ; Unplot the item/enemy and replace it with an explosion.
3493 jsr unplot_character
3495 lda #3 ; explosion
3496 ldy #0
3497 sta ($74),y
3499 lda #4
3500 ldy #1
3501 sta ($74),y
3503 jsr plot_character
3505 ; Play a sound.
3506 ldx #0
3507 jsr play_sound
3509 move_projectile_no_item_collision:
3511 lda $5287 ; type 2 projectiles pass through everything
3512 and #$06
3513 cmp #4
3514 bne move_projectile_remove_projectile
3516 ; Ideally, we would have recorded if the projectile left the screen so
3517 ; that we don't perform these checks again here, but it would just add
3518 ; overhead to the normal movement routines for the other weapons.
3520 lda $5288 ; y
3521 cmp #0
3522 beq move_projectile_remove_projectile
3523 cmp #9
3524 beq move_projectile_remove_projectile
3526 lda $528a ; x
3527 cmp #0
3528 beq move_projectile_remove_projectile
3529 cmp #9
3530 beq move_projectile_remove_projectile
3532 clc
3533 lda #$86
3534 sta $74
3535 lda #$52
3536 sta $75
3538 jsr plot_character
3539 jmp move_projectile_exit
3541 move_projectile_remove_projectile:
3543 lda #0 ; remove the projectile from the character list
3544 sta $5286
3546 move_projectile_exit:
3547 clc
3548 rts
3550 emerge_characters:
3552 lda #$8c ; set the character address
3553 sta $74
3554 lda #$52
3555 sta $75
3557 emerge_characters_loop:
3559 ldy #0
3560 lda ($74),y
3561 cmp #0
3562 bne emerge_characters_next
3564 jmp emerge_character ; optimise away the rts
3566 emerge_characters_next:
3567 clc
3569 ; Examine the next character.
3570 lda $74
3571 adc #6
3573 cmp #$a4
3574 bpl emerge_characters_exit
3575 sta $74
3576 jmp emerge_characters_loop
3578 emerge_characters_exit:
3579 clc
3580 rts
3582 enemy_slots: .byte 0, 6, 12, 18
3584 move_characters:
3586 lda #$8c ; set the character address
3587 sta $74
3588 lda #$52
3589 sta $75
3591 lda $578e ; read a value from 0 to 3 from the motion counter
3592 and #3
3593 tax
3594 lda enemy_slots,x ; look up the corresponding slot in the character list
3595 adc $74
3596 sta $74 ; update the character address
3598 move_characters_loop:
3600 ldy #0
3601 lda ($74),y
3602 cmp #3
3603 bne move_characters_not_emerge_explode
3605 jsr emerge_explode
3606 jmp move_characters_next
3608 move_characters_not_emerge_explode:
3609 cmp #8
3610 bmi move_characters_next
3612 jsr move_enemy
3614 move_characters_next:
3615 clc
3617 lda $74 ; for the last enemy, check the next slot
3618 cmp #$9e ; for the presence of an explosion
3619 bne move_characters_endloop ; otherwise leave the loop (only performing
3620 clc ; one iteration)
3622 adc #6
3623 sta $74
3624 jmp move_characters_loop
3626 move_characters_endloop:
3627 clc
3629 ; Check collisions with the player.
3631 jsr player_collide
3632 bcs move_characters_collisions
3633 jmp move_characters_exit
3635 move_characters_collisions:
3636 clc
3638 ldy #0
3639 lda ($74),y ; type
3640 cmp #8
3641 bpl move_character_destroy_enemy
3643 ; Unplot the item.
3644 jsr unplot_character
3646 ; Remove it from the item table.
3647 jsr remove_room_item
3649 lda #0 ; remove the item from the character list
3650 ldy #0
3651 sta ($74),y
3653 iny
3654 lda ($74),y ; get the item type
3656 sta $8d ; temporarily store A and increase the score
3657 tax
3658 lda item_scores,x
3659 sta $70
3660 jsr add_score
3661 lda $8d
3663 ; Check the item type.
3664 cmp #8
3665 bmi move_characters_not_health
3667 lda #20
3668 sta $70
3669 jsr add_strength
3670 clc
3672 ldx #2
3673 jsr play_sound
3675 rts
3677 move_characters_not_health:
3678 cmp #5
3679 bmi move_characters_not_treasure
3681 ldx #2
3682 jsr play_sound
3684 clc
3685 rts
3687 move_characters_not_treasure:
3688 cmp #4
3689 bmi move_characters_not_key
3691 ; Key - update the item/player flags byte.
3692 lda $5780
3693 ora #$01
3694 sta $5780
3695 clc
3697 ldx #3
3698 jsr play_sound
3700 rts
3702 move_characters_not_key:
3704 ; Update the player's weapon.
3705 asl
3706 sta $5789
3707 clc
3709 ldx #2
3710 jsr play_sound
3712 rts
3714 move_character_destroy_enemy:
3716 ; Unplot the enemy and replace it with an explosion.
3718 jsr unplot_character
3720 lda #3 ; explosion
3721 ldy #0
3722 sta ($74),y
3724 lda #4
3725 ldy #1
3726 sta ($74),y
3728 jsr plot_character
3730 ; Reduce the player's strength.
3732 ldx #1
3733 jsr play_sound
3735 lda #1
3736 sta $70
3737 jmp reduce_strength ; optimise away the rts
3739 move_characters_exit:
3740 clc
3741 rts
3743 remove_room_item:
3745 ldx $5782 ; current room row number
3746 lda eleven_times_table,x
3747 adc $5783 ; current room column number
3748 tax
3749 lda #$80 ; store a value with the top bit set instead of zero because we
3750 sta $5200,x ; have visited this room if we can collect the object within it
3751 clc
3752 rts
3754 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3755 score_vdu_bytes: .byte 1,1,31 ; reversed
3756 score_digits: .byte "0123456789"
3758 add_score: ; $70=score to add
3760 sed
3761 lda $5786
3762 adc $70
3763 sta $5786
3764 lda $5787
3765 adc #0
3766 sta $5787
3767 lda $5788
3768 adc #0
3769 sta $5788
3770 cld
3772 write_score:
3774 lda #$86
3775 sta $70
3776 lda #$57
3777 sta $71
3779 ldx #2
3780 write_score_vdu_bytes:
3781 lda score_vdu_bytes,x
3782 jsr $ffee
3783 dex
3784 bpl write_score_vdu_bytes
3786 write_score_digits: ; $70,$71=address of score bytes
3788 ldy #2
3789 write_score_loop:
3791 lda ($70),y
3792 lsr
3793 lsr
3794 lsr
3795 lsr
3796 tax
3797 lda score_digits,x
3798 jsr $ffee
3800 lda ($70),y
3801 and #$0f
3802 tax
3803 lda score_digits,x
3804 jsr $ffee
3806 dey
3807 bpl write_score_loop
3809 clc
3810 rts
3812 strength_units: .byte $00,$88,$cc,$ee
3814 add_strength: ; $70=strength to add
3816 ; Divide the initial strength by 4 to determine which half character to
3817 ; start plotting at, and multiply by 8 to get the address. The net result
3818 ; is to mask off the bottom two bits and shift left once.
3819 lda $5784
3820 and #$fc
3821 sta $71 ; strength rounded down to a multiple of four units
3822 asl
3823 clc
3824 tay
3826 lda $5784
3827 adc $70
3828 cmp #65
3829 bmi add_strength_update
3831 lda #64
3833 add_strength_update:
3834 clc
3835 sta $5784 ; the final strength
3837 sec
3838 sbc $71
3839 clc
3840 tax ; the number of units to add between the rounded original
3841 ; strength and the final strength
3843 lda #$f3 ; the start of the strength bar
3844 sta $72
3845 lda #$59
3846 sta $73
3848 cpx #4
3849 bmi add_strength_loop_extra
3851 add_strength_loop:
3853 clc
3854 lda #$ff
3855 sta ($72),y
3857 tya
3858 adc #8
3859 tay
3861 txa
3862 sec
3863 sbc #4
3864 clc
3865 tax
3867 cmp #4
3868 bpl add_strength_loop
3870 add_strength_loop_extra:
3871 cpx #0
3872 beq add_strength_exit
3874 ; For any remaining units in excess of the multiples of four units, plot
3875 ; the appropriate byte.
3876 lda $5784
3877 and #3
3878 tax
3880 lda strength_units,x
3881 sta ($72),y
3883 add_strength_exit:
3884 clc
3885 rts
3887 reduce_strength: ; $70=strength to remove
3889 lda $5784
3890 tax
3891 sec
3892 sbc $70
3893 bpl reduce_strength_update
3895 lda #0
3897 reduce_strength_update:
3898 clc
3899 sta $5784
3901 ; Divide the final strength by 4 to determine which half character to
3902 ; plot, and multiply by 8 to get the address. The net result is to mask off
3903 ; the bottom two bits and shift left once.
3904 and #$fc
3905 asl
3906 tay
3908 lda #$f3 ; the start of the strength bar
3909 sta $70
3910 lda #$59
3911 sta $71
3913 lda $5784
3914 and #3
3915 tax
3916 lda strength_units,x
3917 sta ($70),y
3919 lda $5784
3920 cmp #0
3921 bne reduce_strength_exit
3923 lda $5780 ; the player ran out of strength
3924 ora #$40
3925 sta $5780
3927 lda #64 ; reset the delay counter
3928 sta $5785
3930 lda #$80 ; unplot the player
3931 sta $74
3932 lda #$52
3933 sta $75
3935 jsr unplot_character
3937 lda #8 ; change the player's direction to the demise animation
3938 sta $5281
3940 jsr plot_character
3941 jmp destroy_enemies ; optimise away the rts
3943 reduce_strength_exit:
3944 clc
3945 rts
3947 destroy_enemies:
3949 lda #$8c
3950 sta $74
3951 lda #$52
3952 sta $75
3954 destroy_enemies_loop:
3956 ldy #0
3957 lda ($74),y
3958 cmp #8
3959 bmi destroy_enemies_not_enemy
3961 jsr unplot_character
3963 lda #3 ; emerge/explosion
3964 ldy #0
3965 sta ($74),y
3967 iny
3968 lda #4 ; explosion
3969 sta ($74),y
3971 jsr plot_character
3972 jmp destroy_enemies_not_emerging_enemy
3974 destroy_enemies_not_enemy:
3975 cmp #3
3976 bne destroy_enemies_not_emerging_enemy
3978 jsr unplot_character
3980 iny ; whether emerging or exploding, ensure that the enemy
3981 lda ($74),y ; is now exploding
3982 ora #4
3983 sta ($74),y
3985 jsr plot_character
3987 destroy_enemies_not_emerging_enemy:
3988 clc
3989 lda $74
3990 adc #6
3991 sta $74
3992 cmp #$a4
3993 bmi destroy_enemies_loop
3995 clc
3996 rts
3998 remove_characters:
4000 ; Clear the character table.
4002 ldx #6
4003 remove_characters_loop:
4004 lda #0
4005 sta $5280,x
4006 txa
4007 adc #6
4008 tax
4009 cpx #$2a
4010 bmi remove_characters_loop
4012 rts
4014 ; The player collision masks use bits to represent where the player is in a
4015 ; tile. See the collisions.txt file for more information.
4017 ; Player is above, enemy is below, checking the overlap in the lower tile.
4018 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4020 projectile_collision_mask_above: .byte $00, $00, $00, $80
4022 ; Player and enemy share the same tile or player is on the tile below.
4023 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4025 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4027 ; Player is above or on the same tile, enemy is below, checking the overlap in
4028 ; the lower tile.
4029 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4031 ; Enemy is above, player is below, checking the overlap in the lower tile.
4032 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4034 ; Player is to the left, enemy is to the right, checking the overlap in the
4035 ; right hand tile.
4036 player_collision_mask_left:
4037 projectile_collision_mask_left: .byte $00, $00, $00, $08
4039 ; Player and enemy share the same tile or player is on the tile to the right.
4040 player_collision_mask_right:
4041 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4043 ; Player is to the left, enemy is to the right or on the same tile, checking
4044 ; the overlap in the right hand tile.
4045 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4047 ; Enemy is to the left, player is to the right, checking the overlap in the
4048 ; right hand tile.
4049 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4051 player_collide:
4053 lda $5282 ; player y
4054 sta $8a
4055 lda $5284 ; player x
4056 sta $8b
4058 ldx $5283 ; player dy
4059 lda player_collision_mask_above,x
4060 sta $86
4061 lda player_collision_mask_below,x
4062 sta $88
4063 ldx $5285 ; player dx
4064 lda player_collision_mask_left,x
4065 sta $87
4066 lda player_collision_mask_right,x
4067 sta $89
4069 jmp collide ; optimise away the rts
4071 projectile_collide:
4073 lda $5288 ; projectile y
4074 sta $8a
4075 lda $528a ; projectile x
4076 sta $8b
4078 ldx $5289 ; projectile dy
4079 lda projectile_collision_mask_above,x
4080 sta $86
4081 lda projectile_collision_mask_below,x
4082 sta $88
4083 ldx $528b ; projectile dx
4084 lda projectile_collision_mask_left,x
4085 sta $87
4086 lda projectile_collision_mask_right,x
4087 sta $89
4089 ; Run on into the next routine.
4091 collide:
4093 lda #$8c ; set the character address
4094 sta $74
4095 lda #$52
4096 sta $75
4098 collide_loop:
4100 ldy #0
4101 lda ($74),y ; type
4102 cmp #4
4103 bpl collide_check
4105 jmp collide_next
4107 collide_check:
4109 ldy #2
4110 lda ($74),y ; y
4111 sec
4112 sbc $8a ; y - player/projectile y
4113 beq check_collide_y_equal
4114 cmp #1
4115 beq check_collide_y_greater
4116 cmp #255
4117 beq check_collide_y_less
4119 jmp collide_next
4121 check_collide_y_equal:
4122 ; The enemy is on the same tile as the player/projectile so look at the
4123 ; collision on their common tile.
4124 ldy #3
4125 lda ($74),y ; dy
4126 tax
4127 lda enemy_collision_mask_above,x
4128 and $88 ; player/projectile mask below
4129 bne check_collide_x
4131 jmp collide_next
4133 check_collide_y_greater:
4134 ; The enemy is on the tile below the player/projectile so look at the
4135 ; collision on the enemy's tile.
4136 ldy #3
4137 lda ($74),y ; dy
4138 tax
4139 lda enemy_collision_mask_above,x
4140 and $86 ; player mask above
4141 bne check_collide_x
4143 jmp collide_next
4145 check_collide_y_less:
4146 ; The enemy is on the tile above the player/projectile so look at the
4147 ; collision on the player's tile.
4148 ldy #3
4149 lda ($74),y ; dy
4150 tax
4151 lda enemy_collision_mask_below,x
4152 and $88 ; player mask below
4153 bne check_collide_x
4155 jmp collide_next
4157 check_collide_x:
4158 ldy #4
4159 lda ($74),y ; x
4160 sec
4161 sbc $8b ; x - player/projectile x
4162 beq check_collide_x_equal
4163 cmp #1
4164 beq check_collide_x_greater
4165 cmp #255
4166 beq check_collide_x_less
4168 jmp collide_next
4170 check_collide_x_equal:
4171 ; The enemy is on the same tile as the player/projectile so look at the
4172 ; collision on their common tile.
4173 ldy #5
4174 lda ($74),y ; dx
4175 tax
4176 lda enemy_collision_mask_left,x
4177 and $89 ; player mask right
4178 bne check_collide_destroy
4180 jmp collide_next
4182 check_collide_x_greater:
4183 ; The enemy is the tile to the right of the player/projectile so look
4184 ; at the collision on the enemy's tile.
4185 ldy #5
4186 lda ($74),y ; dx
4187 tax
4188 lda enemy_collision_mask_left,x
4189 and $87 ; player mask left
4190 bne check_collide_destroy
4192 jmp collide_next
4194 check_collide_x_less:
4195 ; The enemy is the tile to the left of the player/projectile so look at
4196 ; the collision on the player's tile.
4197 ldy #5
4198 lda ($74),y ; dx
4199 tax
4200 lda enemy_collision_mask_right,x
4201 and $89 ; player mask right
4202 bne check_collide_destroy
4204 collide_next:
4205 clc
4207 ; Examine the next character.
4208 lda $74
4209 adc #6
4211 cmp #$a4
4212 bpl collide_exit
4213 sta $74
4214 jmp collide_loop
4216 check_collide_destroy:
4218 sec ; set the carry flag to inform the caller that the
4219 rts ; player/projectile should be destroyed
4221 collide_exit:
4222 clc
4223 rts
4225 blank_screen:
4226 lda #1
4227 sta $70
4228 lda #0
4229 sta $71
4230 jsr set_palette
4231 lda #2
4232 sta $70
4233 lda #0
4234 sta $71
4235 jsr set_palette
4236 lda #3
4237 sta $70
4238 lda #0
4239 sta $71
4240 ; Run on into set_palette.
4242 set_palette:
4243 ; $70=logical colour
4244 ; $71=physical colour
4245 lda $70
4246 sta $578b
4247 lda $71
4248 sta $578c
4249 lda #0
4250 sta $578d
4251 sta $578e
4252 sta $578f
4254 lda #$c
4255 ldx #$8b
4256 ldy #$57
4257 jsr $fff1
4258 rts
4260 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4261 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4263 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4264 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4265 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4266 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4267 note_sound: .byte $13,0, 241,255
4268 note_pitch: .byte 0,0
4269 note_duration: .byte 4,0
4270 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4272 play_note: ; A=pitch, Y=duration
4274 sta note_pitch
4275 sty note_duration
4276 ldx #4
4277 ; Run on into the next routine.
4279 play_sound: ; X=sound number
4281 lda sounds_high,x
4282 tay
4283 lda sounds_low,x
4284 tax
4285 lda #7
4286 jsr $fff1
4288 rts
4290 copy_title_up:
4292 lda #$00
4293 sta $70
4294 lda #$18
4295 sta $71
4297 lda #$a0
4298 sta $72
4299 lda #$5a
4300 sta $73
4302 ldx #5
4303 ; Run on into the next routine.
4305 copy_title:
4307 copy_title_loop1:
4309 ldy #0
4310 copy_title_loop2:
4312 lda ($70),y
4313 sta ($72),y
4314 iny
4315 cpy #0
4316 bne copy_title_loop2
4318 clc
4319 lda $72
4320 adc #$40
4321 sta $72
4322 lda $73
4323 adc #$01
4324 sta $73
4325 clc
4327 lda $71
4328 adc #$01
4329 sta $71
4330 clc
4332 dex
4333 bpl copy_title_loop1
4335 rts
4337 copy_completed_screen_up:
4339 lda #$00
4340 sta $70
4341 lda #$0f
4342 sta $71
4344 lda #$60
4345 sta $72
4346 lda #$5e
4347 sta $73
4349 ldx #8
4350 jmp copy_title ; optimise away the rts
4352 init:
4353 jsr cls ; clear the text window
4355 lda #26 ; unset the text window
4356 jsr $ffee
4358 ; Define the default high scores.
4359 ldy #0
4360 lda #$80
4361 sta $70
4362 lda #$51
4363 sta $71
4364 lda #$16
4365 sta $72
4367 ldx #0
4368 init_define_high_scores_loop:
4370 lda #0
4371 sta ($70),y
4372 iny
4373 lda $72
4374 sta ($70),y
4375 iny
4376 lda #0
4377 sta ($70),y
4379 iny
4380 init_define_high_score_name_loop:
4382 lda high_score_default_name1,x
4383 sta ($70),y
4384 iny
4385 inx
4386 cpx #9
4387 beq init_define_high_scores_next
4388 cpx #18
4389 bne init_define_high_score_name_loop
4391 ldx #0
4392 init_define_high_scores_next:
4394 sed
4395 lda $72
4396 sec
4397 sbc #2
4398 sta $72
4399 cld
4400 clc
4402 cpy #96
4403 bne init_define_high_scores_loop
4405 ; Disable joystick support.
4406 lda #0
4407 sta $577e
4409 rts
4411 high_score_default_name1: .byte "RETRO "
4412 high_score_default_name2: .byte " SOFTWARE"
4414 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4415 input_message: .byte 17,2, 31,1,27, "Press SPACE / FIRE"
4416 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4417 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4418 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4419 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4421 set_standard_palette:
4423 lda #1
4424 sta $70
4425 lda #1
4426 sta $71
4427 jsr set_palette
4429 jmp set_core_palette ; optimise away the rts
4431 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4433 set_complete_palette:
4435 lda #0
4436 sta $80
4437 lda #25
4438 sta $81
4440 set_complete_palette_loop:
4442 jsr wait_for_vsync
4444 dec $81
4445 lda $81
4446 cmp #0
4447 bne set_complete_palette_loop
4449 lda #25
4450 sta $81
4452 ldx $80
4453 lda complete_palette_bytes,x
4454 sta $70
4455 inx
4456 lda complete_palette_bytes,x
4457 sta $71
4458 inx
4459 stx $80
4460 jsr set_palette
4462 lda $80
4463 cmp #10
4464 bne set_complete_palette_loop
4466 rts
4468 set_hidden_palette:
4470 lda #1
4471 sta $70
4472 lda #0
4473 sta $71
4474 jsr set_palette
4476 ; Run on into the next routine.
4478 set_core_palette:
4480 lda #2
4481 sta $70
4482 lda #2
4483 sta $71
4484 jsr set_palette
4486 lda #3
4487 sta $70
4488 lda #3
4489 sta $71
4490 jsr set_palette
4492 rts
4494 show_title:
4496 jsr set_standard_palette
4498 ldx #0
4499 write_title_text_loop:
4500 lda title_vdu_bytes,x
4501 jsr $ffee
4502 inx
4503 cpx #12
4504 bmi write_title_text_loop
4506 jsr show_input_message
4508 ; Show the title.
4509 jsr copy_title_up
4511 ; Show the high scores.
4513 jsr colour1
4515 lda #$80
4516 sta $70
4517 lda #$51
4518 sta $71
4520 lda #8
4521 sta $80
4523 show_title_high_scores_loop:
4525 lda #31
4526 jsr $ffee
4527 lda #2
4528 jsr $ffee
4529 lda $80
4530 adc #2
4531 sta $80
4532 clc
4533 jsr $ffee
4535 jsr write_score_digits
4537 lda #32
4538 jsr $ffee
4540 ldx #8
4541 ldy #3
4542 show_title_high_scores_vdu_loop2:
4544 lda ($70),y
4545 cmp #32
4546 bmi ignore_char
4547 cmp #123
4548 bpl ignore_char
4549 jsr $ffee
4551 ignore_char:
4552 iny
4553 dex
4554 bpl show_title_high_scores_vdu_loop2
4556 lda $70
4557 adc #12
4558 sta $70
4559 cmp #$e0
4560 bne show_title_high_scores_loop
4562 lda #0 ; message counter
4563 sta $72
4565 show_title_wait_loop:
4567 lda #150
4568 sta $5785
4570 ldx $72
4571 ldy #22
4572 show_title_wait_message_loop:
4574 lda title_vdu_bytes1,x
4575 jsr $ffee
4576 inx
4577 dey
4578 bpl show_title_wait_message_loop
4580 cpx #92
4581 beq show_title_wait_reset_offset
4583 txa
4584 sta $72
4585 jmp show_title_wait_inner_loop
4587 show_title_wait_reset_offset:
4588 lda #0
4589 sta $72
4591 show_title_wait_inner_loop:
4592 jsr wait_for_vsync
4594 dec $5785
4595 beq show_title_wait_loop
4597 show_title_wait_loop_no_update:
4598 lda #128
4599 ldx #0
4600 jsr $fff4
4601 cpx #0 ; fire button pressed?
4602 beq show_title_no_joystick
4604 lda #1 ; enable joystick support
4605 sta $577e
4606 jmp show_title_exit
4608 show_title_no_joystick:
4609 ldx #157 ; SPACE
4610 jsr check_key
4611 cpy #255
4612 bne show_title_wait_inner_loop
4614 lda #0 ; disable joystick support
4615 sta $577e
4617 show_title_exit:
4618 clc
4619 rts
4621 show_input_message:
4623 ldx #0
4624 show_input_message_loop:
4626 lda input_message,x
4627 jsr $ffee
4628 inx
4629 cpx #23
4630 bne show_input_message_loop
4632 rts
4634 wait_for_vsync:
4636 lda #19
4637 jmp $fff4 ; optimise away the rts
4639 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4641 delay:
4643 delay_loop:
4645 jsr wait_for_vsync
4646 dec $5785
4647 bne delay_loop
4649 rts
4651 show_game_over:
4653 lda #128
4654 sta $5785
4655 jsr delay
4657 ldx #0
4658 write_game_over_text_loop:
4659 lda game_over_vdu_bytes,x
4660 jsr $ffee
4661 inx
4662 cpx #33
4663 bmi write_game_over_text_loop
4665 lda #192
4666 sta $5785
4667 jsr delay
4669 rts
4671 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4672 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4674 show_end_of_level_screen:
4676 ; Draw a decorative room.
4678 jsr make_empty_room
4680 ldx #5
4681 end_of_level_h_walls_loop:
4683 lda #3
4684 sta $57b2,x
4685 sta $57e4,x
4686 dex
4687 bpl end_of_level_h_walls_loop
4689 ldx #30
4690 end_of_level_v_walls_loop:
4692 lda #3
4693 sta $57bc,x
4694 sta $57c1,x
4695 txa
4696 sec
4697 sbc #10
4698 tax
4699 bpl end_of_level_v_walls_loop
4701 jsr plot_room_tiles
4702 jsr set_standard_palette
4704 ldx #0
4705 end_of_level_text_loop1:
4707 lda end_of_level_bytes1,x
4708 jsr $ffee
4709 inx
4710 cpx #28
4711 bne end_of_level_text_loop1
4713 ; Count the number of rooms explored.
4714 ldx #0
4715 lda #0
4716 sta $8d
4717 sta $8e
4718 end_of_level_room_count_loop:
4720 lda $5200,x
4721 and #$80
4722 beq end_of_level_room_count_loop_next
4724 sed
4725 lda $8d
4726 adc #1
4727 sta $8d
4728 lda $8e
4729 adc #0
4730 sta $8e
4731 cld
4732 clc
4734 end_of_level_room_count_loop_next:
4735 inx
4736 cpx #121
4737 bne end_of_level_room_count_loop
4739 ; Position the player so that we can perform an animation.
4740 jsr position_player_set_up_plotting
4742 lda $8d
4743 sta $70
4744 lda $8e
4745 sta $71
4746 jsr write_bonus
4748 lda #0 ; reset motion counter
4749 sta $578e
4751 show_end_of_level_bonus_loop:
4753 jsr wait_for_vsync
4755 clc
4756 lda $578e
4757 and #15
4758 bne end_of_level_no_animation
4760 ; Animate the player.
4762 jsr reset_unplot_buffer
4763 jsr reset_plot_buffer
4765 ; $74,$75 should be unchanged
4766 jsr unplot_character
4768 lda $5281
4769 eor #1
4770 sta $5281
4771 jsr plot_character
4773 jsr plot_buffer
4775 end_of_level_no_animation:
4776 clc
4777 lda $578e
4778 and #3
4779 bne end_of_level_no_countdown
4781 ; Transfer the bonus to the score.
4783 sed
4784 sec
4785 lda $8d
4786 sbc #1
4787 sta $8d
4788 sta $70
4789 lda $8e
4790 sbc #0
4791 sta $8e
4792 sta $71
4793 cld
4794 clc
4796 jsr write_bonus
4798 lda #9
4799 sta $70
4800 jsr add_score
4802 lda $8d
4803 and #$3f
4804 asl
4805 ldy #1
4806 jsr play_note
4808 end_of_level_no_countdown:
4809 inc $578e ; update motion counter
4810 clc
4812 lda $8d
4813 cmp #0
4814 bne show_end_of_level_bonus_loop
4816 lda $8e
4817 cmp #0
4818 bne show_end_of_level_bonus_loop
4820 lda #64 ; initialise delay counter
4821 sta $5785
4822 jsr delay
4824 ldx #0
4825 end_of_level_text_loop2:
4827 lda end_of_level_bytes2,x
4828 jsr $ffee
4829 inx
4830 cpx #25
4831 bne end_of_level_text_loop2
4833 lda $578a
4834 cmp #3
4835 bpl show_end_of_level_screen_exit
4837 lda #192 ; initialise delay counter
4838 sta $5785
4839 jsr delay
4841 show_end_of_level_screen_exit:
4842 rts
4844 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4846 write_bonus: ; $70,$71=value
4847 ; $72,$73=address of VDU codes
4849 ldx #4
4850 write_bonus_vdu_bytes:
4852 lda level_bonus_vdu_bytes,x
4853 jsr $ffee
4854 dex
4855 bpl write_bonus_vdu_bytes
4857 ldy #1
4858 write_bonus_loop:
4860 tya
4861 tax ; temporary
4863 lda $70,x
4864 sta $80
4865 lsr
4866 lsr
4867 lsr
4868 lsr
4869 tax
4870 lda score_digits,x
4871 jsr $ffee
4873 lda $80
4874 and #$0f
4875 tax
4876 lda score_digits,x
4877 jsr $ffee
4879 dey
4880 bpl write_bonus_loop
4882 clc
4883 rts
4885 position_player_set_up_plotting:
4887 jsr reset_player_position
4888 jsr remove_characters
4890 jsr reset_unplot_buffer
4891 jsr reset_plot_buffer
4893 ; Run on into the next routine.
4895 plot_the_player:
4897 lda #$80 ; plot the player
4898 sta $74
4899 lda #$52
4900 sta $75
4901 jsr plot_character
4903 jsr plot_buffer
4904 rts
4906 complete_game_vdu_bytes1: .byte 12
4907 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4908 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4909 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4911 show_complete_game:
4913 jsr blank_screen
4915 ldx #0
4916 show_complete_game_vdu_loop:
4918 lda complete_game_vdu_bytes1,x
4919 jsr $ffee
4920 inx
4921 cpx #68
4922 bne show_complete_game_vdu_loop
4924 jsr copy_completed_screen_up
4926 jsr set_complete_palette
4928 lda #255
4929 sta $5785
4931 show_complete_game_delay_loop:
4933 jsr wait_for_vsync
4935 dec $5785
4936 bne show_complete_game_no_message
4938 jsr colour1
4939 jsr show_input_message
4941 show_complete_game_no_message:
4943 lda #128
4944 ldx #0
4945 jsr $fff4
4946 cpx #0 ; fire button pressed?
4947 beq show_complete_game_no_joystick
4948 jmp show_complete_game_exit
4950 show_complete_game_no_joystick:
4952 ldx #157
4953 jsr check_key
4954 cpy #255
4955 bne show_complete_game_delay_loop
4957 show_complete_game_exit:
4958 clc
4959 rts
4961 check_high_scores:
4963 ; Start at the bottom of the table, moving scores down as necessary, and
4964 ; write in the current score at the appropriate place.
4966 lda #$86 ; current score
4967 sta $70
4968 lda #$57
4969 sta $71
4971 lda #$80
4972 sta $72
4973 lda #$51
4974 sta $73
4976 check_high_scores_loop:
4978 ldy #2
4979 check_high_scores_digits_loop:
4981 lda ($72),y
4982 cmp ($70),y ; existing score less than current score?
4983 bmi check_high_scores_move_down
4984 beq check_high_scores_digits_next ; keep checking digits if equal
4985 jmp check_high_scores_next
4987 check_high_scores_digits_next:
4988 dey
4989 bpl check_high_scores_digits_loop
4991 check_high_scores_next:
4992 clc
4993 lda $72
4994 adc #12
4995 sta $72
4996 cmp #$e0
4997 bne check_high_scores_loop
4999 ; The player's score didn't make it into the high score table.
5000 rts
5002 check_high_scores_move_down: ; $70,$71=pointer to current score
5003 ; $72,$73=pointer to old score
5005 ; The current score exceeded the existing entry. Make a note of the
5006 ; position in the high score table, insert the player's score, and take
5007 ; the old score
5009 lda $72 ; Record the position in the high score table of the
5010 sta $8d ; player's score.
5011 lda $73
5012 sta $8e
5014 lda #$e0
5015 sta $74
5016 lda #$51
5017 sta $75
5019 ldy #0
5020 insert_blank_player_name_loop:
5022 cpy #3
5023 bpl insert_blank_player_name_score_only
5025 lda ($70),y
5026 jmp insert_blank_player_name_store
5028 insert_blank_player_name_score_only:
5029 lda #32
5031 insert_blank_player_name_store:
5032 sta ($74),y
5033 iny
5034 cpy #12
5035 bne insert_blank_player_name_loop
5037 check_high_scores_move_down_loop:
5039 ldy #0
5040 check_high_scores_copy_score_and_name:
5042 lda ($72),y ; swap the current score with the score in the table
5043 tax
5044 lda ($74),y
5045 sta ($72),y
5046 txa
5047 sta ($74),y
5048 iny
5049 cpy #12
5050 bne check_high_scores_copy_score_and_name
5052 clc
5053 lda $72
5054 adc #12
5055 sta $72
5056 cmp #$e0
5057 bne check_high_scores_move_down_loop
5059 ; Draw a decorative room.
5061 jsr set_hidden_palette
5063 jsr make_empty_room
5065 lda #3
5066 sta $76
5067 sta $77
5068 jsr draw_top_line
5069 jsr draw_bottom_line
5070 jsr draw_left_line
5072 lda #0
5073 sta $77
5074 jsr draw_right_line
5076 jsr plot_room_tiles
5078 ; Add text characters to the room.
5079 jsr colour3
5081 lda #3 ; x
5082 sta $70
5083 lda #6 ; y
5084 sta $71
5086 lda #65
5087 sta $72
5089 ldx #3
5090 plot_text_characters_loop:
5092 jsr print_xy
5094 lda $70
5095 adc #4
5096 sta $70
5098 dex
5099 bpl plot_text_characters_next
5101 lda #3
5102 sta $70
5103 lda $71
5104 adc #3
5105 sta $71
5107 ldx #3
5109 plot_text_characters_next:
5111 inc $72
5112 lda $72
5113 cmp #91
5114 bne plot_text_characters_loop
5116 lda #11
5117 sta $70
5118 lda #95 ; _ representing a space
5119 sta $72
5120 jsr print_xy
5122 lda #15
5123 sta $70
5124 lda #60 ; < representing delete
5125 sta $72
5126 jsr print_xy
5128 ; Put the player in the centre of the room.
5129 jsr position_player_set_up_plotting
5131 lda #0 ; reset motion counter
5132 sta $578e
5134 lda #0 ; not on a character
5135 sta $578d
5137 lda #0 ; reset the level number so that the correct tiles are used
5138 sta $578a
5140 lda #3 ; cursor position in the high score entry held in $8d,$8e
5141 sta $8f
5143 jsr set_standard_palette
5145 ldx #0
5146 high_score_vdu_loop:
5148 lda high_score_vdu_bytes,x
5149 jsr $ffee
5150 inx
5151 cpx #39
5152 bne high_score_vdu_loop
5154 high_score_entry_loop:
5156 jsr reset_unplot_buffer
5157 jsr reset_plot_buffer
5159 jsr move_player
5160 ; Check if the player leaves the room.
5161 bcc high_score_entry_check_position
5162 jmp high_score_entry_after_loop
5164 high_score_entry_check_position:
5166 lda $5285 ; dx
5167 cmp #2
5168 beq high_score_entry_maybe_aligned
5169 jmp high_score_entry_not_aligned
5171 high_score_entry_maybe_aligned:
5173 lda $5282 ; y
5174 tay
5175 cmp #8
5176 bpl high_score_entry_not_aligned
5178 lda $5284 ; x
5179 tax
5180 cmp #9
5181 beq high_score_entry_not_aligned
5182 and #1
5183 beq high_score_entry_not_aligned
5185 lda $5283 ; dy
5186 cmp #2
5187 bmi high_score_entry_aligned
5188 jmp high_score_entry_not_aligned
5190 lda $5282 ; y again (don't apply the touching rule to the bottom
5191 cmp #7 ; row of characters)
5192 beq high_score_entry_not_aligned
5194 iny ; we are really touching the character below
5196 high_score_entry_aligned:
5198 lda $578d
5199 cmp #1
5200 beq high_score_entry_next
5202 ; The player is aligned with a letter.
5203 txa
5204 sec
5205 sbc #1
5206 lsr
5207 sta $7e ; record (x - 1) / 2
5209 tya ; recall y
5210 sec
5211 sbc #1
5212 asl
5213 asl ; (y - 1) * 4
5214 clc
5216 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5217 adc #65
5218 sta $7e ; record the ASCII code
5220 cmp #91
5221 bmi insert_character
5223 cmp #92
5224 beq delete_character
5226 ; Insert a space.
5227 lda #32
5228 sta $7e
5230 insert_character:
5231 lda $8f
5232 cmp #12
5233 bpl high_score_entry_pressed
5235 tay ; insert the character
5236 lda $7e
5237 sta ($8d),y
5238 jsr print_high_score_character
5240 inc $8f
5241 jmp high_score_entry_pressed
5243 delete_character:
5244 lda $8f
5245 cmp #4
5246 bmi high_score_entry_pressed
5248 cmp #12
5249 beq high_score_delete_previous_character
5251 tay
5252 lda #32 ; insert a space
5253 sta ($8d),y
5254 jsr print_high_score_character
5256 high_score_delete_previous_character:
5257 dec $8f
5258 lda $8f
5259 tay ; insert a space
5260 lda #32
5261 sta ($8d),y
5262 jsr print_high_score_character
5264 high_score_entry_pressed:
5265 lda #1
5266 sta $578d
5267 jmp high_score_entry_next
5269 high_score_entry_not_aligned:
5270 lda #0
5271 sta $578d
5273 high_score_entry_next:
5275 jsr wait_for_vsync
5276 jsr plot_buffer
5278 jmp high_score_entry_loop
5280 inc $578e
5281 clc
5283 high_score_entry_after_loop:
5284 clc
5286 jsr cls
5287 jsr set_hidden_palette
5289 rts
5291 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5293 cls:
5294 lda #12
5295 jsr $ffee
5296 rts
5298 colour1:
5299 lda #17
5300 jsr $ffee
5301 lda #1
5302 jsr $ffee
5303 rts
5305 colour3:
5306 lda #17
5307 jsr $ffee
5308 lda #3
5309 jsr $ffee
5310 rts
5312 print_high_score_character: ; A=ASCII code
5314 clc
5315 sta $72 ; store the character
5316 lda $8f
5317 adc #3
5318 sta $70 ; store the x position of the character
5319 lda #30
5320 sta $71
5321 ; Run on into the next routine.
5323 print_xy:
5325 lda #31
5326 jsr $ffee
5327 lda $70
5328 jsr $ffee
5329 lda $71
5330 jsr $ffee
5331 lda $72
5332 jsr $ffee
5333 rts
5335 disable_sound: ; X=1 (disable); X=0 (enable)
5337 lda #210
5338 ldy #0
5339 jmp $fff4 ; optimise away the rts
5341 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5342 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5344 start_new_game:
5346 ; Clear the screen.
5347 jsr cls
5349 ; Set the level.
5350 lda #0
5351 sta $578a
5353 ; Set the score.
5354 lda #0
5355 sta $5786
5356 lda #0
5357 sta $5787
5358 lda #0
5359 sta $5788
5361 ; Blank the screen now because it will be blanked before the room is shown
5362 ; and otherwise the strength bar will show briefly.
5363 jsr blank_screen
5365 ; Set the player's strength.
5366 lda #0
5367 sta $5784
5368 lda #64
5369 sta $70
5370 jsr add_strength
5372 ; Set the projectile type.
5373 lda #0
5374 sta $5789
5376 rts
5378 reset_player_position:
5380 lda #1 ; player
5381 sta $5280
5382 lda #6 ; down (first frame)
5383 sta $5281
5384 lda #4 ; y=4
5385 sta $5282
5386 lda #2 ; dy=2
5387 sta $5283
5388 lda #4 ; x=4
5389 sta $5284
5390 lda #3 ; dx=3
5391 sta $5285
5393 rts
5395 start_level:
5397 ; Clear the item/player flags.
5398 lda #0
5399 sta $5780
5401 ; Set current room.
5403 ldx $578a
5404 lda start_rooms_y,x
5405 sta $5782
5406 lda start_rooms_x,x
5407 sta $5783
5409 ; Set the player's position.
5411 jsr reset_player_position
5413 ; Reset the weapon counter.
5414 lda #0
5415 sta $577f
5417 ; Fill the treasure table with objects.
5418 ldx $578a ; level
5419 lda key_rooms,x
5420 sta $80
5422 ldx $578a ; level
5423 lda seeds,x
5424 adc #1
5425 and #31
5426 sta $7c
5427 clc
5428 lda seeds,x
5429 adc #2
5430 and #31
5431 sta $7d
5432 clc
5434 lda $578a ; create an upper limit on the weapon type found in this level
5435 adc #2
5436 sta $5781
5437 clc
5439 lda #$00
5440 sta $8e
5441 lda #$52
5442 sta $8f
5444 ldy #0
5445 start_level_add_treasure_loop:
5447 cpy $80 ; check for the key room
5448 bne start_level_add_treasure_item
5450 lda #5 ; the value to store is type + 1
5451 jmp start_level_add_treasure_store
5453 start_level_add_treasure_item:
5454 clc
5455 jsr unlimited_values
5456 and #$0f
5457 cmp #0
5458 beq start_level_add_treasure_none
5460 clc
5461 sta $8c
5462 tya
5463 adc $8c
5464 and #31
5465 clc
5466 tax
5467 lda treasure_table,x
5469 cmp #4
5470 bmi start_level_add_treasure_weapon
5472 clc
5473 adc #1
5474 jmp start_level_add_treasure_store
5476 start_level_add_treasure_weapon:
5478 ; Only add weapons with types that equal the level number or exceed it
5479 ; by one.
5480 cmp $5781
5481 bcs start_level_add_treasure_none
5483 clc
5484 adc #1 ; store values 0-8 as values 1-9
5485 jmp start_level_add_treasure_store
5487 start_level_add_treasure_none:
5488 clc
5489 lda #0 ; do not put treasure in this room
5491 start_level_add_treasure_store:
5492 clc
5493 sta ($8e),y ; add the item to the table
5495 iny
5496 cpy #121
5497 bmi start_level_add_treasure_loop
5499 ; Write the status text.
5500 ldx #0
5501 write_status_text_loop:
5502 lda status_vdu_bytes,x
5503 jsr $ffee
5504 inx
5505 cpx #25
5506 bmi write_status_text_loop
5508 jsr write_score
5510 clc
5511 rts
5513 main:
5514 jsr init
5516 main_loop:
5518 jsr show_title
5520 jsr start_new_game
5522 level_loop:
5524 jsr start_level
5526 game_loop:
5528 jsr remove_characters
5530 jsr reset_unplot_buffer
5531 jsr reset_plot_buffer
5533 lda $5782 ; current room (y)
5534 sta $78
5535 lda $5783 ; current room (x)
5536 sta $79
5537 jsr plot_room
5538 jsr set_room_palette
5539 jsr create_enemy_positions
5540 jsr add_treasure
5542 jsr plot_the_player
5544 lda #0 ; reset projectile counter
5545 sta $578d
5547 lda #0 ; reset motion counter
5548 sta $578e
5550 lda #63 ; reset generation counter
5551 sta $578f
5553 room_loop:
5554 jsr reset_unplot_buffer
5555 jsr reset_plot_buffer
5557 jsr move_characters
5558 jsr move_projectile
5560 lda $5780 ; is player out of strength ($40), leaving the
5561 and #$c2 ; level (0x80) or completing the game (0x02)?
5562 beq room_loop_player_move
5563 clc
5565 dec $5785 ; leave the loop when the delay
5566 bne room_loop_delay_next
5567 jmp after_room_loop ; counter is about to reset
5569 room_loop_delay_next:
5571 lda $5281 ; leave the loop when the player demise
5572 cmp #11 ; animation has finished
5573 beq room_loop_after_player_move
5574 clc
5576 lda $578e
5577 and #7
5578 bne room_loop_after_player_move
5580 lda $5780 ; skip the animation if leaving the level or
5581 and #$82 ; completing the game
5582 bne room_loop_after_player_move
5584 ; Show the demise animation when appropriate.
5586 lda #$80
5587 sta $74
5588 lda #$52
5589 sta $75
5591 jsr unplot_character
5593 inc $5281
5594 jsr plot_character
5595 jmp room_loop_after_player_move
5597 room_loop_player_move:
5599 ; See if it is time to generate a new enemy.
5600 lda $578f
5601 cmp #0
5602 bne no_emerge_characters
5603 jsr emerge_characters
5605 no_emerge_characters:
5606 clc
5608 jsr check_fire_key
5609 jsr move_player
5610 bcs after_room_loop ; check if we are leaving the level
5612 room_loop_after_player_move:
5613 clc
5615 lda #19
5616 jsr $fff4
5617 jsr plot_buffer
5619 ldx #143 ; Escape key check
5620 jsr check_key
5621 cpy #255
5622 beq main_loop_play_again
5624 ldx #174 ; S key check
5625 jsr check_key
5626 cpy #255
5627 bne no_set_sound
5629 ldx #0
5630 jsr disable_sound
5631 jmp after_sound_checks
5633 no_set_sound:
5635 ldx #239 ; Q key check
5636 jsr check_key
5637 cpy #255
5638 bne after_sound_checks
5640 ldx #1
5641 jsr disable_sound
5643 after_sound_checks:
5645 ldx #200 ; P key check
5646 jsr check_key
5647 cpy #255
5648 bne no_pause
5650 pause_loop:
5652 ldx #201 ; O key check
5653 jsr check_key
5654 cpy #255
5655 bne pause_loop
5657 no_pause:
5658 clc
5660 lda $578d
5661 cmp #0
5662 beq room_loop_no_update_projectile_counter
5664 dec $578d
5666 room_loop_no_update_projectile_counter:
5668 dec $578f ; update generation counter
5670 inc $578e ; update motion counter
5671 clc
5672 jmp room_loop
5674 after_room_loop:
5675 clc
5677 lda $5780
5678 and #$80
5679 bne exit_level
5681 lda $5780
5682 and #$40
5683 bne game_over
5685 lda $5780
5686 and #$02
5687 bne complete_game
5689 jmp game_loop
5691 exit_level:
5693 jsr show_end_of_level_screen
5695 inc $578a
5696 clc
5697 jmp level_loop
5699 game_over:
5700 jsr show_game_over
5701 jmp main_loop_play_again
5703 complete_game:
5704 jsr show_end_of_level_screen
5705 jsr show_complete_game
5706 jmp main_loop_play_again
5708 main_loop_play_again:
5709 jsr cls
5711 ; Check the score against the high scores.
5712 jsr check_high_scores
5714 jmp main_loop
5716 exit:
5717 clc
5718 rts