junglejourney
view mapcode.oph @ 212:66abf7c5cf63
Fixed a bug that caused too many types of enemy to be introduced
on each level.
| author | David Boddie <david@boddie.org.uk> |
|---|---|
| date | Sun Oct 09 02:44:28 2011 +0200 |
| parents | 72baa6318192 |
| children | 3ae571b43ba0 |
line source
1 ; Copyright (C) 2011 David Boddie <david@boddie.org.uk>
2 ;
3 ; This program is free software: you can redistribute it and/or modify
4 ; it under the terms of the GNU General Public License as published by
5 ; the Free Software Foundation, either version 3 of the License, or
6 ; (at your option) any later version.
7 ;
8 ; This program is distributed in the hope that it will be useful,
9 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ; GNU General Public License for more details.
12 ;
13 ; You should have received a copy of the GNU General Public License
14 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
16 .org $1e00
17 jmp main
19 seeds: .byte 100, 239, 183, 144 ; $ef, $b7, $90, $d6, $89
20 start_rooms_x: .byte 5, 3, 5, 10
21 start_rooms_y: .byte 5, 8, 1, 8
22 exit_rooms_x: .byte 7, 9, 3, 0
23 exit_rooms_y: .byte 0, 0, 9, 10
25 ; These values need to be kept in sync - the room numbers must match their
26 ; positions in the room array.
27 key_rooms_x: .byte 1, 5, 10, 1
28 key_rooms_y: .byte 0, 2, 6, 4
29 key_rooms: .byte 1, 27, 76, 45 ; ky*11 + kx
31 treasure_table: .byte 6, 5, 7, 1, 1, 5, 2, 7, 6, 2, 1, 7, 1, 7, 8, 7
32 treasure_table_: .byte 0, 7, 6, 7, 7, 7, 5, 0, 6, 3, 7, 7, 5, 7, 5, 0
34 unlimited_values: ; $7c,$7d=first,second
35 ; Add $7c and $7d, store the result in $7d and the original
36 ; $7d value in $7c, returning the sum in the accumulator.
37 lda $7c
38 sta $7b
39 lda $7d
40 sta $7c
41 adc $7b
42 sta $7d
43 clc
44 rts
46 mod9: ; A = value
47 divide_loop:
48 cmp #9
49 bcc after_divide_loop ; bmi should work here, I think, but it doesn't
50 sec
51 sbc #9
52 jmp divide_loop
54 after_divide_loop:
55 clc
56 rts ; A % 9
58 tile_values_map: .byte 0,1,0,0,0,0,2,3
60 next_value: ; no argument
61 jsr unlimited_values
62 lda $7d
63 jsr mod9
64 and #7 ; (next value % 9) & 7
65 tax
66 lda tile_values_map,x
67 sta $7b
68 rts
70 ; Room filling routines, writing to 0x579c to 0x57ff.
72 draw_top_line: ; $76=tile number for exit/wall
73 ldx #9
74 lda #2
76 draw_top_line_loop0:
77 sta $579c,x
78 dex
79 bpl draw_top_line_loop0
81 ldx #3 ; draw the exit or wall
82 lda $76
83 draw_top_line_loop1:
84 sta $579f,x
85 dex
86 bpl draw_top_line_loop1
87 clc
88 rts
90 draw_left_line: ; $77=tile number for exit/wall
91 ldx #90
92 draw_left_line_loop0:
93 lda #2
94 sta $579c,x
95 txa
96 sec
97 sbc #10
98 tax
99 bpl draw_left_line_loop0
101 ldx #30
102 draw_left_line_loop1:
103 lda $77
104 sta $57ba,x
105 txa
106 sec
107 sbc #10
108 tax
109 bpl draw_left_line_loop1
110 clc
111 rts
113 draw_bottom_line: ; $76=tile number for exit/wall
114 ldx #9
115 lda #2
116 draw_bottom_line_loop0:
117 sta $57f6,x
118 dex
119 bpl draw_bottom_line_loop0
121 ldx #3
122 lda $76
123 draw_bottom_line_loop1:
124 sta $57f9,x
125 dex
126 bpl draw_bottom_line_loop1
127 clc
128 rts
130 draw_right_line: ; $77=tile number for exit/wall
131 ldx #99
132 draw_right_line_loop0:
133 lda #2
134 sta $579c,x
135 txa
136 sec
137 sbc #10
138 tax
139 bpl draw_right_line_loop0
141 ldx #30
142 draw_right_line_loop1:
143 lda $77
144 sta $57c3,x
145 txa
146 sec
147 sbc #10
148 tax
149 bpl draw_right_line_loop1
150 clc
151 rts
153 make_empty_room:
155 ldx #99
156 make_empty_room_loop:
157 lda #0
158 sta $579c,x
159 dex
160 bpl make_empty_room_loop
162 rts
164 make_room: ; $78,$79=i,j
166 ; Fills the room array at 579c with values.
167 ; Tiles 0,1,2,3 are map tiles that will be shown by the plot_tile routine.
168 ; Other tiles are plotted separately:
169 ; 4 = exit
170 ; 5 = final exit
171 ; 6 = weapon (bits 3,4 are type)
172 ; 7 = treasure (bits 3,4 are type)
174 ; Fill the room with empty space.
176 jsr make_empty_room
178 ; Determine if there is a top exit.
180 lda #0
181 sta $76
183 lda $78 ; i == 0
184 cmp #0
185 bne not_top_screen
186 lda #2
187 sta $76
188 jmp do_top_exit
190 not_top_screen:
191 clc
193 lda $78
194 and #7 ; i & 7
195 sta $70 ; temporary result
196 lda $79
197 and #7 ; j & 7
198 cmp $70
199 beq do_top_exit
200 clc
202 lda $78
203 eor $79 ; i ^ j
204 adc $78 ; + i
205 clc
206 cmp $79 ; (i ^ j) + i == j
207 bne do_top_exit
208 lda #2
209 sta $76 ; top exit
211 do_top_exit:
212 jsr draw_top_line
214 ; Determine if there is a left exit.
215 lda #0
216 sta $77
218 lda $79
219 cmp #0
220 bne not_left_screen
221 lda #2
222 sta $77
223 jmp do_left_exit
225 not_left_screen:
226 clc
228 lda $78
229 and #3 ; i & 3
230 sta $70 ; temporary result
231 lda $79
232 and #3 ; j & 3
233 cmp $70
234 beq do_left_exit
235 clc
237 lda $78
238 ora $79 ; i | j
239 eor $79 ; ^ j
240 cmp $78 ; (i | j) ^ j == i
241 bne do_left_exit
242 lda #2
243 sta $77 ; left exit
245 do_left_exit:
246 jsr draw_left_line
248 ; Determine if there is a right exit.
249 lda #0
250 sta $77
252 lda $79
253 cmp #10
254 bne not_right_screen
255 lda #2
256 sta $77
257 jmp do_right_exit
259 not_right_screen:
260 clc
262 lda $78
263 and #3 ; i & 3
264 sta $70 ; temporary result
265 lda $79
266 adc #1
267 and #3 ; j & 3
268 cmp $70
269 beq do_right_exit
270 clc
272 lda $79
273 adc #1
274 sta $70
276 lda $78
277 ora $70 ; i | j
278 eor $70 ; ^ j
279 cmp $78 ; (i | j) ^ j == i
280 bne do_right_exit
281 lda #2
282 sta $77 ; right exit
284 do_right_exit:
285 jsr draw_right_line
287 ; Determine if there is a bottom exit.
288 lda #0
289 sta $76
291 lda $78
292 cmp #10
293 bne not_bottom_screen
294 lda #2
295 sta $76
296 jmp do_bottom_exit
298 not_bottom_screen:
299 clc
301 lda $78
302 adc #1
303 and #7 ; i & 7
304 sta $70 ; temporary result
305 lda $79
306 and #7 ; j & 7
307 cmp $70
308 beq do_bottom_exit
309 clc
311 lda $78
312 adc #1
313 sta $70
315 eor $79 ; i ^ j
316 adc $70 ; + i
317 cmp $79 ; (i ^ j) + i == j
318 bne do_bottom_exit
319 lda #2
320 sta $76 ; bottom exit
322 do_bottom_exit:
323 jsr draw_bottom_line
325 ; Add the final exit.
327 lda $578a
328 cmp #3
329 bmi make_room_no_final_exit
331 lda $78
332 cmp #0
333 bne make_room_no_final_exit
335 lda $79
336 cmp #2
337 bne make_room_no_final_exit
339 lda #6
340 sta $57a0
341 lda #7
342 sta $57a1
344 make_room_no_final_exit:
346 ; Make sure that the starting, exit, key rooms are empty.
348 ldx $578a ; level number
349 lda start_rooms_y,x
350 cmp $78
351 bne make_room_not_starting_room
352 lda start_rooms_x,x
353 cmp $79
354 bne make_room_not_starting_room
356 lda #3
357 sta $70
358 jmp add_room_decoration ; optimise away the rts
360 make_room_not_starting_room:
362 lda exit_rooms_y,x
363 cmp $78
364 bne make_room_not_exit_room
365 lda exit_rooms_x,x
366 cmp $79
367 bne make_room_not_exit_room
369 ; Add an exit to the room.
370 lda $78
371 eor $79
372 and #15
373 tax
374 lda exit_room_offsets,x
375 tax
376 lda $5780
377 and #1
378 beq exit_not_open
380 lda #5
381 sta $579c,x
382 jmp exit_decoration
384 exit_not_open:
385 clc
386 lda #4
387 sta $579c,x
389 exit_decoration:
390 lda #3
391 sta $70
392 jmp add_room_decoration ; optimise away the rts
394 make_room_not_exit_room:
396 lda key_rooms_y,x
397 cmp $78
398 bne make_room_not_key_room
399 lda key_rooms_x,x
400 cmp $79
401 bne make_room_not_key_room
403 lda #1
404 sta $70
405 jmp add_room_decoration ; optimise away the rts
407 make_room_not_key_room:
408 clc
410 ; Fill in the room details.
412 lda $79
413 sta $7c
414 sec
415 ldx $578a
416 lda seeds,x
417 sbc $78
418 sec
419 sta $7d
420 clc
422 ; Discard the first ten values.
424 ldy #10
425 make_room_loop0:
426 jsr unlimited_values
427 dey
428 bne make_room_loop0
430 ; Fill the room array with values.
432 lda #$a7
433 sta $70
434 lda #$57
435 sta $71
437 ldy #0
438 make_room_loop1:
440 jsr next_value
441 sta ($70),y
442 iny
443 cpy #8
444 bne make_room_loop1 ; continue the same row
446 lda $70
447 cmp #$ed
448 beq make_room_loop1_exit ; exit after the last row
450 adc #10
451 sta $70
452 ldy #0 ; reset the row counter
453 jmp make_room_loop1
455 make_room_loop1_exit:
456 rts
458 decoration_offsets: .byte 11,18,81,88
460 add_room_decoration:
462 lda #$9c
463 sta $8e
464 lda #$57
465 sta $8f
467 ldx #3
468 add_room_decoration_loop:
470 lda decoration_offsets,x
471 tay
472 lda $70
473 sta ($8e),y
474 dex
475 bpl add_room_decoration_loop
477 clc
478 rts
480 exit_room_offsets: .byte 35,66,63,56,34,44,64,33,36,55,65,53,45,46,54,43
481 treasure_x: .byte 3, 2, 4, 8, 2, 5, 4, 1, 3, 8, 6, 5, 7, 1, 7, 6
482 treasure_y: .byte 1, 3, 7, 7, 2, 3, 6, 1, 4, 6, 8, 5, 5, 4, 8, 2
484 eleven_times_table: .byte 0, 11, 22, 33, 44, 55, 66, 77, 88, 99, 110
486 add_treasure: ; $78,$79 = i,j
488 lda $78
489 tax
490 lda eleven_times_table,x
491 adc $79
492 tax
494 lda $5200,x
495 ora #$80
496 sta $5200,x ; set the top bit (room visited)
497 and #$7f ; mask off the top bit to obtain the item number + 1
498 cmp #0
499 beq add_treasure_exit
501 sec
502 sbc #1
503 sta $528d ; store weapon/treasure type
504 clc
506 lda $78
507 eor $79
508 adc $528d
509 and #15
510 sta $70
512 lda #15
513 sta $8c
514 ldy #0
515 add_treasure_loop:
517 clc
519 ldx $70
520 lda treasure_y,x ; y
521 sta $8d
522 tax
523 lda room_row_offsets_low,x
524 sta $80
526 ldx $70
527 lda treasure_x,x ; x
528 sta $8e
529 adc $80
530 sta $80
532 lda #$57
533 adc #0
534 sta $81
535 clc
537 lda ($80),y ; tile
538 cmp #0
539 bne add_treasure_loop_next
541 lda #4 ; type (weapon/treasure)
542 sta $528c
543 lda $8d ; y
544 sta $528e
545 lda #1 ; dy
546 sta $528f
547 lda $8e ; x
548 sta $5290
549 lda #0 ; dx
550 sta $5291
552 lda #$8c
553 sta $74
554 lda #$52
555 sta $75
556 jmp plot_character ; optimise away the rts
558 add_treasure_loop_next:
559 dec $8c
560 bmi add_treasure_exit
562 dec $70
563 bpl add_treasure_loop
565 lda #15
566 sta $70
567 jmp add_treasure_loop
569 add_treasure_exit:
570 clc
571 rts
573 create_enemy_positions:
575 lda #31 ; counter
576 sta $7e
578 lda #1 ; x
579 sta $70
581 lda #1 ; y
582 sta $71
584 lda #$a7
585 sta $72
586 lda #$57
587 sta $73
589 ldx #15 ; offset into position areas
590 ldy #0
592 create_enemy_positions_loop:
594 jsr unlimited_values
595 and #7
596 sta $80 ; store temporarily
598 lda $72
599 adc $80
600 sta $72 ; update the offset into the room data
601 clc
603 lda $70
604 adc $80 ; update x
605 cmp #10
606 bpl create_enemy_positions_next_row
608 sta $70 ; store x
609 jmp create_enemy_positions_check_tile
611 create_enemy_positions_next_row:
613 sec
614 sbc #10
615 sta $70 ; store the x position on the next row
616 clc
618 lda $71
619 adc #1 ; update the y position
620 cmp #10
621 bpl create_enemy_positions_to_top
623 sta $71 ; store the y position for the next row
624 jmp create_enemy_positions_check_tile
626 create_enemy_positions_to_top:
628 lda #1 ; reset the x, y and offset values
629 sta $70
630 sta $71
631 lda #$a7
632 sta $72
634 create_enemy_positions_check_tile:
636 lda ($72),y
637 cmp #0
638 bne create_enemy_positions_next
640 lda $70
641 sta $0ee0,x ; store the x value
643 lda $71
644 sta $0ef0,x ; store the y value
646 dex
647 bmi create_enemy_positions_exit
649 create_enemy_positions_next:
650 clc
651 dec $7e
652 bpl create_enemy_positions_loop
654 ; The position areas were not filled. Write invalid values into the
655 ; first area for the emerge routine to find.
657 lda #0
658 create_enemy_positions_fill_loop:
660 sta $0ee0,x
661 dex
662 bpl create_enemy_positions_fill_loop
664 create_enemy_positions_exit:
665 clc
666 rts
668 plot: ; $70,$71=source address
669 ; $72,$73=destination address
670 ldy #$1f
671 plotloop0:
672 lda ($70),y
673 sta ($72),y
674 dey
675 bpl plotloop0
677 lda $72
678 adc #$20
679 sta $72
680 lda $73
681 adc #$01
682 sta $73 ; next line minus 0x20
683 clc
685 ldy #$3f
686 plotloop1:
687 lda ($70),y
688 sta ($72),y
689 dey
690 cpy #$20
691 bpl plotloop1
693 lda $72
694 adc #$20
695 sta $72
696 lda $73
697 adc #$01
698 sta $73 ; next line minus 0x20
699 clc
701 ldy #$5f
702 plotloop2:
703 lda ($70),y
704 sta ($72),y
705 dey
706 cpy #$40
707 bpl plotloop2
709 sec
710 lda $72
711 sbc #$20
712 sta $72
713 lda $73
714 sbc #$02
715 sta $73 ; back two lines minus 0x20
716 clc
718 rts
722 plot_blank_xy: ; X=y, Y=x
724 lda screen_rows_low,x
725 sta $72
726 lda screen_rows_high,x
727 sta $73
729 tya
730 tax
731 lda screen_columns_low,x
732 adc $72
733 sta $72
734 lda screen_columns_high,x
735 adc $73
736 sta $73
737 clc
738 ; run on into plot_blank
740 plot_blank: ; $72,$73=destination address
742 ldy #$1f
743 lda #0
744 plot_blank_loop0:
745 sta ($72),y
746 dey
747 bpl plot_blank_loop0
749 lda $72
750 adc #$20
751 sta $72
752 lda $73
753 adc #$01
754 sta $73 ; next line minus 0x20
755 clc
757 ldy #$3f
758 lda #0
759 plot_blank_loop1:
760 sta ($72),y
761 dey
762 cpy #$20
763 bpl plot_blank_loop1
765 lda $72
766 adc #$20
767 sta $72
768 lda $73
769 adc #$01
770 sta $73 ; next line minus 0x20
771 clc
773 ldy #$5f
774 lda #0
775 plot_blank_loop2:
776 sta ($72),y
777 dey
778 cpy #$40
779 bpl plot_blank_loop2
781 sec
782 lda $72
783 sbc #$20
784 sta $72
785 lda $73
786 sbc #$02
787 sta $73 ; back two lines minus 0x20
788 clc
790 rts
792 tile_addresses_low: .byte $00, $60, $c0, $00, $60, $c0, $20
793 tile_addresses_high: .byte $54, $54, $54, $50, $50, $50, $51
795 plot_tile: ; $7b=tile number
796 ; 1 = flowers/decoration
797 ; 2 = trees/wall
798 ; 3 = trees
799 ; 4 = exit
800 ; 5 = open exit
801 ; 6 = final exit (left)
802 ; 7 = final exit (right)
803 ; $72,$73=screen position
805 lda $7b
806 cmp #0
807 bne plot_tile_sprite
808 clc
809 jmp plot_blank ; optimise away the rts
811 plot_tile_sprite:
812 clc
813 tax
814 dex
815 lda tile_addresses_low,x
816 sta $70
817 lda tile_addresses_high,x
818 sta $71
820 lda $7b
821 cmp #4
822 bpl plot_not_blank_after_add_loop ; don't adjust the tile for later levels
824 clc
825 lda $578a
826 and #3 ; change the tile set for later levels
827 tax
829 plot_not_blank_add_loop:
831 cpx #2
832 bne plot_not_blank_not_2
833 dex
834 jmp plot_not_blank_not_0
836 plot_not_blank_not_2:
837 beq plot_not_blank_add_loop
838 cpx #0
840 plot_not_blank_not_0:
841 beq plot_not_blank_after_add_loop
842 clc
843 lda $70
844 adc #$20
845 sta $70
846 lda $71
847 adc #$01
848 sta $71
849 dex
850 jmp plot_not_blank_add_loop
852 plot_not_blank_after_add_loop:
853 clc
854 jsr plot
855 rts
857 plot_room: ; $78,$79 = i,j (from $5782,$5783)
858 jsr blank_screen
860 lda $5782
861 sta $78
862 lda $5783
863 sta $79
865 jsr make_room
866 ; Run on into the next piece of code.
868 plot_room_tiles:
870 lda #$80
871 sta $72
872 lda #$5a
873 sta $73 ; $72,$73 = screen position
875 lda #0
876 sta $7a
877 row_loop:
879 lda #9
880 sta $76
882 column_loop:
883 lda $7a
884 tax
885 lda $579c,x
886 sta $7b
887 jsr plot_tile
889 inc $7a
890 lda $76
891 sec
892 sbc #1
893 sta $76
894 clc
895 cmp #0
896 bpl column_loop
898 clc
900 lda $72
901 adc #$80
902 sta $72
903 lda $73
904 adc #$02
905 sta $73
906 clc
907 cmp #$80
908 beq end_rows
910 jmp row_loop
912 end_rows:
913 rts
915 set_room_palette: ; $78=i; $79=j
917 lda #1
918 sta $70
919 lda $78
920 eor $79
921 and #3
922 tax
923 lda room_palettes,x
924 sta $71
925 jsr set_palette
927 jsr set_core_palette
928 rts
930 room_palettes: .byte 1, 6, 5, 7
932 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c
934 plot8x24_y0: ; $70,$71=source address
935 ; $72,$73=destination address
937 ldx #2
939 plot8x24_y0_loop:
941 ldy #15
943 plotloop8x24_y0_0:
944 lda ($70),y
945 eor ($72),y
946 sta ($72),y
947 dey
948 bpl plotloop8x24_y0_0
950 dex
951 bmi plot8x24_y0_exit
953 lda $72
954 adc #$40
955 sta $72
956 lda $73
957 adc #$01
958 sta $73
959 clc
961 lda $70
962 adc #16
963 sta $70
964 lda $71
965 adc #0
966 sta $71
967 clc
969 jmp plot8x24_y0_loop
971 plot8x24_y0_exit:
972 clc
973 jmp plot_buffer_loop_next
976 plot8x8_y1: ; $70,$71=source address
977 ; $72,$73=destination address
978 lda #2
979 sta $7e
980 lda #10
981 sta $7f
983 lda #0 ; plotting 1 8x8 piece
984 sta $8a
986 jmp plot8x24_y123 ; optimise away the rts
988 plot8x24_y1: ; $70,$71=source address
989 ; $72,$73=destination address
990 lda #2
991 sta $7e
992 lda #10
993 sta $7f
995 lda #2 ; plotting 3 8x8 pieces
996 sta $8a
998 jmp plot8x24_y123 ; optimise away the rts
1000 plot8x8_y2: ; $70,$71=source address
1001 ; $72,$73=destination address
1002 lda #4
1003 sta $7e
1004 lda #12
1005 sta $7f
1007 lda #0 ; plotting 1 8x8 piece
1008 sta $8a
1010 jmp plot8x24_y123 ; optimise away the rts
1012 plot8x24_y2: ; $70,$71=source address
1013 ; $72,$73=destination address
1014 lda #4
1015 sta $7e
1016 lda #12
1017 sta $7f
1019 lda #2 ; plotting 3 8x8 pieces
1020 sta $8a
1022 jmp plot8x24_y123 ; optimise away the rts
1024 plot8x8_y3: ; $70,$71=source address
1025 ; $72,$73=destination address
1026 lda #6
1027 sta $7e
1028 lda #14
1029 sta $7f
1031 lda #0 ; plotting 1 8x8 piece
1032 sta $8a
1034 jmp plot8x24_y123 ; optimise away the rts
1036 plot8x24_y3: ; $70,$71=source address
1037 ; $72,$73=destination address
1038 lda #6
1039 sta $7e
1040 lda #14
1041 sta $7f
1043 lda #2 ; plotting 3 8x8 pieces
1044 sta $8a
1046 ; Run on into the next routine.
1048 plot8x24_y123: ; $70,$71=source address
1049 ; $72,$73=destination address
1050 ; $7e=offset into source data for first column
1051 ; $7f=offset into source data for second column
1053 plot8x24_y123_loop:
1055 ldx #0
1056 plot8x24_y123_upper_loop_outer:
1058 ldy $7e,x
1059 lda plot_upper_offsets,x
1060 sta $89
1062 plot8x24_y123_upper_loop_inner: ; plot the first column until
1063 dey ; we reach the start
1064 cpy $89
1065 bmi plot8x24_y123_upper_loop_inner_endloop
1066 lda ($70),y
1067 eor ($72),y
1068 sta ($72),y
1069 jmp plot8x24_y123_upper_loop_inner
1071 plot8x24_y123_upper_loop_inner_endloop:
1072 clc
1074 inx
1075 cpx #2
1076 bne plot8x24_y123_upper_loop_outer
1078 clc
1079 lda $72 ; move the destination pointer to refer to the next line
1080 adc #$38
1081 sta $72
1082 lda $73
1083 adc #$01
1084 sta $73
1085 clc
1087 ldx #0
1088 plot8x24_y123_lower_loop_outer:
1090 lda plot_lower_offsets,x
1091 tay
1092 lda $7e,x
1093 sta $89
1095 plot8x24_y123_lower_loop_inner: ; plot until we reach the initial
1096 lda ($70),y ; offset for the column
1097 eor ($72),y
1098 sta ($72),y
1099 dey
1100 cpy $89
1101 bpl plot8x24_y123_lower_loop_inner
1103 inx
1104 cpx #2
1105 bne plot8x24_y123_lower_loop_outer
1107 dec $8a
1108 bmi plot8x24_y123_exit
1110 clc
1111 lda $70 ; update the source pointer to refer to the next piece
1112 adc #16 ; of sprite data
1113 sta $70
1114 lda $71
1115 adc #0
1116 sta $71
1117 clc
1119 lda $72 ; update the destination pointer to point to the next
1120 adc #8 ; space
1121 sta $72
1122 lda $73
1123 adc #0
1124 sta $73
1125 clc
1127 jmp plot8x24_y123_loop
1129 plot8x24_y123_exit:
1130 clc
1131 jmp plot_buffer_loop_next
1133 plot16x16_y0: ; $70,$71=source address
1134 ; $72,$73=destination address
1135 ldy #31
1137 plotloop16x16_y0_0:
1138 lda ($70),y
1139 eor ($72),y
1140 sta ($72),y
1141 dey
1142 bpl plotloop16x16_y0_0
1143 clc
1145 lda $72
1146 adc #$20
1147 sta $72
1148 lda $73
1149 adc #$01
1150 sta $73 ; 0x140 - 32
1151 clc
1153 ldy #63
1155 plotloop16x16_y0_1:
1156 lda ($70),y
1157 eor ($72),y
1158 sta ($72),y
1159 dey
1160 cpy #32
1161 bpl plotloop16x16_y0_1
1162 clc
1164 jmp plot_buffer_loop_next
1166 ; Sprite data stored in memory: 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
1168 plot16x16_y1: ; $70,$71=source address
1169 ; $72,$73=destination address
1171 lda #2
1172 sta $7e
1173 lda #10
1174 sta $7f
1175 lda #18
1176 sta $80
1177 lda #26
1178 sta $81
1179 jmp plot16x16_y123 ; optimise away the rts
1181 plot16x16_y2: ; $70,$71=source address
1182 ; $72,$73=destination address
1184 lda #4
1185 sta $7e
1186 lda #12
1187 sta $7f
1188 lda #20
1189 sta $80
1190 lda #28
1191 sta $81
1192 jmp plot16x16_y123 ; optimise away the rts
1194 plot16x16_y3: ; $70,$71=source address
1195 ; $72,$73=destination address
1197 lda #6
1198 sta $7e
1199 lda #14
1200 sta $7f
1201 lda #22
1202 sta $80
1203 lda #30
1204 sta $81
1205 ; Run on into the next routine.
1207 plot16x16_y123: ; $70,$71=source address
1208 ; $72,$73=destination address
1209 ; $7e=offset into source data for first column
1210 ; $7f=offset into source data for second column
1211 ; $80=offset into source data for third column
1212 ; $81=offset into source data for fourth column
1214 lda #1
1215 sta $8a
1217 plot16x16_y123_loop:
1219 ldx #0
1220 plot16x16_y123_upper_loop_outer:
1222 ldy $7e,x
1223 lda plot_upper_offsets,x
1224 sta $89
1226 plot16x16_y123_upper_loop_inner:
1228 dey
1229 cpy $89
1230 bmi plot16x16_y123_upper_loop_inner_endloop
1231 lda ($70),y
1232 eor ($72),y
1233 sta ($72),y
1234 jmp plot16x16_y123_upper_loop_inner
1236 plot16x16_y123_upper_loop_inner_endloop:
1237 clc
1239 inx
1240 cpx #4
1241 bne plot16x16_y123_upper_loop_outer
1243 clc
1244 lda $72 ; move the destination pointer to refer to the next line
1245 adc #$38
1246 sta $72
1247 lda $73
1248 adc #$01
1249 sta $73
1250 clc
1252 ldx #0
1253 plot16x16_y123_lower_loop_outer:
1255 lda plot_lower_offsets,x
1256 tay
1257 lda $7e,x
1258 sta $89
1260 plot16x16_y123_lower_loop_inner: ; plot until we reach the initial offset
1261 lda ($70),y ; for the column
1262 eor ($72),y
1263 sta ($72),y
1264 dey
1265 cpy $89
1266 bpl plot16x16_y123_lower_loop_inner
1268 inx
1269 cpx #4
1270 bne plot16x16_y123_lower_loop_outer
1272 dec $8a
1273 bmi plot16x16_y123_exit
1275 clc
1276 lda $70 ; update the source pointer to refer to the next piece
1277 adc #32 ; of sprite data
1278 sta $70
1279 lda $71
1280 adc #0
1281 sta $71
1282 clc
1284 lda $72 ; update the destination pointer to point to the next
1285 adc #8 ; space
1286 sta $72
1287 lda $73
1288 adc #0
1289 sta $73
1290 clc
1292 jmp plot16x16_y123_loop
1294 plot16x16_y123_exit:
1295 clc
1296 jmp plot_buffer_loop_next
1298 plot_upper_offsets: .byte 0, 8, 16, 24
1299 plot_lower_offsets: .byte 7, 15, 23, 31
1301 plot8x8_y0: ; $70,$71=source address
1302 ; $72,$73=destination address
1303 ldy #15
1305 plotloop8x8_y0_0:
1306 lda ($70),y
1307 eor ($72),y
1308 sta ($72),y
1309 dey
1310 bpl plotloop8x8_y0_0
1311 clc
1313 jmp plot_buffer_loop_next
1316 check_key: ; x=key code
1317 lda #129 ; returns y=255 or 0
1318 ldy #255
1319 jsr $fff4
1320 rts
1322 player_direction_chars_low: .byte $00,$30,$60,$90,$c0,$f0,$20,$50, $80,$b0,$e0,$10
1323 player_direction_chars_high: .byte $3f,$3f,$3f,$3f,$3f,$3f,$40,$40, $40,$40,$40,$41
1325 screen_rows_low: .byte $80,$40,$00,$c0,$80,$40,$00,$c0,$80,$40
1326 screen_rows_high: .byte $5a,$5e,$62,$65,$69,$6d,$71,$74,$78,$7c
1327 screen_subrows_low: .byte $00,$06,$44,$82
1328 screen_subrows_high: .byte $00,$00,$01,$02
1330 screen_columns_low: .byte $00,$20,$40,$60,$80,$a0,$c0,$e0,$00,$20
1331 screen_columns_high: .byte $00,$00,$00,$00,$00,$00,$00,$00,$01,$01
1332 screen_subcolumns_low: .byte $00,$08,$10,$18
1334 enemy_direction_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1335 enemy_direction_chars_high: .byte $41,$42,$42,$42,$42,$43,$43,$43
1337 emerge_explode_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80
1338 emerge_explode_chars_high: .byte $4b,$4c,$4c,$4c,$4c,$4d,$4d,$4d
1340 item_chars_low: .byte $c0,$00,$40,$80,$c0,$00,$40,$80,$c0
1341 item_chars_high: .byte $4d,$4e,$4e,$4e,$4e,$4f,$4f,$4f,$4f
1343 projectile_chars_low: .byte $40,$50,$60,$70,$80,$90,$a0,$b0
1345 unplot_character: ; $74,$75=character address
1347 lda $82 ; store the unplot buffer address in $78,$79
1348 sta $78
1349 lda $83
1350 sta $79
1351 jsr plot_character_sprite
1352 lda $78
1353 sta $82 ; update the latest space in the unplot buffer
1354 rts
1356 plot_character: ; $74,$75=character address
1358 lda $84 ; store the plot buffer address in $78,$79
1359 sta $78
1360 lda $85
1361 sta $79
1362 jsr plot_character_sprite
1363 lda $78
1364 sta $84 ; update the latest space in the plot buffer
1365 rts
1367 plot_character_sprite: ; $74,$75=character address
1368 ; $78,$79=unplot/plot buffer address
1370 ldy #0
1371 lda ($74),y
1372 cmp #0
1373 bne plot_characters_read_character
1374 jmp plot_characters_next
1376 plot_characters_read_character:
1377 clc
1379 sta $77 ; temporarily store the object type
1381 ; Use lookup tables to load the offsets into the sprite.
1383 ; Direction
1384 iny
1385 lda ($74),y
1386 sta $80 ; temporarily store the direction
1388 ; y
1389 iny
1390 lda ($74),y
1391 tax
1392 lda screen_rows_low,x
1393 sta $72
1394 lda screen_rows_high,x
1395 sta $73
1396 clc
1398 ; dy
1399 iny
1400 lda ($74),y
1401 sta $76
1402 tax
1403 lda screen_subrows_low,x
1404 adc $72
1405 sta $72
1406 lda screen_subrows_high,x
1407 adc $73
1408 sta $73
1409 clc
1411 ; x
1412 iny
1413 lda ($74),y
1414 tax
1415 lda screen_columns_low,x
1416 adc $72
1417 sta $72
1418 lda screen_columns_high,x
1419 adc $73
1420 sta $73
1421 clc
1423 ; dx
1424 iny
1425 lda ($74),y
1426 tax
1427 lda screen_subcolumns_low,x
1428 adc $72
1429 sta $72
1430 clc
1432 lda $77
1433 cmp #1
1434 bne plot_characters_loop_not_player
1436 ; Plot 8x24 sprites (player)
1438 ldx $80
1439 lda player_direction_chars_low,x
1440 sta $70
1441 lda player_direction_chars_high,x
1442 sta $71
1444 ; Use the dy value to determine which plotting routine to use.
1446 ldy #0
1447 ldx $76
1448 lda plot_routine_indices_8x24,x
1450 sta ($78),y
1451 jmp plot_characters_stored
1454 plot_characters_loop_not_player:
1455 cmp #2
1456 bne plot_characters_loop_not_projectile
1458 ; Plot 8x8 sprites (projectiles)
1460 lda $80
1461 and #7
1462 tax
1463 lda projectile_chars_low,x
1464 sta $70
1465 lda #$41
1466 sta $71
1468 ; Use the dy value to determine which plotting routine to use.
1470 ldy #0
1471 ldx $76
1472 lda plot_routine_indices_8x8,x
1474 sta ($78),y
1475 jmp plot_characters_stored
1478 plot_characters_loop_not_projectile:
1479 cmp #3
1480 bne plot_characters_loop_not_explosion
1482 ; Plot 16x16 sprites (emerging, explosions)
1484 ; Select the sprites to use.
1486 lda $80
1487 and #7 ; only keep the bits required to find the correct sprite
1488 clc
1489 tax
1490 lda emerge_explode_chars_low,x
1491 sta $70
1492 lda emerge_explode_chars_high,x
1493 sta $71
1495 jmp plot_characters_16x16
1497 plot_characters_loop_not_explosion:
1498 cmp #4
1499 bne plot_characters_loop_not_item
1501 ; Plot 16x16 sprites (items)
1503 ; Select the sprites to use.
1505 lda $80
1506 and #$0f ; only keep the bits required to find the correct sprite
1507 clc
1508 tax
1509 lda item_chars_low,x
1510 sta $70
1511 lda item_chars_high,x
1512 sta $71
1514 jmp plot_characters_16x16
1516 plot_characters_loop_not_item:
1517 cmp #8
1518 bmi plot_characters_loop_not_enemy
1520 ; Plot 16x16 sprites (enemies)
1522 ; Select the set of sprites to use.
1524 and #$70
1525 lsr
1526 lsr
1527 lsr ; bits 4,5,6 >> 3 -> bits 1,2,3
1528 clc
1529 sta $71 ; 0x00, 0x02, 0x04, 0x06, 0x08
1531 lda $80
1532 and #7 ; keep the animation bits
1533 tax
1534 lda enemy_direction_chars_low,x
1535 sta $70
1536 lda enemy_direction_chars_high,x
1537 adc $71
1538 sta $71
1540 plot_characters_16x16:
1542 ; Use the dy value to determine which plotting routine to use.
1544 ldy #0
1545 ldx $76
1546 lda plot_routine_indices_16x16,x
1548 sta ($78),y
1550 plot_characters_stored:
1552 iny
1553 lda $70
1554 sta ($78),y
1555 iny
1556 lda $71
1557 sta ($78),y
1558 iny
1559 lda $72
1560 sta ($78),y
1561 iny
1562 lda $73
1563 sta ($78),y
1565 clc
1566 lda $78
1567 adc #12
1568 sta $78
1570 plot_characters_loop_not_enemy:
1572 plot_characters_next:
1574 lda #255 ; terminate this stream of entries in the plot buffer
1575 ldy #0
1576 sta ($78),y
1577 clc
1578 rts
1580 plot_routine_indices_8x24: .byte 1, 2, 3, 4
1581 plot_routine_indices_8x8: .byte 5, 6, 7, 8
1582 plot_routine_indices_16x16: .byte 9, 10, 11, 12
1584 reset_plot_buffer:
1585 lda #$06 ; reset the index into the plot buffer
1586 sta $84
1587 lda #$53
1588 sta $85
1590 lda #255 ; terminate the plot list
1591 ldy #0
1592 sta ($84),y
1593 rts
1595 reset_unplot_buffer:
1596 lda #$00 ; reset the index into the plot buffer
1597 sta $82
1598 lda #$53
1599 sta $83
1601 lda #255 ; terminate the unplot list
1602 ldy #0
1603 sta ($82),y
1604 rts
1606 plot_buffer_types_low: .byte <plot_buffer_loop_next
1607 plot_buffer_types_low1: .byte <plot8x24_y0, <plot8x24_y1, <plot8x24_y2, <plot8x24_y3
1608 plot_buffer_types_low2: .byte <plot8x8_y0, <plot8x8_y1, <plot8x8_y2, <plot8x8_y3
1609 plot_buffer_types_low3: .byte <plot16x16_y0, <plot16x16_y1, <plot16x16_y2, <plot16x16_y3
1611 plot_buffer_types_high: .byte >plot_buffer_loop_next
1612 plot_buffer_types_high1: .byte >plot8x24_y0, >plot8x24_y1, >plot8x24_y2, >plot8x24_y3
1613 plot_buffer_types_high2: .byte >plot8x8_y0, >plot8x8_y1, >plot8x8_y2, >plot8x8_y3
1614 plot_buffer_types_high3: .byte >plot16x16_y0, >plot16x16_y1, >plot16x16_y2, >plot16x16_y3
1616 plot_buffer:
1618 lda #$00
1619 sta $84
1620 lda #$53
1621 sta $85
1623 lda #6
1624 sta $88
1626 plot_buffer_loop:
1628 ldy #0
1629 lda ($84),y
1630 cmp #255
1631 beq plot_buffer_loop_skip
1633 clc
1634 tax
1635 lda plot_buffer_types_low,x
1636 sta $86
1637 lda plot_buffer_types_high,x
1638 sta $87
1640 iny
1641 lda ($84),y
1642 sta $70
1644 iny
1645 lda ($84),y
1646 sta $71
1648 iny
1649 lda ($84),y
1650 sta $72
1652 iny
1653 lda ($84),y
1654 sta $73
1656 jmp ($86) ; returns to plot_buffer_loop_next
1658 plot_buffer_loop_skip:
1660 lda $88
1661 cmp #12
1662 beq plot_buffer_exit ; both unplot and plot lists have terminated
1664 lda #12
1665 sta $88
1666 lda $84
1667 adc #6
1668 sta $84
1669 jmp plot_buffer_loop
1671 plot_buffer_loop_next:
1672 clc
1674 lda $84
1675 adc $88
1676 sta $84
1677 jmp plot_buffer_loop
1679 plot_buffer_exit:
1680 clc
1681 rts
1683 room_row_offsets_low: .byte $9c,$a6,$b0,$ba,$c4,$ce,$d8,$e2,$ec,$f6
1685 animate_player_left:
1687 ; Set the direction and toggle the animation bit.
1689 lda $5281
1690 and #1
1691 eor #1 ; toggle animation flag
1692 sta $5281 ; left (directional bits are 0)
1694 jsr plot_character
1695 rts
1697 animate_player_right:
1699 ; Set the direction and toggle the animation bit.
1701 lda $5281
1702 and #1 ; remove direction information (result is 0)
1703 eor #1 ; toggle animation flag
1704 ora #2 ; right
1705 sta $5281
1707 jsr plot_character
1708 rts
1710 animate_player_up:
1712 ; Set the direction and toggle the animation bit.
1714 lda $5281
1715 and #1 ; remove direction information (result is 0)
1716 eor #1 ; toggle animation flag
1717 ora #4 ; up
1718 sta $5281
1720 jsr plot_character
1721 rts
1723 animate_player_down:
1725 ; Set the direction and toggle the animation bit.
1727 lda $5281
1728 and #1 ; remove direction information (result is 0)
1729 eor #1 ; toggle animation flag
1730 ora #6 ; down
1731 sta $5281
1733 jsr plot_character
1734 rts
1736 move_player:
1738 lda $578e
1739 and #1
1740 beq move_player_allowed
1742 clc
1743 rts
1745 move_player_allowed:
1747 lda #$80 ; set up the address of the player character
1748 sta $74
1749 lda #$52
1750 sta $75
1752 ; Handle joystick
1754 lda $577e
1755 cmp #0
1756 beq move_player_handle_left_key
1758 lda #128
1759 ldx #1
1760 jsr $fff4
1761 cpy #112 ; <= -16
1762 bcs move_player_check_joystick_left
1763 jmp move_player_right
1765 move_player_check_joystick_left:
1766 cpy #144 ; >= 16
1767 bcc move_player_handle_joystick_up_down
1768 jmp move_player_left
1770 move_player_handle_joystick_up_down:
1772 lda #128
1773 ldx #2
1774 jsr $fff4
1775 cpy #112 ; <= -16
1776 bcs move_player_check_joystick_up
1777 jmp move_player_down
1779 move_player_check_joystick_up:
1780 cpy #144
1781 bcc move_player_no_joystick_input
1782 jmp move_player_up ; >= 16
1784 move_player_no_joystick_input:
1785 clc
1786 rts
1788 move_player_handle_left_key:
1790 ; Handle the left key.
1792 ldx #158 ; (Z)
1793 jsr check_key
1794 cpy #255
1795 bne move_player_not_left_key
1797 move_player_left:
1799 lda $5285 ; read dx
1800 cmp #0
1801 beq move_player_left_check_x
1803 jsr unplot_character ; unplot the player character
1804 dec $5285
1805 clc
1806 jmp animate_player_left ; optimise away the rts
1808 move_player_left_check_x: ; Check the x offset.
1810 lda $5284
1811 cmp #0
1812 beq move_player_leave_room_left
1814 clc
1815 tay
1816 dey ; x - 1
1817 lda $5282 ; load the y offset
1818 tax ; as an index
1819 lda room_row_offsets_low,x ; read the address of the row
1820 sta $70
1821 lda #$57
1822 sta $71
1823 lda ($70),y ; load the tile to the left
1825 cmp #5 ; check for the open exit or final exit
1826 bmi move_player_not_left_exit1
1827 jmp try_to_exit_level ; optimise away the rts
1829 move_player_not_left_exit1:
1830 cmp #0
1831 bne move_player_not_left_key
1833 lda $5283 ; dy
1834 cmp #0
1835 beq move_player_allow_left
1837 clc
1838 lda $70 ; dy > 0 so we need to check another tile
1839 adc #10
1840 sta $70
1841 lda ($70),y ; load the tile below and to the left
1843 cmp #5 ; check for the open exit or final exit
1844 bmi move_player_not_left_exit2
1845 jmp try_to_exit_level ; optimise away the rts
1847 move_player_not_left_exit2:
1848 cmp #0
1849 bne move_player_not_left_key
1851 move_player_allow_left:
1852 tya
1853 sta $81 ; temporary
1854 jsr unplot_character ; unplot the player character
1855 lda $81
1856 sta $5284 ; store the new room x offset
1857 lda #3
1858 sta $5285 ; dx = 3
1859 clc
1860 jmp animate_player_left ; optimise away the rts
1862 move_player_leave_room_left:
1863 sec
1864 lda $5783
1865 sbc #1
1866 sta $5783
1867 clc
1869 ; Set the player's position on the right of the screen.
1871 ; No need to unplot.
1873 lda #9 ; x = 9
1874 sta $5284
1875 lda #2 ; dx = 2
1876 sta $5285
1878 jsr animate_player_left
1879 sec ; indicate to the calling routine that the player
1880 rts ; has left the room
1882 move_player_not_left_key:
1884 ; Handle the right key.
1886 ldx #189 ; (X)
1887 jsr check_key
1888 cpy #255
1889 beq move_player_right
1890 jmp move_player_not_right_key
1892 move_player_right:
1894 lda $5285 ; read dx
1895 cmp #2
1896 beq move_player_right_check_x
1897 cmp #3
1898 beq move_player_right_tile
1900 jsr unplot_character ; unplot the player character
1901 inc $5285
1902 clc
1903 jmp animate_player_right ; optimise away the rts
1905 move_player_right_check_x: ; Check the x offset.
1907 lda $5284
1908 cmp #9
1909 beq move_player_leave_room_right
1911 clc
1912 tay
1913 iny ; x + 1
1914 lda $5282 ; load the y offset
1915 tax ; as an index
1916 lda room_row_offsets_low,x ; read the address of the row
1917 sta $70
1918 lda #$57
1919 sta $71
1920 lda ($70),y ; load the tile to the right
1922 cmp #5 ; check for the open exit or final exit
1923 bmi move_player_not_right_exit1
1924 jmp try_to_exit_level ; optimise away the rts
1926 move_player_not_right_exit1:
1927 cmp #0
1928 bne move_player_not_right_key
1930 lda $5283 ; dy
1931 cmp #0
1932 beq move_player_allow_right
1934 clc ; dy > 0 so we need to check another tile
1935 lda $70
1936 adc #10
1937 sta $70
1938 lda ($70),y ; load the tile below and to the right
1940 cmp #5 ; check for the open exit or final exit
1941 bmi move_player_not_right_exit2
1942 jmp try_to_exit_level ; optimise away the rts
1944 move_player_not_right_exit2:
1945 cmp #0
1946 bne move_player_not_right_key
1948 move_player_allow_right:
1950 jsr unplot_character ; unplot the player character
1951 inc $5285 ; update dx
1952 clc
1953 jmp animate_player_right ; optimise away the rts
1955 move_player_right_tile:
1957 jsr unplot_character ; unplot the player character
1958 inc $5284 ; store the new room x offset
1959 lda #0
1960 sta $5285 ; dx = 0
1961 clc
1962 jmp animate_player_right ; optimise away the rts
1964 move_player_leave_room_right:
1965 clc
1966 inc $5783
1967 clc
1969 ; Set the player's position on the left of the screen.
1971 ; No need to unplot.
1973 lda #0 ; x = 0
1974 sta $5284
1975 lda #0 ; dx = 0
1976 sta $5285
1978 jsr animate_player_right
1979 sec ; indicate to the calling routine that the
1980 rts ; player has left the room
1982 move_player_not_right_key:
1984 ; Handle the up key.
1986 ldx #183 ; (:)
1987 jsr check_key
1988 cpy #255
1989 bne move_player_not_up_key
1991 move_player_up:
1993 lda $5283 ; read dy
1994 cmp #0
1995 beq move_player_up_check_y
1997 jsr unplot_character ; unplot the player character
1998 dec $5283
1999 clc
2000 jmp animate_player_up ; optimise away the rts
2002 move_player_up_check_y: ; Check the y offset.
2004 lda $5282
2005 cmp #0
2006 beq move_player_leave_room_up
2008 tax ; use the y offset as an index
2009 dex ; y - 1
2010 ldy $5284 ; load the x offset
2011 lda room_row_offsets_low,x ; read the address of the row
2012 sta $70
2013 lda #$57
2014 sta $71
2015 lda ($70),y ; load the tile above
2017 cmp #5 ; check for the open exit or final exit
2018 bmi move_player_not_up_exit1
2019 jmp try_to_exit_level ; optimise away the rts
2021 move_player_not_up_exit1:
2022 cmp #0
2023 bne move_player_not_up_key
2025 lda $5285 ; dx
2026 cmp #3
2027 bmi move_player_allow_up
2029 clc ; dx > 2 so we need to check another tile
2030 iny
2031 lda ($70),y ; load the tile above and to the right
2033 cmp #5 ; check for the open exit or final exit
2034 bmi move_player_not_up_exit2
2035 jmp try_to_exit_level ; optimise away the rts
2037 move_player_not_up_exit2:
2038 cmp #0
2039 bne move_player_not_up_key
2041 move_player_allow_up:
2042 txa
2043 sta $81 ; temporary
2044 jsr unplot_character ; unplot the player character
2045 lda $81
2046 sta $5282 ; store the new room y offset
2047 lda #3
2048 sta $5283 ; dy = 3
2049 clc
2050 jmp animate_player_up ; optimise away the rts
2052 move_player_leave_room_up:
2053 sec
2054 lda $5782
2055 sbc #1
2056 sta $5782
2057 clc
2059 ; Set the player's position on the bottom of the screen.
2061 ; No need to unplot.
2063 lda #9 ; y = 9
2064 sta $5282
2065 lda #0 ; dy = 0
2066 sta $5283
2068 jsr animate_player_up
2069 sec ; indicate to the calling routine that the player
2070 rts ; has left the room
2072 move_player_not_up_key:
2074 ; Handle the down key.
2076 ldx #151 ; (/)
2077 jsr check_key
2078 cpy #255
2079 beq move_player_down
2080 jmp move_player_not_down_key
2082 move_player_down:
2084 lda $5283 ; read dy
2085 cmp #0
2086 beq move_player_down_check_y
2087 cmp #3
2088 beq move_player_down_tile
2090 jsr unplot_character ; unplot the player character
2091 inc $5283 ; 0 <= dy < 3
2092 clc
2093 jmp animate_player_down ; optimise away the rts
2095 move_player_down_check_y: ; Check the y offset.
2097 lda $5282
2098 cmp #9
2099 beq move_player_leave_room_down
2101 clc
2102 tax
2103 inx ; y + 1
2104 ldy $5284 ; load the x offset
2105 lda room_row_offsets_low,x ; read the address of the row
2106 sta $70
2107 lda #$57
2108 sta $71
2109 lda ($70),y ; load the tile below
2111 cmp #5 ; check for the open exit or final exit
2112 bmi move_player_not_down_exit1
2113 jmp try_to_exit_level ; optimise away the rts
2115 move_player_not_down_exit1:
2116 cmp #0
2117 bne move_player_not_down_key
2119 lda $5285 ; dx
2120 cmp #3
2121 bmi move_player_allow_down
2123 clc ; dx > 2 so we need to check another tile
2124 iny
2125 lda ($70),y ; load the tile below and to the right
2127 cmp #5 ; check for the open exit or final exit
2128 bmi move_player_not_down_exit2
2129 jmp try_to_exit_level ; optimise away the rts
2131 move_player_not_down_exit2:
2132 cmp #0
2133 bne move_player_not_down_key
2135 move_player_allow_down:
2137 jsr unplot_character ; unplot the player character
2138 inc $5283 ; update dy
2139 clc
2140 jmp animate_player_down ; optimise away the rts
2142 move_player_down_tile:
2144 jsr unplot_character ; unplot the player character
2145 inc $5282 ; store the new room y offset
2146 lda #0
2147 sta $5283 ; dy = 0
2148 clc
2149 jmp animate_player_down ; optimise away the rts
2151 move_player_leave_room_down:
2152 inc $5782
2153 clc
2155 ; Set the player's position on the top of the screen.
2157 ; No need to unplot.
2159 lda #0 ; y = 0
2160 sta $5282
2161 lda #0 ; dy = 0
2162 sta $5283
2164 jsr animate_player_down
2165 sec ; indicate to the calling routine that the
2166 rts ; player has left the room
2168 move_player_not_down_key:
2169 clc
2170 rts
2172 try_to_exit_level:
2174 cmp #6
2175 bmi just_exit_level
2177 lda $5780 ; set the complete game flag
2178 ora #$02
2179 jmp try_to_exit_level_exit
2181 just_exit_level:
2182 lda $5780 ; set the exit level flag
2183 ora #$80
2185 try_to_exit_level_exit:
2186 sta $5780
2188 lda #$80
2189 sta $74
2190 lda #$52
2191 sta $75
2192 jsr unplot_character ; remove the player sprite
2193 jmp destroy_enemies ; optimise away the rts
2195 check_fire_key:
2197 lda $578d
2198 bne check_fire_key_exit
2200 lda $577e
2201 beq check_fire_key_no_joystick
2203 lda #128
2204 ldx #0
2205 jsr $fff4
2206 txa
2207 and #1
2208 bne check_fire_key_fire
2210 clc
2211 rts
2213 check_fire_key_no_joystick:
2215 ldx #182 ; (Return)
2216 jsr check_key
2217 cpy #255
2218 bne check_fire_key_exit
2220 check_fire_key_fire:
2222 lda $5286
2223 cmp #0
2224 bne check_fire_key_exit
2226 lda #16
2227 sta $578d
2229 jmp create_projectile ; optimise away the rts
2231 check_fire_key_exit:
2232 clc
2233 rts
2235 create_projectile:
2237 lda #2
2238 sta $5286
2240 lda $5281
2241 and #$06 ; copy the direction information
2242 asl
2243 asl
2244 asl
2245 ora $5789 ; apply the projectile type
2246 sta $5287
2248 lda $5283 ; player dy
2249 adc $577f ; add the weapon counter
2250 adc #1
2251 cmp #4 ; if dy > 3, create the projectile on the tile below
2252 bpl create_projectile_below
2254 clc
2255 sta $5289 ; dy + weapon counter + 1
2256 lda $5282 ; y
2257 sta $5288
2258 jmp create_projectile_continue
2260 create_projectile_below:
2261 sec
2262 sbc #4
2263 sta $5289 ; dy + weapon counter + 1 - 4
2264 clc
2265 lda $5282 ; y
2266 adc #1
2267 sta $5288
2269 create_projectile_continue:
2270 lda $5284 ; x
2271 sta $528a
2273 lda $5285 ; dx
2274 sta $528b
2276 lda $577f ; toggle the weapon counter
2277 eor #1
2278 sta $577f
2280 ; Move the projectile away from the player.
2282 lda #$86
2283 sta $74
2284 lda #$52
2285 sta $75
2286 jsr move_projectile_after_unplot
2288 jsr move_projectile
2290 clc
2291 rts
2293 emerge_type: ; returns A=type
2294 jsr unlimited_values
2295 lda $7d
2296 and #7
2297 cmp #5
2298 bmi emerge_type_ok
2300 sec
2301 sbc #5
2302 clc
2304 emerge_type_ok:
2305 cmp $5781 ; only allow the appropriate enemies for this level
2306 bmi emerge_type_exit
2307 beq emerge_type_reduce
2309 sec
2310 sbc #1
2312 emerge_type_reduce:
2313 sec
2314 sbc $5781
2315 clc
2317 emerge_type_exit:
2318 asl
2319 asl
2320 asl
2321 asl
2322 clc
2323 rts
2325 emerge_character: ; $74,$75=character address
2327 lda #63
2328 sta $578f
2330 jsr unlimited_values
2331 and #$0f
2332 tax
2333 lda $0ee0,x
2334 cmp #0 ; check for an invalid value and exit if found
2335 beq emerge_character_exit
2337 sta $80 ; temporary
2338 lda $0ef0,x
2339 tax
2341 ; Add an emerging enemy.
2343 ldy #0
2344 lda #3 ; emerge/explosion
2345 sta ($74),y
2347 jsr emerge_type ; obtain an enemy type
2348 iny
2349 sta ($74),y
2351 txa
2352 iny
2353 sta ($74),y ; store the y position
2354 lda #1
2355 iny
2356 sta ($74),y ; store the dy offset
2358 lda $80
2359 iny
2360 sta ($74),y ; store the x position
2361 lda #0
2362 iny
2363 sta ($74),y ; store the dx offset
2365 jsr plot_character
2367 ldx #5
2368 jsr play_sound
2370 emerge_character_exit:
2371 clc
2372 rts
2374 emerge_explode: ; $74,$75=character address
2376 jsr unplot_character
2378 ldy #1
2379 lda ($74),y ; direction/animation
2380 tax
2381 adc #1 ; update the counter
2382 and #3 ; mask off everything else
2383 sta $80 ; store the masked counter value
2384 bne move_characters_explosion_not_finished
2386 txa
2387 and #4
2388 bne move_characters_remove_character
2390 ; For emerges, convert into an enemy.
2391 txa
2392 and #$70 ; only keep bits 4,5,6
2393 ora #8 ; make this an enemy
2395 ldy #0
2396 sta ($74),y ; update the type (>= 8)
2397 iny
2398 lda $7d ; prepare the direction and animation offset
2399 and #$0c
2400 sta ($74),y
2402 jsr plot_character
2403 jmp emerge_explode_exit
2405 move_characters_remove_character:
2407 ; For finished explosions, just write 0 into the character array.
2408 lda #0
2409 ldy #0
2410 sta ($74),y
2411 jmp emerge_explode_exit
2413 move_characters_explosion_not_finished:
2414 txa
2415 and #$fc
2416 ora $80
2418 ldy #1
2419 sta ($74),y
2421 jsr plot_character
2423 emerge_explode_exit:
2424 clc
2425 rts
2427 animate_enemy_left: ; $74,$75=character address
2429 ; Set the direction and toggle the animation bit.
2431 ldy #1
2432 lda ($74),y
2433 and #$fb ; keep vertical direction bit and animation bits
2434 sta ($74),y ; left (horizontal directional bit is 0)
2436 rts
2438 move_enemy_left: ; $74,$75=character address
2440 ldy #5
2441 lda ($74),y ; read dx
2442 cmp #0
2443 beq move_enemy_left_check_x
2445 sec
2446 sbc #1
2447 ldy #5
2448 sta ($74),y ; dx
2449 clc
2450 jmp animate_enemy_left ; optimise away the rts
2452 move_enemy_left_check_x:
2454 ; Check the x offset.
2456 ldy #4
2457 lda ($74),y ; x
2458 cmp #0
2459 beq move_enemy_left_exit
2461 sec
2462 sbc #1 ; x - 1
2463 sta $81 ; temporary
2464 ldy #2
2465 lda ($74),y ; load the y offset
2466 tax ; as an index
2467 lda room_row_offsets_low,x ; read the address of the row
2468 sta $70
2469 lda #$57
2470 sta $71
2471 ldy $81 ; temporary (x - 1)
2472 lda ($70),y ; load the tile to the left
2474 cmp #0
2475 bne move_enemy_left_exit
2477 ldy #3
2478 lda ($74),y ; dy
2479 cmp #2
2480 bmi move_enemy_allow_left
2482 clc
2483 lda $70 ; dy > 1 so we need to check another tile
2484 adc #10
2485 sta $70
2486 ldy $81 ; temporary (x - 1)
2487 lda ($70),y ; load the tile below and to the left
2489 cmp #0
2490 bne move_enemy_left_exit
2492 move_enemy_allow_left:
2493 lda $81
2494 ldy #4
2495 sta ($74),y ; store the new room x offset
2496 lda #3
2497 ldy #5
2498 sta ($74),y ; dx = 3
2499 clc
2500 jmp animate_enemy_left ; optimise away the rts
2502 move_enemy_left_exit:
2503 sec
2504 rts
2506 animate_enemy_right: ; $74,$75=character address
2508 ; Set the direction and toggle the animation bit.
2510 ldy #1
2511 lda ($74),y
2512 ora #$04 ; right (keep vertical direction bit and animation bits)
2513 sta ($74),y
2515 rts
2517 move_enemy_right: ; $74,$75=character_address
2519 ldy #5
2520 lda ($74),y ; read dx
2521 cmp #0
2522 beq move_enemy_right_check_x
2523 cmp #3
2524 beq move_enemy_right_tile
2526 clc
2527 adc #1
2528 ldy #5
2529 sta ($74),y
2530 jmp animate_enemy_right ; optimise away the rts
2532 move_enemy_right_check_x: ; Check the x offset.
2534 ldy #4
2535 lda ($74),y ; x
2536 cmp #9
2537 beq move_enemy_right_exit
2539 clc
2540 adc #1 ; x + 1
2541 sta $81 ; temporary (x + 1)
2542 ldy #2
2543 lda ($74),y ; load the y offset
2544 tax ; as an index
2545 lda room_row_offsets_low,x ; read the address of the row
2546 sta $70
2547 lda #$57
2548 sta $71
2549 ldy $81 ; temporary (x + 1)
2550 lda ($70),y ; load the tile to the right
2552 cmp #0
2553 bne move_enemy_right_exit
2555 ldy #3
2556 lda ($74),y ; dy
2557 cmp #2
2558 bmi move_enemy_allow_right
2560 clc ; dy > 1 so we need to check another tile
2561 lda $70
2562 adc #10
2563 sta $70
2564 ldy $81 ; temporary (x + 1)
2565 lda ($70),y ; load the tile below and to the right
2567 cmp #0
2568 bne move_enemy_right_exit
2570 move_enemy_allow_right:
2571 clc
2573 ldy #5
2574 lda ($74),y ; dx
2575 adc #1
2576 sta ($74),y ; update dx
2577 clc
2578 jmp animate_enemy_right ; optimise away the rts
2580 move_enemy_right_tile:
2581 clc
2583 ldy #4
2584 lda ($74),y ; x
2585 adc #1
2586 sta ($74),y ; store the new room x offset
2587 lda #0
2588 iny
2589 sta ($74),y ; dx = 0
2590 clc
2591 jmp animate_enemy_right ; optimise away the rts
2593 move_enemy_right_exit:
2594 sec
2595 rts
2597 animate_enemy_up: ; $74,$75=character address
2599 ; Set the direction and toggle the animation bit.
2601 ldy #1
2602 lda ($74),y
2603 and #$f7 ; keep horizontal direction bit and animation bits
2604 sta ($74),y
2606 rts
2608 move_enemy_up: ; $74,$75=character address
2610 ldy #3
2611 lda ($74),y ; read dy
2612 cmp #0
2613 beq move_enemy_up_check_y
2615 sec
2616 sbc #1
2617 ldy #3
2618 sta ($74),y ; dy
2619 clc
2620 jmp animate_enemy_up ; optimise away the rts
2622 move_enemy_up_check_y:
2624 ; Check the y offset.
2626 ldy #2
2627 lda ($74),y ; y
2628 cmp #0
2629 beq move_enemy_up_exit
2631 tax ; use the y offset as an index
2632 dex ; y - 1
2633 ldy #4
2634 lda ($74),y ; load the x offset
2635 sta $81 ; temporary (x)
2636 tay
2637 lda room_row_offsets_low,x ; read the address of the row
2638 sta $70
2639 lda #$57
2640 sta $71
2641 lda ($70),y ; load the tile above
2643 cmp #0
2644 bne move_enemy_up_exit
2646 ldy #5
2647 lda ($74),y ; dx
2648 cmp #0
2649 beq move_enemy_allow_up
2651 clc ; dx != 0 so we need to check another tile
2652 ldy $81
2653 iny
2654 lda ($70),y ; load the tile above and to the right
2656 cmp #0
2657 bne move_enemy_up_exit
2659 move_enemy_allow_up:
2660 txa
2661 ldy #2
2662 sta ($74),y ; store the new room y offset
2663 lda #3
2664 iny
2665 sta ($74),y ; dy = 3
2666 clc
2667 jmp animate_enemy_up ; optimise away the rts
2669 move_enemy_up_exit:
2670 sec
2671 rts
2673 animate_enemy_down: ; $74,$75=character address
2675 ; Set the direction and toggle the animation bit.
2677 ldy #1
2678 lda ($74),y
2679 ora #$08 ; down
2680 sta ($74),y
2682 rts
2684 move_enemy_down: ; $74,$75=character address
2686 ldy #3
2687 lda ($74),y ; dy
2688 cmp #1
2689 beq move_enemy_down_check_y
2690 cmp #3
2691 beq move_enemy_down_tile
2693 adc #1
2694 ldy #3
2695 sta ($74),y ; dy
2696 clc
2697 jmp animate_enemy_down ; optimise away the rts
2699 move_enemy_down_check_y:
2701 ; Check the y offset.
2703 ldy #2
2704 lda ($74),y
2705 cmp #9
2706 beq move_enemy_down_exit
2708 clc
2709 adc #1 ; y + 1
2710 tax
2711 ldy #4
2712 lda ($74),y ; load the x offset
2713 sta $81 ; temporary
2714 tay
2715 lda room_row_offsets_low,x ; read the address of the row
2716 sta $70
2717 lda #$57
2718 sta $71
2719 lda ($70),y ; load the tile below
2721 cmp #0
2722 bne move_enemy_down_exit
2724 ldy #5
2725 lda ($74),y ; dx
2726 cmp #0
2727 beq move_enemy_allow_down
2729 clc ; dx != 0 so we need to check another tile
2730 ldy $81 ; x
2731 iny
2732 lda ($70),y ; load the tile below and to the right
2734 cmp #0
2735 bne move_enemy_down_exit
2737 move_enemy_allow_down:
2738 clc
2740 ldy #3
2741 lda ($74),y ; dy
2742 adc #1
2743 sta ($74),y ; update dy
2744 clc
2745 jmp animate_enemy_down ; optimise away the rts
2747 move_enemy_down_tile:
2748 clc
2750 ldy #2
2751 lda ($74),y ; y
2752 adc #1
2753 sta ($74),y ; store the new room y offset
2754 lda #0
2755 iny
2756 sta ($74),y ; dy = 0
2757 clc
2758 jmp animate_enemy_down ; optimise away the rts
2760 move_enemy_down_exit:
2761 sec
2762 rts
2764 move_enemy_animate: ; $74,$75=character address
2766 ldy #1
2767 lda ($74),y ; direction/animation
2768 sta $81
2769 and #$03
2770 adc #1
2771 and #$03 ; keep animation bits
2772 sta $8f
2773 lda $81
2774 and #$fc ; mask off the animation bits
2775 ora $8f
2776 sta ($74),y
2777 rts
2779 move_enemy_next_direction: .byte $04, $0c, $00, $08
2781 move_enemy: ; $74,$75=character address
2783 lda #0
2784 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2785 lda #0
2786 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2788 lda ($74),y ; read the enemy number (Y should be zero)
2789 and #$10
2790 beq move_enemy_homing
2791 clc
2793 ; This enemy is a non-homing enemy.
2795 jsr unplot_character ; unplot now before we change the sprite used
2797 ldy #1
2798 lda ($74),y
2799 and #$f0
2800 cmp #$f0
2801 bne move_enemy_set_direction
2802 clc
2804 ldy #1
2805 lda ($74),y
2806 and #$0c
2807 ror
2808 ror
2809 tax
2810 lda move_enemy_next_direction,x
2811 sta ($74),y
2813 move_enemy_set_direction:
2814 clc
2816 ldy #1
2817 lda ($74),y
2818 sta $7b
2820 adc #$10
2821 sta ($74),y
2822 clc
2824 lda $7b
2825 and #$04
2826 ror
2827 ror
2828 adc #1
2829 sta $8e
2831 lda $7b
2832 and #$08
2833 ror
2834 ror
2835 ror
2836 adc #1
2837 sta $8d
2839 jmp move_enemy_with_direction
2841 move_enemy_homing:
2843 ldy #2
2844 lda ($74),y ; y
2845 cmp $5282 ; player y
2846 bmi move_enemy_downwards
2847 bne move_enemy_upwards
2849 ldy #3
2850 lda ($74),y ; dy
2851 cmp $5283 ; player y
2852 beq move_enemy_horizontally
2853 bpl move_enemy_upwards
2855 move_enemy_downwards:
2856 lda #2
2857 sta $8d
2858 jmp move_enemy_horizontally
2860 move_enemy_upwards:
2861 lda #1
2862 sta $8d
2863 ;jmp move_enemy_horizontally
2865 move_enemy_horizontally:
2866 ldy #4
2867 lda ($74),y ; x
2868 cmp $5284 ; player x
2869 bmi move_enemy_rightwards
2870 bne move_enemy_leftwards
2872 ldy #5
2873 lda ($74),y ; dx
2874 cmp #0
2875 beq move_enemy_with_direction_unplot
2876 bpl move_enemy_leftwards
2878 move_enemy_rightwards:
2879 lda #2
2880 sta $8e
2881 jmp move_enemy_with_direction_unplot
2883 move_enemy_leftwards:
2884 lda #1
2885 sta $8e
2887 move_enemy_with_direction_unplot:
2888 clc
2890 jsr unplot_character
2892 move_enemy_with_direction:
2893 clc
2895 lda $8e
2896 cmp #1
2897 bne move_enemy_not_left
2898 jsr move_enemy_left
2899 clc
2900 jmp move_enemy_not_right
2902 move_enemy_not_left:
2903 lda $8e
2904 cmp #2
2905 bne move_enemy_not_right
2906 jsr move_enemy_right
2907 clc
2909 move_enemy_not_right:
2910 lda $8d
2911 cmp #1
2912 bne move_enemy_not_up
2913 jsr move_enemy_up
2914 clc
2915 jmp move_enemy_toggle
2917 move_enemy_not_up:
2918 lda $8d
2919 cmp #2
2920 bne move_enemy_toggle
2921 jsr move_enemy_down
2923 move_enemy_toggle:
2924 clc
2925 jsr move_enemy_animate
2926 jmp plot_character ; optimise away the rts
2928 move_enemy_exit:
2929 clc
2930 rts
2932 create_explosion: ; X=y, Y=x
2934 lda #3
2935 sta $52a4
2936 lda #4
2937 sta $52a5
2938 txa
2939 sta $52a6
2940 lda #1
2941 sta $52a7
2942 tya
2943 sta $52a8
2944 lda #0
2945 sta $52a9
2946 rts
2948 move_projectile_left:
2950 lda $528b
2951 cmp #0
2952 beq move_projectile_left_check_x
2954 dec $528b
2955 clc
2956 rts
2958 move_projectile_left_check_x:
2960 lda $528a
2961 cmp #0
2962 bne move_projectile_left_in_room
2963 jmp move_projectile_left_exit
2965 move_projectile_left_in_room:
2966 tay
2967 dey ; x - 1
2968 ldx $5288 ; y
2969 lda room_row_offsets_low,x ; read the address of the row
2970 sta $70
2971 lda #$57
2972 sta $71
2973 lda ($70),y ; load the tile to the left
2975 cmp #0
2976 bne move_projectile_left_wall
2978 lda $5289 ; dy
2979 cmp #3
2980 bmi move_projectile_allow_left
2982 clc ; dy > 2 so we need to check another tile
2983 lda $70
2984 adc #10
2985 sta $70
2986 lda ($70),y ; load the tile below and to the left
2987 inx ; y += 1
2989 cmp #0
2990 bne move_projectile_left_wall
2992 move_projectile_allow_left:
2994 sty $528a ; x
2995 lda #3
2996 sta $528b ; dx = 3
2998 clc
2999 rts
3001 move_projectile_left_wall: ; the projectile hit a wall
3002 clc
3004 lda $5287 ; type 2 can pass through walls
3005 and #$06
3006 cmp #4
3007 beq move_projectile_allow_left
3009 cmp #2
3010 bne move_projectile_left_not_boomerang
3012 lda $5287
3013 and #$0f
3014 cmp #8
3015 bpl move_projectile_left_exit
3017 ldx $577f ; weapon counter
3018 ora boomerang_horizontal,x
3019 sta $5287
3020 clc
3021 rts ; exit without moving or registering a collision
3023 move_projectile_left_not_boomerang:
3025 cmp #6 ; type 3 can destroy certain walls
3026 bne move_projectile_left_exit
3028 lda ($70),y ; load the tile to the left
3029 cmp #1 ; decoration can be destroyed
3030 bne move_projectile_left_exit
3031 clc
3033 lda #0
3034 sta ($70),y
3036 ; X=y, Y=x
3037 jsr create_explosion
3038 jsr plot_blank_xy ; corrupted X
3040 lda #$a4
3041 sta $74
3042 lda #$52
3043 sta $75
3044 jsr plot_character
3046 ldx #0
3047 jsr play_sound
3049 lda #16 ; prevent the player from firing a new
3050 sta $578d ; projectile until the explosion has finished
3052 move_projectile_left_exit:
3053 sec
3054 rts
3056 boomerang_horizontal: .byte $28, $38
3058 move_projectile_right:
3060 ; Fire right.
3062 lda $528b
3063 cmp #2
3064 beq move_projectile_right_check_x
3065 cmp #3
3066 beq move_projectile_right_tile
3068 inc $528b
3069 clc
3070 rts
3072 move_projectile_right_check_x:
3074 lda $528a ; x
3075 cmp #9
3076 bne move_projectile_right_not_edge
3077 jmp move_projectile_right_exit
3079 move_projectile_right_not_edge:
3080 clc
3081 tay
3082 iny ; x + 1
3083 ldx $5288 ; y
3084 lda room_row_offsets_low,x ; read the address of the row
3085 sta $70
3086 lda #$57
3087 sta $71
3088 lda ($70),y ; load the tile to the right
3090 cmp #0
3091 bne move_projectile_right_wall
3093 lda $5289 ; dy
3094 cmp #3
3095 bmi move_projectile_allow_right
3097 clc ; dy > 2 so we need to check another tile
3098 lda $70
3099 adc #10
3100 sta $70
3101 lda ($70),y ; load the tile below and to the right
3102 inx ; y += 1
3104 cmp #0
3105 bne move_projectile_right_wall
3107 move_projectile_allow_right:
3109 inc $528b ; dx
3110 clc
3111 rts
3113 move_projectile_right_tile:
3115 inc $528a ; x
3116 lda #0
3117 sta $528b ; dx
3118 clc
3119 rts
3121 move_projectile_right_wall: ; the projectile hit a wall
3122 clc
3124 lda $5287 ; type 2 can pass through walls
3125 and #$06
3126 cmp #4
3127 beq move_projectile_allow_right
3129 cmp #2
3130 bne move_projectile_right_not_boomerang
3132 lda $5287
3133 and #$0f
3134 cmp #8
3135 bpl move_projectile_right_exit
3137 ldx $577f ; weapon counter
3138 ora boomerang_horizontal,x
3139 sta $5287
3140 clc
3141 rts ; exit without moving or registering a collision
3143 move_projectile_right_not_boomerang:
3145 cmp #6 ; type 3 can destroy certain walls
3146 bne move_projectile_right_exit
3148 lda ($70),y ; load the tile to the right
3149 cmp #1 ; decoration can be destroyed
3150 bne move_projectile_right_exit
3151 clc
3153 lda #0
3154 sta ($70),y
3156 ; X=y, Y=x
3157 jsr create_explosion
3158 jsr plot_blank_xy ; corrupted X
3160 lda #$a4
3161 sta $74
3162 lda #$52
3163 sta $75
3164 jsr plot_character
3166 ldx #0
3167 jsr play_sound
3169 lda #16 ; prevent the player from firing a new
3170 sta $578d ; projectile until the explosion has finished
3172 move_projectile_right_exit:
3173 sec
3174 rts
3176 move_projectile_up:
3178 lda $5289 ; read dy
3179 cmp #0
3180 beq move_projectile_up_check_y
3182 dec $5289
3183 clc
3184 rts
3186 move_projectile_up_check_y: ; Check the y offset.
3188 lda $5288
3189 cmp #0
3190 bne move_projectile_up_not_edge
3191 jmp move_projectile_up_exit
3193 move_projectile_up_not_edge:
3194 tax ; use the y offset as an index
3195 dex ; y - 1
3196 ldy $528a ; load the x offset
3197 lda room_row_offsets_low,x ; read the address of the row
3198 sta $70
3199 lda #$57
3200 sta $71
3201 lda ($70),y ; load the tile above
3203 cmp #0
3204 bne move_projectile_up_wall
3206 lda $528b ; dx
3207 cmp #3
3208 bmi move_projectile_allow_up
3210 clc ; dx > 2 so we need to check another tile
3211 iny
3212 lda ($70),y ; load the tile above and to the right
3214 cmp #0
3215 bne move_projectile_up_wall
3217 move_projectile_allow_up:
3218 txa
3219 sta $5288 ; store the new room y offset
3220 lda #3
3221 sta $5289 ; dy = 3
3223 clc
3224 rts
3226 move_projectile_up_wall: ; the projectile hit a wall
3227 clc
3229 lda $5287 ; type 2 can pass through walls
3230 and #$06
3231 cmp #4
3232 beq move_projectile_allow_up
3234 cmp #2
3235 bne move_projectile_up_not_boomerang
3237 lda $5287
3238 and #$0f
3239 cmp #8
3240 bpl move_projectile_up_exit
3242 ldx $577f ; weapon counter
3243 ora boomerang_vertical,x
3244 sta $5287
3245 clc
3246 rts ; exit without moving or registering a collision
3248 move_projectile_up_not_boomerang:
3250 cmp #6 ; type 3 can destroy certain walls
3251 bne move_projectile_up_exit
3253 lda ($70),y ; load the tile above
3254 cmp #1 ; decoration can be destroyed
3255 bne move_projectile_up_exit
3256 clc
3258 lda #0
3259 sta ($70),y
3261 ; X=y, Y=x
3262 jsr create_explosion
3263 jsr plot_blank_xy ; corrupted X
3265 lda #$a4
3266 sta $74
3267 lda #$52
3268 sta $75
3269 jsr plot_character
3271 ldx #0
3272 jsr play_sound
3274 lda #16 ; prevent the player from firing a new
3275 sta $578d ; projectile until the explosion has finished
3277 move_projectile_up_exit:
3278 sec
3279 rts
3281 boomerang_vertical: .byte $08, $18
3283 move_projectile_down:
3285 lda $5289 ; read dy
3286 cmp #2
3287 beq move_projectile_down_check_y
3288 cmp #3
3289 beq move_projectile_down_tile
3291 inc $5289 ; 0 <= dy < 3
3292 clc
3293 rts
3295 move_projectile_down_check_y: ; Check the y offset.
3297 lda $5288
3298 cmp #9
3299 bne move_projectile_down_in_room
3300 jmp move_projectile_down_exit
3302 move_projectile_down_in_room:
3303 clc
3304 tax
3305 inx ; y + 1
3306 ldy $528a ; load the x offset
3307 lda room_row_offsets_low,x ; read the address of the row
3308 sta $70
3309 lda #$57
3310 sta $71
3311 lda ($70),y ; load the tile below
3313 cmp #0
3314 bne move_projectile_down_wall
3316 lda $528b ; dx
3317 cmp #3
3318 bmi move_projectile_allow_down
3320 clc ; dx > 2 so we need to check another tile
3321 iny
3322 lda ($70),y ; load the tile below and to the right
3324 cmp #0
3325 bne move_projectile_down_wall
3327 move_projectile_allow_down:
3329 inc $5289 ; update dy
3330 clc
3331 rts
3333 move_projectile_down_tile:
3335 inc $5288 ; store the new room y offset
3336 lda #0
3337 sta $5289 ; dy = 0
3338 clc
3339 rts
3341 move_projectile_down_wall: ; the projectile hit a wall
3342 clc
3344 lda $5287 ; type 2 can pass through walls
3345 and #$06
3346 cmp #4
3347 beq move_projectile_allow_down
3349 cmp #2
3350 bne move_projectile_down_not_boomerang
3352 lda $5287
3353 and #$0f
3354 cmp #8
3355 bpl move_projectile_down_exit
3357 ldx $577f ; weapon counter
3358 ora boomerang_vertical,x
3359 sta $5287
3360 clc
3361 rts ; exit without moving or registering a collision
3363 move_projectile_down_not_boomerang:
3365 cmp #6 ; type 3 can destroy certain walls
3366 bne move_projectile_down_exit
3368 lda ($70),y ; load the tile below
3369 cmp #1 ; decoration can be destroyed
3370 bne move_projectile_down_exit
3371 clc
3373 lda #0
3374 sta ($70),y
3376 ; X=y, Y=x
3377 jsr create_explosion
3378 jsr plot_blank_xy ; corrupted X
3380 lda #$a4
3381 sta $74
3382 lda #$52
3383 sta $75
3384 jsr plot_character
3386 ldx #0
3387 jsr play_sound
3389 lda #16 ; prevent the player from firing a new
3390 sta $578d ; projectile until the explosion has finished
3392 move_projectile_down_exit:
3393 sec
3394 rts
3396 move_projectile_animate:
3398 lda $5287
3399 eor #1
3400 sta $5287
3401 rts
3403 move_projectile:
3405 lda $5286
3406 cmp #0
3407 bne move_projectile_move
3408 jmp move_projectile_exit
3410 move_projectile_move:
3411 clc
3413 lda #$86
3414 sta $74
3415 lda #$52
3416 sta $75
3417 jsr unplot_character
3419 move_projectile_after_unplot:
3421 lda $5287
3422 and #$30 ; direction
3424 cmp #0
3425 bne move_projectile_not_left
3427 jsr move_projectile_left
3428 bcc move_projectile_toggle
3429 bcs move_projectile_destroy
3431 move_projectile_not_left:
3432 cmp #$10
3433 bne move_projectile_not_right
3435 jsr move_projectile_right
3436 bcc move_projectile_toggle
3437 bcs move_projectile_destroy
3439 move_projectile_not_right:
3440 cmp #$20
3441 bne move_projectile_not_up
3443 jsr move_projectile_up
3444 bcc move_projectile_toggle
3445 bcs move_projectile_destroy
3447 move_projectile_not_up:
3448 cmp #$30
3449 bne move_projectile_toggle
3451 jsr move_projectile_down
3452 bcs move_projectile_destroy
3454 move_projectile_toggle:
3456 jsr projectile_collide
3457 bcs move_projectile_destroy
3459 jsr move_projectile_animate
3461 lda #$86
3462 sta $74
3463 lda #$52
3464 sta $75
3465 jmp plot_character ; optimise away the rts
3467 move_projectile_destroy:
3468 clc
3470 ldy #0
3471 lda ($74),y ; type
3472 cmp #8
3473 bmi move_projectile_no_enemy_collision
3475 and #$70 ; increase the player's score
3476 lsr
3477 lsr
3478 lsr
3479 adc #2
3480 sta $70
3481 jsr add_score
3482 jmp move_projectile_create_explosion
3484 move_projectile_no_enemy_collision:
3486 cmp #4 ; items can be destroyed as well
3487 bne move_projectile_no_item_collision
3489 ldy #1 ; but not keys
3490 lda ($74),y
3491 cmp #4 ; even the mace is stopped by a key
3492 beq move_projectile_remove_projectile
3493 clc
3495 jsr remove_room_item
3497 move_projectile_create_explosion:
3499 ; Unplot the item/enemy and replace it with an explosion.
3501 jsr unplot_character
3503 lda #3 ; explosion
3504 ldy #0
3505 sta ($74),y
3507 lda #4
3508 ldy #1
3509 sta ($74),y
3511 jsr plot_character
3513 ; Play a sound.
3514 ldx #0
3515 jsr play_sound
3517 move_projectile_no_item_collision:
3519 lda $5287 ; type 2 projectiles pass through everything
3520 and #$06
3521 cmp #4
3522 bne move_projectile_remove_projectile
3524 ; Ideally, we would have recorded if the projectile left the screen so
3525 ; that we don't perform these checks again here, but it would just add
3526 ; overhead to the normal movement routines for the other weapons.
3528 lda $5288 ; y
3529 cmp #0
3530 beq move_projectile_remove_projectile
3531 cmp #9
3532 beq move_projectile_remove_projectile
3534 lda $528a ; x
3535 cmp #0
3536 beq move_projectile_remove_projectile
3537 cmp #9
3538 beq move_projectile_remove_projectile
3540 clc
3541 lda #$86
3542 sta $74
3543 lda #$52
3544 sta $75
3546 jsr plot_character
3547 jmp move_projectile_exit
3549 move_projectile_remove_projectile:
3551 lda #0 ; remove the projectile from the character list
3552 sta $5286
3554 move_projectile_exit:
3555 clc
3556 rts
3558 emerge_characters:
3560 lda #$8c ; set the character address
3561 sta $74
3562 lda #$52
3563 sta $75
3565 emerge_characters_loop:
3567 ldy #0
3568 lda ($74),y
3569 cmp #0
3570 bne emerge_characters_next
3572 jmp emerge_character ; optimise away the rts
3574 emerge_characters_next:
3575 clc
3577 ; Examine the next character.
3578 lda $74
3579 adc #6
3581 cmp #$a4
3582 bpl emerge_characters_exit
3583 sta $74
3584 jmp emerge_characters_loop
3586 emerge_characters_exit:
3587 clc
3588 rts
3590 enemy_slots: .byte 0, 6, 12, 18
3592 move_characters:
3594 lda #$8c ; set the character address
3595 sta $74
3596 lda #$52
3597 sta $75
3599 lda $578e ; read a value from 0 to 3 from the motion counter
3600 and #3
3601 tax
3602 lda enemy_slots,x ; look up the corresponding slot in the character list
3603 adc $74
3604 sta $74 ; update the character address
3606 move_characters_loop:
3608 ldy #0
3609 lda ($74),y
3610 cmp #3
3611 bne move_characters_not_emerge_explode
3613 jsr emerge_explode
3614 jmp move_characters_next
3616 move_characters_not_emerge_explode:
3617 cmp #8
3618 bmi move_characters_next
3620 jsr move_enemy
3622 move_characters_next:
3623 clc
3625 lda $74 ; for the last enemy, check the next slot
3626 cmp #$9e ; for the presence of an explosion
3627 bne move_characters_endloop ; otherwise leave the loop (only performing
3628 clc ; one iteration)
3630 adc #6
3631 sta $74
3632 jmp move_characters_loop
3634 move_characters_endloop:
3635 clc
3637 ; Check collisions with the player.
3639 jsr player_collide
3640 bcs move_characters_collisions
3641 jmp move_characters_exit
3643 move_characters_collisions:
3644 clc
3646 ldy #0
3647 lda ($74),y ; type
3648 cmp #8
3649 bpl move_character_destroy_enemy
3651 ; Unplot the item.
3652 jsr unplot_character
3654 ; Remove it from the item table.
3655 jsr remove_room_item
3657 lda #0 ; remove the item from the character list
3658 ldy #0
3659 sta ($74),y
3661 iny
3662 lda ($74),y ; get the item type
3664 sta $8d ; temporarily store A and increase the score
3665 tax
3666 lda item_scores,x
3667 sta $70
3668 jsr add_score
3669 lda $8d
3671 ; Check the item type.
3672 cmp #8
3673 bmi move_characters_not_health
3675 lda #20
3676 sta $70
3677 jsr add_strength
3678 clc
3680 ldx #2
3681 jsr play_sound
3683 rts
3685 move_characters_not_health:
3686 cmp #5
3687 bmi move_characters_not_treasure
3689 ldx #2
3690 jsr play_sound
3692 clc
3693 rts
3695 move_characters_not_treasure:
3696 cmp #4
3697 bmi move_characters_not_key
3699 ; Key - update the item/player flags byte.
3700 lda $5780
3701 ora #$01
3702 sta $5780
3703 clc
3705 ldx #3
3706 jsr play_sound
3708 rts
3710 move_characters_not_key:
3712 ; Update the player's weapon.
3713 asl
3714 sta $5789
3715 clc
3717 ldx #2
3718 jsr play_sound
3720 rts
3722 move_character_destroy_enemy:
3724 ; Unplot the enemy and replace it with an explosion.
3726 jsr unplot_character
3728 lda #3 ; explosion
3729 ldy #0
3730 sta ($74),y
3732 lda #4
3733 ldy #1
3734 sta ($74),y
3736 jsr plot_character
3738 ; Reduce the player's strength.
3740 ldx #1
3741 jsr play_sound
3743 lda #1
3744 sta $70
3745 jmp reduce_strength ; optimise away the rts
3747 move_characters_exit:
3748 clc
3749 rts
3751 remove_room_item:
3753 ldx $5782 ; current room row number
3754 lda eleven_times_table,x
3755 adc $5783 ; current room column number
3756 tax
3757 lda #$80 ; store a value with the top bit set instead of zero because we
3758 sta $5200,x ; have visited this room if we can collect the object within it
3759 clc
3760 rts
3762 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3763 score_vdu_bytes: .byte 1,1,31 ; reversed
3764 score_digits: .byte "0123456789"
3766 add_score: ; $70=score to add
3768 sed
3769 lda $5786
3770 adc $70
3771 sta $5786
3772 lda $5787
3773 adc #0
3774 sta $5787
3775 lda $5788
3776 adc #0
3777 sta $5788
3778 cld
3780 write_score:
3782 lda #$86
3783 sta $70
3784 lda #$57
3785 sta $71
3787 ldx #2
3788 write_score_vdu_bytes:
3789 lda score_vdu_bytes,x
3790 jsr $ffee
3791 dex
3792 bpl write_score_vdu_bytes
3794 write_score_digits: ; $70,$71=address of score bytes
3796 ldy #2
3797 write_score_loop:
3799 lda ($70),y
3800 lsr
3801 lsr
3802 lsr
3803 lsr
3804 tax
3805 lda score_digits,x
3806 jsr $ffee
3808 lda ($70),y
3809 and #$0f
3810 tax
3811 lda score_digits,x
3812 jsr $ffee
3814 dey
3815 bpl write_score_loop
3817 clc
3818 rts
3820 strength_units: .byte $00,$88,$cc,$ee
3822 add_strength: ; $70=strength to add
3824 ; Divide the initial strength by 4 to determine which half character to
3825 ; start plotting at, and multiply by 8 to get the address. The net result
3826 ; is to mask off the bottom two bits and shift left once.
3827 lda $5784
3828 and #$fc
3829 sta $71 ; strength rounded down to a multiple of four units
3830 asl
3831 clc
3832 tay
3834 lda $5784
3835 adc $70
3836 cmp #65
3837 bmi add_strength_update
3839 lda #64
3841 add_strength_update:
3842 clc
3843 sta $5784 ; the final strength
3845 sec
3846 sbc $71
3847 clc
3848 tax ; the number of units to add between the rounded original
3849 ; strength and the final strength
3851 lda #$f3 ; the start of the strength bar
3852 sta $72
3853 lda #$59
3854 sta $73
3856 cpx #4
3857 bmi add_strength_loop_extra
3859 add_strength_loop:
3861 clc
3862 lda #$ff
3863 sta ($72),y
3865 tya
3866 adc #8
3867 tay
3869 txa
3870 sec
3871 sbc #4
3872 clc
3873 tax
3875 cmp #4
3876 bpl add_strength_loop
3878 add_strength_loop_extra:
3879 cpx #0
3880 beq add_strength_exit
3882 ; For any remaining units in excess of the multiples of four units, plot
3883 ; the appropriate byte.
3884 lda $5784
3885 and #3
3886 tax
3888 lda strength_units,x
3889 sta ($72),y
3891 add_strength_exit:
3892 clc
3893 rts
3895 reduce_strength: ; $70=strength to remove
3897 lda $5784
3898 tax
3899 sec
3900 sbc $70
3901 bpl reduce_strength_update
3903 lda #0
3905 reduce_strength_update:
3906 clc
3907 sta $5784
3909 ; Divide the final strength by 4 to determine which half character to
3910 ; plot, and multiply by 8 to get the address. The net result is to mask off
3911 ; the bottom two bits and shift left once.
3912 and #$fc
3913 asl
3914 tay
3916 lda #$f3 ; the start of the strength bar
3917 sta $70
3918 lda #$59
3919 sta $71
3921 lda $5784
3922 and #3
3923 tax
3924 lda strength_units,x
3925 sta ($70),y
3927 lda $5784
3928 cmp #0
3929 bne reduce_strength_exit
3931 lda $5780 ; the player ran out of strength
3932 ora #$40
3933 sta $5780
3935 lda #64 ; reset the delay counter
3936 sta $5785
3938 lda #$80 ; unplot the player
3939 sta $74
3940 lda #$52
3941 sta $75
3943 jsr unplot_character
3945 lda #8 ; change the player's direction to the demise animation
3946 sta $5281
3948 jsr plot_character
3949 jmp destroy_enemies ; optimise away the rts
3951 reduce_strength_exit:
3952 clc
3953 rts
3955 destroy_enemies:
3957 lda #$8c
3958 sta $74
3959 lda #$52
3960 sta $75
3962 destroy_enemies_loop:
3964 ldy #0
3965 lda ($74),y
3966 cmp #8
3967 bmi destroy_enemies_not_enemy
3969 jsr unplot_character
3971 lda #3 ; emerge/explosion
3972 ldy #0
3973 sta ($74),y
3975 iny
3976 lda #4 ; explosion
3977 sta ($74),y
3979 jsr plot_character
3980 jmp destroy_enemies_not_emerging_enemy
3982 destroy_enemies_not_enemy:
3983 cmp #3
3984 bne destroy_enemies_not_emerging_enemy
3986 jsr unplot_character
3988 iny ; whether emerging or exploding, ensure that the enemy
3989 lda ($74),y ; is now exploding
3990 ora #4
3991 sta ($74),y
3993 jsr plot_character
3995 destroy_enemies_not_emerging_enemy:
3996 clc
3997 lda $74
3998 adc #6
3999 sta $74
4000 cmp #$a4
4001 bmi destroy_enemies_loop
4003 clc
4004 rts
4006 remove_characters:
4008 ; Clear the character table.
4010 ldx #6
4011 remove_characters_loop:
4012 lda #0
4013 sta $5280,x
4014 txa
4015 adc #6
4016 tax
4017 cpx #$2a
4018 bmi remove_characters_loop
4020 rts
4022 ; The player collision masks use bits to represent where the player is in a
4023 ; tile. See the collisions.txt file for more information.
4025 ; Player is above, enemy is below, checking the overlap in the lower tile.
4026 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4028 projectile_collision_mask_above: .byte $00, $00, $00, $80
4030 ; Player and enemy share the same tile or player is on the tile below.
4031 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4033 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4035 ; Player is above or on the same tile, enemy is below, checking the overlap in
4036 ; the lower tile.
4037 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4039 ; Enemy is above, player is below, checking the overlap in the lower tile.
4040 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4042 ; Player is to the left, enemy is to the right, checking the overlap in the
4043 ; right hand tile.
4044 player_collision_mask_left:
4045 projectile_collision_mask_left: .byte $00, $00, $00, $08
4047 ; Player and enemy share the same tile or player is on the tile to the right.
4048 player_collision_mask_right:
4049 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4051 ; Player is to the left, enemy is to the right or on the same tile, checking
4052 ; the overlap in the right hand tile.
4053 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4055 ; Enemy is to the left, player is to the right, checking the overlap in the
4056 ; right hand tile.
4057 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4059 player_collide:
4061 lda $5282 ; player y
4062 sta $8a
4063 lda $5284 ; player x
4064 sta $8b
4066 ldx $5283 ; player dy
4067 lda player_collision_mask_above,x
4068 sta $86
4069 lda player_collision_mask_below,x
4070 sta $88
4071 ldx $5285 ; player dx
4072 lda player_collision_mask_left,x
4073 sta $87
4074 lda player_collision_mask_right,x
4075 sta $89
4077 jmp collide ; optimise away the rts
4079 projectile_collide:
4081 lda $5288 ; projectile y
4082 sta $8a
4083 lda $528a ; projectile x
4084 sta $8b
4086 ldx $5289 ; projectile dy
4087 lda projectile_collision_mask_above,x
4088 sta $86
4089 lda projectile_collision_mask_below,x
4090 sta $88
4091 ldx $528b ; projectile dx
4092 lda projectile_collision_mask_left,x
4093 sta $87
4094 lda projectile_collision_mask_right,x
4095 sta $89
4097 ; Run on into the next routine.
4099 collide:
4101 lda #$8c ; set the character address
4102 sta $74
4103 lda #$52
4104 sta $75
4106 collide_loop:
4108 ldy #0
4109 lda ($74),y ; type
4110 cmp #4
4111 bpl collide_check
4113 jmp collide_next
4115 collide_check:
4117 ldy #2
4118 lda ($74),y ; y
4119 sec
4120 sbc $8a ; y - player/projectile y
4121 beq check_collide_y_equal
4122 cmp #1
4123 beq check_collide_y_greater
4124 cmp #255
4125 beq check_collide_y_less
4127 jmp collide_next
4129 check_collide_y_equal:
4130 ; The enemy is on the same tile as the player/projectile so look at the
4131 ; collision on their common tile.
4132 ldy #3
4133 lda ($74),y ; dy
4134 tax
4135 lda enemy_collision_mask_above,x
4136 and $88 ; player/projectile mask below
4137 bne check_collide_x
4139 jmp collide_next
4141 check_collide_y_greater:
4142 ; The enemy is on the tile below the player/projectile so look at the
4143 ; collision on the enemy's tile.
4144 ldy #3
4145 lda ($74),y ; dy
4146 tax
4147 lda enemy_collision_mask_above,x
4148 and $86 ; player mask above
4149 bne check_collide_x
4151 jmp collide_next
4153 check_collide_y_less:
4154 ; The enemy is on the tile above the player/projectile so look at the
4155 ; collision on the player's tile.
4156 ldy #3
4157 lda ($74),y ; dy
4158 tax
4159 lda enemy_collision_mask_below,x
4160 and $88 ; player mask below
4161 bne check_collide_x
4163 jmp collide_next
4165 check_collide_x:
4166 ldy #4
4167 lda ($74),y ; x
4168 sec
4169 sbc $8b ; x - player/projectile x
4170 beq check_collide_x_equal
4171 cmp #1
4172 beq check_collide_x_greater
4173 cmp #255
4174 beq check_collide_x_less
4176 jmp collide_next
4178 check_collide_x_equal:
4179 ; The enemy is on the same tile as the player/projectile so look at the
4180 ; collision on their common tile.
4181 ldy #5
4182 lda ($74),y ; dx
4183 tax
4184 lda enemy_collision_mask_left,x
4185 and $89 ; player mask right
4186 bne check_collide_destroy
4188 jmp collide_next
4190 check_collide_x_greater:
4191 ; The enemy is the tile to the right of the player/projectile so look
4192 ; at the collision on the enemy's tile.
4193 ldy #5
4194 lda ($74),y ; dx
4195 tax
4196 lda enemy_collision_mask_left,x
4197 and $87 ; player mask left
4198 bne check_collide_destroy
4200 jmp collide_next
4202 check_collide_x_less:
4203 ; The enemy is the tile to the left of the player/projectile so look at
4204 ; the collision on the player's tile.
4205 ldy #5
4206 lda ($74),y ; dx
4207 tax
4208 lda enemy_collision_mask_right,x
4209 and $89 ; player mask right
4210 bne check_collide_destroy
4212 collide_next:
4213 clc
4215 ; Examine the next character.
4216 lda $74
4217 adc #6
4219 cmp #$a4
4220 bpl collide_exit
4221 sta $74
4222 jmp collide_loop
4224 check_collide_destroy:
4226 sec ; set the carry flag to inform the caller that the
4227 rts ; player/projectile should be destroyed
4229 collide_exit:
4230 clc
4231 rts
4233 blank_screen:
4234 lda #1
4235 sta $70
4236 lda #0
4237 sta $71
4238 jsr set_palette
4239 lda #2
4240 sta $70
4241 lda #0
4242 sta $71
4243 jsr set_palette
4244 lda #3
4245 sta $70
4246 lda #0
4247 sta $71
4248 ; Run on into set_palette.
4250 set_palette:
4251 ; $70=logical colour
4252 ; $71=physical colour
4253 lda $70
4254 sta $578b
4255 lda $71
4256 sta $578c
4257 lda #0
4258 sta $578d
4259 sta $578e
4260 sta $578f
4262 lda #$c
4263 ldx #$8b
4264 ldy #$57
4265 jsr $fff1
4266 rts
4268 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4269 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4271 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4272 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4273 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4274 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4275 note_sound: .byte $13,0, 241,255
4276 note_pitch: .byte 0,0
4277 note_duration: .byte 4,0
4278 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4280 play_note: ; A=pitch, Y=duration
4282 sta note_pitch
4283 sty note_duration
4284 ldx #4
4285 ; Run on into the next routine.
4287 play_sound: ; X=sound number
4289 lda sounds_high,x
4290 tay
4291 lda sounds_low,x
4292 tax
4293 lda #7
4294 jsr $fff1
4296 rts
4298 copy_title_up:
4300 lda #$00
4301 sta $70
4302 lda #$18
4303 sta $71
4305 lda #$a0
4306 sta $72
4307 lda #$5a
4308 sta $73
4310 ldx #5
4311 ; Run on into the next routine.
4313 copy_title:
4315 copy_title_loop1:
4317 ldy #0
4318 copy_title_loop2:
4320 lda ($70),y
4321 sta ($72),y
4322 iny
4323 cpy #0
4324 bne copy_title_loop2
4326 clc
4327 lda $72
4328 adc #$40
4329 sta $72
4330 lda $73
4331 adc #$01
4332 sta $73
4333 clc
4335 lda $71
4336 adc #$01
4337 sta $71
4338 clc
4340 dex
4341 bpl copy_title_loop1
4343 rts
4345 copy_completed_screen_up:
4347 lda #$00
4348 sta $70
4349 lda #$0f
4350 sta $71
4352 lda #$60
4353 sta $72
4354 lda #$5e
4355 sta $73
4357 ldx #8
4358 jmp copy_title ; optimise away the rts
4360 init:
4361 jsr cls ; clear the text window
4363 lda #26 ; unset the text window
4364 jsr $ffee
4366 ; Define the default high scores.
4367 ldy #0
4368 lda #$80
4369 sta $70
4370 lda #$51
4371 sta $71
4372 lda #$16
4373 sta $72
4375 ldx #0
4376 init_define_high_scores_loop:
4378 lda #0
4379 sta ($70),y
4380 iny
4381 lda $72
4382 sta ($70),y
4383 iny
4384 lda #0
4385 sta ($70),y
4387 iny
4388 init_define_high_score_name_loop:
4390 lda high_score_default_name1,x
4391 sta ($70),y
4392 iny
4393 inx
4394 cpx #9
4395 beq init_define_high_scores_next
4396 cpx #18
4397 bne init_define_high_score_name_loop
4399 ldx #0
4400 init_define_high_scores_next:
4402 sed
4403 lda $72
4404 sec
4405 sbc #2
4406 sta $72
4407 cld
4408 clc
4410 cpy #96
4411 bne init_define_high_scores_loop
4413 ; Disable joystick support.
4414 lda #0
4415 sta $577e
4417 rts
4419 high_score_default_name1: .byte "RETRO "
4420 high_score_default_name2: .byte " SOFTWARE"
4422 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4423 input_message: .byte 17,2, 31,2,27, "Press SPACE/FIRE"
4424 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4425 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4426 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4427 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4429 set_standard_palette:
4431 lda #1
4432 sta $70
4433 lda #1
4434 sta $71
4435 jsr set_palette
4437 jmp set_core_palette ; optimise away the rts
4439 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4441 set_complete_palette:
4443 lda #0
4444 sta $80
4445 lda #25
4446 sta $81
4448 set_complete_palette_loop:
4450 jsr wait_for_vsync
4452 dec $81
4453 lda $81
4454 cmp #0
4455 bne set_complete_palette_loop
4457 lda #25
4458 sta $81
4460 ldx $80
4461 lda complete_palette_bytes,x
4462 sta $70
4463 inx
4464 lda complete_palette_bytes,x
4465 sta $71
4466 inx
4467 stx $80
4468 jsr set_palette
4470 lda $80
4471 cmp #10
4472 bne set_complete_palette_loop
4474 rts
4476 set_hidden_palette:
4478 lda #1
4479 sta $70
4480 lda #0
4481 sta $71
4482 jsr set_palette
4484 ; Run on into the next routine.
4486 set_core_palette:
4488 lda #2
4489 sta $70
4490 lda #2
4491 sta $71
4492 jsr set_palette
4494 lda #3
4495 sta $70
4496 lda #3
4497 sta $71
4498 jsr set_palette
4500 rts
4502 show_title:
4504 jsr set_standard_palette
4506 ldx #0
4507 write_title_text_loop:
4508 lda title_vdu_bytes,x
4509 jsr $ffee
4510 inx
4511 cpx #12
4512 bmi write_title_text_loop
4514 jsr show_input_message
4516 ; Show the title.
4517 jsr copy_title_up
4519 ; Show the high scores.
4521 jsr colour1
4523 lda #$80
4524 sta $70
4525 lda #$51
4526 sta $71
4528 lda #8
4529 sta $80
4531 show_title_high_scores_loop:
4533 lda #31
4534 jsr $ffee
4535 lda #2
4536 jsr $ffee
4537 lda $80
4538 adc #2
4539 sta $80
4540 clc
4541 jsr $ffee
4543 jsr write_score_digits
4545 lda #32
4546 jsr $ffee
4548 ldx #8
4549 ldy #3
4550 show_title_high_scores_vdu_loop2:
4552 lda ($70),y
4553 cmp #32
4554 bmi ignore_char
4555 cmp #123
4556 bpl ignore_char
4557 jsr $ffee
4559 ignore_char:
4560 iny
4561 dex
4562 bpl show_title_high_scores_vdu_loop2
4564 lda $70
4565 adc #12
4566 sta $70
4567 cmp #$e0
4568 bne show_title_high_scores_loop
4570 lda #0 ; message counter
4571 sta $72
4573 show_title_wait_loop:
4575 lda #150
4576 sta $5785
4578 ldx $72
4579 ldy #22
4580 show_title_wait_message_loop:
4582 lda title_vdu_bytes1,x
4583 jsr $ffee
4584 inx
4585 dey
4586 bpl show_title_wait_message_loop
4588 cpx #92
4589 beq show_title_wait_reset_offset
4591 txa
4592 sta $72
4593 jmp show_title_wait_inner_loop
4595 show_title_wait_reset_offset:
4596 lda #0
4597 sta $72
4599 show_title_wait_inner_loop:
4600 jsr wait_for_vsync
4602 dec $5785
4603 beq show_title_wait_loop
4605 show_title_wait_loop_no_update:
4606 lda #128
4607 ldx #0
4608 jsr $fff4
4609 cpx #0 ; fire button pressed?
4610 beq show_title_no_joystick
4612 lda #1 ; enable joystick support
4613 sta $577e
4614 jmp show_title_exit
4616 show_title_no_joystick:
4617 ldx #157 ; SPACE
4618 jsr check_key
4619 cpy #255
4620 bne show_title_wait_inner_loop
4622 lda #0 ; disable joystick support
4623 sta $577e
4625 show_title_exit:
4626 clc
4627 rts
4629 show_input_message:
4631 ldx #0
4632 show_input_message_loop:
4634 lda input_message,x
4635 jsr $ffee
4636 inx
4637 cpx #23
4638 bne show_input_message_loop
4640 rts
4642 wait_for_vsync:
4644 lda #19
4645 jmp $fff4 ; optimise away the rts
4647 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4649 delay:
4651 delay_loop:
4653 jsr wait_for_vsync
4654 dec $5785
4655 bne delay_loop
4657 rts
4659 show_game_over:
4661 lda #128
4662 sta $5785
4663 jsr delay
4665 ldx #0
4666 write_game_over_text_loop:
4667 lda game_over_vdu_bytes,x
4668 jsr $ffee
4669 inx
4670 cpx #33
4671 bmi write_game_over_text_loop
4673 lda #192
4674 sta $5785
4675 jsr delay
4677 rts
4679 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4680 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4682 show_end_of_level_screen:
4684 ; Draw a decorative room.
4686 jsr make_empty_room
4688 ldx #5
4689 end_of_level_h_walls_loop:
4691 lda #3
4692 sta $57b2,x
4693 sta $57e4,x
4694 dex
4695 bpl end_of_level_h_walls_loop
4697 ldx #30
4698 end_of_level_v_walls_loop:
4700 lda #3
4701 sta $57bc,x
4702 sta $57c1,x
4703 txa
4704 sec
4705 sbc #10
4706 tax
4707 bpl end_of_level_v_walls_loop
4709 jsr plot_room_tiles
4710 jsr set_standard_palette
4712 ldx #0
4713 end_of_level_text_loop1:
4715 lda end_of_level_bytes1,x
4716 jsr $ffee
4717 inx
4718 cpx #28
4719 bne end_of_level_text_loop1
4721 ; Count the number of rooms explored.
4722 ldx #0
4723 lda #0
4724 sta $8d
4725 sta $8e
4726 end_of_level_room_count_loop:
4728 lda $5200,x
4729 and #$80
4730 beq end_of_level_room_count_loop_next
4732 sed
4733 lda $8d
4734 adc #1
4735 sta $8d
4736 lda $8e
4737 adc #0
4738 sta $8e
4739 cld
4740 clc
4742 end_of_level_room_count_loop_next:
4743 inx
4744 cpx #121
4745 bne end_of_level_room_count_loop
4747 ; Position the player so that we can perform an animation.
4748 jsr position_player_set_up_plotting
4750 lda $8d
4751 sta $70
4752 lda $8e
4753 sta $71
4754 jsr write_bonus
4756 lda #0 ; reset motion counter
4757 sta $578e
4759 show_end_of_level_bonus_loop:
4761 jsr wait_for_vsync
4763 clc
4764 lda $578e
4765 and #15
4766 bne end_of_level_no_animation
4768 ; Animate the player.
4770 jsr reset_unplot_buffer
4771 jsr reset_plot_buffer
4773 ; $74,$75 should be unchanged
4774 jsr unplot_character
4776 lda $5281
4777 eor #1
4778 sta $5281
4779 jsr plot_character
4781 jsr plot_buffer
4783 end_of_level_no_animation:
4784 clc
4785 lda $578e
4786 and #3
4787 bne end_of_level_no_countdown
4789 ; Transfer the bonus to the score.
4791 sed
4792 sec
4793 lda $8d
4794 sbc #1
4795 sta $8d
4796 sta $70
4797 lda $8e
4798 sbc #0
4799 sta $8e
4800 sta $71
4801 cld
4802 clc
4804 jsr write_bonus
4806 lda #9
4807 sta $70
4808 jsr add_score
4810 lda $8d
4811 and #$3f
4812 asl
4813 ldy #1
4814 jsr play_note
4816 end_of_level_no_countdown:
4817 inc $578e ; update motion counter
4818 clc
4820 lda $8d
4821 cmp #0
4822 bne show_end_of_level_bonus_loop
4824 lda $8e
4825 cmp #0
4826 bne show_end_of_level_bonus_loop
4828 lda #64 ; initialise delay counter
4829 sta $5785
4830 jsr delay
4832 ldx #0
4833 end_of_level_text_loop2:
4835 lda end_of_level_bytes2,x
4836 jsr $ffee
4837 inx
4838 cpx #25
4839 bne end_of_level_text_loop2
4841 lda $578a
4842 cmp #3
4843 bpl show_end_of_level_screen_exit
4845 lda #192 ; initialise delay counter
4846 sta $5785
4847 jsr delay
4849 show_end_of_level_screen_exit:
4850 rts
4852 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4854 write_bonus: ; $70,$71=value
4855 ; $72,$73=address of VDU codes
4857 ldx #4
4858 write_bonus_vdu_bytes:
4860 lda level_bonus_vdu_bytes,x
4861 jsr $ffee
4862 dex
4863 bpl write_bonus_vdu_bytes
4865 ldy #1
4866 write_bonus_loop:
4868 tya
4869 tax ; temporary
4871 lda $70,x
4872 sta $80
4873 lsr
4874 lsr
4875 lsr
4876 lsr
4877 tax
4878 lda score_digits,x
4879 jsr $ffee
4881 lda $80
4882 and #$0f
4883 tax
4884 lda score_digits,x
4885 jsr $ffee
4887 dey
4888 bpl write_bonus_loop
4890 clc
4891 rts
4893 position_player_set_up_plotting:
4895 jsr reset_player_position
4896 jsr remove_characters
4898 jsr reset_unplot_buffer
4899 jsr reset_plot_buffer
4901 ; Run on into the next routine.
4903 plot_the_player:
4905 lda #$80 ; plot the player
4906 sta $74
4907 lda #$52
4908 sta $75
4909 jsr plot_character
4911 jsr plot_buffer
4912 rts
4914 complete_game_vdu_bytes1: .byte 12
4915 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4916 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4917 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4919 show_complete_game:
4921 jsr blank_screen
4923 ldx #0
4924 show_complete_game_vdu_loop:
4926 lda complete_game_vdu_bytes1,x
4927 jsr $ffee
4928 inx
4929 cpx #68
4930 bne show_complete_game_vdu_loop
4932 jsr copy_completed_screen_up
4934 jsr set_complete_palette
4936 lda #255
4937 sta $5785
4939 show_complete_game_delay_loop:
4941 jsr wait_for_vsync
4943 dec $5785
4944 bne show_complete_game_no_message
4946 jsr colour1
4947 jsr show_input_message
4949 show_complete_game_no_message:
4951 lda #128
4952 ldx #0
4953 jsr $fff4
4954 cpx #0 ; fire button pressed?
4955 beq show_complete_game_no_joystick
4956 jmp show_complete_game_exit
4958 show_complete_game_no_joystick:
4960 ldx #157
4961 jsr check_key
4962 cpy #255
4963 bne show_complete_game_delay_loop
4965 show_complete_game_exit:
4966 clc
4967 rts
4969 check_high_scores:
4971 ; Start at the bottom of the table, moving scores down as necessary, and
4972 ; write in the current score at the appropriate place.
4974 lda #$86 ; current score
4975 sta $70
4976 lda #$57
4977 sta $71
4979 lda #$80
4980 sta $72
4981 lda #$51
4982 sta $73
4984 check_high_scores_loop:
4986 ldy #2
4987 check_high_scores_digits_loop:
4989 lda ($72),y
4990 cmp ($70),y ; existing score less than current score?
4991 bmi check_high_scores_move_down
4992 beq check_high_scores_digits_next ; keep checking digits if equal
4993 jmp check_high_scores_next
4995 check_high_scores_digits_next:
4996 dey
4997 bpl check_high_scores_digits_loop
4999 check_high_scores_next:
5000 clc
5001 lda $72
5002 adc #12
5003 sta $72
5004 cmp #$e0
5005 bne check_high_scores_loop
5007 ; The player's score didn't make it into the high score table.
5008 rts
5010 check_high_scores_move_down: ; $70,$71=pointer to current score
5011 ; $72,$73=pointer to old score
5013 ; The current score exceeded the existing entry. Make a note of the
5014 ; position in the high score table, insert the player's score, and take
5015 ; the old score
5017 lda $72 ; Record the position in the high score table of the
5018 sta $8d ; player's score.
5019 lda $73
5020 sta $8e
5022 lda #$e0
5023 sta $74
5024 lda #$51
5025 sta $75
5027 ldy #0
5028 insert_blank_player_name_loop:
5030 cpy #3
5031 bpl insert_blank_player_name_score_only
5033 lda ($70),y
5034 jmp insert_blank_player_name_store
5036 insert_blank_player_name_score_only:
5037 lda #32
5039 insert_blank_player_name_store:
5040 sta ($74),y
5041 iny
5042 cpy #12
5043 bne insert_blank_player_name_loop
5045 check_high_scores_move_down_loop:
5047 ldy #0
5048 check_high_scores_copy_score_and_name:
5050 lda ($72),y ; swap the current score with the score in the table
5051 tax
5052 lda ($74),y
5053 sta ($72),y
5054 txa
5055 sta ($74),y
5056 iny
5057 cpy #12
5058 bne check_high_scores_copy_score_and_name
5060 clc
5061 lda $72
5062 adc #12
5063 sta $72
5064 cmp #$e0
5065 bne check_high_scores_move_down_loop
5067 ; Draw a decorative room.
5069 jsr set_hidden_palette
5071 jsr make_empty_room
5073 lda #3
5074 sta $76
5075 sta $77
5076 jsr draw_top_line
5077 jsr draw_bottom_line
5078 jsr draw_left_line
5080 lda #0
5081 sta $77
5082 jsr draw_right_line
5084 jsr plot_room_tiles
5086 ; Add text characters to the room.
5087 jsr colour3
5089 lda #3 ; x
5090 sta $70
5091 lda #6 ; y
5092 sta $71
5094 lda #65
5095 sta $72
5097 ldx #3
5098 plot_text_characters_loop:
5100 jsr print_xy
5102 lda $70
5103 adc #4
5104 sta $70
5106 dex
5107 bpl plot_text_characters_next
5109 lda #3
5110 sta $70
5111 lda $71
5112 adc #3
5113 sta $71
5115 ldx #3
5117 plot_text_characters_next:
5119 inc $72
5120 lda $72
5121 cmp #91
5122 bne plot_text_characters_loop
5124 lda #11
5125 sta $70
5126 lda #95 ; _ representing a space
5127 sta $72
5128 jsr print_xy
5130 lda #15
5131 sta $70
5132 lda #60 ; < representing delete
5133 sta $72
5134 jsr print_xy
5136 ; Put the player in the centre of the room.
5137 jsr position_player_set_up_plotting
5139 lda #0 ; reset motion counter
5140 sta $578e
5142 lda #0 ; not on a character
5143 sta $578d
5145 lda #0 ; reset the level number so that the correct tiles are used
5146 sta $578a
5148 lda #3 ; cursor position in the high score entry held in $8d,$8e
5149 sta $8f
5151 jsr set_standard_palette
5153 ldx #0
5154 high_score_vdu_loop:
5156 lda high_score_vdu_bytes,x
5157 jsr $ffee
5158 inx
5159 cpx #39
5160 bne high_score_vdu_loop
5162 high_score_entry_loop:
5164 jsr reset_unplot_buffer
5165 jsr reset_plot_buffer
5167 jsr move_player
5168 ; Check if the player leaves the room.
5169 bcc high_score_entry_check_position
5170 jmp high_score_entry_after_loop
5172 high_score_entry_check_position:
5174 lda $5285 ; dx
5175 cmp #2
5176 beq high_score_entry_maybe_aligned
5177 jmp high_score_entry_not_aligned
5179 high_score_entry_maybe_aligned:
5181 lda $5282 ; y
5182 tay
5183 cmp #8
5184 bpl high_score_entry_not_aligned
5186 lda $5284 ; x
5187 tax
5188 cmp #9
5189 beq high_score_entry_not_aligned
5190 and #1
5191 beq high_score_entry_not_aligned
5193 lda $5283 ; dy
5194 cmp #2
5195 bmi high_score_entry_aligned
5196 jmp high_score_entry_not_aligned
5198 lda $5282 ; y again (don't apply the touching rule to the bottom
5199 cmp #7 ; row of characters)
5200 beq high_score_entry_not_aligned
5202 iny ; we are really touching the character below
5204 high_score_entry_aligned:
5206 lda $578d
5207 cmp #1
5208 beq high_score_entry_next
5210 ; The player is aligned with a letter.
5211 txa
5212 sec
5213 sbc #1
5214 lsr
5215 sta $7e ; record (x - 1) / 2
5217 tya ; recall y
5218 sec
5219 sbc #1
5220 asl
5221 asl ; (y - 1) * 4
5222 clc
5224 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5225 adc #65
5226 sta $7e ; record the ASCII code
5228 cmp #91
5229 bmi insert_character
5231 cmp #92
5232 beq delete_character
5234 ; Insert a space.
5235 lda #32
5236 sta $7e
5238 insert_character:
5239 lda $8f
5240 cmp #12
5241 bpl high_score_entry_pressed
5243 tay ; insert the character
5244 lda $7e
5245 sta ($8d),y
5246 jsr print_high_score_character
5248 inc $8f
5249 jmp high_score_entry_pressed
5251 delete_character:
5252 lda $8f
5253 cmp #4
5254 bmi high_score_entry_pressed
5256 cmp #12
5257 beq high_score_delete_previous_character
5259 tay
5260 lda #32 ; insert a space
5261 sta ($8d),y
5262 jsr print_high_score_character
5264 high_score_delete_previous_character:
5265 dec $8f
5266 lda $8f
5267 tay ; insert a space
5268 lda #32
5269 sta ($8d),y
5270 jsr print_high_score_character
5272 high_score_entry_pressed:
5273 lda #1
5274 sta $578d
5275 jmp high_score_entry_next
5277 high_score_entry_not_aligned:
5278 lda #0
5279 sta $578d
5281 high_score_entry_next:
5283 jsr wait_for_vsync
5284 jsr plot_buffer
5286 jmp high_score_entry_loop
5288 inc $578e
5289 clc
5291 high_score_entry_after_loop:
5292 clc
5294 jsr cls
5295 jsr set_hidden_palette
5297 rts
5299 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5301 cls:
5302 lda #12
5303 jsr $ffee
5304 rts
5306 colour1:
5307 lda #17
5308 jsr $ffee
5309 lda #1
5310 jsr $ffee
5311 rts
5313 colour3:
5314 lda #17
5315 jsr $ffee
5316 lda #3
5317 jsr $ffee
5318 rts
5320 print_high_score_character: ; A=ASCII code
5322 clc
5323 sta $72 ; store the character
5324 lda $8f
5325 adc #3
5326 sta $70 ; store the x position of the character
5327 lda #30
5328 sta $71
5329 ; Run on into the next routine.
5331 print_xy:
5333 lda #31
5334 jsr $ffee
5335 lda $70
5336 jsr $ffee
5337 lda $71
5338 jsr $ffee
5339 lda $72
5340 jsr $ffee
5341 rts
5343 disable_sound: ; X=1 (disable); X=0 (enable)
5345 lda #210
5346 ldy #0
5347 jmp $fff4 ; optimise away the rts
5349 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5350 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5352 start_new_game:
5354 ; Clear the screen.
5355 jsr cls
5357 ; Set the level.
5358 lda #0
5359 sta $578a
5361 ; Set the score.
5362 lda #0
5363 sta $5786
5364 lda #0
5365 sta $5787
5366 lda #0
5367 sta $5788
5369 ; Blank the screen now because it will be blanked before the room is shown
5370 ; and otherwise the strength bar will show briefly.
5371 jsr blank_screen
5373 ; Set the player's strength.
5374 lda #0
5375 sta $5784
5376 lda #64
5377 sta $70
5378 jsr add_strength
5380 ; Set the projectile type.
5381 lda #0
5382 sta $5789
5384 rts
5386 reset_player_position:
5388 lda #1 ; player
5389 sta $5280
5390 lda #6 ; down (first frame)
5391 sta $5281
5392 lda #4 ; y=4
5393 sta $5282
5394 lda #2 ; dy=2
5395 sta $5283
5396 lda #4 ; x=4
5397 sta $5284
5398 lda #3 ; dx=3
5399 sta $5285
5401 rts
5403 start_level:
5405 ; Clear the item/player flags.
5406 lda #0
5407 sta $5780
5409 ; Set current room.
5411 ldx $578a
5412 lda start_rooms_y,x
5413 sta $5782
5414 lda start_rooms_x,x
5415 sta $5783
5417 ; Set the player's position.
5419 jsr reset_player_position
5421 ; Reset the weapon counter.
5422 lda #0
5423 sta $577f
5425 ; Fill the treasure table with objects.
5426 ldx $578a ; level
5427 lda key_rooms,x
5428 sta $80
5430 ldx $578a ; level
5431 lda seeds,x
5432 adc #1
5433 and #31
5434 sta $7c
5435 clc
5436 lda seeds,x
5437 adc #2
5438 and #31
5439 sta $7d
5440 clc
5442 lda $578a ; create an upper limit on the weapon type found in this level
5443 adc #2
5444 sta $5781
5445 clc
5447 lda #$00
5448 sta $8e
5449 lda #$52
5450 sta $8f
5452 ldy #0
5453 start_level_add_treasure_loop:
5455 cpy $80 ; check for the key room
5456 bne start_level_add_treasure_item
5458 lda #5 ; the value to store is type + 1
5459 jmp start_level_add_treasure_store
5461 start_level_add_treasure_item:
5462 clc
5463 jsr unlimited_values
5464 and #$0f
5465 cmp #0
5466 beq start_level_add_treasure_none
5468 clc
5469 sta $8c
5470 tya
5471 adc $8c
5472 and #31
5473 clc
5474 tax
5475 lda treasure_table,x
5477 cmp #4
5478 bmi start_level_add_treasure_weapon
5480 clc
5481 adc #1
5482 jmp start_level_add_treasure_store
5484 start_level_add_treasure_weapon:
5486 ; Only add weapons with types that equal the level number or exceed it
5487 ; by one.
5488 cmp $5781
5489 bcs start_level_add_treasure_none
5491 clc
5492 adc #1 ; store values 0-8 as values 1-9
5493 jmp start_level_add_treasure_store
5495 start_level_add_treasure_none:
5496 clc
5497 lda #0 ; do not put treasure in this room
5499 start_level_add_treasure_store:
5500 clc
5501 sta ($8e),y ; add the item to the table
5503 iny
5504 cpy #121
5505 bmi start_level_add_treasure_loop
5507 ; Write the status text.
5508 ldx #0
5509 write_status_text_loop:
5510 lda status_vdu_bytes,x
5511 jsr $ffee
5512 inx
5513 cpx #25
5514 bmi write_status_text_loop
5516 jsr write_score
5518 clc
5519 rts
5521 main:
5522 jsr init
5524 main_loop:
5526 jsr show_title
5528 jsr start_new_game
5530 level_loop:
5532 jsr start_level
5534 game_loop:
5536 jsr remove_characters
5538 jsr reset_unplot_buffer
5539 jsr reset_plot_buffer
5541 lda $5782 ; current room (y)
5542 sta $78
5543 lda $5783 ; current room (x)
5544 sta $79
5545 jsr plot_room
5546 jsr set_room_palette
5547 jsr create_enemy_positions
5548 jsr add_treasure
5550 jsr plot_the_player
5552 lda #0 ; reset projectile counter
5553 sta $578d
5555 lda #0 ; reset motion counter
5556 sta $578e
5558 lda #63 ; reset generation counter
5559 sta $578f
5561 room_loop:
5562 jsr reset_unplot_buffer
5563 jsr reset_plot_buffer
5565 jsr move_characters
5566 jsr move_projectile
5568 lda $5780 ; is player out of strength ($40), leaving the
5569 and #$c2 ; level (0x80) or completing the game (0x02)?
5570 beq room_loop_player_move
5571 clc
5573 dec $5785 ; leave the loop when the delay
5574 bne room_loop_delay_next
5575 jmp after_room_loop ; counter is about to reset
5577 room_loop_delay_next:
5579 lda $5281 ; leave the loop when the player demise
5580 cmp #11 ; animation has finished
5581 beq room_loop_after_player_move
5582 clc
5584 lda $578e
5585 and #7
5586 bne room_loop_after_player_move
5588 lda $5780 ; skip the animation if leaving the level or
5589 and #$82 ; completing the game
5590 bne room_loop_after_player_move
5592 ; Show the demise animation when appropriate.
5594 lda #$80
5595 sta $74
5596 lda #$52
5597 sta $75
5599 jsr unplot_character
5601 inc $5281
5602 jsr plot_character
5603 jmp room_loop_after_player_move
5605 room_loop_player_move:
5607 ; See if it is time to generate a new enemy.
5608 lda $578f
5609 cmp #0
5610 bne no_emerge_characters
5611 jsr emerge_characters
5613 no_emerge_characters:
5614 clc
5616 jsr check_fire_key
5617 jsr move_player
5618 bcs after_room_loop ; check if we are leaving the level
5620 room_loop_after_player_move:
5621 clc
5623 lda #19
5624 jsr $fff4
5625 jsr plot_buffer
5627 ldx #143 ; Escape key check
5628 jsr check_key
5629 cpy #255
5630 beq main_loop_play_again
5632 ldx #174 ; S key check
5633 jsr check_key
5634 cpy #255
5635 bne no_set_sound
5637 ldx #0
5638 jsr disable_sound
5639 jmp after_sound_checks
5641 no_set_sound:
5643 ldx #239 ; Q key check
5644 jsr check_key
5645 cpy #255
5646 bne after_sound_checks
5648 ldx #1
5649 jsr disable_sound
5651 after_sound_checks:
5653 ldx #200 ; P key check
5654 jsr check_key
5655 cpy #255
5656 bne no_pause
5658 pause_loop:
5660 ldx #201 ; O key check
5661 jsr check_key
5662 cpy #255
5663 bne pause_loop
5665 no_pause:
5666 clc
5668 lda $578d
5669 cmp #0
5670 beq room_loop_no_update_projectile_counter
5672 dec $578d
5674 room_loop_no_update_projectile_counter:
5676 dec $578f ; update generation counter
5678 inc $578e ; update motion counter
5679 clc
5680 jmp room_loop
5682 after_room_loop:
5683 clc
5685 lda $5780
5686 and #$80
5687 bne exit_level
5689 lda $5780
5690 and #$40
5691 bne game_over
5693 lda $5780
5694 and #$02
5695 bne complete_game
5697 jmp game_loop
5699 exit_level:
5701 jsr show_end_of_level_screen
5703 inc $578a
5704 clc
5705 jmp level_loop
5707 game_over:
5708 jsr show_game_over
5709 jmp main_loop_play_again
5711 complete_game:
5712 jsr show_end_of_level_screen
5713 jsr show_complete_game
5714 jmp main_loop_play_again
5716 main_loop_play_again:
5717 jsr cls
5719 ; Check the score against the high scores.
5720 jsr check_high_scores
5722 jmp main_loop
5724 exit:
5725 clc
5726 rts
