junglejourney
view mapcode.oph @ 217:59f37c9e74e4
Finished ROM loader and main code programs.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sun Oct 16 21:36:30 2011 +0200 |
| parents | cdceac4f5ea8 |
| children | 02610f059ac0 |
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 move_player:
1720 lda $578e
1721 and #1
1722 beq move_player_allowed
1724 clc
1725 rts
1727 move_player_allowed:
1729 lda #$80 ; set up the address of the player character
1730 sta $74
1731 lda #$52
1732 sta $75
1734 ; Handle joystick
1736 lda $577e
1737 cmp #0
1738 beq move_player_handle_left_key
1740 lda #128
1741 ldx #1
1742 jsr $fff4
1743 cpy #112 ; <= -16
1744 bcs move_player_check_joystick_left
1745 jmp move_player_right
1747 move_player_check_joystick_left:
1748 cpy #144 ; >= 16
1749 bcc move_player_handle_joystick_up_down
1750 jmp move_player_left
1752 move_player_handle_joystick_up_down:
1754 lda #128
1755 ldx #2
1756 jsr $fff4
1757 cpy #112 ; <= -16
1758 bcs move_player_check_joystick_up
1759 jmp move_player_down
1761 move_player_check_joystick_up:
1762 cpy #144
1763 bcc move_player_no_joystick_input
1764 jmp move_player_up ; >= 16
1766 move_player_no_joystick_input:
1767 clc
1768 rts
1770 move_player_handle_left_key:
1772 ; Handle the left key.
1774 ldx #158 ; (Z)
1775 jsr check_key
1776 cpy #255
1777 bne move_player_not_left_key
1779 move_player_left:
1781 lda $5285 ; read dx
1782 cmp #0
1783 beq move_player_left_check_x
1785 jsr unplot_character ; unplot the player character
1786 dec $5285
1787 clc
1788 jmp animate_player_left ; optimise away the rts
1790 move_player_left_check_x: ; Check the x offset.
1792 lda $5284
1793 cmp #0
1794 beq move_player_leave_room_left
1796 clc
1797 tay
1798 dey ; x - 1
1799 lda $5282 ; load the y offset
1800 tax ; as an index
1801 lda room_row_offsets_low,x ; read the address of the row
1802 sta $70
1803 lda #$57
1804 sta $71
1805 lda ($70),y ; load the tile to the left
1807 cmp #5 ; check for the open exit or final exit
1808 bmi move_player_not_left_exit1
1809 jmp try_to_exit_level ; optimise away the rts
1811 move_player_not_left_exit1:
1812 cmp #0
1813 bne move_player_not_left_key
1815 lda $5283 ; dy
1816 cmp #0
1817 beq move_player_allow_left
1819 clc
1820 lda $70 ; dy > 0 so we need to check another tile
1821 adc #10
1822 sta $70
1823 lda ($70),y ; load the tile below and to the left
1825 cmp #5 ; check for the open exit or final exit
1826 bmi move_player_not_left_exit2
1827 jmp try_to_exit_level ; optimise away the rts
1829 move_player_not_left_exit2:
1830 cmp #0
1831 bne move_player_not_left_key
1833 move_player_allow_left:
1834 tya
1835 sta $81 ; temporary
1836 jsr unplot_character ; unplot the player character
1837 lda $81
1838 sta $5284 ; store the new room x offset
1839 lda #3
1840 sta $5285 ; dx = 3
1841 clc
1842 jmp animate_player_left ; optimise away the rts
1844 move_player_leave_room_left:
1845 sec
1846 lda $5783
1847 sbc #1
1848 sta $5783
1849 clc
1851 ; Set the player's position on the right of the screen.
1853 ; No need to unplot.
1855 lda #9 ; x = 9
1856 sta $5284
1857 lda #2 ; dx = 2
1858 sta $5285
1860 jsr animate_player_left
1861 sec ; indicate to the calling routine that the player
1862 rts ; has left the room
1864 move_player_not_left_key:
1866 ; Handle the right key.
1868 ldx #189 ; (X)
1869 jsr check_key
1870 cpy #255
1871 beq move_player_right
1872 jmp move_player_not_right_key
1874 move_player_right:
1876 lda $5285 ; read dx
1877 cmp #2
1878 beq move_player_right_check_x
1879 cmp #3
1880 beq move_player_right_tile
1882 jsr unplot_character ; unplot the player character
1883 inc $5285
1884 clc
1885 jmp animate_player_right ; optimise away the rts
1887 move_player_right_check_x: ; Check the x offset.
1889 lda $5284
1890 cmp #9
1891 beq move_player_leave_room_right
1893 clc
1894 tay
1895 iny ; x + 1
1896 lda $5282 ; load the y offset
1897 tax ; as an index
1898 lda room_row_offsets_low,x ; read the address of the row
1899 sta $70
1900 lda #$57
1901 sta $71
1902 lda ($70),y ; load the tile to the right
1904 cmp #5 ; check for the open exit or final exit
1905 bmi move_player_not_right_exit1
1906 jmp try_to_exit_level ; optimise away the rts
1908 move_player_not_right_exit1:
1909 cmp #0
1910 bne move_player_not_right_key
1912 lda $5283 ; dy
1913 cmp #0
1914 beq move_player_allow_right
1916 clc ; dy > 0 so we need to check another tile
1917 lda $70
1918 adc #10
1919 sta $70
1920 lda ($70),y ; load the tile below and to the right
1922 cmp #5 ; check for the open exit or final exit
1923 bmi move_player_not_right_exit2
1924 jmp try_to_exit_level ; optimise away the rts
1926 move_player_not_right_exit2:
1927 cmp #0
1928 bne move_player_not_right_key
1930 move_player_allow_right:
1932 jsr unplot_character ; unplot the player character
1933 inc $5285 ; update dx
1934 clc
1935 jmp animate_player_right ; optimise away the rts
1937 move_player_right_tile:
1939 jsr unplot_character ; unplot the player character
1940 inc $5284 ; store the new room x offset
1941 lda #0
1942 sta $5285 ; dx = 0
1943 clc
1944 jmp animate_player_right ; optimise away the rts
1946 move_player_leave_room_right:
1947 clc
1948 inc $5783
1949 clc
1951 ; Set the player's position on the left of the screen.
1953 ; No need to unplot.
1955 lda #0 ; x = 0
1956 sta $5284
1957 lda #0 ; dx = 0
1958 sta $5285
1960 jsr animate_player_right
1961 sec ; indicate to the calling routine that the
1962 rts ; player has left the room
1964 move_player_not_right_key:
1966 ; Handle the up key.
1968 ldx #183 ; (:)
1969 jsr check_key
1970 cpy #255
1971 bne move_player_not_up_key
1973 move_player_up:
1975 lda $5283 ; read dy
1976 cmp #0
1977 beq move_player_up_check_y
1979 jsr unplot_character ; unplot the player character
1980 dec $5283
1981 clc
1982 jmp animate_player_up ; optimise away the rts
1984 move_player_up_check_y: ; Check the y offset.
1986 lda $5282
1987 cmp #0
1988 beq move_player_leave_room_up
1990 tax ; use the y offset as an index
1991 dex ; y - 1
1992 ldy $5284 ; load the x offset
1993 lda room_row_offsets_low,x ; read the address of the row
1994 sta $70
1995 lda #$57
1996 sta $71
1997 lda ($70),y ; load the tile above
1999 cmp #5 ; check for the open exit or final exit
2000 bmi move_player_not_up_exit1
2001 jmp try_to_exit_level ; optimise away the rts
2003 move_player_not_up_exit1:
2004 cmp #0
2005 bne move_player_not_up_key
2007 lda $5285 ; dx
2008 cmp #3
2009 bmi move_player_allow_up
2011 clc ; dx > 2 so we need to check another tile
2012 iny
2013 lda ($70),y ; load the tile above and to the right
2015 cmp #5 ; check for the open exit or final exit
2016 bmi move_player_not_up_exit2
2017 jmp try_to_exit_level ; optimise away the rts
2019 move_player_not_up_exit2:
2020 cmp #0
2021 bne move_player_not_up_key
2023 move_player_allow_up:
2024 txa
2025 sta $81 ; temporary
2026 jsr unplot_character ; unplot the player character
2027 lda $81
2028 sta $5282 ; store the new room y offset
2029 lda #3
2030 sta $5283 ; dy = 3
2031 clc
2032 jmp animate_player_up ; optimise away the rts
2034 move_player_leave_room_up:
2035 sec
2036 lda $5782
2037 sbc #1
2038 sta $5782
2039 clc
2041 ; Set the player's position on the bottom of the screen.
2043 ; No need to unplot.
2045 lda #9 ; y = 9
2046 sta $5282
2047 lda #0 ; dy = 0
2048 sta $5283
2050 jsr animate_player_up
2051 sec ; indicate to the calling routine that the player
2052 rts ; has left the room
2054 move_player_not_up_key:
2056 ; Handle the down key.
2058 ldx #151 ; (/)
2059 jsr check_key
2060 cpy #255
2061 beq move_player_down
2062 jmp move_player_not_down_key
2064 move_player_down:
2066 lda $5283 ; read dy
2067 cmp #0
2068 beq move_player_down_check_y
2069 cmp #3
2070 beq move_player_down_tile
2072 jsr unplot_character ; unplot the player character
2073 inc $5283 ; 0 <= dy < 3
2074 clc
2075 jmp animate_player_down ; optimise away the rts
2077 move_player_down_check_y: ; Check the y offset.
2079 lda $5282
2080 cmp #9
2081 beq move_player_leave_room_down
2083 clc
2084 tax
2085 inx ; y + 1
2086 ldy $5284 ; load the x offset
2087 lda room_row_offsets_low,x ; read the address of the row
2088 sta $70
2089 lda #$57
2090 sta $71
2091 lda ($70),y ; load the tile below
2093 cmp #5 ; check for the open exit or final exit
2094 bmi move_player_not_down_exit1
2095 jmp try_to_exit_level ; optimise away the rts
2097 move_player_not_down_exit1:
2098 cmp #0
2099 bne move_player_not_down_key
2101 lda $5285 ; dx
2102 cmp #3
2103 bmi move_player_allow_down
2105 clc ; dx > 2 so we need to check another tile
2106 iny
2107 lda ($70),y ; load the tile below and to the right
2109 cmp #5 ; check for the open exit or final exit
2110 bmi move_player_not_down_exit2
2111 jmp try_to_exit_level ; optimise away the rts
2113 move_player_not_down_exit2:
2114 cmp #0
2115 bne move_player_not_down_key
2117 move_player_allow_down:
2119 jsr unplot_character ; unplot the player character
2120 inc $5283 ; update dy
2121 clc
2122 jmp animate_player_down ; optimise away the rts
2124 move_player_down_tile:
2126 jsr unplot_character ; unplot the player character
2127 inc $5282 ; store the new room y offset
2128 lda #0
2129 sta $5283 ; dy = 0
2130 clc
2131 jmp animate_player_down ; optimise away the rts
2133 move_player_leave_room_down:
2134 inc $5782
2135 clc
2137 ; Set the player's position on the top of the screen.
2139 ; No need to unplot.
2141 lda #0 ; y = 0
2142 sta $5282
2143 lda #0 ; dy = 0
2144 sta $5283
2146 jsr animate_player_down
2147 sec ; indicate to the calling routine that the
2148 rts ; player has left the room
2150 move_player_not_down_key:
2151 clc
2152 rts
2154 try_to_exit_level:
2156 cmp #6
2157 bmi just_exit_level
2159 lda $5780 ; set the complete game flag
2160 ora #$02
2161 jmp try_to_exit_level_exit
2163 just_exit_level:
2164 lda $5780 ; set the exit level flag
2165 ora #$80
2167 try_to_exit_level_exit:
2168 sta $5780
2170 lda #$80
2171 sta $74
2172 lda #$52
2173 sta $75
2174 jsr unplot_character ; remove the player sprite
2175 jmp destroy_enemies ; optimise away the rts
2177 check_fire_key:
2179 lda $578d
2180 bne check_fire_key_exit
2182 lda $577e
2183 beq check_fire_key_no_joystick
2185 lda #128
2186 ldx #0
2187 jsr $fff4
2188 txa
2189 and #1
2190 bne check_fire_key_fire
2192 clc
2193 rts
2195 check_fire_key_no_joystick:
2197 ldx #182 ; (Return)
2198 jsr check_key
2199 cpy #255
2200 bne check_fire_key_exit
2202 check_fire_key_fire:
2204 lda $5286
2205 cmp #0
2206 bne check_fire_key_exit
2208 lda #16
2209 sta $578d
2211 jmp create_projectile ; optimise away the rts
2213 check_fire_key_exit:
2214 clc
2215 rts
2217 create_projectile:
2219 lda #2
2220 sta $5286
2222 lda $5281
2223 and #$06 ; copy the direction information
2224 asl
2225 asl
2226 asl
2227 ora $5789 ; apply the projectile type
2228 sta $5287
2230 lda $5283 ; player dy
2231 adc $577f ; add the weapon counter
2232 adc #1
2233 cmp #4 ; if dy > 3, create the projectile on the tile below
2234 bpl create_projectile_below
2236 clc
2237 sta $5289 ; dy + weapon counter + 1
2238 lda $5282 ; y
2239 sta $5288
2240 jmp create_projectile_continue
2242 create_projectile_below:
2243 sec
2244 sbc #4
2245 sta $5289 ; dy + weapon counter + 1 - 4
2246 clc
2247 lda $5282 ; y
2248 adc #1
2249 sta $5288
2251 create_projectile_continue:
2252 lda $5284 ; x
2253 sta $528a
2255 lda $5285 ; dx
2256 sta $528b
2258 lda $577f ; toggle the weapon counter
2259 eor #1
2260 sta $577f
2262 ; Move the projectile away from the player.
2264 lda #$86
2265 sta $74
2266 lda #$52
2267 sta $75
2268 jsr move_projectile_after_unplot
2270 jsr move_projectile
2272 clc
2273 rts
2275 emerge_type: ; returns A=type
2276 jsr unlimited_values
2277 lda $7d
2278 and #7
2279 cmp #5
2280 bmi emerge_type_ok
2282 sec
2283 sbc #5
2284 clc
2286 emerge_type_ok:
2287 cmp $5781 ; only allow the appropriate enemies for this level
2288 bmi emerge_type_exit
2289 beq emerge_type_reduce
2291 sec
2292 sbc #1
2294 emerge_type_reduce:
2295 sec
2296 sbc $5781
2297 clc
2299 emerge_type_exit:
2300 asl
2301 asl
2302 asl
2303 asl
2304 clc
2305 rts
2307 emerge_character: ; $74,$75=character address
2309 lda #63
2310 sta $578f
2312 jsr unlimited_values
2313 and #$0f
2314 tax
2315 lda $0ee0,x
2316 cmp #0 ; check for an invalid value and exit if found
2317 beq emerge_character_exit
2319 sta $80 ; temporary
2320 lda $0ef0,x
2321 tax
2323 ; Add an emerging enemy.
2325 ldy #0
2326 lda #3 ; emerge/explosion
2327 sta ($74),y
2329 jsr emerge_type ; obtain an enemy type
2330 iny
2331 sta ($74),y
2333 txa
2334 iny
2335 sta ($74),y ; store the y position
2336 lda #1
2337 iny
2338 sta ($74),y ; store the dy offset
2340 lda $80
2341 iny
2342 sta ($74),y ; store the x position
2343 lda #0
2344 iny
2345 sta ($74),y ; store the dx offset
2347 jsr plot_character
2349 ldx #5
2350 jsr play_sound
2352 emerge_character_exit:
2353 clc
2354 rts
2356 emerge_explode: ; $74,$75=character address
2358 jsr unplot_character
2360 ldy #1
2361 lda ($74),y ; direction/animation
2362 tax
2363 adc #1 ; update the counter
2364 and #3 ; mask off everything else
2365 sta $80 ; store the masked counter value
2366 bne move_characters_explosion_not_finished
2368 txa
2369 and #4
2370 bne move_characters_remove_character
2372 ; For emerges, convert into an enemy.
2373 txa
2374 and #$70 ; only keep bits 4,5,6
2375 ora #8 ; make this an enemy
2377 ldy #0
2378 sta ($74),y ; update the type (>= 8)
2379 iny
2380 lda $7d ; prepare the direction and animation offset
2381 and #$0c
2382 sta ($74),y
2384 jsr plot_character
2385 jmp emerge_explode_exit
2387 move_characters_remove_character:
2389 ; For finished explosions, just write 0 into the character array.
2390 lda #0
2391 ldy #0
2392 sta ($74),y
2393 jmp emerge_explode_exit
2395 move_characters_explosion_not_finished:
2396 txa
2397 and #$fc
2398 ora $80
2400 ldy #1
2401 sta ($74),y
2403 jsr plot_character
2405 emerge_explode_exit:
2406 clc
2407 rts
2409 animate_enemy_left: ; $74,$75=character address
2411 ; Set the direction and toggle the animation bit.
2413 ldy #1
2414 lda ($74),y
2415 and #$fb ; keep vertical direction bit and animation bits
2416 sta ($74),y ; left (horizontal directional bit is 0)
2418 rts
2420 move_enemy_left: ; $74,$75=character address
2422 ldy #5
2423 lda ($74),y ; read dx
2424 cmp #0
2425 beq move_enemy_left_check_x
2427 sec
2428 sbc #1
2429 ldy #5
2430 sta ($74),y ; dx
2431 clc
2432 jmp animate_enemy_left ; optimise away the rts
2434 move_enemy_left_check_x:
2436 ; Check the x offset.
2438 ldy #4
2439 lda ($74),y ; x
2440 cmp #0
2441 beq move_enemy_left_exit
2443 sec
2444 sbc #1 ; x - 1
2445 sta $81 ; temporary
2446 ldy #2
2447 lda ($74),y ; load the y offset
2448 tax ; as an index
2449 lda room_row_offsets_low,x ; read the address of the row
2450 sta $70
2451 lda #$57
2452 sta $71
2453 ldy $81 ; temporary (x - 1)
2454 lda ($70),y ; load the tile to the left
2456 cmp #0
2457 bne move_enemy_left_exit
2459 ldy #3
2460 lda ($74),y ; dy
2461 cmp #2
2462 bmi move_enemy_allow_left
2464 clc
2465 lda $70 ; dy > 1 so we need to check another tile
2466 adc #10
2467 sta $70
2468 ldy $81 ; temporary (x - 1)
2469 lda ($70),y ; load the tile below and to the left
2471 cmp #0
2472 bne move_enemy_left_exit
2474 move_enemy_allow_left:
2475 lda $81
2476 ldy #4
2477 sta ($74),y ; store the new room x offset
2478 lda #3
2479 ldy #5
2480 sta ($74),y ; dx = 3
2481 clc
2482 jmp animate_enemy_left ; optimise away the rts
2484 move_enemy_left_exit:
2485 sec
2486 rts
2488 animate_enemy_right: ; $74,$75=character address
2490 ; Set the direction and toggle the animation bit.
2492 ldy #1
2493 lda ($74),y
2494 ora #$04 ; right (keep vertical direction bit and animation bits)
2495 sta ($74),y
2497 rts
2499 move_enemy_right: ; $74,$75=character_address
2501 ldy #5
2502 lda ($74),y ; read dx
2503 cmp #0
2504 beq move_enemy_right_check_x
2505 cmp #3
2506 beq move_enemy_right_tile
2508 clc
2509 adc #1
2510 ldy #5
2511 sta ($74),y
2512 jmp animate_enemy_right ; optimise away the rts
2514 move_enemy_right_check_x: ; Check the x offset.
2516 ldy #4
2517 lda ($74),y ; x
2518 cmp #9
2519 beq move_enemy_right_exit
2521 clc
2522 adc #1 ; x + 1
2523 sta $81 ; temporary (x + 1)
2524 ldy #2
2525 lda ($74),y ; load the y offset
2526 tax ; as an index
2527 lda room_row_offsets_low,x ; read the address of the row
2528 sta $70
2529 lda #$57
2530 sta $71
2531 ldy $81 ; temporary (x + 1)
2532 lda ($70),y ; load the tile to the right
2534 cmp #0
2535 bne move_enemy_right_exit
2537 ldy #3
2538 lda ($74),y ; dy
2539 cmp #2
2540 bmi move_enemy_allow_right
2542 clc ; dy > 1 so we need to check another tile
2543 lda $70
2544 adc #10
2545 sta $70
2546 ldy $81 ; temporary (x + 1)
2547 lda ($70),y ; load the tile below and to the right
2549 cmp #0
2550 bne move_enemy_right_exit
2552 move_enemy_allow_right:
2553 clc
2555 ldy #5
2556 lda ($74),y ; dx
2557 adc #1
2558 sta ($74),y ; update dx
2559 clc
2560 jmp animate_enemy_right ; optimise away the rts
2562 move_enemy_right_tile:
2563 clc
2565 ldy #4
2566 lda ($74),y ; x
2567 adc #1
2568 sta ($74),y ; store the new room x offset
2569 lda #0
2570 iny
2571 sta ($74),y ; dx = 0
2572 clc
2573 jmp animate_enemy_right ; optimise away the rts
2575 move_enemy_right_exit:
2576 sec
2577 rts
2579 animate_enemy_up: ; $74,$75=character address
2581 ; Set the direction and toggle the animation bit.
2583 ldy #1
2584 lda ($74),y
2585 and #$f7 ; keep horizontal direction bit and animation bits
2586 sta ($74),y
2588 rts
2590 move_enemy_up: ; $74,$75=character address
2592 ldy #3
2593 lda ($74),y ; read dy
2594 cmp #0
2595 beq move_enemy_up_check_y
2597 sec
2598 sbc #1
2599 ldy #3
2600 sta ($74),y ; dy
2601 clc
2602 jmp animate_enemy_up ; optimise away the rts
2604 move_enemy_up_check_y:
2606 ; Check the y offset.
2608 ldy #2
2609 lda ($74),y ; y
2610 cmp #0
2611 beq move_enemy_up_exit
2613 tax ; use the y offset as an index
2614 dex ; y - 1
2615 ldy #4
2616 lda ($74),y ; load the x offset
2617 sta $81 ; temporary (x)
2618 tay
2619 lda room_row_offsets_low,x ; read the address of the row
2620 sta $70
2621 lda #$57
2622 sta $71
2623 lda ($70),y ; load the tile above
2625 cmp #0
2626 bne move_enemy_up_exit
2628 ldy #5
2629 lda ($74),y ; dx
2630 cmp #0
2631 beq move_enemy_allow_up
2633 clc ; dx != 0 so we need to check another tile
2634 ldy $81
2635 iny
2636 lda ($70),y ; load the tile above and to the right
2638 cmp #0
2639 bne move_enemy_up_exit
2641 move_enemy_allow_up:
2642 txa
2643 ldy #2
2644 sta ($74),y ; store the new room y offset
2645 lda #3
2646 iny
2647 sta ($74),y ; dy = 3
2648 clc
2649 jmp animate_enemy_up ; optimise away the rts
2651 move_enemy_up_exit:
2652 sec
2653 rts
2655 animate_enemy_down: ; $74,$75=character address
2657 ; Set the direction and toggle the animation bit.
2659 ldy #1
2660 lda ($74),y
2661 ora #$08 ; down
2662 sta ($74),y
2664 rts
2666 move_enemy_down: ; $74,$75=character address
2668 ldy #3
2669 lda ($74),y ; dy
2670 cmp #1
2671 beq move_enemy_down_check_y
2672 cmp #3
2673 beq move_enemy_down_tile
2675 adc #1
2676 ldy #3
2677 sta ($74),y ; dy
2678 clc
2679 jmp animate_enemy_down ; optimise away the rts
2681 move_enemy_down_check_y:
2683 ; Check the y offset.
2685 ldy #2
2686 lda ($74),y
2687 cmp #9
2688 beq move_enemy_down_exit
2690 clc
2691 adc #1 ; y + 1
2692 tax
2693 ldy #4
2694 lda ($74),y ; load the x offset
2695 sta $81 ; temporary
2696 tay
2697 lda room_row_offsets_low,x ; read the address of the row
2698 sta $70
2699 lda #$57
2700 sta $71
2701 lda ($70),y ; load the tile below
2703 cmp #0
2704 bne move_enemy_down_exit
2706 ldy #5
2707 lda ($74),y ; dx
2708 cmp #0
2709 beq move_enemy_allow_down
2711 clc ; dx != 0 so we need to check another tile
2712 ldy $81 ; x
2713 iny
2714 lda ($70),y ; load the tile below and to the right
2716 cmp #0
2717 bne move_enemy_down_exit
2719 move_enemy_allow_down:
2720 clc
2722 ldy #3
2723 lda ($74),y ; dy
2724 adc #1
2725 sta ($74),y ; update dy
2726 clc
2727 jmp animate_enemy_down ; optimise away the rts
2729 move_enemy_down_tile:
2730 clc
2732 ldy #2
2733 lda ($74),y ; y
2734 adc #1
2735 sta ($74),y ; store the new room y offset
2736 lda #0
2737 iny
2738 sta ($74),y ; dy = 0
2739 clc
2740 jmp animate_enemy_down ; optimise away the rts
2742 move_enemy_down_exit:
2743 sec
2744 rts
2746 move_enemy_animate: ; $74,$75=character address
2748 ldy #1
2749 lda ($74),y ; direction/animation
2750 sta $81
2751 and #$03
2752 adc #1
2753 and #$03 ; keep animation bits
2754 sta $8f
2755 lda $81
2756 and #$fc ; mask off the animation bits
2757 ora $8f
2758 sta ($74),y
2759 rts
2761 move_enemy_next_direction: .byte $04, $0c, $00, $08
2763 move_enemy: ; $74,$75=character address
2765 lda #0
2766 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2767 lda #0
2768 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2770 lda ($74),y ; read the enemy number (Y should be zero)
2771 and #$10
2772 beq move_enemy_homing
2773 clc
2775 ; This enemy is a non-homing enemy.
2777 jsr unplot_character ; unplot now before we change the sprite used
2779 ldy #1
2780 lda ($74),y
2781 and #$f0
2782 cmp #$f0
2783 bne move_enemy_set_direction
2784 clc
2786 ldy #1
2787 lda ($74),y
2788 and #$0c
2789 ror
2790 ror
2791 tax
2792 lda move_enemy_next_direction,x
2793 sta ($74),y
2795 move_enemy_set_direction:
2796 clc
2798 ldy #1
2799 lda ($74),y
2800 sta $7b
2802 adc #$10
2803 sta ($74),y
2804 clc
2806 lda $7b
2807 and #$04
2808 ror
2809 ror
2810 adc #1
2811 sta $8e
2813 lda $7b
2814 and #$08
2815 ror
2816 ror
2817 ror
2818 adc #1
2819 sta $8d
2821 jmp move_enemy_with_direction
2823 move_enemy_homing:
2825 ldy #2
2826 lda ($74),y ; y
2827 cmp $5282 ; player y
2828 bmi move_enemy_downwards
2829 bne move_enemy_upwards
2831 ldy #3
2832 lda ($74),y ; dy
2833 cmp $5283 ; player y
2834 beq move_enemy_horizontally
2835 bpl move_enemy_upwards
2837 move_enemy_downwards:
2838 lda #2
2839 sta $8d
2840 jmp move_enemy_horizontally
2842 move_enemy_upwards:
2843 lda #1
2844 sta $8d
2845 ;jmp move_enemy_horizontally
2847 move_enemy_horizontally:
2848 ldy #4
2849 lda ($74),y ; x
2850 cmp $5284 ; player x
2851 bmi move_enemy_rightwards
2852 bne move_enemy_leftwards
2854 ldy #5
2855 lda ($74),y ; dx
2856 cmp #0
2857 beq move_enemy_with_direction_unplot
2858 bpl move_enemy_leftwards
2860 move_enemy_rightwards:
2861 lda #2
2862 sta $8e
2863 jmp move_enemy_with_direction_unplot
2865 move_enemy_leftwards:
2866 lda #1
2867 sta $8e
2869 move_enemy_with_direction_unplot:
2870 clc
2872 jsr unplot_character
2874 move_enemy_with_direction:
2875 clc
2877 lda $8e
2878 cmp #1
2879 bne move_enemy_not_left
2880 jsr move_enemy_left
2881 clc
2882 jmp move_enemy_not_right
2884 move_enemy_not_left:
2885 lda $8e
2886 cmp #2
2887 bne move_enemy_not_right
2888 jsr move_enemy_right
2889 clc
2891 move_enemy_not_right:
2892 lda $8d
2893 cmp #1
2894 bne move_enemy_not_up
2895 jsr move_enemy_up
2896 clc
2897 jmp move_enemy_toggle
2899 move_enemy_not_up:
2900 lda $8d
2901 cmp #2
2902 bne move_enemy_toggle
2903 jsr move_enemy_down
2905 move_enemy_toggle:
2906 clc
2907 jsr move_enemy_animate
2908 jmp plot_character ; optimise away the rts
2910 move_enemy_exit:
2911 clc
2912 rts
2914 create_explosion: ; X=y, Y=x
2916 lda #3
2917 sta $52a4
2918 lda #4
2919 sta $52a5
2920 txa
2921 sta $52a6
2922 lda #1
2923 sta $52a7
2924 tya
2925 sta $52a8
2926 lda #0
2927 sta $52a9
2928 rts
2930 move_projectile_left:
2932 lda $528b
2933 cmp #0
2934 beq move_projectile_left_check_x
2936 dec $528b
2937 clc
2938 rts
2940 move_projectile_left_check_x:
2942 lda $528a
2943 cmp #0
2944 bne move_projectile_left_in_room
2945 jmp move_projectile_left_exit
2947 move_projectile_left_in_room:
2948 tay
2949 dey ; x - 1
2950 ldx $5288 ; y
2951 lda room_row_offsets_low,x ; read the address of the row
2952 sta $70
2953 lda #$57
2954 sta $71
2955 lda ($70),y ; load the tile to the left
2957 cmp #0
2958 bne move_projectile_left_wall
2960 lda $5289 ; dy
2961 cmp #3
2962 bmi move_projectile_allow_left
2964 clc ; dy > 2 so we need to check another tile
2965 lda $70
2966 adc #10
2967 sta $70
2968 lda ($70),y ; load the tile below and to the left
2969 inx ; y += 1
2971 cmp #0
2972 bne move_projectile_left_wall
2974 move_projectile_allow_left:
2976 sty $528a ; x
2977 lda #3
2978 sta $528b ; dx = 3
2980 clc
2981 rts
2983 move_projectile_left_wall: ; the projectile hit a wall
2984 clc
2986 lda $5287 ; type 2 can pass through walls
2987 and #$06
2988 cmp #4
2989 beq move_projectile_allow_left
2991 cmp #2
2992 bne move_projectile_left_not_boomerang
2994 lda $5287
2995 and #$0f
2996 cmp #8
2997 bpl move_projectile_left_exit
2999 ldx $577f ; weapon counter
3000 ora boomerang_horizontal,x
3001 sta $5287
3002 clc
3003 rts ; exit without moving or registering a collision
3005 move_projectile_left_not_boomerang:
3007 cmp #6 ; type 3 can destroy certain walls
3008 bne move_projectile_left_exit
3010 lda ($70),y ; load the tile to the left
3011 cmp #1 ; decoration can be destroyed
3012 bne move_projectile_left_exit
3013 clc
3015 lda #0
3016 sta ($70),y
3018 ; X=y, Y=x
3019 jsr create_explosion
3020 jsr plot_blank_xy ; corrupted X
3022 lda #$a4
3023 sta $74
3024 lda #$52
3025 sta $75
3026 jsr plot_character
3028 ldx #0
3029 jsr play_sound
3031 lda #16 ; prevent the player from firing a new
3032 sta $578d ; projectile until the explosion has finished
3034 move_projectile_left_exit:
3035 sec
3036 rts
3038 boomerang_horizontal: .byte $28, $38
3040 move_projectile_right:
3042 ; Fire right.
3044 lda $528b
3045 cmp #2
3046 beq move_projectile_right_check_x
3047 cmp #3
3048 beq move_projectile_right_tile
3050 inc $528b
3051 clc
3052 rts
3054 move_projectile_right_check_x:
3056 lda $528a ; x
3057 cmp #9
3058 bne move_projectile_right_not_edge
3059 jmp move_projectile_right_exit
3061 move_projectile_right_not_edge:
3062 clc
3063 tay
3064 iny ; x + 1
3065 ldx $5288 ; y
3066 lda room_row_offsets_low,x ; read the address of the row
3067 sta $70
3068 lda #$57
3069 sta $71
3070 lda ($70),y ; load the tile to the right
3072 cmp #0
3073 bne move_projectile_right_wall
3075 lda $5289 ; dy
3076 cmp #3
3077 bmi move_projectile_allow_right
3079 clc ; dy > 2 so we need to check another tile
3080 lda $70
3081 adc #10
3082 sta $70
3083 lda ($70),y ; load the tile below and to the right
3084 inx ; y += 1
3086 cmp #0
3087 bne move_projectile_right_wall
3089 move_projectile_allow_right:
3091 inc $528b ; dx
3092 clc
3093 rts
3095 move_projectile_right_tile:
3097 inc $528a ; x
3098 lda #0
3099 sta $528b ; dx
3100 clc
3101 rts
3103 move_projectile_right_wall: ; the projectile hit a wall
3104 clc
3106 lda $5287 ; type 2 can pass through walls
3107 and #$06
3108 cmp #4
3109 beq move_projectile_allow_right
3111 cmp #2
3112 bne move_projectile_right_not_boomerang
3114 lda $5287
3115 and #$0f
3116 cmp #8
3117 bpl move_projectile_right_exit
3119 ldx $577f ; weapon counter
3120 ora boomerang_horizontal,x
3121 sta $5287
3122 clc
3123 rts ; exit without moving or registering a collision
3125 move_projectile_right_not_boomerang:
3127 cmp #6 ; type 3 can destroy certain walls
3128 bne move_projectile_right_exit
3130 lda ($70),y ; load the tile to the right
3131 cmp #1 ; decoration can be destroyed
3132 bne move_projectile_right_exit
3133 clc
3135 lda #0
3136 sta ($70),y
3138 ; X=y, Y=x
3139 jsr create_explosion
3140 jsr plot_blank_xy ; corrupted X
3142 lda #$a4
3143 sta $74
3144 lda #$52
3145 sta $75
3146 jsr plot_character
3148 ldx #0
3149 jsr play_sound
3151 lda #16 ; prevent the player from firing a new
3152 sta $578d ; projectile until the explosion has finished
3154 move_projectile_right_exit:
3155 sec
3156 rts
3158 move_projectile_up:
3160 lda $5289 ; read dy
3161 cmp #0
3162 beq move_projectile_up_check_y
3164 dec $5289
3165 clc
3166 rts
3168 move_projectile_up_check_y: ; Check the y offset.
3170 lda $5288
3171 cmp #0
3172 bne move_projectile_up_not_edge
3173 jmp move_projectile_up_exit
3175 move_projectile_up_not_edge:
3176 tax ; use the y offset as an index
3177 dex ; y - 1
3178 ldy $528a ; load the x offset
3179 lda room_row_offsets_low,x ; read the address of the row
3180 sta $70
3181 lda #$57
3182 sta $71
3183 lda ($70),y ; load the tile above
3185 cmp #0
3186 bne move_projectile_up_wall
3188 lda $528b ; dx
3189 cmp #3
3190 bmi move_projectile_allow_up
3192 clc ; dx > 2 so we need to check another tile
3193 iny
3194 lda ($70),y ; load the tile above and to the right
3196 cmp #0
3197 bne move_projectile_up_wall
3199 move_projectile_allow_up:
3200 txa
3201 sta $5288 ; store the new room y offset
3202 lda #3
3203 sta $5289 ; dy = 3
3205 clc
3206 rts
3208 move_projectile_up_wall: ; the projectile hit a wall
3209 clc
3211 lda $5287 ; type 2 can pass through walls
3212 and #$06
3213 cmp #4
3214 beq move_projectile_allow_up
3216 cmp #2
3217 bne move_projectile_up_not_boomerang
3219 lda $5287
3220 and #$0f
3221 cmp #8
3222 bpl move_projectile_up_exit
3224 ldx $577f ; weapon counter
3225 ora boomerang_vertical,x
3226 sta $5287
3227 clc
3228 rts ; exit without moving or registering a collision
3230 move_projectile_up_not_boomerang:
3232 cmp #6 ; type 3 can destroy certain walls
3233 bne move_projectile_up_exit
3235 lda ($70),y ; load the tile above
3236 cmp #1 ; decoration can be destroyed
3237 bne move_projectile_up_exit
3238 clc
3240 lda #0
3241 sta ($70),y
3243 ; X=y, Y=x
3244 jsr create_explosion
3245 jsr plot_blank_xy ; corrupted X
3247 lda #$a4
3248 sta $74
3249 lda #$52
3250 sta $75
3251 jsr plot_character
3253 ldx #0
3254 jsr play_sound
3256 lda #16 ; prevent the player from firing a new
3257 sta $578d ; projectile until the explosion has finished
3259 move_projectile_up_exit:
3260 sec
3261 rts
3263 boomerang_vertical: .byte $08, $18
3265 move_projectile_down:
3267 lda $5289 ; read dy
3268 cmp #2
3269 beq move_projectile_down_check_y
3270 cmp #3
3271 beq move_projectile_down_tile
3273 inc $5289 ; 0 <= dy < 3
3274 clc
3275 rts
3277 move_projectile_down_check_y: ; Check the y offset.
3279 lda $5288
3280 cmp #9
3281 bne move_projectile_down_in_room
3282 jmp move_projectile_down_exit
3284 move_projectile_down_in_room:
3285 clc
3286 tax
3287 inx ; y + 1
3288 ldy $528a ; load the x offset
3289 lda room_row_offsets_low,x ; read the address of the row
3290 sta $70
3291 lda #$57
3292 sta $71
3293 lda ($70),y ; load the tile below
3295 cmp #0
3296 bne move_projectile_down_wall
3298 lda $528b ; dx
3299 cmp #3
3300 bmi move_projectile_allow_down
3302 clc ; dx > 2 so we need to check another tile
3303 iny
3304 lda ($70),y ; load the tile below and to the right
3306 cmp #0
3307 bne move_projectile_down_wall
3309 move_projectile_allow_down:
3311 inc $5289 ; update dy
3312 clc
3313 rts
3315 move_projectile_down_tile:
3317 inc $5288 ; store the new room y offset
3318 lda #0
3319 sta $5289 ; dy = 0
3320 clc
3321 rts
3323 move_projectile_down_wall: ; the projectile hit a wall
3324 clc
3326 lda $5287 ; type 2 can pass through walls
3327 and #$06
3328 cmp #4
3329 beq move_projectile_allow_down
3331 cmp #2
3332 bne move_projectile_down_not_boomerang
3334 lda $5287
3335 and #$0f
3336 cmp #8
3337 bpl move_projectile_down_exit
3339 ldx $577f ; weapon counter
3340 ora boomerang_vertical,x
3341 sta $5287
3342 clc
3343 rts ; exit without moving or registering a collision
3345 move_projectile_down_not_boomerang:
3347 cmp #6 ; type 3 can destroy certain walls
3348 bne move_projectile_down_exit
3350 lda ($70),y ; load the tile below
3351 cmp #1 ; decoration can be destroyed
3352 bne move_projectile_down_exit
3353 clc
3355 lda #0
3356 sta ($70),y
3358 ; X=y, Y=x
3359 jsr create_explosion
3360 jsr plot_blank_xy ; corrupted X
3362 lda #$a4
3363 sta $74
3364 lda #$52
3365 sta $75
3366 jsr plot_character
3368 ldx #0
3369 jsr play_sound
3371 lda #16 ; prevent the player from firing a new
3372 sta $578d ; projectile until the explosion has finished
3374 move_projectile_down_exit:
3375 sec
3376 rts
3378 move_projectile_animate:
3380 lda $5287
3381 eor #1
3382 sta $5287
3383 rts
3385 move_projectile:
3387 lda $5286
3388 cmp #0
3389 bne move_projectile_move
3390 jmp move_projectile_exit
3392 move_projectile_move:
3393 clc
3395 lda #$86
3396 sta $74
3397 lda #$52
3398 sta $75
3399 jsr unplot_character
3401 move_projectile_after_unplot:
3403 lda $5287
3404 and #$30 ; direction
3406 cmp #0
3407 bne move_projectile_not_left
3409 jsr move_projectile_left
3410 bcc move_projectile_toggle
3411 bcs move_projectile_destroy
3413 move_projectile_not_left:
3414 cmp #$10
3415 bne move_projectile_not_right
3417 jsr move_projectile_right
3418 bcc move_projectile_toggle
3419 bcs move_projectile_destroy
3421 move_projectile_not_right:
3422 cmp #$20
3423 bne move_projectile_not_up
3425 jsr move_projectile_up
3426 bcc move_projectile_toggle
3427 bcs move_projectile_destroy
3429 move_projectile_not_up:
3430 cmp #$30
3431 bne move_projectile_toggle
3433 jsr move_projectile_down
3434 bcs move_projectile_destroy
3436 move_projectile_toggle:
3438 jsr projectile_collide
3439 bcs move_projectile_destroy
3441 jsr move_projectile_animate
3443 lda #$86
3444 sta $74
3445 lda #$52
3446 sta $75
3447 jmp plot_character ; optimise away the rts
3449 move_projectile_destroy:
3450 clc
3452 ldy #0
3453 lda ($74),y ; type
3454 cmp #8
3455 bmi move_projectile_no_enemy_collision
3457 and #$70 ; increase the player's score
3458 lsr
3459 lsr
3460 lsr
3461 adc #2
3462 sta $70
3463 jsr add_score
3464 jmp move_projectile_create_explosion
3466 move_projectile_no_enemy_collision:
3468 cmp #4 ; items can be destroyed as well
3469 bne move_projectile_no_item_collision
3471 ldy #1 ; but not keys
3472 lda ($74),y
3473 cmp #4 ; even the mace is stopped by a key
3474 beq move_projectile_remove_projectile
3475 clc
3477 jsr remove_room_item
3479 move_projectile_create_explosion:
3481 ; Unplot the item/enemy and replace it with an explosion.
3483 jsr unplot_character
3485 lda #3 ; explosion
3486 ldy #0
3487 sta ($74),y
3489 lda #4
3490 ldy #1
3491 sta ($74),y
3493 jsr plot_character
3495 ; Play a sound.
3496 ldx #0
3497 jsr play_sound
3499 move_projectile_no_item_collision:
3501 lda $5287 ; type 2 projectiles pass through everything
3502 and #$06
3503 cmp #4
3504 bne move_projectile_remove_projectile
3506 ; Ideally, we would have recorded if the projectile left the screen so
3507 ; that we don't perform these checks again here, but it would just add
3508 ; overhead to the normal movement routines for the other weapons.
3510 lda $5288 ; y
3511 cmp #0
3512 beq move_projectile_remove_projectile
3513 cmp #9
3514 beq move_projectile_remove_projectile
3516 lda $528a ; x
3517 cmp #0
3518 beq move_projectile_remove_projectile
3519 cmp #9
3520 beq move_projectile_remove_projectile
3522 clc
3523 lda #$86
3524 sta $74
3525 lda #$52
3526 sta $75
3528 jsr plot_character
3529 jmp move_projectile_exit
3531 move_projectile_remove_projectile:
3533 lda #0 ; remove the projectile from the character list
3534 sta $5286
3536 move_projectile_exit:
3537 clc
3538 rts
3540 emerge_characters:
3542 lda #$8c ; set the character address
3543 sta $74
3544 lda #$52
3545 sta $75
3547 emerge_characters_loop:
3549 ldy #0
3550 lda ($74),y
3551 cmp #0
3552 bne emerge_characters_next
3554 jmp emerge_character ; optimise away the rts
3556 emerge_characters_next:
3557 clc
3559 ; Examine the next character.
3560 lda $74
3561 adc #6
3563 cmp #$a4
3564 bpl emerge_characters_exit
3565 sta $74
3566 jmp emerge_characters_loop
3568 emerge_characters_exit:
3569 clc
3570 rts
3572 enemy_slots: .byte 0, 6, 12, 18
3574 move_characters:
3576 lda #$8c ; set the character address
3577 sta $74
3578 lda #$52
3579 sta $75
3581 lda $578e ; read a value from 0 to 3 from the motion counter
3582 and #3
3583 tax
3584 lda enemy_slots,x ; look up the corresponding slot in the character list
3585 adc $74
3586 sta $74 ; update the character address
3588 move_characters_loop:
3590 ldy #0
3591 lda ($74),y
3592 cmp #3
3593 bne move_characters_not_emerge_explode
3595 jsr emerge_explode
3596 jmp move_characters_next
3598 move_characters_not_emerge_explode:
3599 cmp #8
3600 bmi move_characters_next
3602 jsr move_enemy
3604 move_characters_next:
3605 clc
3607 lda $74 ; for the last enemy, check the next slot
3608 cmp #$9e ; for the presence of an explosion
3609 bne move_characters_endloop ; otherwise leave the loop (only performing
3610 clc ; one iteration)
3612 adc #6
3613 sta $74
3614 jmp move_characters_loop
3616 move_characters_endloop:
3617 clc
3619 ; Check collisions with the player.
3621 jsr player_collide
3622 bcs move_characters_collisions
3623 jmp move_characters_exit
3625 move_characters_collisions:
3626 clc
3628 ldy #0
3629 lda ($74),y ; type
3630 cmp #8
3631 bpl move_character_destroy_enemy
3633 ; Unplot the item.
3634 jsr unplot_character
3636 ; Remove it from the item table.
3637 jsr remove_room_item
3639 lda #0 ; remove the item from the character list
3640 ldy #0
3641 sta ($74),y
3643 iny
3644 lda ($74),y ; get the item type
3646 sta $8d ; temporarily store A and increase the score
3647 tax
3648 lda item_scores,x
3649 sta $70
3650 jsr add_score
3651 lda $8d
3653 ; Check the item type.
3654 cmp #8
3655 bmi move_characters_not_health
3657 lda #20
3658 sta $70
3659 jsr add_strength
3660 clc
3662 ldx #2
3663 jsr play_sound
3665 rts
3667 move_characters_not_health:
3668 cmp #5
3669 bmi move_characters_not_treasure
3671 ldx #2
3672 jsr play_sound
3674 clc
3675 rts
3677 move_characters_not_treasure:
3678 cmp #4
3679 bmi move_characters_not_key
3681 ; Key - update the item/player flags byte.
3682 lda $5780
3683 ora #$01
3684 sta $5780
3685 clc
3687 ldx #3
3688 jsr play_sound
3690 rts
3692 move_characters_not_key:
3694 ; Update the player's weapon.
3695 asl
3696 sta $5789
3697 clc
3699 ldx #2
3700 jsr play_sound
3702 rts
3704 move_character_destroy_enemy:
3706 ; Unplot the enemy and replace it with an explosion.
3708 jsr unplot_character
3710 lda #3 ; explosion
3711 ldy #0
3712 sta ($74),y
3714 lda #4
3715 ldy #1
3716 sta ($74),y
3718 jsr plot_character
3720 ; Reduce the player's strength.
3722 ldx #1
3723 jsr play_sound
3725 lda #1
3726 sta $70
3727 jmp reduce_strength ; optimise away the rts
3729 move_characters_exit:
3730 clc
3731 rts
3733 remove_room_item:
3735 ldx $5782 ; current room row number
3736 lda eleven_times_table,x
3737 adc $5783 ; current room column number
3738 tax
3739 lda #$80 ; store a value with the top bit set instead of zero because we
3740 sta $5200,x ; have visited this room if we can collect the object within it
3741 clc
3742 rts
3744 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3745 score_vdu_bytes: .byte 1,1,31 ; reversed
3746 score_digits: .byte "0123456789"
3748 add_score: ; $70=score to add
3750 sed
3751 lda $5786
3752 adc $70
3753 sta $5786
3754 lda $5787
3755 adc #0
3756 sta $5787
3757 lda $5788
3758 adc #0
3759 sta $5788
3760 cld
3762 write_score:
3764 lda #$86
3765 sta $70
3766 lda #$57
3767 sta $71
3769 ldx #2
3770 write_score_vdu_bytes:
3771 lda score_vdu_bytes,x
3772 jsr $ffee
3773 dex
3774 bpl write_score_vdu_bytes
3776 write_score_digits: ; $70,$71=address of score bytes
3778 ldy #2
3779 write_score_loop:
3781 lda ($70),y
3782 lsr
3783 lsr
3784 lsr
3785 lsr
3786 tax
3787 lda score_digits,x
3788 jsr $ffee
3790 lda ($70),y
3791 and #$0f
3792 tax
3793 lda score_digits,x
3794 jsr $ffee
3796 dey
3797 bpl write_score_loop
3799 clc
3800 rts
3802 strength_units: .byte $00,$88,$cc,$ee
3804 add_strength: ; $70=strength to add
3806 ; Divide the initial strength by 4 to determine which half character to
3807 ; start plotting at, and multiply by 8 to get the address. The net result
3808 ; is to mask off the bottom two bits and shift left once.
3809 lda $5784
3810 and #$fc
3811 sta $71 ; strength rounded down to a multiple of four units
3812 asl
3813 clc
3814 tay
3816 lda $5784
3817 adc $70
3818 cmp #65
3819 bmi add_strength_update
3821 lda #64
3823 add_strength_update:
3824 clc
3825 sta $5784 ; the final strength
3827 sec
3828 sbc $71
3829 clc
3830 tax ; the number of units to add between the rounded original
3831 ; strength and the final strength
3833 lda #$f3 ; the start of the strength bar
3834 sta $72
3835 lda #$59
3836 sta $73
3838 cpx #4
3839 bmi add_strength_loop_extra
3841 add_strength_loop:
3843 clc
3844 lda #$ff
3845 sta ($72),y
3847 tya
3848 adc #8
3849 tay
3851 txa
3852 sec
3853 sbc #4
3854 clc
3855 tax
3857 cmp #4
3858 bpl add_strength_loop
3860 add_strength_loop_extra:
3861 cpx #0
3862 beq add_strength_exit
3864 ; For any remaining units in excess of the multiples of four units, plot
3865 ; the appropriate byte.
3866 lda $5784
3867 and #3
3868 tax
3870 lda strength_units,x
3871 sta ($72),y
3873 add_strength_exit:
3874 clc
3875 rts
3877 reduce_strength: ; $70=strength to remove
3879 lda $5784
3880 tax
3881 sec
3882 sbc $70
3883 bpl reduce_strength_update
3885 lda #0
3887 reduce_strength_update:
3888 clc
3889 sta $5784
3891 ; Divide the final strength by 4 to determine which half character to
3892 ; plot, and multiply by 8 to get the address. The net result is to mask off
3893 ; the bottom two bits and shift left once.
3894 and #$fc
3895 asl
3896 tay
3898 lda #$f3 ; the start of the strength bar
3899 sta $70
3900 lda #$59
3901 sta $71
3903 lda $5784
3904 and #3
3905 tax
3906 lda strength_units,x
3907 sta ($70),y
3909 lda $5784
3910 cmp #0
3911 bne reduce_strength_exit
3913 lda $5780 ; the player ran out of strength
3914 ora #$40
3915 sta $5780
3917 lda #64 ; reset the delay counter
3918 sta $5785
3920 lda #$80 ; unplot the player
3921 sta $74
3922 lda #$52
3923 sta $75
3925 jsr unplot_character
3927 lda #8 ; change the player's direction to the demise animation
3928 sta $5281
3930 jsr plot_character
3931 jmp destroy_enemies ; optimise away the rts
3933 reduce_strength_exit:
3934 clc
3935 rts
3937 destroy_enemies:
3939 lda #$8c
3940 sta $74
3941 lda #$52
3942 sta $75
3944 destroy_enemies_loop:
3946 ldy #0
3947 lda ($74),y
3948 cmp #8
3949 bmi destroy_enemies_not_enemy
3951 jsr unplot_character
3953 lda #3 ; emerge/explosion
3954 ldy #0
3955 sta ($74),y
3957 iny
3958 lda #4 ; explosion
3959 sta ($74),y
3961 jsr plot_character
3962 jmp destroy_enemies_not_emerging_enemy
3964 destroy_enemies_not_enemy:
3965 cmp #3
3966 bne destroy_enemies_not_emerging_enemy
3968 jsr unplot_character
3970 iny ; whether emerging or exploding, ensure that the enemy
3971 lda ($74),y ; is now exploding
3972 ora #4
3973 sta ($74),y
3975 jsr plot_character
3977 destroy_enemies_not_emerging_enemy:
3978 clc
3979 lda $74
3980 adc #6
3981 sta $74
3982 cmp #$a4
3983 bmi destroy_enemies_loop
3985 clc
3986 rts
3988 remove_characters:
3990 ; Clear the character table.
3992 ldx #6
3993 remove_characters_loop:
3994 lda #0
3995 sta $5280,x
3996 txa
3997 adc #6
3998 tax
3999 cpx #$2a
4000 bmi remove_characters_loop
4002 rts
4004 ; The player collision masks use bits to represent where the player is in a
4005 ; tile. See the collisions.txt file for more information.
4007 ; Player is above, enemy is below, checking the overlap in the lower tile.
4008 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4010 projectile_collision_mask_above: .byte $00, $00, $00, $80
4012 ; Player and enemy share the same tile or player is on the tile below.
4013 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4015 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4017 ; Player is above or on the same tile, enemy is below, checking the overlap in
4018 ; the lower tile.
4019 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4021 ; Enemy is above, player is below, checking the overlap in the lower tile.
4022 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4024 ; Player is to the left, enemy is to the right, checking the overlap in the
4025 ; right hand tile.
4026 player_collision_mask_left:
4027 projectile_collision_mask_left: .byte $00, $00, $00, $08
4029 ; Player and enemy share the same tile or player is on the tile to the right.
4030 player_collision_mask_right:
4031 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4033 ; Player is to the left, enemy is to the right or on the same tile, checking
4034 ; the overlap in the right hand tile.
4035 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4037 ; Enemy is to the left, player is to the right, checking the overlap in the
4038 ; right hand tile.
4039 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4041 player_collide:
4043 lda $5282 ; player y
4044 sta $8a
4045 lda $5284 ; player x
4046 sta $8b
4048 ldx $5283 ; player dy
4049 lda player_collision_mask_above,x
4050 sta $86
4051 lda player_collision_mask_below,x
4052 sta $88
4053 ldx $5285 ; player dx
4054 lda player_collision_mask_left,x
4055 sta $87
4056 lda player_collision_mask_right,x
4057 sta $89
4059 jmp collide ; optimise away the rts
4061 projectile_collide:
4063 lda $5288 ; projectile y
4064 sta $8a
4065 lda $528a ; projectile x
4066 sta $8b
4068 ldx $5289 ; projectile dy
4069 lda projectile_collision_mask_above,x
4070 sta $86
4071 lda projectile_collision_mask_below,x
4072 sta $88
4073 ldx $528b ; projectile dx
4074 lda projectile_collision_mask_left,x
4075 sta $87
4076 lda projectile_collision_mask_right,x
4077 sta $89
4079 ; Run on into the next routine.
4081 collide:
4083 lda #$8c ; set the character address
4084 sta $74
4085 lda #$52
4086 sta $75
4088 collide_loop:
4090 ldy #0
4091 lda ($74),y ; type
4092 cmp #4
4093 bpl collide_check
4095 jmp collide_next
4097 collide_check:
4099 ldy #2
4100 lda ($74),y ; y
4101 sec
4102 sbc $8a ; y - player/projectile y
4103 beq check_collide_y_equal
4104 cmp #1
4105 beq check_collide_y_greater
4106 cmp #255
4107 beq check_collide_y_less
4109 jmp collide_next
4111 check_collide_y_equal:
4112 ; The enemy is on the same tile as the player/projectile so look at the
4113 ; collision on their common tile.
4114 ldy #3
4115 lda ($74),y ; dy
4116 tax
4117 lda enemy_collision_mask_above,x
4118 and $88 ; player/projectile mask below
4119 bne check_collide_x
4121 jmp collide_next
4123 check_collide_y_greater:
4124 ; The enemy is on the tile below the player/projectile so look at the
4125 ; collision on the enemy's tile.
4126 ldy #3
4127 lda ($74),y ; dy
4128 tax
4129 lda enemy_collision_mask_above,x
4130 and $86 ; player mask above
4131 bne check_collide_x
4133 jmp collide_next
4135 check_collide_y_less:
4136 ; The enemy is on the tile above the player/projectile so look at the
4137 ; collision on the player's tile.
4138 ldy #3
4139 lda ($74),y ; dy
4140 tax
4141 lda enemy_collision_mask_below,x
4142 and $88 ; player mask below
4143 bne check_collide_x
4145 jmp collide_next
4147 check_collide_x:
4148 ldy #4
4149 lda ($74),y ; x
4150 sec
4151 sbc $8b ; x - player/projectile x
4152 beq check_collide_x_equal
4153 cmp #1
4154 beq check_collide_x_greater
4155 cmp #255
4156 beq check_collide_x_less
4158 jmp collide_next
4160 check_collide_x_equal:
4161 ; The enemy is on the same tile as the player/projectile so look at the
4162 ; collision on their common tile.
4163 ldy #5
4164 lda ($74),y ; dx
4165 tax
4166 lda enemy_collision_mask_left,x
4167 and $89 ; player mask right
4168 bne check_collide_destroy
4170 jmp collide_next
4172 check_collide_x_greater:
4173 ; The enemy is the tile to the right of the player/projectile so look
4174 ; at the collision on the enemy's tile.
4175 ldy #5
4176 lda ($74),y ; dx
4177 tax
4178 lda enemy_collision_mask_left,x
4179 and $87 ; player mask left
4180 bne check_collide_destroy
4182 jmp collide_next
4184 check_collide_x_less:
4185 ; The enemy is the tile to the left of the player/projectile so look at
4186 ; the collision on the player's tile.
4187 ldy #5
4188 lda ($74),y ; dx
4189 tax
4190 lda enemy_collision_mask_right,x
4191 and $89 ; player mask right
4192 bne check_collide_destroy
4194 collide_next:
4195 clc
4197 ; Examine the next character.
4198 lda $74
4199 adc #6
4201 cmp #$a4
4202 bpl collide_exit
4203 sta $74
4204 jmp collide_loop
4206 check_collide_destroy:
4208 sec ; set the carry flag to inform the caller that the
4209 rts ; player/projectile should be destroyed
4211 collide_exit:
4212 clc
4213 rts
4215 blank_screen:
4216 lda #1
4217 sta $70
4218 lda #0
4219 sta $71
4220 jsr set_palette
4221 lda #2
4222 sta $70
4223 lda #0
4224 sta $71
4225 jsr set_palette
4226 lda #3
4227 sta $70
4228 lda #0
4229 sta $71
4230 ; Run on into set_palette.
4232 set_palette:
4233 ; $70=logical colour
4234 ; $71=physical colour
4235 lda $70
4236 sta $578b
4237 lda $71
4238 sta $578c
4239 lda #0
4240 sta $578d
4241 sta $578e
4242 sta $578f
4244 lda #$c
4245 ldx #$8b
4246 ldy #$57
4247 jsr $fff1
4248 rts
4250 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4251 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4253 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4254 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4255 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4256 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4257 note_sound: .byte $13,0, 241,255
4258 note_pitch: .byte 0,0
4259 note_duration: .byte 4,0
4260 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4262 play_note: ; A=pitch, Y=duration
4264 sta note_pitch
4265 sty note_duration
4266 ldx #4
4267 ; Run on into the next routine.
4269 play_sound: ; X=sound number
4271 lda sounds_high,x
4272 tay
4273 lda sounds_low,x
4274 tax
4275 lda #7
4276 jsr $fff1
4278 rts
4280 copy_title_up:
4282 lda #$00
4283 sta $70
4284 lda #$18
4285 sta $71
4287 lda #$a0
4288 sta $72
4289 lda #$5a
4290 sta $73
4292 ldx #5
4293 ; Run on into the next routine.
4295 copy_title:
4297 copy_title_loop1:
4299 ldy #0
4300 copy_title_loop2:
4302 lda ($70),y
4303 sta ($72),y
4304 iny
4305 cpy #0
4306 bne copy_title_loop2
4308 clc
4309 lda $72
4310 adc #$40
4311 sta $72
4312 lda $73
4313 adc #$01
4314 sta $73
4315 clc
4317 lda $71
4318 adc #$01
4319 sta $71
4320 clc
4322 dex
4323 bpl copy_title_loop1
4325 rts
4327 copy_completed_screen_up:
4329 lda #$00
4330 sta $70
4331 lda #$0f
4332 sta $71
4334 lda #$60
4335 sta $72
4336 lda #$5e
4337 sta $73
4339 ldx #8
4340 jmp copy_title ; optimise away the rts
4342 init:
4343 jsr cls ; clear the text window
4345 lda #26 ; unset the text window
4346 jsr $ffee
4348 ; Define the default high scores.
4349 ldy #0
4350 lda #$80
4351 sta $70
4352 lda #$51
4353 sta $71
4354 lda #$16
4355 sta $72
4357 ldx #0
4358 init_define_high_scores_loop:
4360 lda #0
4361 sta ($70),y
4362 iny
4363 lda $72
4364 sta ($70),y
4365 iny
4366 lda #0
4367 sta ($70),y
4369 iny
4370 init_define_high_score_name_loop:
4372 lda high_score_default_name1,x
4373 sta ($70),y
4374 iny
4375 inx
4376 cpx #9
4377 beq init_define_high_scores_next
4378 cpx #18
4379 bne init_define_high_score_name_loop
4381 ldx #0
4382 init_define_high_scores_next:
4384 sed
4385 lda $72
4386 sec
4387 sbc #2
4388 sta $72
4389 cld
4390 clc
4392 cpy #96
4393 bne init_define_high_scores_loop
4395 ; Disable joystick support.
4396 lda #0
4397 sta $577e
4399 rts
4401 high_score_default_name1: .byte "RETRO "
4402 high_score_default_name2: .byte " SOFTWARE"
4404 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4405 input_message: .byte 17,2, 31,2,27, "Press SPACE/FIRE"
4406 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4407 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4408 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4409 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4411 set_standard_palette:
4413 lda #1
4414 sta $70
4415 lda #1
4416 sta $71
4417 jsr set_palette
4419 jmp set_core_palette ; optimise away the rts
4421 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4423 set_complete_palette:
4425 lda #0
4426 sta $80
4427 lda #25
4428 sta $81
4430 set_complete_palette_loop:
4432 jsr wait_for_vsync
4434 dec $81
4435 lda $81
4436 cmp #0
4437 bne set_complete_palette_loop
4439 lda #25
4440 sta $81
4442 ldx $80
4443 lda complete_palette_bytes,x
4444 sta $70
4445 inx
4446 lda complete_palette_bytes,x
4447 sta $71
4448 inx
4449 stx $80
4450 jsr set_palette
4452 lda $80
4453 cmp #10
4454 bne set_complete_palette_loop
4456 rts
4458 set_hidden_palette:
4460 lda #1
4461 sta $70
4462 lda #0
4463 sta $71
4464 jsr set_palette
4466 ; Run on into the next routine.
4468 set_core_palette:
4470 lda #2
4471 sta $70
4472 lda #2
4473 sta $71
4474 jsr set_palette
4476 lda #3
4477 sta $70
4478 lda #3
4479 sta $71
4480 jsr set_palette
4482 rts
4484 show_title:
4486 jsr set_standard_palette
4488 ldx #0
4489 write_title_text_loop:
4490 lda title_vdu_bytes,x
4491 jsr $ffee
4492 inx
4493 cpx #12
4494 bmi write_title_text_loop
4496 jsr show_input_message
4498 ; Show the title.
4499 jsr copy_title_up
4501 ; Show the high scores.
4503 jsr colour1
4505 lda #$80
4506 sta $70
4507 lda #$51
4508 sta $71
4510 lda #8
4511 sta $80
4513 show_title_high_scores_loop:
4515 lda #31
4516 jsr $ffee
4517 lda #2
4518 jsr $ffee
4519 lda $80
4520 adc #2
4521 sta $80
4522 clc
4523 jsr $ffee
4525 jsr write_score_digits
4527 lda #32
4528 jsr $ffee
4530 ldx #8
4531 ldy #3
4532 show_title_high_scores_vdu_loop2:
4534 lda ($70),y
4535 cmp #32
4536 bmi ignore_char
4537 cmp #123
4538 bpl ignore_char
4539 jsr $ffee
4541 ignore_char:
4542 iny
4543 dex
4544 bpl show_title_high_scores_vdu_loop2
4546 lda $70
4547 adc #12
4548 sta $70
4549 cmp #$e0
4550 bne show_title_high_scores_loop
4552 lda #0 ; message counter
4553 sta $72
4555 show_title_wait_loop:
4557 lda #150
4558 sta $5785
4560 ldx $72
4561 ldy #22
4562 show_title_wait_message_loop:
4564 lda title_vdu_bytes1,x
4565 jsr $ffee
4566 inx
4567 dey
4568 bpl show_title_wait_message_loop
4570 cpx #92
4571 beq show_title_wait_reset_offset
4573 txa
4574 sta $72
4575 jmp show_title_wait_inner_loop
4577 show_title_wait_reset_offset:
4578 lda #0
4579 sta $72
4581 show_title_wait_inner_loop:
4582 jsr wait_for_vsync
4584 dec $5785
4585 beq show_title_wait_loop
4587 show_title_wait_loop_no_update:
4588 lda #128
4589 ldx #0
4590 jsr $fff4
4591 cpx #0 ; fire button pressed?
4592 beq show_title_no_joystick
4594 lda #1 ; enable joystick support
4595 sta $577e
4596 jmp show_title_exit
4598 show_title_no_joystick:
4599 ldx #157 ; SPACE
4600 jsr check_key
4601 cpy #255
4602 bne show_title_wait_inner_loop
4604 lda #0 ; disable joystick support
4605 sta $577e
4607 show_title_exit:
4608 clc
4609 rts
4611 show_input_message:
4613 ldx #0
4614 show_input_message_loop:
4616 lda input_message,x
4617 jsr $ffee
4618 inx
4619 cpx #21
4620 bne show_input_message_loop
4622 rts
4624 wait_for_vsync:
4626 lda #19
4627 jmp $fff4 ; optimise away the rts
4629 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4631 delay:
4633 delay_loop:
4635 jsr wait_for_vsync
4636 dec $5785
4637 bne delay_loop
4639 rts
4641 show_game_over:
4643 lda #128
4644 sta $5785
4645 jsr delay
4647 ldx #0
4648 write_game_over_text_loop:
4649 lda game_over_vdu_bytes,x
4650 jsr $ffee
4651 inx
4652 cpx #33
4653 bmi write_game_over_text_loop
4655 lda #192
4656 sta $5785
4657 jsr delay
4659 rts
4661 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4662 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4664 show_end_of_level_screen:
4666 ; Draw a decorative room.
4668 jsr make_empty_room
4670 ldx #5
4671 end_of_level_h_walls_loop:
4673 lda #3
4674 sta $57b2,x
4675 sta $57e4,x
4676 dex
4677 bpl end_of_level_h_walls_loop
4679 ldx #30
4680 end_of_level_v_walls_loop:
4682 lda #3
4683 sta $57bc,x
4684 sta $57c1,x
4685 txa
4686 sec
4687 sbc #10
4688 tax
4689 bpl end_of_level_v_walls_loop
4691 jsr plot_room_tiles
4692 jsr set_standard_palette
4694 ldx #0
4695 end_of_level_text_loop1:
4697 lda end_of_level_bytes1,x
4698 jsr $ffee
4699 inx
4700 cpx #28
4701 bne end_of_level_text_loop1
4703 ; Count the number of rooms explored.
4704 ldx #0
4705 lda #0
4706 sta $8d
4707 sta $8e
4708 end_of_level_room_count_loop:
4710 lda $5200,x
4711 and #$80
4712 beq end_of_level_room_count_loop_next
4714 sed
4715 lda $8d
4716 adc #1
4717 sta $8d
4718 lda $8e
4719 adc #0
4720 sta $8e
4721 cld
4722 clc
4724 end_of_level_room_count_loop_next:
4725 inx
4726 cpx #121
4727 bne end_of_level_room_count_loop
4729 ; Position the player so that we can perform an animation.
4730 jsr position_player_set_up_plotting
4732 lda $8d
4733 sta $70
4734 lda $8e
4735 sta $71
4736 jsr write_bonus
4738 lda #0 ; reset motion counter
4739 sta $578e
4741 show_end_of_level_bonus_loop:
4743 jsr wait_for_vsync
4745 clc
4746 lda $578e
4747 and #15
4748 bne end_of_level_no_animation
4750 ; Animate the player.
4752 jsr reset_unplot_buffer
4753 jsr reset_plot_buffer
4755 ; $74,$75 should be unchanged
4756 jsr unplot_character
4758 lda $5281
4759 eor #1
4760 sta $5281
4761 jsr plot_character
4763 jsr plot_buffer
4765 end_of_level_no_animation:
4766 clc
4767 lda $578e
4768 and #3
4769 bne end_of_level_no_countdown
4771 ; Transfer the bonus to the score.
4773 sed
4774 sec
4775 lda $8d
4776 sbc #1
4777 sta $8d
4778 sta $70
4779 lda $8e
4780 sbc #0
4781 sta $8e
4782 sta $71
4783 cld
4784 clc
4786 jsr write_bonus
4788 lda #9
4789 sta $70
4790 jsr add_score
4792 lda $8d
4793 and #$3f
4794 asl
4795 ldy #1
4796 jsr play_note
4798 end_of_level_no_countdown:
4799 inc $578e ; update motion counter
4800 clc
4802 lda $8d
4803 cmp #0
4804 bne show_end_of_level_bonus_loop
4806 lda $8e
4807 cmp #0
4808 bne show_end_of_level_bonus_loop
4810 lda #64 ; initialise delay counter
4811 sta $5785
4812 jsr delay
4814 ldx #0
4815 end_of_level_text_loop2:
4817 lda end_of_level_bytes2,x
4818 jsr $ffee
4819 inx
4820 cpx #25
4821 bne end_of_level_text_loop2
4823 lda $578a
4824 cmp #3
4825 bpl show_end_of_level_screen_exit
4827 lda #192 ; initialise delay counter
4828 sta $5785
4829 jsr delay
4831 show_end_of_level_screen_exit:
4832 rts
4834 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4836 write_bonus: ; $70,$71=value
4837 ; $72,$73=address of VDU codes
4839 ldx #4
4840 write_bonus_vdu_bytes:
4842 lda level_bonus_vdu_bytes,x
4843 jsr $ffee
4844 dex
4845 bpl write_bonus_vdu_bytes
4847 ldy #1
4848 write_bonus_loop:
4850 tya
4851 tax ; temporary
4853 lda $70,x
4854 sta $80
4855 lsr
4856 lsr
4857 lsr
4858 lsr
4859 tax
4860 lda score_digits,x
4861 jsr $ffee
4863 lda $80
4864 and #$0f
4865 tax
4866 lda score_digits,x
4867 jsr $ffee
4869 dey
4870 bpl write_bonus_loop
4872 clc
4873 rts
4875 position_player_set_up_plotting:
4877 jsr reset_player_position
4878 jsr remove_characters
4880 jsr reset_unplot_buffer
4881 jsr reset_plot_buffer
4883 ; Run on into the next routine.
4885 plot_the_player:
4887 lda #$80 ; plot the player
4888 sta $74
4889 lda #$52
4890 sta $75
4891 jsr plot_character
4893 jsr plot_buffer
4894 rts
4896 complete_game_vdu_bytes1: .byte 12
4897 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4898 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4899 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4901 show_complete_game:
4903 jsr blank_screen
4905 ldx #0
4906 show_complete_game_vdu_loop:
4908 lda complete_game_vdu_bytes1,x
4909 jsr $ffee
4910 inx
4911 cpx #68
4912 bne show_complete_game_vdu_loop
4914 jsr copy_completed_screen_up
4916 jsr set_complete_palette
4918 lda #255
4919 sta $5785
4921 show_complete_game_delay_loop:
4923 jsr wait_for_vsync
4925 dec $5785
4926 bne show_complete_game_no_message
4928 jsr colour1
4929 jsr show_input_message
4931 show_complete_game_no_message:
4933 lda #128
4934 ldx #0
4935 jsr $fff4
4936 cpx #0 ; fire button pressed?
4937 beq show_complete_game_no_joystick
4938 jmp show_complete_game_exit
4940 show_complete_game_no_joystick:
4942 ldx #157
4943 jsr check_key
4944 cpy #255
4945 bne show_complete_game_delay_loop
4947 show_complete_game_exit:
4948 clc
4949 rts
4951 check_high_scores:
4953 ; Start at the bottom of the table, moving scores down as necessary, and
4954 ; write in the current score at the appropriate place.
4956 lda #$86 ; current score
4957 sta $70
4958 lda #$57
4959 sta $71
4961 lda #$80
4962 sta $72
4963 lda #$51
4964 sta $73
4966 check_high_scores_loop:
4968 ldy #2
4969 check_high_scores_digits_loop:
4971 lda ($72),y
4972 cmp ($70),y ; existing score less than current score?
4973 bmi check_high_scores_move_down
4974 beq check_high_scores_digits_next ; keep checking digits if equal
4975 jmp check_high_scores_next
4977 check_high_scores_digits_next:
4978 dey
4979 bpl check_high_scores_digits_loop
4981 check_high_scores_next:
4982 clc
4983 lda $72
4984 adc #12
4985 sta $72
4986 cmp #$e0
4987 bne check_high_scores_loop
4989 ; The player's score didn't make it into the high score table.
4990 rts
4992 check_high_scores_move_down: ; $70,$71=pointer to current score
4993 ; $72,$73=pointer to old score
4995 ; The current score exceeded the existing entry. Make a note of the
4996 ; position in the high score table, insert the player's score, and take
4997 ; the old score
4999 lda $72 ; Record the position in the high score table of the
5000 sta $8d ; player's score.
5001 lda $73
5002 sta $8e
5004 lda #$e0
5005 sta $74
5006 lda #$51
5007 sta $75
5009 ldy #0
5010 insert_blank_player_name_loop:
5012 cpy #3
5013 bpl insert_blank_player_name_score_only
5015 lda ($70),y
5016 jmp insert_blank_player_name_store
5018 insert_blank_player_name_score_only:
5019 lda #32
5021 insert_blank_player_name_store:
5022 sta ($74),y
5023 iny
5024 cpy #12
5025 bne insert_blank_player_name_loop
5027 check_high_scores_move_down_loop:
5029 ldy #0
5030 check_high_scores_copy_score_and_name:
5032 lda ($72),y ; swap the current score with the score in the table
5033 tax
5034 lda ($74),y
5035 sta ($72),y
5036 txa
5037 sta ($74),y
5038 iny
5039 cpy #12
5040 bne check_high_scores_copy_score_and_name
5042 clc
5043 lda $72
5044 adc #12
5045 sta $72
5046 cmp #$e0
5047 bne check_high_scores_move_down_loop
5049 ; Draw a decorative room.
5051 jsr set_hidden_palette
5053 jsr make_empty_room
5055 lda #3
5056 sta $76
5057 sta $77
5058 jsr draw_top_line
5059 jsr draw_bottom_line
5060 jsr draw_left_line
5062 lda #0
5063 sta $77
5064 jsr draw_right_line
5066 jsr plot_room_tiles
5068 ; Add text characters to the room.
5069 jsr colour3
5071 lda #3 ; x
5072 sta $70
5073 lda #6 ; y
5074 sta $71
5076 lda #65
5077 sta $72
5079 ldx #3
5080 plot_text_characters_loop:
5082 jsr print_xy
5084 lda $70
5085 adc #4
5086 sta $70
5088 dex
5089 bpl plot_text_characters_next
5091 lda #3
5092 sta $70
5093 lda $71
5094 adc #3
5095 sta $71
5097 ldx #3
5099 plot_text_characters_next:
5101 inc $72
5102 lda $72
5103 cmp #91
5104 bne plot_text_characters_loop
5106 lda #11
5107 sta $70
5108 lda #95 ; _ representing a space
5109 sta $72
5110 jsr print_xy
5112 lda #15
5113 sta $70
5114 lda #60 ; < representing delete
5115 sta $72
5116 jsr print_xy
5118 ; Put the player in the centre of the room.
5119 jsr position_player_set_up_plotting
5121 lda #0 ; reset motion counter
5122 sta $578e
5124 lda #0 ; not on a character
5125 sta $578d
5127 lda #0 ; reset the level number so that the correct tiles are used
5128 sta $578a
5130 lda #3 ; cursor position in the high score entry held in $8d,$8e
5131 sta $8f
5133 jsr set_standard_palette
5135 ldx #0
5136 high_score_vdu_loop:
5138 lda high_score_vdu_bytes,x
5139 jsr $ffee
5140 inx
5141 cpx #39
5142 bne high_score_vdu_loop
5144 high_score_entry_loop:
5146 jsr reset_unplot_buffer
5147 jsr reset_plot_buffer
5149 jsr move_player
5150 ; Check if the player leaves the room.
5151 bcc high_score_entry_check_position
5152 jmp high_score_entry_after_loop
5154 high_score_entry_check_position:
5156 lda $5285 ; dx
5157 cmp #2
5158 beq high_score_entry_maybe_aligned
5159 jmp high_score_entry_not_aligned
5161 high_score_entry_maybe_aligned:
5163 lda $5282 ; y
5164 tay
5165 cmp #8
5166 bpl high_score_entry_not_aligned
5168 lda $5284 ; x
5169 tax
5170 cmp #9
5171 beq high_score_entry_not_aligned
5172 and #1
5173 beq high_score_entry_not_aligned
5175 lda $5283 ; dy
5176 cmp #2
5177 bmi high_score_entry_aligned
5178 jmp high_score_entry_not_aligned
5180 lda $5282 ; y again (don't apply the touching rule to the bottom
5181 cmp #7 ; row of characters)
5182 beq high_score_entry_not_aligned
5184 iny ; we are really touching the character below
5186 high_score_entry_aligned:
5188 lda $578d
5189 cmp #1
5190 beq high_score_entry_next
5192 ; The player is aligned with a letter.
5193 txa
5194 sec
5195 sbc #1
5196 lsr
5197 sta $7e ; record (x - 1) / 2
5199 tya ; recall y
5200 sec
5201 sbc #1
5202 asl
5203 asl ; (y - 1) * 4
5204 clc
5206 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5207 adc #65
5208 sta $7e ; record the ASCII code
5210 cmp #91
5211 bmi insert_character
5213 cmp #92
5214 beq delete_character
5216 ; Insert a space.
5217 lda #32
5218 sta $7e
5220 insert_character:
5221 lda $8f
5222 cmp #12
5223 bpl high_score_entry_pressed
5225 tay ; insert the character
5226 lda $7e
5227 sta ($8d),y
5228 jsr print_high_score_character
5230 inc $8f
5231 jmp high_score_entry_pressed
5233 delete_character:
5234 lda $8f
5235 cmp #4
5236 bmi high_score_entry_pressed
5238 cmp #12
5239 beq high_score_delete_previous_character
5241 tay
5242 lda #32 ; insert a space
5243 sta ($8d),y
5244 jsr print_high_score_character
5246 high_score_delete_previous_character:
5247 dec $8f
5248 lda $8f
5249 tay ; insert a space
5250 lda #32
5251 sta ($8d),y
5252 jsr print_high_score_character
5254 high_score_entry_pressed:
5255 lda #1
5256 sta $578d
5257 jmp high_score_entry_next
5259 high_score_entry_not_aligned:
5260 lda #0
5261 sta $578d
5263 high_score_entry_next:
5265 jsr wait_for_vsync
5266 jsr plot_buffer
5268 jmp high_score_entry_loop
5270 inc $578e
5271 clc
5273 high_score_entry_after_loop:
5274 clc
5276 jsr cls
5277 jsr set_hidden_palette
5279 rts
5281 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5283 cls:
5284 lda #12
5285 jsr $ffee
5286 rts
5288 colour1:
5289 lda #17
5290 jsr $ffee
5291 lda #1
5292 jsr $ffee
5293 rts
5295 colour3:
5296 lda #17
5297 jsr $ffee
5298 lda #3
5299 jsr $ffee
5300 rts
5302 print_high_score_character: ; A=ASCII code
5304 clc
5305 sta $72 ; store the character
5306 lda $8f
5307 adc #3
5308 sta $70 ; store the x position of the character
5309 lda #30
5310 sta $71
5311 ; Run on into the next routine.
5313 print_xy:
5315 lda #31
5316 jsr $ffee
5317 lda $70
5318 jsr $ffee
5319 lda $71
5320 jsr $ffee
5321 lda $72
5322 jsr $ffee
5323 rts
5325 disable_sound: ; X=1 (disable); X=0 (enable)
5327 lda #210
5328 ldy #0
5329 jmp $fff4 ; optimise away the rts
5331 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5332 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5334 start_new_game:
5336 ; Clear the screen.
5337 jsr cls
5339 ; Set the level.
5340 lda #0
5341 sta $578a
5343 ; Set the score.
5344 lda #0
5345 sta $5786
5346 lda #0
5347 sta $5787
5348 lda #0
5349 sta $5788
5351 ; Blank the screen now because it will be blanked before the room is shown
5352 ; and otherwise the strength bar will show briefly.
5353 jsr blank_screen
5355 ; Set the player's strength.
5356 lda #0
5357 sta $5784
5358 lda #64
5359 sta $70
5360 jsr add_strength
5362 ; Set the projectile type.
5363 lda #0
5364 sta $5789
5366 rts
5368 reset_player_position:
5370 lda #1 ; player
5371 sta $5280
5372 lda #6 ; down (first frame)
5373 sta $5281
5374 lda #4 ; y=4
5375 sta $5282
5376 lda #2 ; dy=2
5377 sta $5283
5378 lda #4 ; x=4
5379 sta $5284
5380 lda #3 ; dx=3
5381 sta $5285
5383 rts
5385 start_level:
5387 ; Clear the item/player flags.
5388 lda #0
5389 sta $5780
5391 ; Set current room.
5393 ldx $578a
5394 lda start_rooms_y,x
5395 sta $5782
5396 lda start_rooms_x,x
5397 sta $5783
5399 ; Set the player's position.
5401 jsr reset_player_position
5403 ; Reset the weapon counter.
5404 lda #0
5405 sta $577f
5407 ; Fill the treasure table with objects.
5408 ldx $578a ; level
5409 lda key_rooms,x
5410 sta $80
5412 ldx $578a ; level
5413 lda seeds,x
5414 adc #1
5415 and #31
5416 sta $7c
5417 clc
5418 lda seeds,x
5419 adc #2
5420 and #31
5421 sta $7d
5422 clc
5424 lda $578a ; create an upper limit on the weapon type found in this level
5425 adc #2
5426 sta $5781
5427 clc
5429 lda #$00
5430 sta $8e
5431 lda #$52
5432 sta $8f
5434 ldy #0
5435 start_level_add_treasure_loop:
5437 cpy $80 ; check for the key room
5438 bne start_level_add_treasure_item
5440 lda #5 ; the value to store is type + 1
5441 jmp start_level_add_treasure_store
5443 start_level_add_treasure_item:
5444 clc
5445 jsr unlimited_values
5446 and #$0f
5447 cmp #0
5448 beq start_level_add_treasure_none
5450 clc
5451 sta $8c
5452 tya
5453 adc $8c
5454 and #31
5455 clc
5456 tax
5457 lda treasure_table,x
5459 cmp #4
5460 bmi start_level_add_treasure_weapon
5462 clc
5463 adc #1
5464 jmp start_level_add_treasure_store
5466 start_level_add_treasure_weapon:
5468 ; Only add weapons with types that equal the level number or exceed it
5469 ; by one.
5470 cmp $5781
5471 bcs start_level_add_treasure_none
5473 clc
5474 adc #1 ; store values 0-8 as values 1-9
5475 jmp start_level_add_treasure_store
5477 start_level_add_treasure_none:
5478 clc
5479 lda #0 ; do not put treasure in this room
5481 start_level_add_treasure_store:
5482 clc
5483 sta ($8e),y ; add the item to the table
5485 iny
5486 cpy #121
5487 bmi start_level_add_treasure_loop
5489 ; Write the status text.
5490 ldx #0
5491 write_status_text_loop:
5492 lda status_vdu_bytes,x
5493 jsr $ffee
5494 inx
5495 cpx #25
5496 bmi write_status_text_loop
5498 jsr write_score
5500 clc
5501 rts
5503 main:
5504 jsr init
5506 main_loop:
5508 jsr show_title
5510 jsr start_new_game
5512 level_loop:
5514 jsr start_level
5516 game_loop:
5518 jsr remove_characters
5520 jsr reset_unplot_buffer
5521 jsr reset_plot_buffer
5523 lda $5782 ; current room (y)
5524 sta $78
5525 lda $5783 ; current room (x)
5526 sta $79
5527 jsr plot_room
5528 jsr set_room_palette
5529 jsr create_enemy_positions
5530 jsr add_treasure
5532 jsr plot_the_player
5534 lda #0 ; reset projectile counter
5535 sta $578d
5537 lda #0 ; reset motion counter
5538 sta $578e
5540 lda #63 ; reset generation counter
5541 sta $578f
5543 room_loop:
5544 jsr reset_unplot_buffer
5545 jsr reset_plot_buffer
5547 jsr move_characters
5548 jsr move_projectile
5550 lda $5780 ; is player out of strength ($40), leaving the
5551 and #$c2 ; level (0x80) or completing the game (0x02)?
5552 beq room_loop_player_move
5553 clc
5555 dec $5785 ; leave the loop when the delay
5556 bne room_loop_delay_next
5557 jmp after_room_loop ; counter is about to reset
5559 room_loop_delay_next:
5561 lda $5281 ; leave the loop when the player demise
5562 cmp #11 ; animation has finished
5563 beq room_loop_after_player_move
5564 clc
5566 lda $578e
5567 and #7
5568 bne room_loop_after_player_move
5570 lda $5780 ; skip the animation if leaving the level or
5571 and #$82 ; completing the game
5572 bne room_loop_after_player_move
5574 ; Show the demise animation when appropriate.
5576 lda #$80
5577 sta $74
5578 lda #$52
5579 sta $75
5581 jsr unplot_character
5583 inc $5281
5584 jsr plot_character
5585 jmp room_loop_after_player_move
5587 room_loop_player_move:
5589 ; See if it is time to generate a new enemy.
5590 lda $578f
5591 cmp #0
5592 bne no_emerge_characters
5593 jsr emerge_characters
5595 no_emerge_characters:
5596 clc
5598 jsr check_fire_key
5599 jsr move_player
5600 bcs after_room_loop ; check if we are leaving the level
5602 room_loop_after_player_move:
5603 clc
5605 lda #19
5606 jsr $fff4
5607 jsr plot_buffer
5609 ldx #143 ; Escape key check
5610 jsr check_key
5611 cpy #255
5612 beq main_loop_play_again
5614 ldx #174 ; S key check
5615 jsr check_key
5616 cpy #255
5617 bne no_set_sound
5619 ldx #0
5620 jsr disable_sound
5621 jmp after_sound_checks
5623 no_set_sound:
5625 ldx #239 ; Q key check
5626 jsr check_key
5627 cpy #255
5628 bne after_sound_checks
5630 ldx #1
5631 jsr disable_sound
5633 after_sound_checks:
5635 ldx #200 ; P key check
5636 jsr check_key
5637 cpy #255
5638 bne no_pause
5640 pause_loop:
5642 ldx #201 ; O key check
5643 jsr check_key
5644 cpy #255
5645 bne pause_loop
5647 no_pause:
5648 clc
5650 lda $578d
5651 cmp #0
5652 beq room_loop_no_update_projectile_counter
5654 dec $578d
5656 room_loop_no_update_projectile_counter:
5658 dec $578f ; update generation counter
5660 inc $578e ; update motion counter
5661 clc
5662 jmp room_loop
5664 after_room_loop:
5665 clc
5667 lda $5780
5668 and #$80
5669 bne exit_level
5671 lda $5780
5672 and #$40
5673 bne game_over
5675 lda $5780
5676 and #$02
5677 bne complete_game
5679 jmp game_loop
5681 exit_level:
5683 jsr show_end_of_level_screen
5685 inc $578a
5686 clc
5687 jmp level_loop
5689 game_over:
5690 jsr show_game_over
5691 jmp main_loop_play_again
5693 complete_game:
5694 jsr show_end_of_level_screen
5695 jsr show_complete_game
5696 jmp main_loop_play_again
5698 main_loop_play_again:
5699 jsr cls
5701 ; Check the score against the high scores.
5702 jsr check_high_scores
5704 jmp main_loop
5706 exit:
5707 clc
5708 rts
