junglejourney
view mapcode.oph @ 242:94246db7b5e5
Added comments to help explain how the joystick routine works.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Fri Mar 21 19:10:25 2014 +0100 |
| parents | 42c8701f4bc7 |
| children |
line source
1 ; Copyright (C) 2011 David Boddie <david@boddie.org.uk>
2 ;
3 ; This program is free software: you can redistribute it and/or modify
4 ; it under the terms of the GNU General Public License as published by
5 ; the Free Software Foundation, either version 3 of the License, or
6 ; (at your option) any later version.
7 ;
8 ; This program is distributed in the hope that it will be useful,
9 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ; GNU General Public License for more details.
12 ;
13 ; You should have received a copy of the GNU General Public License
14 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
16 jmp main
18 seeds: .byte 100, 239, 183, 144 ; $ef, $b7, $90, $d6, $89
19 start_rooms_x: .byte 5, 3, 5, 10
20 start_rooms_y: .byte 5, 8, 1, 8
21 exit_rooms_x: .byte 7, 9, 3, 0
22 exit_rooms_y: .byte 0, 0, 9, 10
24 ; These values need to be kept in sync - the room numbers must match their
25 ; positions in the room array.
26 key_rooms_x: .byte 1, 5, 10, 1
27 key_rooms_y: .byte 0, 2, 6, 4
28 key_rooms: .byte 1, 27, 76, 45 ; ky*11 + kx
30 treasure_table: .byte 6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7
31 treasure_table_: .byte 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0
33 unlimited_values: ; $7c,$7d=first,second
34 ; Add $7c and $7d, store the result in $7d and the original
35 ; $7d value in $7c, returning the sum in the accumulator.
36 lda $7c
37 sta $7b
38 lda $7d
39 sta $7c
40 adc $7b
41 sta $7d
42 clc
43 rts
45 mod9: ; A = value
46 divide_loop:
47 cmp #9
48 bcc after_divide_loop ; bmi should work here, I think, but it doesn't
49 sec
50 sbc #9
51 jmp divide_loop
53 after_divide_loop:
54 clc
55 rts ; A % 9
57 tile_values_map: .byte 0,1,0,0,0,0,2,3
59 next_value: ; no argument
60 jsr unlimited_values
61 lda $7d
62 jsr mod9
63 and #7 ; (next value % 9) & 7
64 tax
65 lda tile_values_map,x
66 sta $7b
67 rts
69 ; Room filling routines, writing to 0x579c to 0x57ff.
71 draw_top_line: ; $76=tile number for exit/wall
72 ldx #9
73 lda #2
75 draw_top_line_loop0:
76 sta $579c,x
77 dex
78 bpl draw_top_line_loop0
80 ldx #3 ; draw the exit or wall
81 lda $76
82 draw_top_line_loop1:
83 sta $579f,x
84 dex
85 bpl draw_top_line_loop1
86 clc
87 rts
89 draw_left_line: ; $77=tile number for exit/wall
90 ldx #90
91 draw_left_line_loop0:
92 lda #2
93 sta $579c,x
94 txa
95 sec
96 sbc #10
97 tax
98 bpl draw_left_line_loop0
100 ldx #30
101 draw_left_line_loop1:
102 lda $77
103 sta $57ba,x
104 txa
105 sec
106 sbc #10
107 tax
108 bpl draw_left_line_loop1
109 clc
110 rts
112 draw_bottom_line: ; $76=tile number for exit/wall
113 ldx #9
114 lda #2
115 draw_bottom_line_loop0:
116 sta $57f6,x
117 dex
118 bpl draw_bottom_line_loop0
120 ldx #3
121 lda $76
122 draw_bottom_line_loop1:
123 sta $57f9,x
124 dex
125 bpl draw_bottom_line_loop1
126 clc
127 rts
129 draw_right_line: ; $77=tile number for exit/wall
130 ldx #99
131 draw_right_line_loop0:
132 lda #2
133 sta $579c,x
134 txa
135 sec
136 sbc #10
137 tax
138 bpl draw_right_line_loop0
140 ldx #30
141 draw_right_line_loop1:
142 lda $77
143 sta $57c3,x
144 txa
145 sec
146 sbc #10
147 tax
148 bpl draw_right_line_loop1
149 clc
150 rts
152 make_empty_room:
154 ldx #99
155 make_empty_room_loop:
156 lda #0
157 sta $579c,x
158 dex
159 bpl make_empty_room_loop
161 rts
163 make_room: ; $78,$79=i,j
165 ; Fills the room array at 579c with values.
166 ; Tiles 0,1,2,3 are map tiles that will be shown by the plot_tile routine.
167 ; Other tiles are plotted separately:
168 ; 4 = exit
169 ; 5 = final exit
170 ; 6 = weapon (bits 3,4 are type)
171 ; 7 = treasure (bits 3,4 are type)
173 ; Fill the room with empty space.
175 jsr make_empty_room
177 ; Determine if there is a top exit.
179 lda #0
180 sta $76
182 lda $78 ; i == 0
183 cmp #0
184 bne not_top_screen
185 lda #2
186 sta $76
187 jmp do_top_exit
189 not_top_screen:
190 clc
192 lda $78
193 and #7 ; i & 7
194 sta $70 ; temporary result
195 lda $79
196 and #7 ; j & 7
197 cmp $70
198 beq do_top_exit
199 clc
201 lda $78
202 eor $79 ; i ^ j
203 adc $78 ; + i
204 clc
205 cmp $79 ; (i ^ j) + i == j
206 bne do_top_exit
207 lda #2
208 sta $76 ; top exit
210 do_top_exit:
211 jsr draw_top_line
213 ; Determine if there is a left exit.
214 lda #0
215 sta $77
217 lda $79
218 cmp #0
219 bne not_left_screen
220 lda #2
221 sta $77
222 jmp do_left_exit
224 not_left_screen:
225 clc
227 lda $78
228 and #3 ; i & 3
229 sta $70 ; temporary result
230 lda $79
231 and #3 ; j & 3
232 cmp $70
233 beq do_left_exit
234 clc
236 lda $78
237 ora $79 ; i | j
238 eor $79 ; ^ j
239 cmp $78 ; (i | j) ^ j == i
240 bne do_left_exit
241 lda #2
242 sta $77 ; left exit
244 do_left_exit:
245 jsr draw_left_line
247 ; Determine if there is a right exit.
248 lda #0
249 sta $77
251 lda $79
252 cmp #10
253 bne not_right_screen
254 lda #2
255 sta $77
256 jmp do_right_exit
258 not_right_screen:
259 clc
261 lda $78
262 and #3 ; i & 3
263 sta $70 ; temporary result
264 lda $79
265 adc #1
266 and #3 ; j & 3
267 cmp $70
268 beq do_right_exit
269 clc
271 lda $79
272 adc #1
273 sta $70
275 lda $78
276 ora $70 ; i | j
277 eor $70 ; ^ j
278 cmp $78 ; (i | j) ^ j == i
279 bne do_right_exit
280 lda #2
281 sta $77 ; right exit
283 do_right_exit:
284 jsr draw_right_line
286 ; Determine if there is a bottom exit.
287 lda #0
288 sta $76
290 lda $78
291 cmp #10
292 bne not_bottom_screen
293 lda #2
294 sta $76
295 jmp do_bottom_exit
297 not_bottom_screen:
298 clc
300 lda $78
301 adc #1
302 and #7 ; i & 7
303 sta $70 ; temporary result
304 lda $79
305 and #7 ; j & 7
306 cmp $70
307 beq do_bottom_exit
308 clc
310 lda $78
311 adc #1
312 sta $70
314 eor $79 ; i ^ j
315 adc $70 ; + i
316 cmp $79 ; (i ^ j) + i == j
317 bne do_bottom_exit
318 lda #2
319 sta $76 ; bottom exit
321 do_bottom_exit:
322 jsr draw_bottom_line
324 ; Add the final exit.
326 lda $578a
327 cmp #3
328 bmi make_room_no_final_exit
330 lda $78
331 cmp #0
332 bne make_room_no_final_exit
334 lda $79
335 cmp #2
336 bne make_room_no_final_exit
338 lda #6
339 sta $57a0
340 lda #7
341 sta $57a1
343 make_room_no_final_exit:
345 ; Make sure that the starting, exit, key rooms are empty.
347 ldx $578a ; level number
348 lda start_rooms_y,x
349 cmp $78
350 bne make_room_not_starting_room
351 lda start_rooms_x,x
352 cmp $79
353 bne make_room_not_starting_room
355 lda #3
356 sta $70
357 jmp add_room_decoration ; optimise away the rts
359 make_room_not_starting_room:
361 lda exit_rooms_y,x
362 cmp $78
363 bne make_room_not_exit_room
364 lda exit_rooms_x,x
365 cmp $79
366 bne make_room_not_exit_room
368 ; Add an exit to the room.
369 lda $78
370 eor $79
371 and #15
372 tax
373 lda exit_room_offsets,x
374 tax
375 lda $5780
376 and #1
377 beq exit_not_open
379 lda #5
380 sta $579c,x
381 jmp exit_decoration
383 exit_not_open:
384 clc
385 lda #4
386 sta $579c,x
388 exit_decoration:
389 lda #3
390 sta $70
391 jmp add_room_decoration ; optimise away the rts
393 make_room_not_exit_room:
395 lda key_rooms_y,x
396 cmp $78
397 bne make_room_not_key_room
398 lda key_rooms_x,x
399 cmp $79
400 bne make_room_not_key_room
402 lda #1
403 sta $70
404 jmp add_room_decoration ; optimise away the rts
406 make_room_not_key_room:
407 clc
409 ; Fill in the room details.
411 lda $79
412 sta $7c
413 sec
414 ldx $578a
415 lda seeds,x
416 sbc $78
417 sec
418 sta $7d
419 clc
421 ; Discard the first ten values.
423 ldy #10
424 make_room_loop0:
425 jsr unlimited_values
426 dey
427 bne make_room_loop0
429 ; Fill the room array with values.
431 lda #$a7
432 sta $70
433 lda #$57
434 sta $71
436 ldy #0
437 make_room_loop1:
439 jsr next_value
440 sta ($70),y
441 iny
442 cpy #8
443 bne make_room_loop1 ; continue the same row
445 lda $70
446 cmp #$ed
447 beq make_room_loop1_exit ; exit after the last row
449 adc #10
450 sta $70
451 ldy #0 ; reset the row counter
452 jmp make_room_loop1
454 make_room_loop1_exit:
455 rts
457 decoration_offsets: .byte 11,18,81,88
459 add_room_decoration:
461 lda #$9c
462 sta $8e
463 lda #$57
464 sta $8f
466 ldx #3
467 add_room_decoration_loop:
469 lda decoration_offsets,x
470 tay
471 lda $70
472 sta ($8e),y
473 dex
474 bpl add_room_decoration_loop
476 clc
477 rts
479 exit_room_offsets: .byte 35,66,63,56,34,44,64,33,36,55,65,53,45,46,54,43
480 treasure_x: .byte 3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6
481 treasure_y: .byte 1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2
483 eleven_times_table: .byte 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110
485 add_treasure: ; $78,$79 = i,j
487 lda $78
488 tax
489 lda eleven_times_table,x
490 adc $79
491 tax
493 lda $5200,x
494 ora #$80
495 sta $5200,x ; set the top bit (room visited)
496 and #$7f ; mask off the top bit to obtain the item number + 1
497 cmp #0
498 beq add_treasure_exit
500 sec
501 sbc #1
502 sta $528d ; store weapon/treasure type
503 clc
505 lda $78
506 eor $79
507 adc $528d
508 and #15
509 sta $70
511 lda #15
512 sta $8c
513 ldy #0
514 add_treasure_loop:
516 clc
518 ldx $70
519 lda treasure_y,x ; y
520 sta $8d
521 tax
522 lda room_row_offsets_low,x
523 sta $80
525 ldx $70
526 lda treasure_x,x ; x
527 sta $8e
528 adc $80
529 sta $80
531 lda #$57
532 adc #0
533 sta $81
534 clc
536 lda ($80),y ; tile
537 cmp #0
538 bne add_treasure_loop_next
540 lda #4 ; type (weapon/treasure)
541 sta $528c
542 lda $8d ; y
543 sta $528e
544 lda #1 ; dy
545 sta $528f
546 lda $8e ; x
547 sta $5290
548 lda #0 ; dx
549 sta $5291
551 lda #$8c
552 sta $74
553 lda #$52
554 sta $75
555 jmp plot_character ; optimise away the rts
557 add_treasure_loop_next:
558 dec $8c
559 bmi add_treasure_exit
561 dec $70
562 bpl add_treasure_loop
564 lda #15
565 sta $70
566 jmp add_treasure_loop
568 add_treasure_exit:
569 clc
570 rts
572 create_enemy_positions:
574 lda #31 ; counter
575 sta $7e
577 lda #1 ; x
578 sta $70
580 lda #1 ; y
581 sta $71
583 lda #$a7
584 sta $72
585 lda #$57
586 sta $73
588 ldx #15 ; offset into position areas
589 ldy #0
591 create_enemy_positions_loop:
593 jsr unlimited_values
594 and #7
595 sta $80 ; store temporarily
597 lda $72
598 adc $80
599 sta $72 ; update the offset into the room data
600 clc
602 lda $70
603 adc $80 ; update x
604 cmp #10
605 bpl create_enemy_positions_next_row
607 sta $70 ; store x
608 jmp create_enemy_positions_check_tile
610 create_enemy_positions_next_row:
612 sec
613 sbc #10
614 sta $70 ; store the x position on the next row
615 clc
617 lda $71
618 adc #1 ; update the y position
619 cmp #10
620 bpl create_enemy_positions_to_top
622 sta $71 ; store the y position for the next row
623 jmp create_enemy_positions_check_tile
625 create_enemy_positions_to_top:
627 lda #1 ; reset the x, y and offset values
628 sta $70
629 sta $71
630 lda #$a7
631 sta $72
633 create_enemy_positions_check_tile:
635 lda ($72),y
636 cmp #0
637 bne create_enemy_positions_next
639 lda $70
640 sta $0ee0,x ; store the x value
642 lda $71
643 sta $0ef0,x ; store the y value
645 dex
646 bmi create_enemy_positions_exit
648 create_enemy_positions_next:
649 clc
650 dec $7e
651 bpl create_enemy_positions_loop
653 ; The position areas were not filled. Write invalid values into the
654 ; first area for the emerge routine to find.
656 lda #0
657 create_enemy_positions_fill_loop:
659 sta $0ee0,x
660 dex
661 bpl create_enemy_positions_fill_loop
663 create_enemy_positions_exit:
664 clc
665 rts
667 plot: ; $70,$71=source address
668 ; $72,$73=destination address
669 ldy #$1f
670 plotloop0:
671 lda ($70),y
672 sta ($72),y
673 dey
674 bpl plotloop0
676 lda $72
677 adc #$20
678 sta $72
679 lda $73
680 adc #$01
681 sta $73 ; next line minus 0x20
682 clc
684 ldy #$3f
685 plotloop1:
686 lda ($70),y
687 sta ($72),y
688 dey
689 cpy #$20
690 bpl plotloop1
692 lda $72
693 adc #$20
694 sta $72
695 lda $73
696 adc #$01
697 sta $73 ; next line minus 0x20
698 clc
700 ldy #$5f
701 plotloop2:
702 lda ($70),y
703 sta ($72),y
704 dey
705 cpy #$40
706 bpl plotloop2
708 sec
709 lda $72
710 sbc #$20
711 sta $72
712 lda $73
713 sbc #$02
714 sta $73 ; back two lines minus 0x20
715 clc
717 rts
721 plot_blank_xy: ; X=y, Y=x
723 lda screen_rows_low,x
724 sta $72
725 lda screen_rows_high,x
726 sta $73
728 tya
729 tax
730 lda screen_columns_low,x
731 adc $72
732 sta $72
733 lda screen_columns_high,x
734 adc $73
735 sta $73
736 clc
737 ; run on into plot_blank
739 plot_blank: ; $72,$73=destination address
741 ldy #$1f
742 lda #0
743 plot_blank_loop0:
744 sta ($72),y
745 dey
746 bpl plot_blank_loop0
748 lda $72
749 adc #$20
750 sta $72
751 lda $73
752 adc #$01
753 sta $73 ; next line minus 0x20
754 clc
756 ldy #$3f
757 lda #0
758 plot_blank_loop1:
759 sta ($72),y
760 dey
761 cpy #$20
762 bpl plot_blank_loop1
764 lda $72
765 adc #$20
766 sta $72
767 lda $73
768 adc #$01
769 sta $73 ; next line minus 0x20
770 clc
772 ldy #$5f
773 lda #0
774 plot_blank_loop2:
775 sta ($72),y
776 dey
777 cpy #$40
778 bpl plot_blank_loop2
780 sec
781 lda $72
782 sbc #$20
783 sta $72
784 lda $73
785 sbc #$02
786 sta $73 ; back two lines minus 0x20
787 clc
789 rts
791 plot_tile: ; $7b=tile number
792 ; 1 = flowers/decoration
793 ; 2 = trees/wall
794 ; 3 = trees
795 ; 4 = exit
796 ; 5 = open exit
797 ; 6 = final exit (left)
798 ; 7 = final exit (right)
799 ; $72,$73=screen position
801 lda $7b
802 cmp #0
803 bne plot_tile_sprite
804 clc
805 jmp plot_blank ; optimise away the rts
807 plot_tile_sprite:
808 clc
809 tax
810 dex
811 lda tile_addresses_low,x
812 sta $70
813 lda tile_addresses_high,x
814 sta $71
816 lda $7b
817 cmp #4
818 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
820 clc
821 lda $578a
822 and #3 ; change the tile set for later levels
823 tax
825 plot_not_blank_add_loop:
827 cpx #2
828 bne plot_not_blank_not_2
829 dex
830 jmp plot_not_blank_not_0
832 plot_not_blank_not_2:
833 beq plot_not_blank_add_loop
834 cpx #0
836 plot_not_blank_not_0:
837 beq plot_not_blank_after_add_loop
838 clc
839 lda $70
840 adc #$20
841 sta $70
842 lda $71
843 adc #$01
844 sta $71
845 dex
846 jmp plot_not_blank_add_loop
848 plot_not_blank_after_add_loop:
849 clc
850 jsr plot
851 rts
853 plot_room: ; $78,$79 = i,j (from $5782,$5783)
854 jsr blank_screen
856 lda $5782
857 sta $78
858 lda $5783
859 sta $79
861 jsr make_room
862 ; Run on into the next piece of code.
864 plot_room_tiles:
866 lda #$80
867 sta $72
868 lda #$5a
869 sta $73 ; $72,$73 = screen position
871 lda #0
872 sta $7a
873 row_loop:
875 lda #9
876 sta $76
878 column_loop:
879 lda $7a
880 tax
881 lda $579c,x
882 sta $7b
883 jsr plot_tile
885 inc $7a
886 lda $76
887 sec
888 sbc #1
889 sta $76
890 clc
891 cmp #0
892 bpl column_loop
894 clc
896 lda $72
897 adc #$80
898 sta $72
899 lda $73
900 adc #$02
901 sta $73
902 clc
903 cmp #$80
904 beq end_rows
906 jmp row_loop
908 end_rows:
909 rts
911 set_room_palette: ; $78=i; $79=j
913 lda #1
914 sta $70
915 lda $78
916 eor $79
917 and #3
918 tax
919 lda room_palettes,x
920 sta $71
921 jsr set_palette
923 jsr set_core_palette
924 rts
926 room_palettes: .byte 1, 6, 5, 7
928 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
930 plot8x24_y0: ; $70,$71=source address
931 ; $72,$73=destination address
933 ldx #2
935 plot8x24_y0_loop:
937 ldy #15
939 plotloop8x24_y0_0:
940 lda ($70),y
941 eor ($72),y
942 sta ($72),y
943 dey
944 bpl plotloop8x24_y0_0
946 dex
947 bmi plot8x24_y0_exit
949 lda $72
950 adc #$40
951 sta $72
952 lda $73
953 adc #$01
954 sta $73
955 clc
957 lda $70
958 adc #16
959 sta $70
960 lda $71
961 adc #0
962 sta $71
963 clc
965 jmp plot8x24_y0_loop
967 plot8x24_y0_exit:
968 clc
969 jmp plot_buffer_loop_next
972 plot8x8_y1: ; $70,$71=source address
973 ; $72,$73=destination address
974 lda #2
975 sta $7e
976 lda #10
977 sta $7f
979 lda #0 ; plotting 1 8x8 piece
980 sta $8a
982 jmp plot8x24_y123 ; optimise away the rts
984 plot8x24_y1: ; $70,$71=source address
985 ; $72,$73=destination address
986 lda #2
987 sta $7e
988 lda #10
989 sta $7f
991 lda #2 ; plotting 3 8x8 pieces
992 sta $8a
994 jmp plot8x24_y123 ; optimise away the rts
996 plot8x8_y2: ; $70,$71=source address
997 ; $72,$73=destination address
998 lda #4
999 sta $7e
1000 lda #12
1001 sta $7f
1003 lda #0 ; plotting 1 8x8 piece
1004 sta $8a
1006 jmp plot8x24_y123 ; optimise away the rts
1008 plot8x24_y2: ; $70,$71=source address
1009 ; $72,$73=destination address
1010 lda #4
1011 sta $7e
1012 lda #12
1013 sta $7f
1015 lda #2 ; plotting 3 8x8 pieces
1016 sta $8a
1018 jmp plot8x24_y123 ; optimise away the rts
1020 plot8x8_y3: ; $70,$71=source address
1021 ; $72,$73=destination address
1022 lda #6
1023 sta $7e
1024 lda #14
1025 sta $7f
1027 lda #0 ; plotting 1 8x8 piece
1028 sta $8a
1030 jmp plot8x24_y123 ; optimise away the rts
1032 plot8x24_y3: ; $70,$71=source address
1033 ; $72,$73=destination address
1034 lda #6
1035 sta $7e
1036 lda #14
1037 sta $7f
1039 lda #2 ; plotting 3 8x8 pieces
1040 sta $8a
1042 ; Run on into the next routine.
1044 plot8x24_y123: ; $70,$71=source address
1045 ; $72,$73=destination address
1046 ; $7e=offset into source data for first column
1047 ; $7f=offset into source data for second column
1049 plot8x24_y123_loop:
1051 ldx #0
1052 plot8x24_y123_upper_loop_outer:
1054 ldy $7e,x
1055 lda plot_upper_offsets,x
1056 sta $89
1058 plot8x24_y123_upper_loop_inner: ; plot the first column until
1059 dey ; we reach the start
1060 cpy $89
1061 bmi plot8x24_y123_upper_loop_inner_endloop
1062 lda ($70),y
1063 eor ($72),y
1064 sta ($72),y
1065 jmp plot8x24_y123_upper_loop_inner
1067 plot8x24_y123_upper_loop_inner_endloop:
1068 clc
1070 inx
1071 cpx #2
1072 bne plot8x24_y123_upper_loop_outer
1074 clc
1075 lda $72 ; move the destination pointer to refer to the next line
1076 adc #$38
1077 sta $72
1078 lda $73
1079 adc #$01
1080 sta $73
1081 clc
1083 ldx #0
1084 plot8x24_y123_lower_loop_outer:
1086 lda plot_lower_offsets,x
1087 tay
1088 lda $7e,x
1089 sta $89
1091 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1092 lda ($70),y ; offset for the column
1093 eor ($72),y
1094 sta ($72),y
1095 dey
1096 cpy $89
1097 bpl plot8x24_y123_lower_loop_inner
1099 inx
1100 cpx #2
1101 bne plot8x24_y123_lower_loop_outer
1103 dec $8a
1104 bmi plot8x24_y123_exit
1106 clc
1107 lda $70 ; update the source pointer to refer to the next piece
1108 adc #16 ; of sprite data
1109 sta $70
1110 lda $71
1111 adc #0
1112 sta $71
1113 clc
1115 lda $72 ; update the destination pointer to point to the next
1116 adc #8 ; space
1117 sta $72
1118 lda $73
1119 adc #0
1120 sta $73
1121 clc
1123 jmp plot8x24_y123_loop
1125 plot8x24_y123_exit:
1126 clc
1127 jmp plot_buffer_loop_next
1129 plot16x16_y0: ; $70,$71=source address
1130 ; $72,$73=destination address
1131 ldy #31
1133 plotloop16x16_y0_0:
1134 lda ($70),y
1135 eor ($72),y
1136 sta ($72),y
1137 dey
1138 bpl plotloop16x16_y0_0
1139 clc
1141 lda $72
1142 adc #$20
1143 sta $72
1144 lda $73
1145 adc #$01
1146 sta $73 ; 0x140 - 32
1147 clc
1149 ldy #63
1151 plotloop16x16_y0_1:
1152 lda ($70),y
1153 eor ($72),y
1154 sta ($72),y
1155 dey
1156 cpy #32
1157 bpl plotloop16x16_y0_1
1158 clc
1160 jmp plot_buffer_loop_next
1162 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1164 plot16x16_y1: ; $70,$71=source address
1165 ; $72,$73=destination address
1167 lda #2
1168 sta $7e
1169 lda #10
1170 sta $7f
1171 lda #18
1172 sta $80
1173 lda #26
1174 sta $81
1175 jmp plot16x16_y123 ; optimise away the rts
1177 plot16x16_y2: ; $70,$71=source address
1178 ; $72,$73=destination address
1180 lda #4
1181 sta $7e
1182 lda #12
1183 sta $7f
1184 lda #20
1185 sta $80
1186 lda #28
1187 sta $81
1188 jmp plot16x16_y123 ; optimise away the rts
1190 plot16x16_y3: ; $70,$71=source address
1191 ; $72,$73=destination address
1193 lda #6
1194 sta $7e
1195 lda #14
1196 sta $7f
1197 lda #22
1198 sta $80
1199 lda #30
1200 sta $81
1201 ; Run on into the next routine.
1203 plot16x16_y123: ; $70,$71=source address
1204 ; $72,$73=destination address
1205 ; $7e=offset into source data for first column
1206 ; $7f=offset into source data for second column
1207 ; $80=offset into source data for third column
1208 ; $81=offset into source data for fourth column
1210 lda #1
1211 sta $8a
1213 plot16x16_y123_loop:
1215 ldx #0
1216 plot16x16_y123_upper_loop_outer:
1218 ldy $7e,x
1219 lda plot_upper_offsets,x
1220 sta $89
1222 plot16x16_y123_upper_loop_inner:
1224 dey
1225 cpy $89
1226 bmi plot16x16_y123_upper_loop_inner_endloop
1227 lda ($70),y
1228 eor ($72),y
1229 sta ($72),y
1230 jmp plot16x16_y123_upper_loop_inner
1232 plot16x16_y123_upper_loop_inner_endloop:
1233 clc
1235 inx
1236 cpx #4
1237 bne plot16x16_y123_upper_loop_outer
1239 clc
1240 lda $72 ; move the destination pointer to refer to the next line
1241 adc #$38
1242 sta $72
1243 lda $73
1244 adc #$01
1245 sta $73
1246 clc
1248 ldx #0
1249 plot16x16_y123_lower_loop_outer:
1251 lda plot_lower_offsets,x
1252 tay
1253 lda $7e,x
1254 sta $89
1256 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1257 lda ($70),y ; for the column
1258 eor ($72),y
1259 sta ($72),y
1260 dey
1261 cpy $89
1262 bpl plot16x16_y123_lower_loop_inner
1264 inx
1265 cpx #4
1266 bne plot16x16_y123_lower_loop_outer
1268 dec $8a
1269 bmi plot16x16_y123_exit
1271 clc
1272 lda $70 ; update the source pointer to refer to the next piece
1273 adc #32 ; of sprite data
1274 sta $70
1275 lda $71
1276 adc #0
1277 sta $71
1278 clc
1280 lda $72 ; update the destination pointer to point to the next
1281 adc #8 ; space
1282 sta $72
1283 lda $73
1284 adc #0
1285 sta $73
1286 clc
1288 jmp plot16x16_y123_loop
1290 plot16x16_y123_exit:
1291 clc
1292 jmp plot_buffer_loop_next
1294 plot_upper_offsets: .byte 0, 8, 16, 24
1295 plot_lower_offsets: .byte 7, 15, 23, 31
1297 plot8x8_y0: ; $70,$71=source address
1298 ; $72,$73=destination address
1299 ldy #15
1301 plotloop8x8_y0_0:
1302 lda ($70),y
1303 eor ($72),y
1304 sta ($72),y
1305 dey
1306 bpl plotloop8x8_y0_0
1307 clc
1309 jmp plot_buffer_loop_next
1312 check_key: ; x=key code
1313 lda #129 ; returns y=255 or 0
1314 ldy #255
1315 jsr $fff4
1316 rts
1318 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1319 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1320 screen_subrows_low: .byte $00,$06,$44,$82
1321 screen_subrows_high: .byte $00,$00,$01,$02
1323 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1324 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1325 screen_subcolumns_low: .byte $00,$08,$10,$18
1327 unplot_character: ; $74,$75=character address
1329 lda $82 ; store the unplot buffer address in $78,$79
1330 sta $78
1331 lda $83
1332 sta $79
1333 jsr plot_character_sprite
1334 lda $78
1335 sta $82 ; update the latest space in the unplot buffer
1336 rts
1338 plot_character: ; $74,$75=character address
1340 lda $84 ; store the plot buffer address in $78,$79
1341 sta $78
1342 lda $85
1343 sta $79
1344 jsr plot_character_sprite
1345 lda $78
1346 sta $84 ; update the latest space in the plot buffer
1347 rts
1349 plot_character_sprite: ; $74,$75=character address
1350 ; $78,$79=unplot/plot buffer address
1352 ldy #0
1353 lda ($74),y
1354 cmp #0
1355 bne plot_characters_read_character
1356 jmp plot_characters_next
1358 plot_characters_read_character:
1359 clc
1361 sta $77 ; temporarily store the object type
1363 ; Use lookup tables to load the offsets into the sprite.
1365 ; Direction
1366 iny
1367 lda ($74),y
1368 sta $80 ; temporarily store the direction
1370 ; y
1371 iny
1372 lda ($74),y
1373 tax
1374 lda screen_rows_low,x
1375 sta $72
1376 lda screen_rows_high,x
1377 sta $73
1378 clc
1380 ; dy
1381 iny
1382 lda ($74),y
1383 sta $76
1384 tax
1385 lda screen_subrows_low,x
1386 adc $72
1387 sta $72
1388 lda screen_subrows_high,x
1389 adc $73
1390 sta $73
1391 clc
1393 ; x
1394 iny
1395 lda ($74),y
1396 tax
1397 lda screen_columns_low,x
1398 adc $72
1399 sta $72
1400 lda screen_columns_high,x
1401 adc $73
1402 sta $73
1403 clc
1405 ; dx
1406 iny
1407 lda ($74),y
1408 tax
1409 lda screen_subcolumns_low,x
1410 adc $72
1411 sta $72
1412 clc
1414 lda $77
1415 cmp #1
1416 bne plot_characters_loop_not_player
1418 ; Plot 8x24 sprites (player)
1420 ldx $80
1421 lda player_direction_chars_low,x
1422 sta $70
1423 lda player_direction_chars_high,x
1424 sta $71
1426 ; Use the dy value to determine which plotting routine to use.
1428 ldy #0
1429 ldx $76
1430 lda plot_routine_indices_8x24,x
1432 sta ($78),y
1433 jmp plot_characters_stored
1436 plot_characters_loop_not_player:
1437 cmp #2
1438 bne plot_characters_loop_not_projectile
1440 ; Plot 8x8 sprites (projectiles)
1442 lda $80
1443 and #7
1444 tax
1445 lda projectile_chars_low,x
1446 sta $70
1447 lda #projectile_chars_high
1448 sta $71
1450 ; Use the dy value to determine which plotting routine to use.
1452 ldy #0
1453 ldx $76
1454 lda plot_routine_indices_8x8,x
1456 sta ($78),y
1457 jmp plot_characters_stored
1460 plot_characters_loop_not_projectile:
1461 cmp #3
1462 bne plot_characters_loop_not_explosion
1464 ; Plot 16x16 sprites (emerging, explosions)
1466 ; Select the sprites to use.
1468 lda $80
1469 and #7 ; only keep the bits required to find the correct sprite
1470 clc
1471 tax
1472 lda emerge_explode_chars_low,x
1473 sta $70
1474 lda emerge_explode_chars_high,x
1475 sta $71
1477 jmp plot_characters_16x16
1479 plot_characters_loop_not_explosion:
1480 cmp #4
1481 bne plot_characters_loop_not_item
1483 ; Plot 16x16 sprites (items)
1485 ; Select the sprites to use.
1487 lda $80
1488 and #$0f ; only keep the bits required to find the correct sprite
1489 clc
1490 tax
1491 lda item_chars_low,x
1492 sta $70
1493 lda item_chars_high,x
1494 sta $71
1496 jmp plot_characters_16x16
1498 plot_characters_loop_not_item:
1499 cmp #8
1500 bmi plot_characters_loop_not_enemy
1502 ; Plot 16x16 sprites (enemies)
1504 ; Select the set of sprites to use.
1506 and #$70
1507 lsr
1508 lsr
1509 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1510 clc
1511 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1513 lda $80
1514 and #7 ; keep the animation bits
1515 tax
1516 lda enemy_direction_chars_low,x
1517 sta $70
1518 lda enemy_direction_chars_high,x
1519 adc $71
1520 sta $71
1522 plot_characters_16x16:
1524 ; Use the dy value to determine which plotting routine to use.
1526 ldy #0
1527 ldx $76
1528 lda plot_routine_indices_16x16,x
1530 sta ($78),y
1532 plot_characters_stored:
1534 iny
1535 lda $70
1536 sta ($78),y
1537 iny
1538 lda $71
1539 sta ($78),y
1540 iny
1541 lda $72
1542 sta ($78),y
1543 iny
1544 lda $73
1545 sta ($78),y
1547 clc
1548 lda $78
1549 adc #12
1550 sta $78
1552 plot_characters_loop_not_enemy:
1554 plot_characters_next:
1556 lda #255 ; terminate this stream of entries in the plot buffer
1557 ldy #0
1558 sta ($78),y
1559 clc
1560 rts
1562 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1563 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1564 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1566 reset_plot_buffer:
1567 lda #$06 ; reset the index into the plot buffer
1568 sta $84
1569 lda #$53
1570 sta $85
1572 lda #255 ; terminate the plot list
1573 ldy #0
1574 sta ($84),y
1575 rts
1577 reset_unplot_buffer:
1578 lda #$00 ; reset the index into the plot buffer
1579 sta $82
1580 lda #$53
1581 sta $83
1583 lda #255 ; terminate the unplot list
1584 ldy #0
1585 sta ($82),y
1586 rts
1588 plot_buffer_types_low: .byte <plot_buffer_loop_next
1589 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1590 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1591 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1593 plot_buffer_types_high: .byte >plot_buffer_loop_next
1594 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1595 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1596 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1598 plot_buffer:
1600 lda #$00
1601 sta $84
1602 lda #$53
1603 sta $85
1605 lda #6
1606 sta $88
1608 plot_buffer_loop:
1610 ldy #0
1611 lda ($84),y
1612 cmp #255
1613 beq plot_buffer_loop_skip
1615 clc
1616 tax
1617 lda plot_buffer_types_low,x
1618 sta $86
1619 lda plot_buffer_types_high,x
1620 sta $87
1622 iny
1623 lda ($84),y
1624 sta $70
1626 iny
1627 lda ($84),y
1628 sta $71
1630 iny
1631 lda ($84),y
1632 sta $72
1634 iny
1635 lda ($84),y
1636 sta $73
1638 jmp ($86) ; returns to plot_buffer_loop_next
1640 plot_buffer_loop_skip:
1642 lda $88
1643 cmp #12
1644 beq plot_buffer_exit ; both unplot and plot lists have terminated
1646 lda #12
1647 sta $88
1648 lda $84
1649 adc #6
1650 sta $84
1651 jmp plot_buffer_loop
1653 plot_buffer_loop_next:
1654 clc
1656 lda $84
1657 adc $88
1658 sta $84
1659 jmp plot_buffer_loop
1661 plot_buffer_exit:
1662 clc
1663 rts
1665 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1667 animate_player_left:
1669 ; Set the direction and toggle the animation bit.
1671 lda $5281
1672 and #1
1673 eor #1 ; toggle animation flag
1674 sta $5281 ; left (directional bits are 0)
1676 jsr plot_character
1677 rts
1679 animate_player_right:
1681 ; Set the direction and toggle the animation bit.
1683 lda $5281
1684 and #1 ; remove direction information (result is 0)
1685 eor #1 ; toggle animation flag
1686 ora #2 ; right
1687 sta $5281
1689 jsr plot_character
1690 rts
1692 animate_player_up:
1694 ; Set the direction and toggle the animation bit.
1696 lda $5281
1697 and #1 ; remove direction information (result is 0)
1698 eor #1 ; toggle animation flag
1699 ora #4 ; up
1700 sta $5281
1702 jsr plot_character
1703 rts
1705 animate_player_down:
1707 ; Set the direction and toggle the animation bit.
1709 lda $5281
1710 and #1 ; remove direction information (result is 0)
1711 eor #1 ; toggle animation flag
1712 ora #6 ; down
1713 sta $5281
1715 jsr plot_character
1716 rts
1718 joystick_abs: ; A=value for a joystick axis read from the ADC
1719 ; Returns 0 for insufficiently large values,
1720 ; Returns [32, 127] for right/up movement.
1721 ; Returns [32, 128] for left/down movement.
1722 cmp #160
1723 bcc joystick_abs_next1
1725 sec
1726 sbc #128
1727 clc
1728 rts
1730 joystick_abs_next1:
1732 cmp #97
1733 bcs joystick_abs_next2
1735 sta $81
1736 lda #128
1737 sec
1738 sbc $81
1739 clc
1740 rts
1742 joystick_abs_next2:
1743 lda #0
1744 clc
1745 rts
1747 read_joystick:
1749 lda #128
1750 ldx #2
1751 jsr $fff4
1752 tya
1753 sta $8e ; store the original vertical value
1755 jsr joystick_abs
1756 sta $8f ; absolute vertical value
1758 lda #128
1759 ldx #1
1760 jsr $fff4
1761 tya
1762 sta $8d ; store the original horizontal value
1764 jsr joystick_abs
1765 cmp #0 ; If no horizontal input then branch to
1766 beq read_joystick_vertical_check ; the vertical check.
1767 cmp $8f ; If the horizontal input is less than
1768 bcc read_joystick_vertical_check ; the vertical input then branch to the
1769 ; vertical check.
1770 lda $8d
1771 cmp #128
1772 bcs read_joystick_left
1773 jmp move_player_right
1775 read_joystick_left:
1776 jmp move_player_left
1778 read_joystick_vertical_check:
1780 lda $8f
1781 cmp #0
1782 bne read_joystick_vertical
1783 clc
1784 rts
1786 read_joystick_vertical:
1788 lda $8e
1789 cmp #128
1790 bcs read_joystick_up
1791 jmp move_player_down
1793 read_joystick_up:
1794 jmp move_player_up
1796 move_player:
1798 lda $578e
1799 and #1
1800 beq move_player_allowed
1802 clc
1803 rts
1805 move_player_allowed:
1807 lda #$80 ; set up the address of the player character
1808 sta $74
1809 lda #$52
1810 sta $75
1812 ; Handle joystick
1814 lda $577e
1815 cmp #0
1816 beq move_player_handle_left_key
1817 jmp read_joystick
1819 move_player_handle_left_key:
1821 ; Handle the left key.
1823 ldx #158 ; (Z)
1824 jsr check_key
1825 cpy #255
1826 beq move_player_left
1827 jmp move_player_check_right_key
1829 move_player_left:
1831 lda $5285 ; read dx
1832 cmp #0
1833 beq move_player_left_check_x
1835 jsr unplot_character ; unplot the player character
1836 dec $5285
1837 clc
1838 jmp animate_player_left ; optimise away the rts
1840 move_player_left_check_x: ; Check the x offset.
1842 lda $5284
1843 cmp #0
1844 beq move_player_leave_room_left
1846 clc
1847 tay
1848 dey ; x - 1
1849 lda $5282 ; load the y offset
1850 tax ; as an index
1851 lda room_row_offsets_low,x ; read the address of the row
1852 sta $70
1853 lda #$57
1854 sta $71
1855 lda ($70),y ; load the tile to the left
1857 cmp #5 ; check for the open exit or final exit
1858 bmi move_player_not_left_exit1
1859 jmp try_to_exit_level ; optimise away the rts
1861 move_player_not_left_exit1:
1862 cmp #0
1863 beq move_player_left_check_dy
1864 jmp move_player_not_horizontal
1866 move_player_left_check_dy:
1868 lda $5283 ; dy
1869 cmp #0
1870 beq move_player_allow_left
1872 clc
1873 lda $70 ; dy > 0 so we need to check another tile
1874 adc #10
1875 sta $70
1876 lda ($70),y ; load the tile below and to the left
1878 cmp #5 ; check for the open exit or final exit
1879 bmi move_player_not_left_exit2
1880 jmp try_to_exit_level ; optimise away the rts
1882 move_player_not_left_exit2:
1883 cmp #0
1884 beq move_player_allow_left
1885 jmp move_player_not_horizontal
1887 move_player_allow_left:
1888 tya
1889 sta $81 ; temporary
1890 jsr unplot_character ; unplot the player character
1891 lda $81
1892 sta $5284 ; store the new room x offset
1893 lda #3
1894 sta $5285 ; dx = 3
1895 clc
1896 jmp animate_player_left ; optimise away the rts
1898 move_player_leave_room_left:
1899 sec
1900 lda $5783
1901 sbc #1
1902 sta $5783
1903 clc
1905 ; Set the player's position on the right of the screen.
1907 ; No need to unplot.
1909 lda #9 ; x = 9
1910 sta $5284
1911 lda #2 ; dx = 2
1912 sta $5285
1914 jsr animate_player_left
1915 sec ; indicate to the calling routine that the player
1916 rts ; has left the room
1918 move_player_check_right_key:
1920 ; Handle the right key.
1922 ldx #189 ; (X)
1923 jsr check_key
1924 cpy #255
1925 beq move_player_right
1926 jmp move_player_not_horizontal
1928 move_player_right:
1930 lda $5285 ; read dx
1931 cmp #2
1932 beq move_player_right_check_x
1933 cmp #3
1934 beq move_player_right_tile
1936 jsr unplot_character ; unplot the player character
1937 inc $5285
1938 clc
1939 jmp animate_player_right ; optimise away the rts
1941 move_player_right_check_x: ; Check the x offset.
1943 lda $5284
1944 cmp #9
1945 beq move_player_leave_room_right
1947 clc
1948 tay
1949 iny ; x + 1
1950 lda $5282 ; load the y offset
1951 tax ; as an index
1952 lda room_row_offsets_low,x ; read the address of the row
1953 sta $70
1954 lda #$57
1955 sta $71
1956 lda ($70),y ; load the tile to the right
1958 cmp #5 ; check for the open exit or final exit
1959 bmi move_player_not_right_exit1
1960 jmp try_to_exit_level ; optimise away the rts
1962 move_player_not_right_exit1:
1963 cmp #0
1964 bne move_player_not_horizontal
1966 lda $5283 ; dy
1967 cmp #0
1968 beq move_player_allow_right
1970 clc ; dy > 0 so we need to check another tile
1971 lda $70
1972 adc #10
1973 sta $70
1974 lda ($70),y ; load the tile below and to the right
1976 cmp #5 ; check for the open exit or final exit
1977 bmi move_player_not_right_exit2
1978 jmp try_to_exit_level ; optimise away the rts
1980 move_player_not_right_exit2:
1981 cmp #0
1982 bne move_player_not_horizontal
1984 move_player_allow_right:
1986 jsr unplot_character ; unplot the player character
1987 inc $5285 ; update dx
1988 clc
1989 jmp animate_player_right ; optimise away the rts
1991 move_player_right_tile:
1993 jsr unplot_character ; unplot the player character
1994 inc $5284 ; store the new room x offset
1995 lda #0
1996 sta $5285 ; dx = 0
1997 clc
1998 jmp animate_player_right ; optimise away the rts
2000 move_player_leave_room_right:
2001 clc
2002 inc $5783
2003 clc
2005 ; Set the player's position on the left of the screen.
2007 ; No need to unplot.
2009 lda #0 ; x = 0
2010 sta $5284
2011 lda #0 ; dx = 0
2012 sta $5285
2014 jsr animate_player_right
2015 sec ; indicate to the calling routine that the
2016 rts ; player has left the room
2018 move_player_not_horizontal:
2019 lda $577e
2020 cmp #0
2021 beq move_player_handle_up_key
2022 jmp read_joystick_vertical_check
2024 move_player_handle_up_key:
2026 ; Handle the up key.
2028 ldx #183 ; (:)
2029 jsr check_key
2030 cpy #255
2031 beq move_player_up
2033 ; Handle the down key.
2035 ldx #151 ; (/)
2036 jsr check_key
2037 cpy #255
2038 beq move_player_down
2039 jmp move_player_not_vertical
2041 move_player_up:
2043 lda $5283 ; read dy
2044 cmp #0
2045 beq move_player_up_check_y
2047 jsr unplot_character ; unplot the player character
2048 dec $5283
2049 clc
2050 jmp animate_player_up ; optimise away the rts
2052 move_player_up_check_y: ; Check the y offset.
2054 lda $5282
2055 cmp #0
2056 beq move_player_leave_room_up
2058 tax ; use the y offset as an index
2059 dex ; y - 1
2060 ldy $5284 ; load the x offset
2061 lda room_row_offsets_low,x ; read the address of the row
2062 sta $70
2063 lda #$57
2064 sta $71
2065 lda ($70),y ; load the tile above
2067 cmp #5 ; check for the open exit or final exit
2068 bmi move_player_not_up_exit1
2069 jmp try_to_exit_level ; optimise away the rts
2071 move_player_not_up_exit1:
2072 cmp #0
2073 beq move_player_up_check_dx
2074 clc
2075 rts
2077 move_player_up_check_dx:
2079 lda $5285 ; dx
2080 cmp #3
2081 bmi move_player_allow_up
2083 clc ; dx > 2 so we need to check another tile
2084 iny
2085 lda ($70),y ; load the tile above and to the right
2087 cmp #5 ; check for the open exit or final exit
2088 bmi move_player_not_up_exit2
2089 jmp try_to_exit_level ; optimise away the rts
2091 move_player_not_up_exit2:
2092 cmp #0
2093 beq move_player_allow_up
2094 clc
2095 rts
2097 move_player_allow_up:
2098 txa
2099 sta $81 ; temporary
2100 jsr unplot_character ; unplot the player character
2101 lda $81
2102 sta $5282 ; store the new room y offset
2103 lda #3
2104 sta $5283 ; dy = 3
2105 clc
2106 jmp animate_player_up ; optimise away the rts
2108 move_player_leave_room_up:
2109 sec
2110 lda $5782
2111 sbc #1
2112 sta $5782
2113 clc
2115 ; Set the player's position on the bottom of the screen.
2117 ; No need to unplot.
2119 lda #9 ; y = 9
2120 sta $5282
2121 lda #0 ; dy = 0
2122 sta $5283
2124 jsr animate_player_up
2125 sec ; indicate to the calling routine that the player
2126 rts ; has left the room
2128 move_player_down:
2130 lda $5283 ; read dy
2131 cmp #0
2132 beq move_player_down_check_y
2133 cmp #3
2134 beq move_player_down_tile
2136 jsr unplot_character ; unplot the player character
2137 inc $5283 ; 0 <= dy < 3
2138 clc
2139 jmp animate_player_down ; optimise away the rts
2141 move_player_down_check_y: ; Check the y offset.
2143 lda $5282
2144 cmp #9
2145 beq move_player_leave_room_down
2147 clc
2148 tax
2149 inx ; y + 1
2150 ldy $5284 ; load the x offset
2151 lda room_row_offsets_low,x ; read the address of the row
2152 sta $70
2153 lda #$57
2154 sta $71
2155 lda ($70),y ; load the tile below
2157 cmp #5 ; check for the open exit or final exit
2158 bmi move_player_not_down_exit1
2159 jmp try_to_exit_level ; optimise away the rts
2161 move_player_not_down_exit1:
2162 cmp #0
2163 bne move_player_not_vertical
2165 lda $5285 ; dx
2166 cmp #3
2167 bmi move_player_allow_down
2169 clc ; dx > 2 so we need to check another tile
2170 iny
2171 lda ($70),y ; load the tile below and to the right
2173 cmp #5 ; check for the open exit or final exit
2174 bmi move_player_not_down_exit2
2175 jmp try_to_exit_level ; optimise away the rts
2177 move_player_not_down_exit2:
2178 cmp #0
2179 bne move_player_not_vertical
2181 move_player_allow_down:
2183 jsr unplot_character ; unplot the player character
2184 inc $5283 ; update dy
2185 clc
2186 jmp animate_player_down ; optimise away the rts
2188 move_player_down_tile:
2190 jsr unplot_character ; unplot the player character
2191 inc $5282 ; store the new room y offset
2192 lda #0
2193 sta $5283 ; dy = 0
2194 clc
2195 jmp animate_player_down ; optimise away the rts
2197 move_player_leave_room_down:
2198 inc $5782
2199 clc
2201 ; Set the player's position on the top of the screen.
2203 ; No need to unplot.
2205 lda #0 ; y = 0
2206 sta $5282
2207 lda #0 ; dy = 0
2208 sta $5283
2210 jsr animate_player_down
2211 sec ; indicate to the calling routine that the
2212 rts ; player has left the room
2214 move_player_not_vertical:
2215 clc
2216 rts
2218 try_to_exit_level:
2220 cmp #6
2221 bmi just_exit_level
2223 lda $5780 ; set the complete game flag
2224 ora #$02
2225 jmp try_to_exit_level_exit
2227 just_exit_level:
2228 lda $5780 ; set the exit level flag
2229 ora #$80
2231 try_to_exit_level_exit:
2232 sta $5780
2234 lda #$80
2235 sta $74
2236 lda #$52
2237 sta $75
2238 jsr unplot_character ; remove the player sprite
2239 jmp destroy_enemies ; optimise away the rts
2241 check_fire_key:
2243 lda $578d
2244 bne check_fire_key_exit
2246 lda $577e
2247 beq check_fire_key_no_joystick
2249 lda #128
2250 ldx #0
2251 jsr $fff4
2252 txa
2253 and #1
2254 bne check_fire_key_fire
2256 clc
2257 rts
2259 check_fire_key_no_joystick:
2261 ldx #182 ; (Return)
2262 jsr check_key
2263 cpy #255
2264 bne check_fire_key_exit
2266 check_fire_key_fire:
2268 lda $5286
2269 cmp #0
2270 bne check_fire_key_exit
2272 lda #16
2273 sta $578d
2275 jmp create_projectile ; optimise away the rts
2277 check_fire_key_exit:
2278 clc
2279 rts
2281 create_projectile:
2283 lda #2
2284 sta $5286
2286 lda $5281
2287 and #$06 ; copy the direction information
2288 asl
2289 asl
2290 asl
2291 ora $5789 ; apply the projectile type
2292 sta $5287
2294 lda $5283 ; player dy
2295 adc $577f ; add the weapon counter
2296 adc #1
2297 cmp #4 ; if dy > 3, create the projectile on the tile below
2298 bpl create_projectile_below
2300 clc
2301 sta $5289 ; dy + weapon counter + 1
2302 lda $5282 ; y
2303 sta $5288
2304 jmp create_projectile_continue
2306 create_projectile_below:
2307 sec
2308 sbc #4
2309 sta $5289 ; dy + weapon counter + 1 - 4
2310 clc
2311 lda $5282 ; y
2312 adc #1
2313 sta $5288
2315 create_projectile_continue:
2316 lda $5284 ; x
2317 sta $528a
2319 lda $5285 ; dx
2320 sta $528b
2322 lda $577f ; toggle the weapon counter
2323 eor #1
2324 sta $577f
2326 ; Move the projectile away from the player.
2328 lda #$86
2329 sta $74
2330 lda #$52
2331 sta $75
2332 jsr move_projectile_after_unplot
2334 jsr move_projectile
2336 clc
2337 rts
2339 emerge_type: ; returns A=type
2340 jsr unlimited_values
2341 lda $7d
2342 and #7
2343 cmp #5
2344 bmi emerge_type_ok
2346 sec
2347 sbc #5
2348 clc
2350 emerge_type_ok:
2351 cmp $5781 ; only allow the appropriate enemies for this level
2352 bmi emerge_type_exit
2353 beq emerge_type_reduce
2355 sec
2356 sbc #1
2358 emerge_type_reduce:
2359 sec
2360 sbc $5781
2361 clc
2363 emerge_type_exit:
2364 asl
2365 asl
2366 asl
2367 asl
2368 clc
2369 rts
2371 emerge_character: ; $74,$75=character address
2373 lda #63
2374 sta $578f
2376 jsr unlimited_values
2377 and #$0f
2378 tax
2379 lda $0ee0,x
2380 cmp #0 ; check for an invalid value and exit if found
2381 beq emerge_character_exit
2383 sta $80 ; temporary
2384 lda $0ef0,x
2385 tax
2387 ; Add an emerging enemy.
2389 ldy #0
2390 lda #3 ; emerge/explosion
2391 sta ($74),y
2393 jsr emerge_type ; obtain an enemy type
2394 iny
2395 sta ($74),y
2397 txa
2398 iny
2399 sta ($74),y ; store the y position
2400 lda #1
2401 iny
2402 sta ($74),y ; store the dy offset
2404 lda $80
2405 iny
2406 sta ($74),y ; store the x position
2407 lda #0
2408 iny
2409 sta ($74),y ; store the dx offset
2411 jsr plot_character
2413 ldx #5
2414 jsr play_sound
2416 emerge_character_exit:
2417 clc
2418 rts
2420 emerge_explode: ; $74,$75=character address
2422 jsr unplot_character
2424 ldy #1
2425 lda ($74),y ; direction/animation
2426 tax
2427 adc #1 ; update the counter
2428 and #3 ; mask off everything else
2429 sta $80 ; store the masked counter value
2430 bne move_characters_explosion_not_finished
2432 txa
2433 and #4
2434 bne move_characters_remove_character
2436 ; For emerges, convert into an enemy.
2437 txa
2438 and #$70 ; only keep bits 4,5,6
2439 ora #8 ; make this an enemy
2441 ldy #0
2442 sta ($74),y ; update the type (>= 8)
2443 iny
2444 lda $7d ; prepare the direction and animation offset
2445 and #$0c
2446 sta ($74),y
2448 jsr plot_character
2449 jmp emerge_explode_exit
2451 move_characters_remove_character:
2453 ; For finished explosions, just write 0 into the character array.
2454 lda #0
2455 ldy #0
2456 sta ($74),y
2457 jmp emerge_explode_exit
2459 move_characters_explosion_not_finished:
2460 txa
2461 and #$fc
2462 ora $80
2464 ldy #1
2465 sta ($74),y
2467 jsr plot_character
2469 emerge_explode_exit:
2470 clc
2471 rts
2473 animate_enemy_left: ; $74,$75=character address
2475 ; Set the direction and toggle the animation bit.
2477 ldy #1
2478 lda ($74),y
2479 and #$fb ; keep vertical direction bit and animation bits
2480 sta ($74),y ; left (horizontal directional bit is 0)
2482 rts
2484 move_enemy_left: ; $74,$75=character address
2486 ldy #5
2487 lda ($74),y ; read dx
2488 cmp #0
2489 beq move_enemy_left_check_x
2491 sec
2492 sbc #1
2493 ldy #5
2494 sta ($74),y ; dx
2495 clc
2496 jmp animate_enemy_left ; optimise away the rts
2498 move_enemy_left_check_x:
2500 ; Check the x offset.
2502 ldy #4
2503 lda ($74),y ; x
2504 cmp #0
2505 beq move_enemy_left_exit
2507 sec
2508 sbc #1 ; x - 1
2509 sta $81 ; temporary
2510 ldy #2
2511 lda ($74),y ; load the y offset
2512 tax ; as an index
2513 lda room_row_offsets_low,x ; read the address of the row
2514 sta $70
2515 lda #$57
2516 sta $71
2517 ldy $81 ; temporary (x - 1)
2518 lda ($70),y ; load the tile to the left
2520 cmp #0
2521 bne move_enemy_left_exit
2523 ldy #3
2524 lda ($74),y ; dy
2525 cmp #2
2526 bmi move_enemy_allow_left
2528 clc
2529 lda $70 ; dy > 1 so we need to check another tile
2530 adc #10
2531 sta $70
2532 ldy $81 ; temporary (x - 1)
2533 lda ($70),y ; load the tile below and to the left
2535 cmp #0
2536 bne move_enemy_left_exit
2538 move_enemy_allow_left:
2539 lda $81
2540 ldy #4
2541 sta ($74),y ; store the new room x offset
2542 lda #3
2543 ldy #5
2544 sta ($74),y ; dx = 3
2545 clc
2546 jmp animate_enemy_left ; optimise away the rts
2548 move_enemy_left_exit:
2549 sec
2550 rts
2552 animate_enemy_right: ; $74,$75=character address
2554 ; Set the direction and toggle the animation bit.
2556 ldy #1
2557 lda ($74),y
2558 ora #$04 ; right (keep vertical direction bit and animation bits)
2559 sta ($74),y
2561 rts
2563 move_enemy_right: ; $74,$75=character_address
2565 ldy #5
2566 lda ($74),y ; read dx
2567 cmp #0
2568 beq move_enemy_right_check_x
2569 cmp #3
2570 beq move_enemy_right_tile
2572 clc
2573 adc #1
2574 ldy #5
2575 sta ($74),y
2576 jmp animate_enemy_right ; optimise away the rts
2578 move_enemy_right_check_x: ; Check the x offset.
2580 ldy #4
2581 lda ($74),y ; x
2582 cmp #9
2583 beq move_enemy_right_exit
2585 clc
2586 adc #1 ; x + 1
2587 sta $81 ; temporary (x + 1)
2588 ldy #2
2589 lda ($74),y ; load the y offset
2590 tax ; as an index
2591 lda room_row_offsets_low,x ; read the address of the row
2592 sta $70
2593 lda #$57
2594 sta $71
2595 ldy $81 ; temporary (x + 1)
2596 lda ($70),y ; load the tile to the right
2598 cmp #0
2599 bne move_enemy_right_exit
2601 ldy #3
2602 lda ($74),y ; dy
2603 cmp #2
2604 bmi move_enemy_allow_right
2606 clc ; dy > 1 so we need to check another tile
2607 lda $70
2608 adc #10
2609 sta $70
2610 ldy $81 ; temporary (x + 1)
2611 lda ($70),y ; load the tile below and to the right
2613 cmp #0
2614 bne move_enemy_right_exit
2616 move_enemy_allow_right:
2617 clc
2619 ldy #5
2620 lda ($74),y ; dx
2621 adc #1
2622 sta ($74),y ; update dx
2623 clc
2624 jmp animate_enemy_right ; optimise away the rts
2626 move_enemy_right_tile:
2627 clc
2629 ldy #4
2630 lda ($74),y ; x
2631 adc #1
2632 sta ($74),y ; store the new room x offset
2633 lda #0
2634 iny
2635 sta ($74),y ; dx = 0
2636 clc
2637 jmp animate_enemy_right ; optimise away the rts
2639 move_enemy_right_exit:
2640 sec
2641 rts
2643 animate_enemy_up: ; $74,$75=character address
2645 ; Set the direction and toggle the animation bit.
2647 ldy #1
2648 lda ($74),y
2649 and #$f7 ; keep horizontal direction bit and animation bits
2650 sta ($74),y
2652 rts
2654 move_enemy_up: ; $74,$75=character address
2656 ldy #3
2657 lda ($74),y ; read dy
2658 cmp #0
2659 beq move_enemy_up_check_y
2661 sec
2662 sbc #1
2663 ldy #3
2664 sta ($74),y ; dy
2665 clc
2666 jmp animate_enemy_up ; optimise away the rts
2668 move_enemy_up_check_y:
2670 ; Check the y offset.
2672 ldy #2
2673 lda ($74),y ; y
2674 cmp #0
2675 beq move_enemy_up_exit
2677 tax ; use the y offset as an index
2678 dex ; y - 1
2679 ldy #4
2680 lda ($74),y ; load the x offset
2681 sta $81 ; temporary (x)
2682 tay
2683 lda room_row_offsets_low,x ; read the address of the row
2684 sta $70
2685 lda #$57
2686 sta $71
2687 lda ($70),y ; load the tile above
2689 cmp #0
2690 bne move_enemy_up_exit
2692 ldy #5
2693 lda ($74),y ; dx
2694 cmp #0
2695 beq move_enemy_allow_up
2697 clc ; dx != 0 so we need to check another tile
2698 ldy $81
2699 iny
2700 lda ($70),y ; load the tile above and to the right
2702 cmp #0
2703 bne move_enemy_up_exit
2705 move_enemy_allow_up:
2706 txa
2707 ldy #2
2708 sta ($74),y ; store the new room y offset
2709 lda #3
2710 iny
2711 sta ($74),y ; dy = 3
2712 clc
2713 jmp animate_enemy_up ; optimise away the rts
2715 move_enemy_up_exit:
2716 sec
2717 rts
2719 animate_enemy_down: ; $74,$75=character address
2721 ; Set the direction and toggle the animation bit.
2723 ldy #1
2724 lda ($74),y
2725 ora #$08 ; down
2726 sta ($74),y
2728 rts
2730 move_enemy_down: ; $74,$75=character address
2732 ldy #3
2733 lda ($74),y ; dy
2734 cmp #1
2735 beq move_enemy_down_check_y
2736 cmp #3
2737 beq move_enemy_down_tile
2739 adc #1
2740 ldy #3
2741 sta ($74),y ; dy
2742 clc
2743 jmp animate_enemy_down ; optimise away the rts
2745 move_enemy_down_check_y:
2747 ; Check the y offset.
2749 ldy #2
2750 lda ($74),y
2751 cmp #9
2752 beq move_enemy_down_exit
2754 clc
2755 adc #1 ; y + 1
2756 tax
2757 ldy #4
2758 lda ($74),y ; load the x offset
2759 sta $81 ; temporary
2760 tay
2761 lda room_row_offsets_low,x ; read the address of the row
2762 sta $70
2763 lda #$57
2764 sta $71
2765 lda ($70),y ; load the tile below
2767 cmp #0
2768 bne move_enemy_down_exit
2770 ldy #5
2771 lda ($74),y ; dx
2772 cmp #0
2773 beq move_enemy_allow_down
2775 clc ; dx != 0 so we need to check another tile
2776 ldy $81 ; x
2777 iny
2778 lda ($70),y ; load the tile below and to the right
2780 cmp #0
2781 bne move_enemy_down_exit
2783 move_enemy_allow_down:
2784 clc
2786 ldy #3
2787 lda ($74),y ; dy
2788 adc #1
2789 sta ($74),y ; update dy
2790 clc
2791 jmp animate_enemy_down ; optimise away the rts
2793 move_enemy_down_tile:
2794 clc
2796 ldy #2
2797 lda ($74),y ; y
2798 adc #1
2799 sta ($74),y ; store the new room y offset
2800 lda #0
2801 iny
2802 sta ($74),y ; dy = 0
2803 clc
2804 jmp animate_enemy_down ; optimise away the rts
2806 move_enemy_down_exit:
2807 sec
2808 rts
2810 move_enemy_animate: ; $74,$75=character address
2812 ldy #1
2813 lda ($74),y ; direction/animation
2814 sta $81
2815 and #$03
2816 adc #1
2817 and #$03 ; keep animation bits
2818 sta $8f
2819 lda $81
2820 and #$fc ; mask off the animation bits
2821 ora $8f
2822 sta ($74),y
2823 rts
2825 move_enemy_next_direction: .byte $04, $0c, $00, $08
2827 move_enemy: ; $74,$75=character address
2829 lda #0
2830 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2831 lda #0
2832 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2834 lda ($74),y ; read the enemy number (Y should be zero)
2835 and #$10
2836 beq move_enemy_homing
2837 clc
2839 ; This enemy is a non-homing enemy.
2841 jsr unplot_character ; unplot now before we change the sprite used
2843 ldy #1
2844 lda ($74),y
2845 and #$f0
2846 cmp #$f0
2847 bne move_enemy_set_direction
2848 clc
2850 ldy #1
2851 lda ($74),y
2852 and #$0c
2853 ror
2854 ror
2855 tax
2856 lda move_enemy_next_direction,x
2857 sta ($74),y
2859 move_enemy_set_direction:
2860 clc
2862 ldy #1
2863 lda ($74),y
2864 sta $7b
2866 adc #$10
2867 sta ($74),y
2868 clc
2870 lda $7b
2871 and #$04
2872 ror
2873 ror
2874 adc #1
2875 sta $8e
2877 lda $7b
2878 and #$08
2879 ror
2880 ror
2881 ror
2882 adc #1
2883 sta $8d
2885 jmp move_enemy_with_direction
2887 move_enemy_homing:
2889 ldy #2
2890 lda ($74),y ; y
2891 cmp $5282 ; player y
2892 bmi move_enemy_downwards
2893 bne move_enemy_upwards
2895 ldy #3
2896 lda ($74),y ; dy
2897 cmp $5283 ; player y
2898 beq move_enemy_horizontally
2899 bpl move_enemy_upwards
2901 move_enemy_downwards:
2902 lda #2
2903 sta $8d
2904 jmp move_enemy_horizontally
2906 move_enemy_upwards:
2907 lda #1
2908 sta $8d
2909 ;jmp move_enemy_horizontally
2911 move_enemy_horizontally:
2912 ldy #4
2913 lda ($74),y ; x
2914 cmp $5284 ; player x
2915 bmi move_enemy_rightwards
2916 bne move_enemy_leftwards
2918 ldy #5
2919 lda ($74),y ; dx
2920 cmp #0
2921 beq move_enemy_with_direction_unplot
2922 bpl move_enemy_leftwards
2924 move_enemy_rightwards:
2925 lda #2
2926 sta $8e
2927 jmp move_enemy_with_direction_unplot
2929 move_enemy_leftwards:
2930 lda #1
2931 sta $8e
2933 move_enemy_with_direction_unplot:
2934 clc
2936 jsr unplot_character
2938 move_enemy_with_direction:
2939 clc
2941 lda $8e
2942 cmp #1
2943 bne move_enemy_not_left
2944 jsr move_enemy_left
2945 clc
2946 jmp move_enemy_not_right
2948 move_enemy_not_left:
2949 lda $8e
2950 cmp #2
2951 bne move_enemy_not_right
2952 jsr move_enemy_right
2953 clc
2955 move_enemy_not_right:
2956 lda $8d
2957 cmp #1
2958 bne move_enemy_not_up
2959 jsr move_enemy_up
2960 clc
2961 jmp move_enemy_toggle
2963 move_enemy_not_up:
2964 lda $8d
2965 cmp #2
2966 bne move_enemy_toggle
2967 jsr move_enemy_down
2969 move_enemy_toggle:
2970 clc
2971 jsr move_enemy_animate
2972 jmp plot_character ; optimise away the rts
2974 move_enemy_exit:
2975 clc
2976 rts
2978 create_explosion: ; X=y, Y=x
2980 lda #3
2981 sta $52a4
2982 lda #4
2983 sta $52a5
2984 txa
2985 sta $52a6
2986 lda #1
2987 sta $52a7
2988 tya
2989 sta $52a8
2990 lda #0
2991 sta $52a9
2992 rts
2994 move_projectile_left:
2996 lda $528b
2997 cmp #0
2998 beq move_projectile_left_check_x
3000 dec $528b
3001 clc
3002 rts
3004 move_projectile_left_check_x:
3006 lda $528a
3007 cmp #0
3008 bne move_projectile_left_in_room
3009 jmp move_projectile_left_exit
3011 move_projectile_left_in_room:
3012 tay
3013 dey ; x - 1
3014 ldx $5288 ; y
3015 lda room_row_offsets_low,x ; read the address of the row
3016 sta $70
3017 lda #$57
3018 sta $71
3019 lda ($70),y ; load the tile to the left
3021 cmp #0
3022 bne move_projectile_left_wall
3024 lda $5289 ; dy
3025 cmp #3
3026 bmi move_projectile_allow_left
3028 clc ; dy > 2 so we need to check another tile
3029 lda $70
3030 adc #10
3031 sta $70
3032 lda ($70),y ; load the tile below and to the left
3033 inx ; y += 1
3035 cmp #0
3036 bne move_projectile_left_wall
3038 move_projectile_allow_left:
3040 sty $528a ; x
3041 lda #3
3042 sta $528b ; dx = 3
3044 clc
3045 rts
3047 move_projectile_left_wall: ; the projectile hit a wall
3048 clc
3050 lda $5287 ; type 2 can pass through walls
3051 and #$06
3052 cmp #4
3053 beq move_projectile_allow_left
3055 cmp #2
3056 bne move_projectile_left_not_boomerang
3058 lda $5287
3059 and #$0f
3060 cmp #8
3061 bpl move_projectile_left_exit
3063 ldx $577f ; weapon counter
3064 ora boomerang_horizontal,x
3065 sta $5287
3066 clc
3067 rts ; exit without moving or registering a collision
3069 move_projectile_left_not_boomerang:
3071 cmp #6 ; type 3 can destroy certain walls
3072 bne move_projectile_left_exit
3074 lda ($70),y ; load the tile to the left
3075 cmp #1 ; decoration can be destroyed
3076 bne move_projectile_left_exit
3077 clc
3079 lda #0
3080 sta ($70),y
3082 ; X=y, Y=x
3083 jsr create_explosion
3084 jsr plot_blank_xy ; corrupted X
3086 lda #$a4
3087 sta $74
3088 lda #$52
3089 sta $75
3090 jsr plot_character
3092 ldx #0
3093 jsr play_sound
3095 lda #16 ; prevent the player from firing a new
3096 sta $578d ; projectile until the explosion has finished
3098 move_projectile_left_exit:
3099 sec
3100 rts
3102 boomerang_horizontal: .byte $28, $38
3104 move_projectile_right:
3106 ; Fire right.
3108 lda $528b
3109 cmp #2
3110 beq move_projectile_right_check_x
3111 cmp #3
3112 beq move_projectile_right_tile
3114 inc $528b
3115 clc
3116 rts
3118 move_projectile_right_check_x:
3120 lda $528a ; x
3121 cmp #9
3122 bne move_projectile_right_not_edge
3123 jmp move_projectile_right_exit
3125 move_projectile_right_not_edge:
3126 clc
3127 tay
3128 iny ; x + 1
3129 ldx $5288 ; y
3130 lda room_row_offsets_low,x ; read the address of the row
3131 sta $70
3132 lda #$57
3133 sta $71
3134 lda ($70),y ; load the tile to the right
3136 cmp #0
3137 bne move_projectile_right_wall
3139 lda $5289 ; dy
3140 cmp #3
3141 bmi move_projectile_allow_right
3143 clc ; dy > 2 so we need to check another tile
3144 lda $70
3145 adc #10
3146 sta $70
3147 lda ($70),y ; load the tile below and to the right
3148 inx ; y += 1
3150 cmp #0
3151 bne move_projectile_right_wall
3153 move_projectile_allow_right:
3155 inc $528b ; dx
3156 clc
3157 rts
3159 move_projectile_right_tile:
3161 inc $528a ; x
3162 lda #0
3163 sta $528b ; dx
3164 clc
3165 rts
3167 move_projectile_right_wall: ; the projectile hit a wall
3168 clc
3170 lda $5287 ; type 2 can pass through walls
3171 and #$06
3172 cmp #4
3173 beq move_projectile_allow_right
3175 cmp #2
3176 bne move_projectile_right_not_boomerang
3178 lda $5287
3179 and #$0f
3180 cmp #8
3181 bpl move_projectile_right_exit
3183 ldx $577f ; weapon counter
3184 ora boomerang_horizontal,x
3185 sta $5287
3186 clc
3187 rts ; exit without moving or registering a collision
3189 move_projectile_right_not_boomerang:
3191 cmp #6 ; type 3 can destroy certain walls
3192 bne move_projectile_right_exit
3194 lda ($70),y ; load the tile to the right
3195 cmp #1 ; decoration can be destroyed
3196 bne move_projectile_right_exit
3197 clc
3199 lda #0
3200 sta ($70),y
3202 ; X=y, Y=x
3203 jsr create_explosion
3204 jsr plot_blank_xy ; corrupted X
3206 lda #$a4
3207 sta $74
3208 lda #$52
3209 sta $75
3210 jsr plot_character
3212 ldx #0
3213 jsr play_sound
3215 lda #16 ; prevent the player from firing a new
3216 sta $578d ; projectile until the explosion has finished
3218 move_projectile_right_exit:
3219 sec
3220 rts
3222 move_projectile_up:
3224 lda $5289 ; read dy
3225 cmp #0
3226 beq move_projectile_up_check_y
3228 dec $5289
3229 clc
3230 rts
3232 move_projectile_up_check_y: ; Check the y offset.
3234 lda $5288
3235 cmp #0
3236 bne move_projectile_up_not_edge
3237 jmp move_projectile_up_exit
3239 move_projectile_up_not_edge:
3240 tax ; use the y offset as an index
3241 dex ; y - 1
3242 ldy $528a ; load the x offset
3243 lda room_row_offsets_low,x ; read the address of the row
3244 sta $70
3245 lda #$57
3246 sta $71
3247 lda ($70),y ; load the tile above
3249 cmp #0
3250 bne move_projectile_up_wall
3252 lda $528b ; dx
3253 cmp #3
3254 bmi move_projectile_allow_up
3256 clc ; dx > 2 so we need to check another tile
3257 iny
3258 lda ($70),y ; load the tile above and to the right
3260 cmp #0
3261 bne move_projectile_up_wall
3263 move_projectile_allow_up:
3264 txa
3265 sta $5288 ; store the new room y offset
3266 lda #3
3267 sta $5289 ; dy = 3
3269 clc
3270 rts
3272 move_projectile_up_wall: ; the projectile hit a wall
3273 clc
3275 lda $5287 ; type 2 can pass through walls
3276 and #$06
3277 cmp #4
3278 beq move_projectile_allow_up
3280 cmp #2
3281 bne move_projectile_up_not_boomerang
3283 lda $5287
3284 and #$0f
3285 cmp #8
3286 bpl move_projectile_up_exit
3288 ldx $577f ; weapon counter
3289 ora boomerang_vertical,x
3290 sta $5287
3291 clc
3292 rts ; exit without moving or registering a collision
3294 move_projectile_up_not_boomerang:
3296 cmp #6 ; type 3 can destroy certain walls
3297 bne move_projectile_up_exit
3299 lda ($70),y ; load the tile above
3300 cmp #1 ; decoration can be destroyed
3301 bne move_projectile_up_exit
3302 clc
3304 lda #0
3305 sta ($70),y
3307 ; X=y, Y=x
3308 jsr create_explosion
3309 jsr plot_blank_xy ; corrupted X
3311 lda #$a4
3312 sta $74
3313 lda #$52
3314 sta $75
3315 jsr plot_character
3317 ldx #0
3318 jsr play_sound
3320 lda #16 ; prevent the player from firing a new
3321 sta $578d ; projectile until the explosion has finished
3323 move_projectile_up_exit:
3324 sec
3325 rts
3327 boomerang_vertical: .byte $08, $18
3329 move_projectile_down:
3331 lda $5289 ; read dy
3332 cmp #2
3333 beq move_projectile_down_check_y
3334 cmp #3
3335 beq move_projectile_down_tile
3337 inc $5289 ; 0 <= dy < 3
3338 clc
3339 rts
3341 move_projectile_down_check_y: ; Check the y offset.
3343 lda $5288
3344 cmp #9
3345 bne move_projectile_down_in_room
3346 jmp move_projectile_down_exit
3348 move_projectile_down_in_room:
3349 clc
3350 tax
3351 inx ; y + 1
3352 ldy $528a ; load the x offset
3353 lda room_row_offsets_low,x ; read the address of the row
3354 sta $70
3355 lda #$57
3356 sta $71
3357 lda ($70),y ; load the tile below
3359 cmp #0
3360 bne move_projectile_down_wall
3362 lda $528b ; dx
3363 cmp #3
3364 bmi move_projectile_allow_down
3366 clc ; dx > 2 so we need to check another tile
3367 iny
3368 lda ($70),y ; load the tile below and to the right
3370 cmp #0
3371 bne move_projectile_down_wall
3373 move_projectile_allow_down:
3375 inc $5289 ; update dy
3376 clc
3377 rts
3379 move_projectile_down_tile:
3381 inc $5288 ; store the new room y offset
3382 lda #0
3383 sta $5289 ; dy = 0
3384 clc
3385 rts
3387 move_projectile_down_wall: ; the projectile hit a wall
3388 clc
3390 lda $5287 ; type 2 can pass through walls
3391 and #$06
3392 cmp #4
3393 beq move_projectile_allow_down
3395 cmp #2
3396 bne move_projectile_down_not_boomerang
3398 lda $5287
3399 and #$0f
3400 cmp #8
3401 bpl move_projectile_down_exit
3403 ldx $577f ; weapon counter
3404 ora boomerang_vertical,x
3405 sta $5287
3406 clc
3407 rts ; exit without moving or registering a collision
3409 move_projectile_down_not_boomerang:
3411 cmp #6 ; type 3 can destroy certain walls
3412 bne move_projectile_down_exit
3414 lda ($70),y ; load the tile below
3415 cmp #1 ; decoration can be destroyed
3416 bne move_projectile_down_exit
3417 clc
3419 lda #0
3420 sta ($70),y
3422 ; X=y, Y=x
3423 jsr create_explosion
3424 jsr plot_blank_xy ; corrupted X
3426 lda #$a4
3427 sta $74
3428 lda #$52
3429 sta $75
3430 jsr plot_character
3432 ldx #0
3433 jsr play_sound
3435 lda #16 ; prevent the player from firing a new
3436 sta $578d ; projectile until the explosion has finished
3438 move_projectile_down_exit:
3439 sec
3440 rts
3442 move_projectile_animate:
3444 lda $5287
3445 eor #1
3446 sta $5287
3447 rts
3449 move_projectile:
3451 lda $5286
3452 cmp #0
3453 bne move_projectile_move
3454 jmp move_projectile_exit
3456 move_projectile_move:
3457 clc
3459 lda #$86
3460 sta $74
3461 lda #$52
3462 sta $75
3463 jsr unplot_character
3465 move_projectile_after_unplot:
3467 lda $5287
3468 and #$30 ; direction
3470 cmp #0
3471 bne move_projectile_not_left
3473 jsr move_projectile_left
3474 bcc move_projectile_toggle
3475 bcs move_projectile_destroy
3477 move_projectile_not_left:
3478 cmp #$10
3479 bne move_projectile_not_right
3481 jsr move_projectile_right
3482 bcc move_projectile_toggle
3483 bcs move_projectile_destroy
3485 move_projectile_not_right:
3486 cmp #$20
3487 bne move_projectile_not_up
3489 jsr move_projectile_up
3490 bcc move_projectile_toggle
3491 bcs move_projectile_destroy
3493 move_projectile_not_up:
3494 cmp #$30
3495 bne move_projectile_toggle
3497 jsr move_projectile_down
3498 bcs move_projectile_destroy
3500 move_projectile_toggle:
3502 jsr projectile_collide
3503 bcs move_projectile_destroy
3505 jsr move_projectile_animate
3507 lda #$86
3508 sta $74
3509 lda #$52
3510 sta $75
3511 jmp plot_character ; optimise away the rts
3513 move_projectile_destroy:
3514 clc
3516 ldy #0
3517 lda ($74),y ; type
3518 cmp #8
3519 bmi move_projectile_no_enemy_collision
3521 and #$70 ; increase the player's score
3522 lsr
3523 lsr
3524 lsr
3525 adc #2
3526 sta $70
3527 jsr add_score
3528 jmp move_projectile_create_explosion
3530 move_projectile_no_enemy_collision:
3532 cmp #4 ; items can be destroyed as well
3533 bne move_projectile_no_item_collision
3535 ldy #1 ; but not keys
3536 lda ($74),y
3537 cmp #4 ; even the mace is stopped by a key
3538 beq move_projectile_remove_projectile
3539 clc
3541 jsr remove_room_item
3543 move_projectile_create_explosion:
3545 ; Unplot the item/enemy and replace it with an explosion.
3547 jsr unplot_character
3549 lda #3 ; explosion
3550 ldy #0
3551 sta ($74),y
3553 lda #4
3554 ldy #1
3555 sta ($74),y
3557 jsr plot_character
3559 ; Play a sound.
3560 ldx #0
3561 jsr play_sound
3563 move_projectile_no_item_collision:
3565 lda $5287 ; type 2 projectiles pass through everything
3566 and #$06
3567 cmp #4
3568 bne move_projectile_remove_projectile
3570 ; Ideally, we would have recorded if the projectile left the screen so
3571 ; that we don't perform these checks again here, but it would just add
3572 ; overhead to the normal movement routines for the other weapons.
3574 lda $5288 ; y
3575 cmp #0
3576 beq move_projectile_remove_projectile
3577 cmp #9
3578 beq move_projectile_remove_projectile
3580 lda $528a ; x
3581 cmp #0
3582 beq move_projectile_remove_projectile
3583 cmp #9
3584 beq move_projectile_remove_projectile
3586 clc
3587 lda #$86
3588 sta $74
3589 lda #$52
3590 sta $75
3592 jsr plot_character
3593 jmp move_projectile_exit
3595 move_projectile_remove_projectile:
3597 lda #0 ; remove the projectile from the character list
3598 sta $5286
3600 move_projectile_exit:
3601 clc
3602 rts
3604 emerge_characters:
3606 lda #$8c ; set the character address
3607 sta $74
3608 lda #$52
3609 sta $75
3611 emerge_characters_loop:
3613 ldy #0
3614 lda ($74),y
3615 cmp #0
3616 bne emerge_characters_next
3618 jmp emerge_character ; optimise away the rts
3620 emerge_characters_next:
3621 clc
3623 ; Examine the next character.
3624 lda $74
3625 adc #6
3627 cmp #$a4
3628 bpl emerge_characters_exit
3629 sta $74
3630 jmp emerge_characters_loop
3632 emerge_characters_exit:
3633 clc
3634 rts
3636 enemy_slots: .byte 0, 6, 12, 18
3638 move_characters:
3640 lda #$8c ; set the character address
3641 sta $74
3642 lda #$52
3643 sta $75
3645 lda $578e ; read a value from 0 to 3 from the motion counter
3646 and #3
3647 tax
3648 lda enemy_slots,x ; look up the corresponding slot in the character list
3649 adc $74
3650 sta $74 ; update the character address
3652 move_characters_loop:
3654 ldy #0
3655 lda ($74),y
3656 cmp #3
3657 bne move_characters_not_emerge_explode
3659 jsr emerge_explode
3660 jmp move_characters_next
3662 move_characters_not_emerge_explode:
3663 cmp #8
3664 bmi move_characters_next
3666 jsr move_enemy
3668 move_characters_next:
3669 clc
3671 lda $74 ; for the last enemy, check the next slot
3672 cmp #$9e ; for the presence of an explosion
3673 bne move_characters_endloop ; otherwise leave the loop (only performing
3674 clc ; one iteration)
3676 adc #6
3677 sta $74
3678 jmp move_characters_loop
3680 move_characters_endloop:
3681 clc
3683 ; Check collisions with the player.
3685 jsr player_collide
3686 bcs move_characters_collisions
3687 jmp move_characters_exit
3689 move_characters_collisions:
3690 clc
3692 ldy #0
3693 lda ($74),y ; type
3694 cmp #8
3695 bpl move_character_destroy_enemy
3697 ; Unplot the item.
3698 jsr unplot_character
3700 ; Remove it from the item table.
3701 jsr remove_room_item
3703 lda #0 ; remove the item from the character list
3704 ldy #0
3705 sta ($74),y
3707 iny
3708 lda ($74),y ; get the item type
3710 sta $8d ; temporarily store A and increase the score
3711 tax
3712 lda item_scores,x
3713 sta $70
3714 jsr add_score
3715 lda $8d
3717 ; Check the item type.
3718 cmp #8
3719 bmi move_characters_not_health
3721 lda #20
3722 sta $70
3723 jsr add_strength
3724 clc
3726 ldx #2
3727 jsr play_sound
3729 rts
3731 move_characters_not_health:
3732 cmp #5
3733 bmi move_characters_not_treasure
3735 ldx #2
3736 jsr play_sound
3738 clc
3739 rts
3741 move_characters_not_treasure:
3742 cmp #4
3743 bmi move_characters_not_key
3745 ; Key - update the item/player flags byte.
3746 lda $5780
3747 ora #$01
3748 sta $5780
3749 clc
3751 ldx #3
3752 jsr play_sound
3754 rts
3756 move_characters_not_key:
3758 ; Update the player's weapon.
3759 asl
3760 sta $5789
3761 clc
3763 ldx #2
3764 jsr play_sound
3766 rts
3768 move_character_destroy_enemy:
3770 ; Unplot the enemy and replace it with an explosion.
3772 jsr unplot_character
3774 lda #3 ; explosion
3775 ldy #0
3776 sta ($74),y
3778 lda #4
3779 ldy #1
3780 sta ($74),y
3782 jsr plot_character
3784 ; Reduce the player's strength.
3786 ldx #1
3787 jsr play_sound
3789 lda #1
3790 sta $70
3791 jmp reduce_strength ; optimise away the rts
3793 move_characters_exit:
3794 clc
3795 rts
3797 remove_room_item:
3799 ldx $5782 ; current room row number
3800 lda eleven_times_table,x
3801 adc $5783 ; current room column number
3802 tax
3803 lda #$80 ; store a value with the top bit set instead of zero because we
3804 sta $5200,x ; have visited this room if we can collect the object within it
3805 clc
3806 rts
3808 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3809 score_vdu_bytes: .byte 1,1,31 ; reversed
3810 score_digits: .byte "0123456789"
3812 add_score: ; $70=score to add
3814 sed
3815 lda $5786
3816 adc $70
3817 sta $5786
3818 lda $5787
3819 adc #0
3820 sta $5787
3821 lda $5788
3822 adc #0
3823 sta $5788
3824 cld
3826 write_score:
3828 lda #$86
3829 sta $70
3830 lda #$57
3831 sta $71
3833 ldx #2
3834 write_score_vdu_bytes:
3835 lda score_vdu_bytes,x
3836 jsr $ffee
3837 dex
3838 bpl write_score_vdu_bytes
3840 write_score_digits: ; $70,$71=address of score bytes
3842 ldy #2
3843 write_score_loop:
3845 lda ($70),y
3846 lsr
3847 lsr
3848 lsr
3849 lsr
3850 tax
3851 lda score_digits,x
3852 jsr $ffee
3854 lda ($70),y
3855 and #$0f
3856 tax
3857 lda score_digits,x
3858 jsr $ffee
3860 dey
3861 bpl write_score_loop
3863 clc
3864 rts
3866 strength_units: .byte $00,$88,$cc,$ee
3868 add_strength: ; $70=strength to add
3870 ; Divide the initial strength by 4 to determine which half character to
3871 ; start plotting at, and multiply by 8 to get the address. The net result
3872 ; is to mask off the bottom two bits and shift left once.
3873 lda $5784
3874 and #$fc
3875 sta $71 ; strength rounded down to a multiple of four units
3876 asl
3877 clc
3878 tay
3880 lda $5784
3881 adc $70
3882 cmp #65
3883 bmi add_strength_update
3885 lda #64
3887 add_strength_update:
3888 clc
3889 sta $5784 ; the final strength
3891 sec
3892 sbc $71
3893 clc
3894 tax ; the number of units to add between the rounded original
3895 ; strength and the final strength
3897 lda #$f3 ; the start of the strength bar
3898 sta $72
3899 lda #$59
3900 sta $73
3902 cpx #4
3903 bmi add_strength_loop_extra
3905 add_strength_loop:
3907 clc
3908 lda #$ff
3909 sta ($72),y
3911 tya
3912 adc #8
3913 tay
3915 txa
3916 sec
3917 sbc #4
3918 clc
3919 tax
3921 cmp #4
3922 bpl add_strength_loop
3924 add_strength_loop_extra:
3925 cpx #0
3926 beq add_strength_exit
3928 ; For any remaining units in excess of the multiples of four units, plot
3929 ; the appropriate byte.
3930 lda $5784
3931 and #3
3932 tax
3934 lda strength_units,x
3935 sta ($72),y
3937 add_strength_exit:
3938 clc
3939 rts
3941 reduce_strength: ; $70=strength to remove
3943 lda $5784
3944 tax
3945 sec
3946 sbc $70
3947 bpl reduce_strength_update
3949 lda #0
3951 reduce_strength_update:
3952 clc
3953 sta $5784
3955 ; Divide the final strength by 4 to determine which half character to
3956 ; plot, and multiply by 8 to get the address. The net result is to mask off
3957 ; the bottom two bits and shift left once.
3958 and #$fc
3959 asl
3960 tay
3962 lda #$f3 ; the start of the strength bar
3963 sta $70
3964 lda #$59
3965 sta $71
3967 lda $5784
3968 and #3
3969 tax
3970 lda strength_units,x
3971 sta ($70),y
3973 lda $5784
3974 cmp #0
3975 bne reduce_strength_exit
3977 lda $5780 ; the player ran out of strength
3978 ora #$40
3979 sta $5780
3981 lda #64 ; reset the delay counter
3982 sta $5785
3984 lda #$80 ; unplot the player
3985 sta $74
3986 lda #$52
3987 sta $75
3989 jsr unplot_character
3991 lda #8 ; change the player's direction to the demise animation
3992 sta $5281
3994 jsr plot_character
3995 jmp destroy_enemies ; optimise away the rts
3997 reduce_strength_exit:
3998 clc
3999 rts
4001 destroy_enemies:
4003 lda #$8c
4004 sta $74
4005 lda #$52
4006 sta $75
4008 destroy_enemies_loop:
4010 ldy #0
4011 lda ($74),y
4012 cmp #8
4013 bmi destroy_enemies_not_enemy
4015 jsr unplot_character
4017 lda #3 ; emerge/explosion
4018 ldy #0
4019 sta ($74),y
4021 iny
4022 lda #4 ; explosion
4023 sta ($74),y
4025 jsr plot_character
4026 jmp destroy_enemies_not_emerging_enemy
4028 destroy_enemies_not_enemy:
4029 cmp #3
4030 bne destroy_enemies_not_emerging_enemy
4032 jsr unplot_character
4034 iny ; whether emerging or exploding, ensure that the enemy
4035 lda ($74),y ; is now exploding
4036 ora #4
4037 sta ($74),y
4039 jsr plot_character
4041 destroy_enemies_not_emerging_enemy:
4042 clc
4043 lda $74
4044 adc #6
4045 sta $74
4046 cmp #$a4
4047 bmi destroy_enemies_loop
4049 clc
4050 rts
4052 remove_characters:
4054 ; Clear the character table.
4056 ldx #6
4057 remove_characters_loop:
4058 lda #0
4059 sta $5280,x
4060 txa
4061 adc #6
4062 tax
4063 cpx #$2a
4064 bmi remove_characters_loop
4066 rts
4068 ; The player collision masks use bits to represent where the player is in a
4069 ; tile. See the collisions.txt file for more information.
4071 ; Player is above, enemy is below, checking the overlap in the lower tile.
4072 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4074 projectile_collision_mask_above: .byte $00, $00, $00, $80
4076 ; Player and enemy share the same tile or player is on the tile below.
4077 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4079 projectile_collision_mask_below: .byte $e0, $38, $0e, $03
4081 ; Player is above or on the same tile, enemy is below, checking the overlap in
4082 ; the lower tile.
4083 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4085 ; Enemy is above, player is below, checking the overlap in the lower tile.
4086 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4088 ; Player is to the left, enemy is to the right, checking the overlap in the
4089 ; right hand tile.
4090 player_collision_mask_left:
4091 projectile_collision_mask_left: .byte $00, $00, $00, $08
4093 ; Player and enemy share the same tile or player is on the tile to the right.
4094 player_collision_mask_right:
4095 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4097 ; Player is to the left, enemy is to the right or on the same tile, checking
4098 ; the overlap in the right hand tile.
4099 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4101 ; Enemy is to the left, player is to the right, checking the overlap in the
4102 ; right hand tile.
4103 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4105 player_collide:
4107 lda $5282 ; player y
4108 sta $8a
4109 lda $5284 ; player x
4110 sta $8b
4112 ldx $5283 ; player dy
4113 lda player_collision_mask_above,x
4114 sta $86
4115 lda player_collision_mask_below,x
4116 sta $88
4117 ldx $5285 ; player dx
4118 lda player_collision_mask_left,x
4119 sta $87
4120 lda player_collision_mask_right,x
4121 sta $89
4123 jmp collide ; optimise away the rts
4125 projectile_collide:
4127 lda $5288 ; projectile y
4128 sta $8a
4129 lda $528a ; projectile x
4130 sta $8b
4132 ldx $5289 ; projectile dy
4133 lda projectile_collision_mask_above,x
4134 sta $86
4135 lda projectile_collision_mask_below,x
4136 sta $88
4137 ldx $528b ; projectile dx
4138 lda projectile_collision_mask_left,x
4139 sta $87
4140 lda projectile_collision_mask_right,x
4141 sta $89
4143 ; Run on into the next routine.
4145 collide:
4147 lda #$8c ; set the character address
4148 sta $74
4149 lda #$52
4150 sta $75
4152 collide_loop:
4154 ldy #0
4155 lda ($74),y ; type
4156 cmp #4
4157 bpl collide_check
4159 jmp collide_next
4161 collide_check:
4163 ldy #2
4164 lda ($74),y ; y
4165 sec
4166 sbc $8a ; y - player/projectile y
4167 beq check_collide_y_equal
4168 cmp #1
4169 beq check_collide_y_greater
4170 cmp #255
4171 beq check_collide_y_less
4173 jmp collide_next
4175 check_collide_y_equal:
4176 ; The enemy is on the same tile as the player/projectile so look at the
4177 ; collision on their common tile.
4178 ldy #3
4179 lda ($74),y ; dy
4180 tax
4181 lda enemy_collision_mask_above,x
4182 and $88 ; player/projectile mask below
4183 bne check_collide_x
4185 jmp collide_next
4187 check_collide_y_greater:
4188 ; The enemy is on the tile below the player/projectile so look at the
4189 ; collision on the enemy's tile.
4190 ldy #3
4191 lda ($74),y ; dy
4192 tax
4193 lda enemy_collision_mask_above,x
4194 and $86 ; player mask above
4195 bne check_collide_x
4197 jmp collide_next
4199 check_collide_y_less:
4200 ; The enemy is on the tile above the player/projectile so look at the
4201 ; collision on the player's tile.
4202 ldy #3
4203 lda ($74),y ; dy
4204 tax
4205 lda enemy_collision_mask_below,x
4206 and $88 ; player mask below
4207 bne check_collide_x
4209 jmp collide_next
4211 check_collide_x:
4212 ldy #4
4213 lda ($74),y ; x
4214 sec
4215 sbc $8b ; x - player/projectile x
4216 beq check_collide_x_equal
4217 cmp #1
4218 beq check_collide_x_greater
4219 cmp #255
4220 beq check_collide_x_less
4222 jmp collide_next
4224 check_collide_x_equal:
4225 ; The enemy is on the same tile as the player/projectile so look at the
4226 ; collision on their common tile.
4227 ldy #5
4228 lda ($74),y ; dx
4229 tax
4230 lda enemy_collision_mask_left,x
4231 and $89 ; player mask right
4232 bne check_collide_destroy
4234 jmp collide_next
4236 check_collide_x_greater:
4237 ; The enemy is the tile to the right of the player/projectile so look
4238 ; at the collision on the enemy's tile.
4239 ldy #5
4240 lda ($74),y ; dx
4241 tax
4242 lda enemy_collision_mask_left,x
4243 and $87 ; player mask left
4244 bne check_collide_destroy
4246 jmp collide_next
4248 check_collide_x_less:
4249 ; The enemy is the tile to the left of the player/projectile so look at
4250 ; the collision on the player's tile.
4251 ldy #5
4252 lda ($74),y ; dx
4253 tax
4254 lda enemy_collision_mask_right,x
4255 and $89 ; player mask right
4256 bne check_collide_destroy
4258 collide_next:
4259 clc
4261 ; Examine the next character.
4262 lda $74
4263 adc #6
4265 cmp #$a4
4266 bpl collide_exit
4267 sta $74
4268 jmp collide_loop
4270 check_collide_destroy:
4272 sec ; set the carry flag to inform the caller that the
4273 rts ; player/projectile should be destroyed
4275 collide_exit:
4276 clc
4277 rts
4279 blank_screen:
4280 lda #1
4281 sta $70
4282 lda #0
4283 sta $71
4284 jsr set_palette
4285 lda #2
4286 sta $70
4287 lda #0
4288 sta $71
4289 jsr set_palette
4290 lda #3
4291 sta $70
4292 lda #0
4293 sta $71
4294 ; Run on into set_palette.
4296 set_palette:
4297 ; $70=logical colour
4298 ; $71=physical colour
4299 lda $70
4300 sta $578b
4301 lda $71
4302 sta $578c
4303 lda #0
4304 sta $578d
4305 sta $578e
4306 sta $578f
4308 lda #$c
4309 ldx #$8b
4310 ldy #$57
4311 jsr $fff1
4312 rts
4314 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4315 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4317 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4318 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4319 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4320 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4321 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4323 .alias note_sound $5760
4324 .alias note_pitch $5764
4325 .alias note_duration $5766
4327 play_note: ; A=pitch, Y=duration
4329 sta note_pitch
4330 sty note_duration
4331 ldx #4
4332 ; Run on into the next routine.
4334 play_sound: ; X=sound number
4336 lda sounds_high,x
4337 tay
4338 lda sounds_low,x
4339 tax
4340 lda #7
4341 jsr $fff1
4343 rts
4345 copy_title_up:
4347 lda #$00
4348 sta $70
4349 lda #$18
4350 sta $71
4352 lda #$a0
4353 sta $72
4354 lda #$5a
4355 sta $73
4357 ldx #5
4358 ; Run on into the next routine.
4360 copy_title:
4362 copy_title_loop1:
4364 ldy #0
4365 copy_title_loop2:
4367 lda ($70),y
4368 sta ($72),y
4369 iny
4370 cpy #0
4371 bne copy_title_loop2
4373 clc
4374 lda $72
4375 adc #$40
4376 sta $72
4377 lda $73
4378 adc #$01
4379 sta $73
4380 clc
4382 lda $71
4383 adc #$01
4384 sta $71
4385 clc
4387 dex
4388 bpl copy_title_loop1
4390 rts
4392 copy_completed_screen_up:
4394 lda #$00
4395 sta $70
4396 lda #$0f
4397 sta $71
4399 lda #$60
4400 sta $72
4401 lda #$5e
4402 sta $73
4404 ldx #8
4405 jmp copy_title ; optimise away the rts
4407 init:
4408 ; Set up note data.
4409 ldx #7
4410 set_up_note_loop:
4411 lda note_data,x
4412 sta $5760,x
4413 dex
4414 bpl set_up_note_loop
4416 jsr cls ; clear the text window
4418 lda #26 ; unset the text window
4419 jsr $ffee
4421 ; Define the default high scores.
4422 ldy #0
4423 lda #$80
4424 sta $70
4425 lda #$51
4426 sta $71
4427 lda #$16
4428 sta $72
4430 ldx #0
4431 init_define_high_scores_loop:
4433 lda #0
4434 sta ($70),y
4435 iny
4436 lda $72
4437 sta ($70),y
4438 iny
4439 lda #0
4440 sta ($70),y
4442 iny
4443 init_define_high_score_name_loop:
4445 lda high_score_default_name1,x
4446 sta ($70),y
4447 iny
4448 inx
4449 cpx #9
4450 beq init_define_high_scores_next
4451 cpx #18
4452 bne init_define_high_score_name_loop
4454 ldx #0
4455 init_define_high_scores_next:
4457 sed
4458 lda $72
4459 sec
4460 sbc #2
4461 sta $72
4462 cld
4463 clc
4465 cpy #96
4466 bne init_define_high_scores_loop
4468 ; Disable joystick support.
4469 lda #0
4470 sta $577e
4472 rts
4474 note_data: .byte $13,0, 241,255, 0,0, 4,0
4476 high_score_default_name1: .byte "RETRO "
4477 high_score_default_name2: .byte " SOFTWARE"
4479 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4480 input_message: .byte 17,2, 31,2,27, "Press SPACE/FIRE"
4481 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4482 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4483 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4484 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4486 set_standard_palette:
4488 lda #1
4489 sta $70
4490 lda #1
4491 sta $71
4492 jsr set_palette
4494 jmp set_core_palette ; optimise away the rts
4496 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4498 set_complete_palette:
4500 lda #0
4501 sta $80
4502 lda #25
4503 sta $81
4505 set_complete_palette_loop:
4507 jsr wait_for_vsync
4509 dec $81
4510 lda $81
4511 cmp #0
4512 bne set_complete_palette_loop
4514 lda #25
4515 sta $81
4517 ldx $80
4518 lda complete_palette_bytes,x
4519 sta $70
4520 inx
4521 lda complete_palette_bytes,x
4522 sta $71
4523 inx
4524 stx $80
4525 jsr set_palette
4527 lda $80
4528 cmp #10
4529 bne set_complete_palette_loop
4531 rts
4533 set_hidden_palette:
4535 lda #1
4536 sta $70
4537 lda #0
4538 sta $71
4539 jsr set_palette
4541 ; Run on into the next routine.
4543 set_core_palette:
4545 lda #2
4546 sta $70
4547 lda #2
4548 sta $71
4549 jsr set_palette
4551 lda #3
4552 sta $70
4553 lda #3
4554 sta $71
4555 jsr set_palette
4557 rts
4559 show_title:
4561 jsr set_standard_palette
4563 ldx #0
4564 write_title_text_loop:
4565 lda title_vdu_bytes,x
4566 jsr $ffee
4567 inx
4568 cpx #12
4569 bmi write_title_text_loop
4571 jsr show_input_message
4573 ; Show the title.
4574 jsr copy_title_up
4576 ; Show the high scores.
4578 jsr colour1
4580 lda #$80
4581 sta $70
4582 lda #$51
4583 sta $71
4585 lda #8
4586 sta $80
4588 show_title_high_scores_loop:
4590 lda #31
4591 jsr $ffee
4592 lda #2
4593 jsr $ffee
4594 lda $80
4595 adc #2
4596 sta $80
4597 clc
4598 jsr $ffee
4600 jsr write_score_digits
4602 lda #32
4603 jsr $ffee
4605 ldx #8
4606 ldy #3
4607 show_title_high_scores_vdu_loop2:
4609 lda ($70),y
4610 cmp #32
4611 bmi ignore_char
4612 cmp #123
4613 bpl ignore_char
4614 jsr $ffee
4616 ignore_char:
4617 iny
4618 dex
4619 bpl show_title_high_scores_vdu_loop2
4621 lda $70
4622 adc #12
4623 sta $70
4624 cmp #$e0
4625 bne show_title_high_scores_loop
4627 lda #0 ; message counter
4628 sta $72
4630 show_title_wait_loop:
4632 lda #150
4633 sta $5785
4635 ldx $72
4636 ldy #22
4637 show_title_wait_message_loop:
4639 lda title_vdu_bytes1,x
4640 jsr $ffee
4641 inx
4642 dey
4643 bpl show_title_wait_message_loop
4645 cpx #92
4646 beq show_title_wait_reset_offset
4648 txa
4649 sta $72
4650 jmp show_title_wait_inner_loop
4652 show_title_wait_reset_offset:
4653 lda #0
4654 sta $72
4656 show_title_wait_inner_loop:
4657 jsr wait_for_vsync
4659 dec $5785
4660 beq show_title_wait_loop
4662 show_title_wait_loop_no_update:
4663 lda #128
4664 ldx #0
4665 jsr $fff4
4666 cpx #0 ; fire button pressed?
4667 beq show_title_no_joystick
4669 lda #1 ; enable joystick support
4670 sta $577e
4671 jmp show_title_exit
4673 show_title_no_joystick:
4674 ldx #157 ; SPACE
4675 jsr check_key
4676 cpy #255
4677 bne show_title_wait_inner_loop
4679 lda #0 ; disable joystick support
4680 sta $577e
4682 show_title_exit:
4683 clc
4684 rts
4686 show_input_message:
4688 ldx #0
4689 show_input_message_loop:
4691 lda input_message,x
4692 jsr $ffee
4693 inx
4694 cpx #21
4695 bne show_input_message_loop
4697 rts
4699 wait_for_vsync:
4701 lda #19
4702 jmp $fff4 ; optimise away the rts
4704 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4706 delay:
4708 delay_loop:
4710 jsr wait_for_vsync
4711 dec $5785
4712 bne delay_loop
4714 rts
4716 show_game_over:
4718 lda #128
4719 sta $5785
4720 jsr delay
4722 ldx #0
4723 write_game_over_text_loop:
4724 lda game_over_vdu_bytes,x
4725 jsr $ffee
4726 inx
4727 cpx #33
4728 bmi write_game_over_text_loop
4730 lda #192
4731 sta $5785
4732 jsr delay
4734 rts
4736 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4737 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4739 show_end_of_level_screen:
4741 ; Draw a decorative room.
4743 jsr make_empty_room
4745 ldx #5
4746 end_of_level_h_walls_loop:
4748 lda #3
4749 sta $57b2,x
4750 sta $57e4,x
4751 dex
4752 bpl end_of_level_h_walls_loop
4754 ldx #30
4755 end_of_level_v_walls_loop:
4757 lda #3
4758 sta $57bc,x
4759 sta $57c1,x
4760 txa
4761 sec
4762 sbc #10
4763 tax
4764 bpl end_of_level_v_walls_loop
4766 jsr plot_room_tiles
4767 jsr set_standard_palette
4769 ldx #0
4770 end_of_level_text_loop1:
4772 lda end_of_level_bytes1,x
4773 jsr $ffee
4774 inx
4775 cpx #28
4776 bne end_of_level_text_loop1
4778 ; Count the number of rooms explored.
4779 ldx #0
4780 lda #0
4781 sta $8d
4782 sta $8e
4783 end_of_level_room_count_loop:
4785 lda $5200,x
4786 and #$80
4787 beq end_of_level_room_count_loop_next
4789 sed
4790 lda $8d
4791 adc #1
4792 sta $8d
4793 lda $8e
4794 adc #0
4795 sta $8e
4796 cld
4797 clc
4799 end_of_level_room_count_loop_next:
4800 inx
4801 cpx #121
4802 bne end_of_level_room_count_loop
4804 ; Position the player so that we can perform an animation.
4805 jsr position_player_set_up_plotting
4807 lda $8d
4808 sta $70
4809 lda $8e
4810 sta $71
4811 jsr write_bonus
4813 lda #0 ; reset motion counter
4814 sta $578e
4816 show_end_of_level_bonus_loop:
4818 jsr wait_for_vsync
4820 clc
4821 lda $578e
4822 and #15
4823 bne end_of_level_no_animation
4825 ; Animate the player.
4827 jsr reset_unplot_buffer
4828 jsr reset_plot_buffer
4830 ; $74,$75 should be unchanged
4831 jsr unplot_character
4833 lda $5281
4834 eor #1
4835 sta $5281
4836 jsr plot_character
4838 jsr plot_buffer
4840 end_of_level_no_animation:
4841 clc
4842 lda $578e
4843 and #3
4844 bne end_of_level_no_countdown
4846 ; Transfer the bonus to the score.
4848 sed
4849 sec
4850 lda $8d
4851 sbc #1
4852 sta $8d
4853 sta $70
4854 lda $8e
4855 sbc #0
4856 sta $8e
4857 sta $71
4858 cld
4859 clc
4861 jsr write_bonus
4863 lda #9
4864 sta $70
4865 jsr add_score
4867 lda $8d
4868 and #$3f
4869 asl
4870 ldy #1
4871 jsr play_note
4873 end_of_level_no_countdown:
4874 inc $578e ; update motion counter
4875 clc
4877 lda $8d
4878 cmp #0
4879 bne show_end_of_level_bonus_loop
4881 lda $8e
4882 cmp #0
4883 bne show_end_of_level_bonus_loop
4885 lda #64 ; initialise delay counter
4886 sta $5785
4887 jsr delay
4889 ldx #0
4890 end_of_level_text_loop2:
4892 lda end_of_level_bytes2,x
4893 jsr $ffee
4894 inx
4895 cpx #25
4896 bne end_of_level_text_loop2
4898 lda $578a
4899 cmp #3
4900 bpl show_end_of_level_screen_exit
4902 lda #192 ; initialise delay counter
4903 sta $5785
4904 jsr delay
4906 show_end_of_level_screen_exit:
4907 rts
4909 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4911 write_bonus: ; $70,$71=value
4912 ; $72,$73=address of VDU codes
4914 ldx #4
4915 write_bonus_vdu_bytes:
4917 lda level_bonus_vdu_bytes,x
4918 jsr $ffee
4919 dex
4920 bpl write_bonus_vdu_bytes
4922 ldy #1
4923 write_bonus_loop:
4925 tya
4926 tax ; temporary
4928 lda $70,x
4929 sta $80
4930 lsr
4931 lsr
4932 lsr
4933 lsr
4934 tax
4935 lda score_digits,x
4936 jsr $ffee
4938 lda $80
4939 and #$0f
4940 tax
4941 lda score_digits,x
4942 jsr $ffee
4944 dey
4945 bpl write_bonus_loop
4947 clc
4948 rts
4950 position_player_set_up_plotting:
4952 jsr reset_player_position
4953 jsr remove_characters
4955 jsr reset_unplot_buffer
4956 jsr reset_plot_buffer
4958 ; Run on into the next routine.
4960 plot_the_player:
4962 lda #$80 ; plot the player
4963 sta $74
4964 lda #$52
4965 sta $75
4966 jsr plot_character
4968 jsr plot_buffer
4969 rts
4971 complete_game_vdu_bytes1: .byte 12
4972 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4973 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4974 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4976 show_complete_game:
4978 jsr blank_screen
4980 ldx #0
4981 show_complete_game_vdu_loop:
4983 lda complete_game_vdu_bytes1,x
4984 jsr $ffee
4985 inx
4986 cpx #68
4987 bne show_complete_game_vdu_loop
4989 jsr copy_completed_screen_up
4991 jsr set_complete_palette
4993 lda #255
4994 sta $5785
4996 show_complete_game_delay_loop:
4998 jsr wait_for_vsync
5000 dec $5785
5001 bne show_complete_game_no_message
5003 jsr colour1
5004 jsr show_input_message
5006 show_complete_game_no_message:
5008 lda #128
5009 ldx #0
5010 jsr $fff4
5011 cpx #0 ; fire button pressed?
5012 beq show_complete_game_no_joystick
5013 jmp show_complete_game_exit
5015 show_complete_game_no_joystick:
5017 ldx #157
5018 jsr check_key
5019 cpy #255
5020 bne show_complete_game_delay_loop
5022 show_complete_game_exit:
5023 clc
5024 rts
5026 check_high_scores:
5028 ; Start at the bottom of the table, moving scores down as necessary, and
5029 ; write in the current score at the appropriate place.
5031 lda #$86 ; current score
5032 sta $70
5033 lda #$57
5034 sta $71
5036 lda #$80
5037 sta $72
5038 lda #$51
5039 sta $73
5041 check_high_scores_loop:
5043 ldy #2
5044 check_high_scores_digits_loop:
5046 lda ($72),y
5047 cmp ($70),y ; existing score less than current score?
5048 bcc check_high_scores_move_down
5049 beq check_high_scores_digits_next ; keep checking digits if equal
5050 jmp check_high_scores_next
5052 check_high_scores_digits_next:
5053 dey
5054 bpl check_high_scores_digits_loop
5056 check_high_scores_next:
5057 clc
5058 lda $72
5059 adc #12
5060 sta $72
5061 cmp #$e0
5062 bne check_high_scores_loop
5064 ; The player's score didn't make it into the high score table.
5065 rts
5067 check_high_scores_move_down: ; $70,$71=pointer to current score
5068 ; $72,$73=pointer to old score
5070 ; The current score exceeded the existing entry. Make a note of the
5071 ; position in the high score table, insert the player's score, and take
5072 ; the old score
5074 lda $72 ; Record the position in the high score table of the
5075 sta $8d ; player's score.
5076 lda $73
5077 sta $8e
5079 lda #$e0
5080 sta $74
5081 lda #$51
5082 sta $75
5084 ldy #0
5085 insert_blank_player_name_loop:
5087 cpy #3
5088 bpl insert_blank_player_name_score_only
5090 lda ($70),y
5091 jmp insert_blank_player_name_store
5093 insert_blank_player_name_score_only:
5094 lda #32
5096 insert_blank_player_name_store:
5097 sta ($74),y
5098 iny
5099 cpy #12
5100 bne insert_blank_player_name_loop
5102 check_high_scores_move_down_loop:
5104 ldy #0
5105 check_high_scores_copy_score_and_name:
5107 lda ($72),y ; swap the current score with the score in the table
5108 tax
5109 lda ($74),y
5110 sta ($72),y
5111 txa
5112 sta ($74),y
5113 iny
5114 cpy #12
5115 bne check_high_scores_copy_score_and_name
5117 clc
5118 lda $72
5119 adc #12
5120 sta $72
5121 cmp #$e0
5122 bne check_high_scores_move_down_loop
5124 ; Draw a decorative room.
5126 jsr set_hidden_palette
5128 jsr make_empty_room
5130 lda #3
5131 sta $76
5132 sta $77
5133 jsr draw_top_line
5134 jsr draw_bottom_line
5135 jsr draw_left_line
5137 lda #0
5138 sta $77
5139 jsr draw_right_line
5141 jsr plot_room_tiles
5143 ; Add text characters to the room.
5144 jsr colour3
5146 lda #3 ; x
5147 sta $70
5148 lda #6 ; y
5149 sta $71
5151 lda #65
5152 sta $72
5154 ldx #3
5155 plot_text_characters_loop:
5157 jsr print_xy
5159 lda $70
5160 adc #4
5161 sta $70
5163 dex
5164 bpl plot_text_characters_next
5166 lda #3
5167 sta $70
5168 lda $71
5169 adc #3
5170 sta $71
5172 ldx #3
5174 plot_text_characters_next:
5176 inc $72
5177 lda $72
5178 cmp #91
5179 bne plot_text_characters_loop
5181 lda #11
5182 sta $70
5183 lda #95 ; _ representing a space
5184 sta $72
5185 jsr print_xy
5187 lda #15
5188 sta $70
5189 lda #60 ; < representing delete
5190 sta $72
5191 jsr print_xy
5193 ; Put the player in the centre of the room.
5194 jsr position_player_set_up_plotting
5196 lda #0 ; reset motion counter
5197 sta $578e
5199 lda #0 ; not on a character
5200 sta $578d
5202 lda #0 ; reset the level number so that the correct tiles are used
5203 sta $578a
5205 lda #3 ; cursor position in the high score entry held in $8d,$8e
5206 sta $8f
5208 jsr set_standard_palette
5210 ldx #0
5211 high_score_vdu_loop:
5213 lda high_score_vdu_bytes,x
5214 jsr $ffee
5215 inx
5216 cpx #39
5217 bne high_score_vdu_loop
5219 high_score_entry_loop:
5221 jsr reset_unplot_buffer
5222 jsr reset_plot_buffer
5224 jsr move_player
5225 ; Check if the player leaves the room.
5226 bcc high_score_entry_check_position
5227 jmp high_score_entry_after_loop
5229 high_score_entry_check_position:
5231 lda $5285 ; dx
5232 cmp #2
5233 beq high_score_entry_maybe_aligned
5234 jmp high_score_entry_not_aligned
5236 high_score_entry_maybe_aligned:
5238 lda $5282 ; y
5239 tay
5240 cmp #8
5241 bpl high_score_entry_not_aligned
5243 lda $5284 ; x
5244 tax
5245 cmp #9
5246 beq high_score_entry_not_aligned
5247 and #1
5248 beq high_score_entry_not_aligned
5250 lda $5283 ; dy
5251 cmp #2
5252 bmi high_score_entry_aligned
5253 jmp high_score_entry_not_aligned
5255 lda $5282 ; y again (don't apply the touching rule to the bottom
5256 cmp #7 ; row of characters)
5257 beq high_score_entry_not_aligned
5259 iny ; we are really touching the character below
5261 high_score_entry_aligned:
5263 lda $578d
5264 cmp #1
5265 beq high_score_entry_next
5267 ; The player is aligned with a letter.
5268 txa
5269 sec
5270 sbc #1
5271 lsr
5272 sta $7e ; record (x - 1) / 2
5274 tya ; recall y
5275 sec
5276 sbc #1
5277 asl
5278 asl ; (y - 1) * 4
5279 clc
5281 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5282 adc #65
5283 sta $7e ; record the ASCII code
5285 cmp #91
5286 bmi insert_character
5288 cmp #92
5289 beq delete_character
5291 ; Insert a space.
5292 lda #32
5293 sta $7e
5295 insert_character:
5296 lda $8f
5297 cmp #12
5298 bpl high_score_entry_pressed
5300 tay ; insert the character
5301 lda $7e
5302 sta ($8d),y
5303 jsr print_high_score_character
5305 inc $8f
5306 jmp high_score_entry_pressed
5308 delete_character:
5309 lda $8f
5310 cmp #4
5311 bmi high_score_entry_pressed
5313 cmp #12
5314 beq high_score_delete_previous_character
5316 tay
5317 lda #32 ; insert a space
5318 sta ($8d),y
5319 jsr print_high_score_character
5321 high_score_delete_previous_character:
5322 dec $8f
5323 lda $8f
5324 tay ; insert a space
5325 lda #32
5326 sta ($8d),y
5327 jsr print_high_score_character
5329 high_score_entry_pressed:
5330 lda #1
5331 sta $578d
5332 jmp high_score_entry_next
5334 high_score_entry_not_aligned:
5335 lda #0
5336 sta $578d
5338 high_score_entry_next:
5340 jsr wait_for_vsync
5341 jsr wait_for_vsync
5342 jsr plot_buffer
5344 jmp high_score_entry_loop
5346 inc $578e
5347 clc
5349 high_score_entry_after_loop:
5350 clc
5352 jsr cls
5353 jsr set_hidden_palette
5355 rts
5357 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5359 cls:
5360 lda #12
5361 jsr $ffee
5362 rts
5364 colour1:
5365 lda #17
5366 jsr $ffee
5367 lda #1
5368 jsr $ffee
5369 rts
5371 colour3:
5372 lda #17
5373 jsr $ffee
5374 lda #3
5375 jsr $ffee
5376 rts
5378 print_high_score_character: ; A=ASCII code
5380 clc
5381 sta $72 ; store the character
5382 lda $8f
5383 adc #3
5384 sta $70 ; store the x position of the character
5385 lda #30
5386 sta $71
5387 ; Run on into the next routine.
5389 print_xy:
5391 lda #31
5392 jsr $ffee
5393 lda $70
5394 jsr $ffee
5395 lda $71
5396 jsr $ffee
5397 lda $72
5398 jsr $ffee
5399 rts
5401 disable_sound: ; X=1 (disable); X=0 (enable)
5403 lda #210
5404 ldy #0
5405 jmp $fff4 ; optimise away the rts
5407 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5408 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5410 start_new_game:
5412 ; Clear the screen.
5413 jsr cls
5415 ; Set the level.
5416 lda #0
5417 sta $578a
5419 ; Set the score.
5420 lda #0
5421 sta $5786
5422 lda #0
5423 sta $5787
5424 lda #0
5425 sta $5788
5427 ; Blank the screen now because it will be blanked before the room is shown
5428 ; and otherwise the strength bar will show briefly.
5429 jsr blank_screen
5431 ; Set the player's strength.
5432 lda #0
5433 sta $5784
5434 lda #64
5435 sta $70
5436 jsr add_strength
5438 ; Set the projectile type.
5439 lda #0
5440 sta $5789
5442 rts
5444 reset_player_position:
5446 lda #1 ; player
5447 sta $5280
5448 lda #6 ; down (first frame)
5449 sta $5281
5450 lda #4 ; y=4
5451 sta $5282
5452 lda #2 ; dy=2
5453 sta $5283
5454 lda #4 ; x=4
5455 sta $5284
5456 lda #3 ; dx=3
5457 sta $5285
5459 rts
5461 start_level:
5463 ; Clear the item/player flags.
5464 lda #0
5465 sta $5780
5467 ; Set current room.
5469 ldx $578a
5470 lda start_rooms_y,x
5471 sta $5782
5472 lda start_rooms_x,x
5473 sta $5783
5475 ; Set the player's position.
5477 jsr reset_player_position
5479 ; Reset the weapon counter.
5480 lda #0
5481 sta $577f
5483 ; Fill the treasure table with objects.
5484 ldx $578a ; level
5485 lda key_rooms,x
5486 sta $80
5488 ldx $578a ; level
5489 lda seeds,x
5490 adc #1
5491 and #31
5492 sta $7c
5493 clc
5494 lda seeds,x
5495 adc #2
5496 and #31
5497 sta $7d
5498 clc
5500 lda $578a ; create an upper limit on the weapon type found in this level
5501 adc #2
5502 sta $5781
5503 clc
5505 lda #$00
5506 sta $8e
5507 lda #$52
5508 sta $8f
5510 ldy #0
5511 start_level_add_treasure_loop:
5513 cpy $80 ; check for the key room
5514 bne start_level_add_treasure_item
5516 lda #5 ; the value to store is type + 1
5517 jmp start_level_add_treasure_store
5519 start_level_add_treasure_item:
5520 clc
5521 jsr unlimited_values
5522 and #$0f
5523 cmp #0
5524 beq start_level_add_treasure_none
5526 clc
5527 sta $8c
5528 tya
5529 adc $8c
5530 and #31
5531 clc
5532 tax
5533 lda treasure_table,x
5535 cmp #4
5536 bmi start_level_add_treasure_weapon
5538 clc
5539 adc #1
5540 jmp start_level_add_treasure_store
5542 start_level_add_treasure_weapon:
5544 ; Only add weapons with types that equal the level number or exceed it
5545 ; by one.
5546 cmp $5781
5547 bcs start_level_add_treasure_none
5549 clc
5550 adc #1 ; store values 0-8 as values 1-9
5551 jmp start_level_add_treasure_store
5553 start_level_add_treasure_none:
5554 clc
5555 lda #0 ; do not put treasure in this room
5557 start_level_add_treasure_store:
5558 clc
5559 sta ($8e),y ; add the item to the table
5561 iny
5562 cpy #121
5563 bmi start_level_add_treasure_loop
5565 ; Write the status text.
5566 ldx #0
5567 write_status_text_loop:
5568 lda status_vdu_bytes,x
5569 jsr $ffee
5570 inx
5571 cpx #25
5572 bmi write_status_text_loop
5574 jsr write_score
5576 clc
5577 rts
5579 main:
5580 jsr init
5582 main_loop:
5584 jsr show_title
5586 jsr start_new_game
5588 level_loop:
5590 jsr start_level
5592 game_loop:
5594 jsr remove_characters
5596 jsr reset_unplot_buffer
5597 jsr reset_plot_buffer
5599 lda $5782 ; current room (y)
5600 sta $78
5601 lda $5783 ; current room (x)
5602 sta $79
5603 jsr plot_room
5604 jsr set_room_palette
5605 jsr create_enemy_positions
5606 jsr add_treasure
5608 jsr plot_the_player
5610 lda #0 ; reset projectile counter
5611 sta $578d
5613 lda #0 ; reset motion counter
5614 sta $578e
5616 lda #63 ; reset generation counter
5617 sta $578f
5619 room_loop:
5620 jsr reset_unplot_buffer
5621 jsr reset_plot_buffer
5623 jsr move_characters
5624 jsr move_projectile
5626 lda $5780 ; is player out of strength ($40), leaving the
5627 and #$c2 ; level (0x80) or completing the game (0x02)?
5628 beq room_loop_player_move
5629 clc
5631 dec $5785 ; leave the loop when the delay
5632 bne room_loop_delay_next
5633 jmp after_room_loop ; counter is about to reset
5635 room_loop_delay_next:
5637 lda $5281 ; leave the loop when the player demise
5638 cmp #11 ; animation has finished
5639 beq room_loop_after_player_move
5640 clc
5642 lda $578e
5643 and #7
5644 bne room_loop_after_player_move
5646 lda $5780 ; skip the animation if leaving the level or
5647 and #$82 ; completing the game
5648 bne room_loop_after_player_move
5650 ; Show the demise animation when appropriate.
5652 lda #$80
5653 sta $74
5654 lda #$52
5655 sta $75
5657 jsr unplot_character
5659 inc $5281
5660 jsr plot_character
5661 jmp room_loop_after_player_move
5663 room_loop_player_move:
5665 ; See if it is time to generate a new enemy.
5666 lda $578f
5667 cmp #0
5668 bne no_emerge_characters
5669 jsr emerge_characters
5671 no_emerge_characters:
5672 clc
5674 jsr check_fire_key
5675 jsr move_player
5676 bcs after_room_loop ; check if we are leaving the level
5678 room_loop_after_player_move:
5679 clc
5681 lda #19
5682 jsr $fff4
5683 jsr plot_buffer
5685 ldx #143 ; Escape key check
5686 jsr check_key
5687 cpy #255
5688 beq main_loop_play_again
5690 ldx #174 ; S key check
5691 jsr check_key
5692 cpy #255
5693 bne no_set_sound
5695 ldx #0
5696 jsr disable_sound
5697 jmp after_sound_checks
5699 no_set_sound:
5701 ldx #239 ; Q key check
5702 jsr check_key
5703 cpy #255
5704 bne after_sound_checks
5706 ldx #1
5707 jsr disable_sound
5709 after_sound_checks:
5711 ldx #200 ; P key check
5712 jsr check_key
5713 cpy #255
5714 bne no_pause
5716 pause_loop:
5718 ldx #201 ; O key check
5719 jsr check_key
5720 cpy #255
5721 bne pause_loop
5723 no_pause:
5724 clc
5726 lda $578d
5727 cmp #0
5728 beq room_loop_no_update_projectile_counter
5730 dec $578d
5732 room_loop_no_update_projectile_counter:
5734 dec $578f ; update generation counter
5736 inc $578e ; update motion counter
5737 clc
5738 jmp room_loop
5740 after_room_loop:
5741 clc
5743 lda $5780
5744 and #$80
5745 bne exit_level
5747 lda $5780
5748 and #$40
5749 bne game_over
5751 lda $5780
5752 and #$02
5753 bne complete_game
5755 jmp game_loop
5757 exit_level:
5759 jsr show_end_of_level_screen
5761 inc $578a
5762 clc
5763 jmp level_loop
5765 game_over:
5766 jsr show_game_over
5767 jmp main_loop_play_again
5769 complete_game:
5770 jsr show_end_of_level_screen
5771 jsr show_complete_game
5772 jmp main_loop_play_again
5774 main_loop_play_again:
5775 jsr cls
5777 ; Check the score against the high scores.
5778 jsr check_high_scores
5780 jmp main_loop
5782 exit:
5783 clc
5784 rts
