junglejourney

view mapcode.oph @ 199:aa9f05624182

Ensured that the keyboard controls cannot be used if the game is started with the joystick's Fire button. Fixed use of incorrectly initialised zero page memory when moving the projectile - this could cause an enemy to be destroyed if the player stood by a wall and fired a projectile at it. Added a *TAPE call to the loader to ensure that DFS workspace is no longer in use.
author David Boddie <david@boddie.org.uk>
date Sun Oct 02 19:45:54 2011 +0200
parents 8ff47d1667f7
children 2e43c7e90f42
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 #4
2298 bmi emerge_type_ok
2300 sec
2301 sbc #4
2302 clc
2304 emerge_type_ok:
2305 cmp $5781 ; only allow the appropriate enemies for this level
2306 bmi emerge_type_exit
2308 sec
2309 sbc $5781
2310 clc
2312 emerge_type_exit:
2313 asl
2314 asl
2315 asl
2316 asl
2317 clc
2318 rts
2320 emerge_character: ; $74,$75=character address
2322 lda #63
2323 sta $578f
2325 jsr unlimited_values
2326 and #$0f
2327 tax
2328 lda $0ee0,x
2329 cmp #0 ; check for an invalid value and exit if found
2330 beq emerge_character_exit
2332 sta $80 ; temporary
2333 lda $0ef0,x
2334 tax
2336 ; Add an emerging enemy.
2338 ldy #0
2339 lda #3 ; emerge/explosion
2340 sta ($74),y
2342 jsr emerge_type ; obtain an enemy type
2343 iny
2344 sta ($74),y
2346 txa
2347 iny
2348 sta ($74),y ; store the y position
2349 lda #1
2350 iny
2351 sta ($74),y ; store the dy offset
2353 lda $80
2354 iny
2355 sta ($74),y ; store the x position
2356 lda #0
2357 iny
2358 sta ($74),y ; store the dx offset
2360 jsr plot_character
2362 ldx #5
2363 jsr play_sound
2365 emerge_character_exit:
2366 clc
2367 rts
2369 emerge_explode: ; $74,$75=character address
2371 jsr unplot_character
2373 ldy #1
2374 lda ($74),y ; direction/animation
2375 tax
2376 adc #1 ; update the counter
2377 and #3 ; mask off everything else
2378 sta $80 ; store the masked counter value
2379 bne move_characters_explosion_not_finished
2381 txa
2382 and #4
2383 bne move_characters_remove_character
2385 ; For emerges, convert into an enemy.
2386 txa
2387 and #$70 ; only keep bits 4,5,6
2388 ora #8 ; make this an enemy
2390 ldy #0
2391 sta ($74),y ; update the type (>= 8)
2392 iny
2393 lda $7d ; prepare the direction and animation offset
2394 and #$0c
2395 sta ($74),y
2397 jsr plot_character
2398 jmp emerge_explode_exit
2400 move_characters_remove_character:
2402 ; For finished explosions, just write 0 into the character array.
2403 lda #0
2404 ldy #0
2405 sta ($74),y
2406 jmp emerge_explode_exit
2408 move_characters_explosion_not_finished:
2409 txa
2410 and #$fc
2411 ora $80
2413 ldy #1
2414 sta ($74),y
2416 jsr plot_character
2418 emerge_explode_exit:
2419 clc
2420 rts
2422 animate_enemy_left: ; $74,$75=character address
2424 ; Set the direction and toggle the animation bit.
2426 ldy #1
2427 lda ($74),y
2428 and #$fb ; keep vertical direction bit and animation bits
2429 sta ($74),y ; left (horizontal directional bit is 0)
2431 rts
2433 move_enemy_left: ; $74,$75=character address
2435 ldy #5
2436 lda ($74),y ; read dx
2437 cmp #0
2438 beq move_enemy_left_check_x
2440 sec
2441 sbc #1
2442 ldy #5
2443 sta ($74),y ; dx
2444 clc
2445 jmp animate_enemy_left ; optimise away the rts
2447 move_enemy_left_check_x:
2449 ; Check the x offset.
2451 ldy #4
2452 lda ($74),y ; x
2453 cmp #0
2454 beq move_enemy_left_exit
2456 sec
2457 sbc #1 ; x - 1
2458 sta $81 ; temporary
2459 ldy #2
2460 lda ($74),y ; load the y offset
2461 tax ; as an index
2462 lda room_row_offsets_low,x ; read the address of the row
2463 sta $70
2464 lda #$57
2465 sta $71
2466 ldy $81 ; temporary (x - 1)
2467 lda ($70),y ; load the tile to the left
2469 cmp #0
2470 bne move_enemy_left_exit
2472 ldy #3
2473 lda ($74),y ; dy
2474 cmp #2
2475 bmi move_enemy_allow_left
2477 clc
2478 lda $70 ; dy > 1 so we need to check another tile
2479 adc #10
2480 sta $70
2481 ldy $81 ; temporary (x - 1)
2482 lda ($70),y ; load the tile below and to the left
2484 cmp #0
2485 bne move_enemy_left_exit
2487 move_enemy_allow_left:
2488 lda $81
2489 ldy #4
2490 sta ($74),y ; store the new room x offset
2491 lda #3
2492 ldy #5
2493 sta ($74),y ; dx = 3
2494 clc
2495 jmp animate_enemy_left ; optimise away the rts
2497 move_enemy_left_exit:
2498 sec
2499 rts
2501 animate_enemy_right: ; $74,$75=character address
2503 ; Set the direction and toggle the animation bit.
2505 ldy #1
2506 lda ($74),y
2507 ora #$04 ; right (keep vertical direction bit and animation bits)
2508 sta ($74),y
2510 rts
2512 move_enemy_right: ; $74,$75=character_address
2514 ldy #5
2515 lda ($74),y ; read dx
2516 cmp #0
2517 beq move_enemy_right_check_x
2518 cmp #3
2519 beq move_enemy_right_tile
2521 clc
2522 adc #1
2523 ldy #5
2524 sta ($74),y
2525 jmp animate_enemy_right ; optimise away the rts
2527 move_enemy_right_check_x: ; Check the x offset.
2529 ldy #4
2530 lda ($74),y ; x
2531 cmp #9
2532 beq move_enemy_right_exit
2534 clc
2535 adc #1 ; x + 1
2536 sta $81 ; temporary (x + 1)
2537 ldy #2
2538 lda ($74),y ; load the y offset
2539 tax ; as an index
2540 lda room_row_offsets_low,x ; read the address of the row
2541 sta $70
2542 lda #$57
2543 sta $71
2544 ldy $81 ; temporary (x + 1)
2545 lda ($70),y ; load the tile to the right
2547 cmp #0
2548 bne move_enemy_right_exit
2550 ldy #3
2551 lda ($74),y ; dy
2552 cmp #2
2553 bmi move_enemy_allow_right
2555 clc ; dy > 1 so we need to check another tile
2556 lda $70
2557 adc #10
2558 sta $70
2559 ldy $81 ; temporary (x + 1)
2560 lda ($70),y ; load the tile below and to the right
2562 cmp #0
2563 bne move_enemy_right_exit
2565 move_enemy_allow_right:
2566 clc
2568 ldy #5
2569 lda ($74),y ; dx
2570 adc #1
2571 sta ($74),y ; update dx
2572 clc
2573 jmp animate_enemy_right ; optimise away the rts
2575 move_enemy_right_tile:
2576 clc
2578 ldy #4
2579 lda ($74),y ; x
2580 adc #1
2581 sta ($74),y ; store the new room x offset
2582 lda #0
2583 iny
2584 sta ($74),y ; dx = 0
2585 clc
2586 jmp animate_enemy_right ; optimise away the rts
2588 move_enemy_right_exit:
2589 sec
2590 rts
2592 animate_enemy_up: ; $74,$75=character address
2594 ; Set the direction and toggle the animation bit.
2596 ldy #1
2597 lda ($74),y
2598 and #$f7 ; keep horizontal direction bit and animation bits
2599 sta ($74),y
2601 rts
2603 move_enemy_up: ; $74,$75=character address
2605 ldy #3
2606 lda ($74),y ; read dy
2607 cmp #0
2608 beq move_enemy_up_check_y
2610 sec
2611 sbc #1
2612 ldy #3
2613 sta ($74),y ; dy
2614 clc
2615 jmp animate_enemy_up ; optimise away the rts
2617 move_enemy_up_check_y:
2619 ; Check the y offset.
2621 ldy #2
2622 lda ($74),y ; y
2623 cmp #0
2624 beq move_enemy_up_exit
2626 tax ; use the y offset as an index
2627 dex ; y - 1
2628 ldy #4
2629 lda ($74),y ; load the x offset
2630 sta $81 ; temporary (x)
2631 tay
2632 lda room_row_offsets_low,x ; read the address of the row
2633 sta $70
2634 lda #$57
2635 sta $71
2636 lda ($70),y ; load the tile above
2638 cmp #0
2639 bne move_enemy_up_exit
2641 ldy #5
2642 lda ($74),y ; dx
2643 cmp #0
2644 beq move_enemy_allow_up
2646 clc ; dx != 0 so we need to check another tile
2647 ldy $81
2648 iny
2649 lda ($70),y ; load the tile above and to the right
2651 cmp #0
2652 bne move_enemy_up_exit
2654 move_enemy_allow_up:
2655 txa
2656 ldy #2
2657 sta ($74),y ; store the new room y offset
2658 lda #3
2659 iny
2660 sta ($74),y ; dy = 3
2661 clc
2662 jmp animate_enemy_up ; optimise away the rts
2664 move_enemy_up_exit:
2665 sec
2666 rts
2668 animate_enemy_down: ; $74,$75=character address
2670 ; Set the direction and toggle the animation bit.
2672 ldy #1
2673 lda ($74),y
2674 ora #$08 ; down
2675 sta ($74),y
2677 rts
2679 move_enemy_down: ; $74,$75=character address
2681 ldy #3
2682 lda ($74),y ; dy
2683 cmp #1
2684 beq move_enemy_down_check_y
2685 cmp #3
2686 beq move_enemy_down_tile
2688 adc #1
2689 ldy #3
2690 sta ($74),y ; dy
2691 clc
2692 jmp animate_enemy_down ; optimise away the rts
2694 move_enemy_down_check_y:
2696 ; Check the y offset.
2698 ldy #2
2699 lda ($74),y
2700 cmp #9
2701 beq move_enemy_down_exit
2703 clc
2704 adc #1 ; y + 1
2705 tax
2706 ldy #4
2707 lda ($74),y ; load the x offset
2708 sta $81 ; temporary
2709 tay
2710 lda room_row_offsets_low,x ; read the address of the row
2711 sta $70
2712 lda #$57
2713 sta $71
2714 lda ($70),y ; load the tile below
2716 cmp #0
2717 bne move_enemy_down_exit
2719 ldy #5
2720 lda ($74),y ; dx
2721 cmp #0
2722 beq move_enemy_allow_down
2724 clc ; dx != 0 so we need to check another tile
2725 ldy $81 ; x
2726 iny
2727 lda ($70),y ; load the tile below and to the right
2729 cmp #0
2730 bne move_enemy_down_exit
2732 move_enemy_allow_down:
2733 clc
2735 ldy #3
2736 lda ($74),y ; dy
2737 adc #1
2738 sta ($74),y ; update dy
2739 clc
2740 jmp animate_enemy_down ; optimise away the rts
2742 move_enemy_down_tile:
2743 clc
2745 ldy #2
2746 lda ($74),y ; y
2747 adc #1
2748 sta ($74),y ; store the new room y offset
2749 lda #0
2750 iny
2751 sta ($74),y ; dy = 0
2752 clc
2753 jmp animate_enemy_down ; optimise away the rts
2755 move_enemy_down_exit:
2756 sec
2757 rts
2759 move_enemy_animate: ; $74,$75=character address
2761 ldy #1
2762 lda ($74),y ; direction/animation
2763 sta $81
2764 and #$03
2765 adc #1
2766 and #$03 ; keep animation bits
2767 sta $8f
2768 lda $81
2769 and #$fc ; mask off the animation bits
2770 ora $8f
2771 sta ($74),y
2772 rts
2774 move_enemy_next_direction: .byte $04, $0c, $00, $08
2776 move_enemy: ; $74,$75=character address
2778 lda #0
2779 sta $8d ; vertical motion value (0=no motion; 1=up; 2=down)
2780 lda #0
2781 sta $8e ; horizontal motion value (0=no motion; 1=left; 2=right)
2783 lda ($74),y ; read the enemy number (Y should be zero)
2784 and #$10
2785 beq move_enemy_homing
2786 clc
2788 ; This enemy is a non-homing enemy.
2790 jsr unplot_character ; unplot now before we change the sprite used
2792 ldy #1
2793 lda ($74),y
2794 and #$f0
2795 cmp #$f0
2796 bne move_enemy_set_direction
2797 clc
2799 ldy #1
2800 lda ($74),y
2801 and #$0c
2802 ror
2803 ror
2804 tax
2805 lda move_enemy_next_direction,x
2806 sta ($74),y
2808 move_enemy_set_direction:
2809 clc
2811 ldy #1
2812 lda ($74),y
2813 sta $7b
2815 adc #$10
2816 sta ($74),y
2817 clc
2819 lda $7b
2820 and #$04
2821 ror
2822 ror
2823 adc #1
2824 sta $8e
2826 lda $7b
2827 and #$08
2828 ror
2829 ror
2830 ror
2831 adc #1
2832 sta $8d
2834 jmp move_enemy_with_direction
2836 move_enemy_homing:
2838 ldy #2
2839 lda ($74),y ; y
2840 cmp $5282 ; player y
2841 bmi move_enemy_downwards
2842 bne move_enemy_upwards
2844 ldy #3
2845 lda ($74),y ; dy
2846 cmp $5283 ; player y
2847 beq move_enemy_horizontally
2848 bpl move_enemy_upwards
2850 move_enemy_downwards:
2851 lda #2
2852 sta $8d
2853 jmp move_enemy_horizontally
2855 move_enemy_upwards:
2856 lda #1
2857 sta $8d
2858 ;jmp move_enemy_horizontally
2860 move_enemy_horizontally:
2861 ldy #4
2862 lda ($74),y ; x
2863 cmp $5284 ; player x
2864 bmi move_enemy_rightwards
2865 bne move_enemy_leftwards
2867 ldy #5
2868 lda ($74),y ; dx
2869 cmp #0
2870 beq move_enemy_with_direction_unplot
2871 bpl move_enemy_leftwards
2873 move_enemy_rightwards:
2874 lda #2
2875 sta $8e
2876 jmp move_enemy_with_direction_unplot
2878 move_enemy_leftwards:
2879 lda #1
2880 sta $8e
2882 move_enemy_with_direction_unplot:
2883 clc
2885 jsr unplot_character
2887 move_enemy_with_direction:
2888 clc
2890 lda $8e
2891 cmp #1
2892 bne move_enemy_not_left
2893 jsr move_enemy_left
2894 clc
2895 jmp move_enemy_not_right
2897 move_enemy_not_left:
2898 lda $8e
2899 cmp #2
2900 bne move_enemy_not_right
2901 jsr move_enemy_right
2902 clc
2904 move_enemy_not_right:
2905 lda $8d
2906 cmp #1
2907 bne move_enemy_not_up
2908 jsr move_enemy_up
2909 clc
2910 jmp move_enemy_toggle
2912 move_enemy_not_up:
2913 lda $8d
2914 cmp #2
2915 bne move_enemy_toggle
2916 jsr move_enemy_down
2918 move_enemy_toggle:
2919 clc
2920 jsr move_enemy_animate
2921 jmp plot_character ; optimise away the rts
2923 move_enemy_exit:
2924 clc
2925 rts
2927 create_explosion: ; X=y, Y=x
2929 lda #3
2930 sta $52a4
2931 lda #4
2932 sta $52a5
2933 txa
2934 sta $52a6
2935 lda #1
2936 sta $52a7
2937 tya
2938 sta $52a8
2939 lda #0
2940 sta $52a9
2941 rts
2943 move_projectile_left:
2945 lda $528b
2946 cmp #0
2947 beq move_projectile_left_check_x
2949 dec $528b
2950 clc
2951 rts
2953 move_projectile_left_check_x:
2955 lda $528a
2956 cmp #0
2957 bne move_projectile_left_in_room
2958 jmp move_projectile_left_exit
2960 move_projectile_left_in_room:
2961 tay
2962 dey ; x - 1
2963 ldx $5288 ; y
2964 lda room_row_offsets_low,x ; read the address of the row
2965 sta $70
2966 lda #$57
2967 sta $71
2968 lda ($70),y ; load the tile to the left
2970 cmp #0
2971 bne move_projectile_left_wall
2973 lda $5289 ; dy
2974 cmp #3
2975 bmi move_projectile_allow_left
2977 clc ; dy > 2 so we need to check another tile
2978 lda $70
2979 adc #10
2980 sta $70
2981 lda ($70),y ; load the tile below and to the left
2982 inx ; y += 1
2984 cmp #0
2985 bne move_projectile_left_wall
2987 move_projectile_allow_left:
2989 sty $528a ; x
2990 lda #3
2991 sta $528b ; dx = 3
2993 clc
2994 rts
2996 move_projectile_left_wall: ; the projectile hit a wall
2997 clc
2999 lda $5287 ; type 2 can pass through walls
3000 and #$06
3001 cmp #4
3002 beq move_projectile_allow_left
3004 cmp #2
3005 bne move_projectile_left_not_boomerang
3007 lda $5287
3008 and #$0f
3009 cmp #8
3010 bpl move_projectile_left_exit
3012 ldx $577f ; weapon counter
3013 ora boomerang_horizontal,x
3014 sta $5287
3015 clc
3016 rts ; exit without moving or registering a collision
3018 move_projectile_left_not_boomerang:
3020 cmp #6 ; type 3 can destroy certain walls
3021 bne move_projectile_left_exit
3023 lda ($70),y ; load the tile to the left
3024 cmp #1 ; decoration can be destroyed
3025 bne move_projectile_left_exit
3026 clc
3028 lda #0
3029 sta ($70),y
3031 ; X=y, Y=x
3032 jsr create_explosion
3033 jsr plot_blank_xy ; corrupted X
3035 lda #$a4
3036 sta $74
3037 lda #$52
3038 sta $75
3039 jsr plot_character
3041 ldx #0
3042 jsr play_sound
3044 lda #16 ; prevent the player from firing a new
3045 sta $578d ; projectile until the explosion has finished
3047 move_projectile_left_exit:
3048 sec
3049 rts
3051 boomerang_horizontal: .byte $28, $38
3053 move_projectile_right:
3055 ; Fire right.
3057 lda $528b
3058 cmp #2
3059 beq move_projectile_right_check_x
3060 cmp #3
3061 beq move_projectile_right_tile
3063 inc $528b
3064 clc
3065 rts
3067 move_projectile_right_check_x:
3069 lda $528a ; x
3070 cmp #9
3071 bne move_projectile_right_not_edge
3072 jmp move_projectile_right_exit
3074 move_projectile_right_not_edge:
3075 clc
3076 tay
3077 iny ; x + 1
3078 ldx $5288 ; y
3079 lda room_row_offsets_low,x ; read the address of the row
3080 sta $70
3081 lda #$57
3082 sta $71
3083 lda ($70),y ; load the tile to the right
3085 cmp #0
3086 bne move_projectile_right_wall
3088 lda $5289 ; dy
3089 cmp #3
3090 bmi move_projectile_allow_right
3092 clc ; dy > 2 so we need to check another tile
3093 lda $70
3094 adc #10
3095 sta $70
3096 lda ($70),y ; load the tile below and to the right
3097 inx ; y += 1
3099 cmp #0
3100 bne move_projectile_right_wall
3102 move_projectile_allow_right:
3104 inc $528b ; dx
3105 clc
3106 rts
3108 move_projectile_right_tile:
3110 inc $528a ; x
3111 lda #0
3112 sta $528b ; dx
3113 clc
3114 rts
3116 move_projectile_right_wall: ; the projectile hit a wall
3117 clc
3119 lda $5287 ; type 2 can pass through walls
3120 and #$06
3121 cmp #4
3122 beq move_projectile_allow_right
3124 cmp #2
3125 bne move_projectile_right_not_boomerang
3127 lda $5287
3128 and #$0f
3129 cmp #8
3130 bpl move_projectile_right_exit
3132 ldx $577f ; weapon counter
3133 ora boomerang_horizontal,x
3134 sta $5287
3135 clc
3136 rts ; exit without moving or registering a collision
3138 move_projectile_right_not_boomerang:
3140 cmp #6 ; type 3 can destroy certain walls
3141 bne move_projectile_right_exit
3143 lda ($70),y ; load the tile to the right
3144 cmp #1 ; decoration can be destroyed
3145 bne move_projectile_right_exit
3146 clc
3148 lda #0
3149 sta ($70),y
3151 ; X=y, Y=x
3152 jsr create_explosion
3153 jsr plot_blank_xy ; corrupted X
3155 lda #$a4
3156 sta $74
3157 lda #$52
3158 sta $75
3159 jsr plot_character
3161 ldx #0
3162 jsr play_sound
3164 lda #16 ; prevent the player from firing a new
3165 sta $578d ; projectile until the explosion has finished
3167 move_projectile_right_exit:
3168 sec
3169 rts
3171 move_projectile_up:
3173 lda $5289 ; read dy
3174 cmp #0
3175 beq move_projectile_up_check_y
3177 dec $5289
3178 clc
3179 rts
3181 move_projectile_up_check_y: ; Check the y offset.
3183 lda $5288
3184 cmp #0
3185 bne move_projectile_up_not_edge
3186 jmp move_projectile_up_exit
3188 move_projectile_up_not_edge:
3189 tax ; use the y offset as an index
3190 dex ; y - 1
3191 ldy $528a ; load the x offset
3192 lda room_row_offsets_low,x ; read the address of the row
3193 sta $70
3194 lda #$57
3195 sta $71
3196 lda ($70),y ; load the tile above
3198 cmp #0
3199 bne move_projectile_up_wall
3201 lda $528b ; dx
3202 cmp #3
3203 bmi move_projectile_allow_up
3205 clc ; dx > 2 so we need to check another tile
3206 iny
3207 lda ($70),y ; load the tile above and to the right
3209 cmp #0
3210 bne move_projectile_up_wall
3212 move_projectile_allow_up:
3213 txa
3214 sta $5288 ; store the new room y offset
3215 lda #3
3216 sta $5289 ; dy = 3
3218 clc
3219 rts
3221 move_projectile_up_wall: ; the projectile hit a wall
3222 clc
3224 lda $5287 ; type 2 can pass through walls
3225 and #$06
3226 cmp #4
3227 beq move_projectile_allow_up
3229 cmp #2
3230 bne move_projectile_up_not_boomerang
3232 lda $5287
3233 and #$0f
3234 cmp #8
3235 bpl move_projectile_up_exit
3237 ldx $577f ; weapon counter
3238 ora boomerang_vertical,x
3239 sta $5287
3240 clc
3241 rts ; exit without moving or registering a collision
3243 move_projectile_up_not_boomerang:
3245 cmp #6 ; type 3 can destroy certain walls
3246 bne move_projectile_up_exit
3248 lda ($70),y ; load the tile above
3249 cmp #1 ; decoration can be destroyed
3250 bne move_projectile_up_exit
3251 clc
3253 lda #0
3254 sta ($70),y
3256 ; X=y, Y=x
3257 jsr create_explosion
3258 jsr plot_blank_xy ; corrupted X
3260 lda #$a4
3261 sta $74
3262 lda #$52
3263 sta $75
3264 jsr plot_character
3266 ldx #0
3267 jsr play_sound
3269 lda #16 ; prevent the player from firing a new
3270 sta $578d ; projectile until the explosion has finished
3272 move_projectile_up_exit:
3273 sec
3274 rts
3276 boomerang_vertical: .byte $08, $18
3278 move_projectile_down:
3280 lda $5289 ; read dy
3281 cmp #2
3282 beq move_projectile_down_check_y
3283 cmp #3
3284 beq move_projectile_down_tile
3286 inc $5289 ; 0 <= dy < 3
3287 clc
3288 rts
3290 move_projectile_down_check_y: ; Check the y offset.
3292 lda $5288
3293 cmp #9
3294 bne move_projectile_down_in_room
3295 jmp move_projectile_down_exit
3297 move_projectile_down_in_room:
3298 clc
3299 tax
3300 inx ; y + 1
3301 ldy $528a ; load the x offset
3302 lda room_row_offsets_low,x ; read the address of the row
3303 sta $70
3304 lda #$57
3305 sta $71
3306 lda ($70),y ; load the tile below
3308 cmp #0
3309 bne move_projectile_down_wall
3311 lda $528b ; dx
3312 cmp #3
3313 bmi move_projectile_allow_down
3315 clc ; dx > 2 so we need to check another tile
3316 iny
3317 lda ($70),y ; load the tile below and to the right
3319 cmp #0
3320 bne move_projectile_down_wall
3322 move_projectile_allow_down:
3324 inc $5289 ; update dy
3325 clc
3326 rts
3328 move_projectile_down_tile:
3330 inc $5288 ; store the new room y offset
3331 lda #0
3332 sta $5289 ; dy = 0
3333 clc
3334 rts
3336 move_projectile_down_wall: ; the projectile hit a wall
3337 clc
3339 lda $5287 ; type 2 can pass through walls
3340 and #$06
3341 cmp #4
3342 beq move_projectile_allow_down
3344 cmp #2
3345 bne move_projectile_down_not_boomerang
3347 lda $5287
3348 and #$0f
3349 cmp #8
3350 bpl move_projectile_down_exit
3352 ldx $577f ; weapon counter
3353 ora boomerang_vertical,x
3354 sta $5287
3355 clc
3356 rts ; exit without moving or registering a collision
3358 move_projectile_down_not_boomerang:
3360 cmp #6 ; type 3 can destroy certain walls
3361 bne move_projectile_down_exit
3363 lda ($70),y ; load the tile below
3364 cmp #1 ; decoration can be destroyed
3365 bne move_projectile_down_exit
3366 clc
3368 lda #0
3369 sta ($70),y
3371 ; X=y, Y=x
3372 jsr create_explosion
3373 jsr plot_blank_xy ; corrupted X
3375 lda #$a4
3376 sta $74
3377 lda #$52
3378 sta $75
3379 jsr plot_character
3381 ldx #0
3382 jsr play_sound
3384 lda #16 ; prevent the player from firing a new
3385 sta $578d ; projectile until the explosion has finished
3387 move_projectile_down_exit:
3388 sec
3389 rts
3391 move_projectile_animate:
3393 lda $5287
3394 eor #1
3395 sta $5287
3396 rts
3398 move_projectile:
3400 lda $5286
3401 cmp #0
3402 bne move_projectile_move
3403 jmp move_projectile_exit
3405 move_projectile_move:
3406 clc
3408 lda #$86
3409 sta $74
3410 lda #$52
3411 sta $75
3412 jsr unplot_character
3414 move_projectile_after_unplot:
3416 lda $5287
3417 and #$30 ; direction
3419 cmp #0
3420 bne move_projectile_not_left
3422 jsr move_projectile_left
3423 bcc move_projectile_toggle
3424 bcs move_projectile_destroy
3426 move_projectile_not_left:
3427 cmp #$10
3428 bne move_projectile_not_right
3430 jsr move_projectile_right
3431 bcc move_projectile_toggle
3432 bcs move_projectile_destroy
3434 move_projectile_not_right:
3435 cmp #$20
3436 bne move_projectile_not_up
3438 jsr move_projectile_up
3439 bcc move_projectile_toggle
3440 bcs move_projectile_destroy
3442 move_projectile_not_up:
3443 cmp #$30
3444 bne move_projectile_toggle
3446 jsr move_projectile_down
3447 bcs move_projectile_destroy
3449 move_projectile_toggle:
3451 jsr projectile_collide
3452 bcs move_projectile_destroy
3454 jsr move_projectile_animate
3456 lda #$86
3457 sta $74
3458 lda #$52
3459 sta $75
3460 jmp plot_character ; optimise away the rts
3462 move_projectile_destroy:
3463 clc
3465 ldy #0
3466 lda ($74),y ; type
3467 cmp #8
3468 bmi move_projectile_no_enemy_collision
3470 and #$70 ; increase the player's score
3471 lsr
3472 lsr
3473 lsr
3474 adc #2
3475 sta $70
3476 jsr add_score
3477 jmp move_projectile_create_explosion
3479 move_projectile_no_enemy_collision:
3481 cmp #4 ; items can be destroyed as well
3482 bne move_projectile_no_item_collision
3484 ldy #1 ; but not keys
3485 lda ($74),y
3486 cmp #4 ; even the mace is stopped by a key
3487 beq move_projectile_remove_projectile
3488 clc
3490 jsr remove_room_item
3492 move_projectile_create_explosion:
3494 ; Unplot the item/enemy and replace it with an explosion.
3496 jsr unplot_character
3498 lda #3 ; explosion
3499 ldy #0
3500 sta ($74),y
3502 lda #4
3503 ldy #1
3504 sta ($74),y
3506 jsr plot_character
3508 ; Play a sound.
3509 ldx #0
3510 jsr play_sound
3512 move_projectile_no_item_collision:
3514 lda $5287 ; type 2 projectiles pass through everything
3515 and #$06
3516 cmp #4
3517 bne move_projectile_remove_projectile
3519 ; Ideally, we would have recorded if the projectile left the screen so
3520 ; that we don't perform these checks again here, but it would just add
3521 ; overhead to the normal movement routines for the other weapons.
3523 lda $5288 ; y
3524 cmp #0
3525 beq move_projectile_remove_projectile
3526 cmp #9
3527 beq move_projectile_remove_projectile
3529 lda $528a ; x
3530 cmp #0
3531 beq move_projectile_remove_projectile
3532 cmp #9
3533 beq move_projectile_remove_projectile
3535 clc
3536 lda #$86
3537 sta $74
3538 lda #$52
3539 sta $75
3541 jsr plot_character
3542 jmp move_projectile_exit
3544 move_projectile_remove_projectile:
3546 lda #0 ; remove the projectile from the character list
3547 sta $5286
3549 move_projectile_exit:
3550 clc
3551 rts
3553 emerge_characters:
3555 lda #$8c ; set the character address
3556 sta $74
3557 lda #$52
3558 sta $75
3560 emerge_characters_loop:
3562 ldy #0
3563 lda ($74),y
3564 cmp #0
3565 bne emerge_characters_next
3567 jmp emerge_character ; optimise away the rts
3569 emerge_characters_next:
3570 clc
3572 ; Examine the next character.
3573 lda $74
3574 adc #6
3576 cmp #$a4
3577 bpl emerge_characters_exit
3578 sta $74
3579 jmp emerge_characters_loop
3581 emerge_characters_exit:
3582 clc
3583 rts
3585 enemy_slots: .byte 0, 6, 12, 18
3587 move_characters:
3589 lda #$8c ; set the character address
3590 sta $74
3591 lda #$52
3592 sta $75
3594 lda $578e ; read a value from 0 to 3 from the motion counter
3595 and #3
3596 tax
3597 lda enemy_slots,x ; look up the corresponding slot in the character list
3598 adc $74
3599 sta $74 ; update the character address
3601 move_characters_loop:
3603 ldy #0
3604 lda ($74),y
3605 cmp #3
3606 bne move_characters_not_emerge_explode
3608 jsr emerge_explode
3609 jmp move_characters_next
3611 move_characters_not_emerge_explode:
3612 cmp #8
3613 bmi move_characters_next
3615 jsr move_enemy
3617 move_characters_next:
3618 clc
3620 lda $74 ; for the last enemy, check the next slot
3621 cmp #$9e ; for the presence of an explosion
3622 bne move_characters_endloop ; otherwise leave the loop (only performing
3623 clc ; one iteration)
3625 adc #6
3626 sta $74
3627 jmp move_characters_loop
3629 move_characters_endloop:
3630 clc
3632 ; Check collisions with the player.
3634 jsr player_collide
3635 bcs move_characters_collisions
3636 jmp move_characters_exit
3638 move_characters_collisions:
3639 clc
3641 ldy #0
3642 lda ($74),y ; type
3643 cmp #8
3644 bpl move_character_destroy_enemy
3646 ; Unplot the item.
3647 jsr unplot_character
3649 ; Remove it from the item table.
3650 jsr remove_room_item
3652 lda #0 ; remove the item from the character list
3653 ldy #0
3654 sta ($74),y
3656 iny
3657 lda ($74),y ; get the item type
3659 sta $8d ; temporarily store A and increase the score
3660 tax
3661 lda item_scores,x
3662 sta $70
3663 jsr add_score
3664 lda $8d
3666 ; Check the item type.
3667 cmp #8
3668 bmi move_characters_not_health
3670 lda #20
3671 sta $70
3672 jsr add_strength
3673 clc
3675 ldx #2
3676 jsr play_sound
3678 rts
3680 move_characters_not_health:
3681 cmp #5
3682 bmi move_characters_not_treasure
3684 ldx #2
3685 jsr play_sound
3687 clc
3688 rts
3690 move_characters_not_treasure:
3691 cmp #4
3692 bmi move_characters_not_key
3694 ; Key - update the item/player flags byte.
3695 lda $5780
3696 ora #$01
3697 sta $5780
3698 clc
3700 ldx #3
3701 jsr play_sound
3703 rts
3705 move_characters_not_key:
3707 ; Update the player's weapon.
3708 asl
3709 sta $5789
3710 clc
3712 ldx #2
3713 jsr play_sound
3715 rts
3717 move_character_destroy_enemy:
3719 ; Unplot the enemy and replace it with an explosion.
3721 jsr unplot_character
3723 lda #3 ; explosion
3724 ldy #0
3725 sta ($74),y
3727 lda #4
3728 ldy #1
3729 sta ($74),y
3731 jsr plot_character
3733 ; Reduce the player's strength.
3735 ldx #1
3736 jsr play_sound
3738 lda #1
3739 sta $70
3740 jmp reduce_strength ; optimise away the rts
3742 move_characters_exit:
3743 clc
3744 rts
3746 remove_room_item:
3748 ldx $5782 ; current room row number
3749 lda eleven_times_table,x
3750 adc $5783 ; current room column number
3751 tax
3752 lda #$80 ; store a value with the top bit set instead of zero because we
3753 sta $5200,x ; have visited this room if we can collect the object within it
3754 clc
3755 rts
3757 item_scores: .byte $1,$4,$9,$16, $50,$20,$5,$10,$40
3758 score_vdu_bytes: .byte 1,1,31 ; reversed
3759 score_digits: .byte "0123456789"
3761 add_score: ; $70=score to add
3763 sed
3764 lda $5786
3765 adc $70
3766 sta $5786
3767 lda $5787
3768 adc #0
3769 sta $5787
3770 lda $5788
3771 adc #0
3772 sta $5788
3773 cld
3775 write_score:
3777 lda #$86
3778 sta $70
3779 lda #$57
3780 sta $71
3782 ldx #2
3783 write_score_vdu_bytes:
3784 lda score_vdu_bytes,x
3785 jsr $ffee
3786 dex
3787 bpl write_score_vdu_bytes
3789 write_score_digits: ; $70,$71=address of score bytes
3791 ldy #2
3792 write_score_loop:
3794 lda ($70),y
3795 lsr
3796 lsr
3797 lsr
3798 lsr
3799 tax
3800 lda score_digits,x
3801 jsr $ffee
3803 lda ($70),y
3804 and #$0f
3805 tax
3806 lda score_digits,x
3807 jsr $ffee
3809 dey
3810 bpl write_score_loop
3812 clc
3813 rts
3815 strength_units: .byte $00,$88,$cc,$ee
3817 add_strength: ; $70=strength to add
3819 ; Divide the initial strength by 4 to determine which half character to
3820 ; start plotting at, and multiply by 8 to get the address. The net result
3821 ; is to mask off the bottom two bits and shift left once.
3822 lda $5784
3823 and #$fc
3824 sta $71 ; strength rounded down to a multiple of four units
3825 asl
3826 clc
3827 tay
3829 lda $5784
3830 adc $70
3831 cmp #65
3832 bmi add_strength_update
3834 lda #64
3836 add_strength_update:
3837 clc
3838 sta $5784 ; the final strength
3840 sec
3841 sbc $71
3842 clc
3843 tax ; the number of units to add between the rounded original
3844 ; strength and the final strength
3846 lda #$f3 ; the start of the strength bar
3847 sta $72
3848 lda #$59
3849 sta $73
3851 cpx #4
3852 bmi add_strength_loop_extra
3854 add_strength_loop:
3856 clc
3857 lda #$ff
3858 sta ($72),y
3860 tya
3861 adc #8
3862 tay
3864 txa
3865 sec
3866 sbc #4
3867 clc
3868 tax
3870 cmp #4
3871 bpl add_strength_loop
3873 add_strength_loop_extra:
3874 cpx #0
3875 beq add_strength_exit
3877 ; For any remaining units in excess of the multiples of four units, plot
3878 ; the appropriate byte.
3879 lda $5784
3880 and #3
3881 tax
3883 lda strength_units,x
3884 sta ($72),y
3886 add_strength_exit:
3887 clc
3888 rts
3890 reduce_strength: ; $70=strength to remove
3892 lda $5784
3893 tax
3894 sec
3895 sbc $70
3896 bpl reduce_strength_update
3898 lda #0
3900 reduce_strength_update:
3901 clc
3902 sta $5784
3904 ; Divide the final strength by 4 to determine which half character to
3905 ; plot, and multiply by 8 to get the address. The net result is to mask off
3906 ; the bottom two bits and shift left once.
3907 and #$fc
3908 asl
3909 tay
3911 lda #$f3 ; the start of the strength bar
3912 sta $70
3913 lda #$59
3914 sta $71
3916 lda $5784
3917 and #3
3918 tax
3919 lda strength_units,x
3920 sta ($70),y
3922 lda $5784
3923 cmp #0
3924 bne reduce_strength_exit
3926 lda $5780 ; the player ran out of strength
3927 ora #$40
3928 sta $5780
3930 lda #64 ; reset the delay counter
3931 sta $5785
3933 lda #$80 ; unplot the player
3934 sta $74
3935 lda #$52
3936 sta $75
3938 jsr unplot_character
3940 lda #8 ; change the player's direction to the demise animation
3941 sta $5281
3943 jsr plot_character
3944 jmp destroy_enemies ; optimise away the rts
3946 reduce_strength_exit:
3947 clc
3948 rts
3950 destroy_enemies:
3952 lda #$8c
3953 sta $74
3954 lda #$52
3955 sta $75
3957 destroy_enemies_loop:
3959 ldy #0
3960 lda ($74),y
3961 cmp #8
3962 bmi destroy_enemies_not_enemy
3964 jsr unplot_character
3966 lda #3 ; emerge/explosion
3967 ldy #0
3968 sta ($74),y
3970 iny
3971 lda #4 ; explosion
3972 sta ($74),y
3974 jsr plot_character
3975 jmp destroy_enemies_not_emerging_enemy
3977 destroy_enemies_not_enemy:
3978 cmp #3
3979 bne destroy_enemies_not_emerging_enemy
3981 jsr unplot_character
3983 iny ; whether emerging or exploding, ensure that the enemy
3984 lda ($74),y ; is now exploding
3985 ora #4
3986 sta ($74),y
3988 jsr plot_character
3990 destroy_enemies_not_emerging_enemy:
3991 clc
3992 lda $74
3993 adc #6
3994 sta $74
3995 cmp #$a4
3996 bmi destroy_enemies_loop
3998 clc
3999 rts
4001 remove_characters:
4003 ; Clear the character table.
4005 ldx #6
4006 remove_characters_loop:
4007 lda #0
4008 sta $5280,x
4009 txa
4010 adc #6
4011 tax
4012 cpx #$2a
4013 bmi remove_characters_loop
4015 rts
4017 ; The player collision masks use bits to represent where the player is in a
4018 ; tile. See the collisions.txt file for more information.
4020 ; Player is above, enemy is below, checking the overlap in the lower tile.
4021 player_collision_mask_above: .byte $00, $c0, $f0, $fc
4023 projectile_collision_mask_above: .byte $00, $00, $00, $80
4025 ; Player and enemy share the same tile or player is on the tile below.
4026 player_collision_mask_below: .byte $ff, $3f, $0f, $03
4028 projectile_collision_mask_below: .byte $e0, $38, $e0, $03
4030 ; Player is above or on the same tile, enemy is below, checking the overlap in
4031 ; the lower tile.
4032 enemy_collision_mask_above: .byte $f8, $3f, $0f, $03
4034 ; Enemy is above, player is below, checking the overlap in the lower tile.
4035 enemy_collision_mask_below: .byte $00, $00, $c0, $f0
4037 ; Player is to the left, enemy is to the right, checking the overlap in the
4038 ; right hand tile.
4039 player_collision_mask_left:
4040 projectile_collision_mask_left: .byte $00, $00, $00, $08
4042 ; Player and enemy share the same tile or player is on the tile to the right.
4043 player_collision_mask_right:
4044 projectile_collision_mask_right: .byte $0c, $06, $03, $01
4046 ; Player is to the left, enemy is to the right or on the same tile, checking
4047 ; the overlap in the right hand tile.
4048 enemy_collision_mask_left: .byte $0f, $07, $03, $01
4050 ; Enemy is to the left, player is to the right, checking the overlap in the
4051 ; right hand tile.
4052 enemy_collision_mask_right: .byte $00, $08, $0c, $0e
4054 player_collide:
4056 lda $5282 ; player y
4057 sta $8a
4058 lda $5284 ; player x
4059 sta $8b
4061 ldx $5283 ; player dy
4062 lda player_collision_mask_above,x
4063 sta $86
4064 lda player_collision_mask_below,x
4065 sta $88
4066 ldx $5285 ; player dx
4067 lda player_collision_mask_left,x
4068 sta $87
4069 lda player_collision_mask_right,x
4070 sta $89
4072 jmp collide ; optimise away the rts
4074 projectile_collide:
4076 lda $5288 ; projectile y
4077 sta $8a
4078 lda $528a ; projectile x
4079 sta $8b
4081 ldx $5289 ; projectile dy
4082 lda projectile_collision_mask_above,x
4083 sta $86
4084 lda projectile_collision_mask_below,x
4085 sta $88
4086 ldx $528b ; projectile dx
4087 lda projectile_collision_mask_left,x
4088 sta $87
4089 lda projectile_collision_mask_right,x
4090 sta $89
4092 ; Run on into the next routine.
4094 collide:
4096 lda #$8c ; set the character address
4097 sta $74
4098 lda #$52
4099 sta $75
4101 collide_loop:
4103 ldy #0
4104 lda ($74),y ; type
4105 cmp #4
4106 bpl collide_check
4108 jmp collide_next
4110 collide_check:
4112 ldy #2
4113 lda ($74),y ; y
4114 sec
4115 sbc $8a ; y - player/projectile y
4116 beq check_collide_y_equal
4117 cmp #1
4118 beq check_collide_y_greater
4119 cmp #255
4120 beq check_collide_y_less
4122 jmp collide_next
4124 check_collide_y_equal:
4125 ; The enemy is on the same tile as the player/projectile so look at the
4126 ; collision on their common tile.
4127 ldy #3
4128 lda ($74),y ; dy
4129 tax
4130 lda enemy_collision_mask_above,x
4131 and $88 ; player/projectile mask below
4132 bne check_collide_x
4134 jmp collide_next
4136 check_collide_y_greater:
4137 ; The enemy is on the tile below the player/projectile so look at the
4138 ; collision on the enemy's tile.
4139 ldy #3
4140 lda ($74),y ; dy
4141 tax
4142 lda enemy_collision_mask_above,x
4143 and $86 ; player mask above
4144 bne check_collide_x
4146 jmp collide_next
4148 check_collide_y_less:
4149 ; The enemy is on the tile above the player/projectile so look at the
4150 ; collision on the player's tile.
4151 ldy #3
4152 lda ($74),y ; dy
4153 tax
4154 lda enemy_collision_mask_below,x
4155 and $88 ; player mask below
4156 bne check_collide_x
4158 jmp collide_next
4160 check_collide_x:
4161 ldy #4
4162 lda ($74),y ; x
4163 sec
4164 sbc $8b ; x - player/projectile x
4165 beq check_collide_x_equal
4166 cmp #1
4167 beq check_collide_x_greater
4168 cmp #255
4169 beq check_collide_x_less
4171 jmp collide_next
4173 check_collide_x_equal:
4174 ; The enemy is on the same tile as the player/projectile so look at the
4175 ; collision on their common tile.
4176 ldy #5
4177 lda ($74),y ; dx
4178 tax
4179 lda enemy_collision_mask_left,x
4180 and $89 ; player mask right
4181 bne check_collide_destroy
4183 jmp collide_next
4185 check_collide_x_greater:
4186 ; The enemy is the tile to the right of the player/projectile so look
4187 ; at the collision on the enemy's tile.
4188 ldy #5
4189 lda ($74),y ; dx
4190 tax
4191 lda enemy_collision_mask_left,x
4192 and $87 ; player mask left
4193 bne check_collide_destroy
4195 jmp collide_next
4197 check_collide_x_less:
4198 ; The enemy is the tile to the left of the player/projectile so look at
4199 ; the collision on the player's tile.
4200 ldy #5
4201 lda ($74),y ; dx
4202 tax
4203 lda enemy_collision_mask_right,x
4204 and $89 ; player mask right
4205 bne check_collide_destroy
4207 collide_next:
4208 clc
4210 ; Examine the next character.
4211 lda $74
4212 adc #6
4214 cmp #$a4
4215 bpl collide_exit
4216 sta $74
4217 jmp collide_loop
4219 check_collide_destroy:
4221 sec ; set the carry flag to inform the caller that the
4222 rts ; player/projectile should be destroyed
4224 collide_exit:
4225 clc
4226 rts
4228 blank_screen:
4229 lda #1
4230 sta $70
4231 lda #0
4232 sta $71
4233 jsr set_palette
4234 lda #2
4235 sta $70
4236 lda #0
4237 sta $71
4238 jsr set_palette
4239 lda #3
4240 sta $70
4241 lda #0
4242 sta $71
4243 ; Run on into set_palette.
4245 set_palette:
4246 ; $70=logical colour
4247 ; $71=physical colour
4248 lda $70
4249 sta $578b
4250 lda $71
4251 sta $578c
4252 lda #0
4253 sta $578d
4254 sta $578e
4255 sta $578f
4257 lda #$c
4258 ldx #$8b
4259 ldy #$57
4260 jsr $fff1
4261 rts
4263 sounds_low: .byte <explosion_sound, <damage_sound, <item_sound, <key_sound, <note_sound, <emerge_sound
4264 sounds_high: .byte >explosion_sound, >damage_sound, >item_sound, >key_sound, >note_sound, >emerge_sound
4266 explosion_sound: .byte 1,0, 1,0, 60,0, 2,0
4267 damage_sound: .byte 1,0, 2,0, 40,0, 4,0
4268 item_sound: .byte $13,0, 3,0, 32,0, 3,0
4269 key_sound: .byte $13,0, 4,0, 50,0, 5,0
4270 note_sound: .byte $13,0, 241,255
4271 note_pitch: .byte 0,0
4272 note_duration: .byte 4,0
4273 emerge_sound: .byte 2,0, 3,0, 0,0, 2,0
4275 play_note: ; A=pitch, Y=duration
4277 sta note_pitch
4278 sty note_duration
4279 ldx #4
4280 ; Run on into the next routine.
4282 play_sound: ; X=sound number
4284 lda sounds_high,x
4285 tay
4286 lda sounds_low,x
4287 tax
4288 lda #7
4289 jsr $fff1
4291 rts
4293 copy_title_up:
4295 lda #$00
4296 sta $70
4297 lda #$18
4298 sta $71
4300 lda #$a0
4301 sta $72
4302 lda #$5a
4303 sta $73
4305 ldx #5
4306 ; Run on into the next routine.
4308 copy_title:
4310 copy_title_loop1:
4312 ldy #0
4313 copy_title_loop2:
4315 lda ($70),y
4316 sta ($72),y
4317 iny
4318 cpy #0
4319 bne copy_title_loop2
4321 clc
4322 lda $72
4323 adc #$40
4324 sta $72
4325 lda $73
4326 adc #$01
4327 sta $73
4328 clc
4330 lda $71
4331 adc #$01
4332 sta $71
4333 clc
4335 dex
4336 bpl copy_title_loop1
4338 rts
4340 copy_completed_screen_up:
4342 lda #$00
4343 sta $70
4344 lda #$0f
4345 sta $71
4347 lda #$60
4348 sta $72
4349 lda #$5e
4350 sta $73
4352 ldx #8
4353 jmp copy_title ; optimise away the rts
4355 init:
4356 jsr cls ; clear the text window
4358 lda #26 ; unset the text window
4359 jsr $ffee
4361 ; Define the default high scores.
4362 ldy #0
4363 lda #$80
4364 sta $70
4365 lda #$51
4366 sta $71
4367 lda #$16
4368 sta $72
4370 ldx #0
4371 init_define_high_scores_loop:
4373 lda #0
4374 sta ($70),y
4375 iny
4376 lda $72
4377 sta ($70),y
4378 iny
4379 lda #0
4380 sta ($70),y
4382 iny
4383 init_define_high_score_name_loop:
4385 lda high_score_default_name1,x
4386 sta ($70),y
4387 iny
4388 inx
4389 cpx #9
4390 beq init_define_high_scores_next
4391 cpx #18
4392 bne init_define_high_score_name_loop
4394 ldx #0
4395 init_define_high_scores_next:
4397 sed
4398 lda $72
4399 sec
4400 sbc #2
4401 sta $72
4402 cld
4403 clc
4405 cpy #96
4406 bne init_define_high_scores_loop
4408 ; Disable joystick support.
4409 lda #0
4410 sta $577e
4412 rts
4414 high_score_default_name1: .byte "RETRO "
4415 high_score_default_name2: .byte " SOFTWARE"
4417 title_vdu_bytes: .byte 17,2, 31,7,28, "to play"
4418 input_message: .byte 17,2, 31,1,27, "Press SPACE / FIRE"
4419 title_vdu_bytes1: .byte 17,3, 31,1,30, "Copyright (c) 2011"
4420 title_vdu_bytes2: .byte 17,3, 31,1,30, " David Boddie "
4421 title_vdu_bytes3: .byte 17,1, 31,1,30, "for Retro Software"
4422 title_vdu_bytes4: .byte 17,3, 31,1,30, "GNU GPL 3 or later"
4424 set_standard_palette:
4426 lda #1
4427 sta $70
4428 lda #1
4429 sta $71
4430 jsr set_palette
4432 jmp set_core_palette ; optimise away the rts
4434 complete_palette_bytes: .byte 2,4, 3,5, 1,4, 3,3, 2,2
4436 set_complete_palette:
4438 lda #0
4439 sta $80
4440 lda #25
4441 sta $81
4443 set_complete_palette_loop:
4445 jsr wait_for_vsync
4447 dec $81
4448 lda $81
4449 cmp #0
4450 bne set_complete_palette_loop
4452 lda #25
4453 sta $81
4455 ldx $80
4456 lda complete_palette_bytes,x
4457 sta $70
4458 inx
4459 lda complete_palette_bytes,x
4460 sta $71
4461 inx
4462 stx $80
4463 jsr set_palette
4465 lda $80
4466 cmp #10
4467 bne set_complete_palette_loop
4469 rts
4471 set_hidden_palette:
4473 lda #1
4474 sta $70
4475 lda #0
4476 sta $71
4477 jsr set_palette
4479 ; Run on into the next routine.
4481 set_core_palette:
4483 lda #2
4484 sta $70
4485 lda #2
4486 sta $71
4487 jsr set_palette
4489 lda #3
4490 sta $70
4491 lda #3
4492 sta $71
4493 jsr set_palette
4495 rts
4497 show_title:
4499 jsr set_standard_palette
4501 ldx #0
4502 write_title_text_loop:
4503 lda title_vdu_bytes,x
4504 jsr $ffee
4505 inx
4506 cpx #12
4507 bmi write_title_text_loop
4509 jsr show_input_message
4511 ; Show the title.
4512 jsr copy_title_up
4514 ; Show the high scores.
4516 jsr colour1
4518 lda #$80
4519 sta $70
4520 lda #$51
4521 sta $71
4523 lda #8
4524 sta $80
4526 show_title_high_scores_loop:
4528 lda #31
4529 jsr $ffee
4530 lda #2
4531 jsr $ffee
4532 lda $80
4533 adc #2
4534 sta $80
4535 clc
4536 jsr $ffee
4538 jsr write_score_digits
4540 lda #32
4541 jsr $ffee
4543 ldx #8
4544 ldy #3
4545 show_title_high_scores_vdu_loop2:
4547 lda ($70),y
4548 cmp #32
4549 bmi ignore_char
4550 cmp #123
4551 bpl ignore_char
4552 jsr $ffee
4554 ignore_char:
4555 iny
4556 dex
4557 bpl show_title_high_scores_vdu_loop2
4559 lda $70
4560 adc #12
4561 sta $70
4562 cmp #$e0
4563 bne show_title_high_scores_loop
4565 lda #0 ; message counter
4566 sta $72
4568 show_title_wait_loop:
4570 lda #150
4571 sta $5785
4573 ldx $72
4574 ldy #22
4575 show_title_wait_message_loop:
4577 lda title_vdu_bytes1,x
4578 jsr $ffee
4579 inx
4580 dey
4581 bpl show_title_wait_message_loop
4583 cpx #92
4584 beq show_title_wait_reset_offset
4586 txa
4587 sta $72
4588 jmp show_title_wait_inner_loop
4590 show_title_wait_reset_offset:
4591 lda #0
4592 sta $72
4594 show_title_wait_inner_loop:
4595 jsr wait_for_vsync
4597 dec $5785
4598 beq show_title_wait_loop
4600 show_title_wait_loop_no_update:
4601 lda #128
4602 ldx #0
4603 jsr $fff4
4604 cpx #0 ; fire button pressed?
4605 beq show_title_no_joystick
4607 lda #1 ; enable joystick support
4608 sta $577e
4609 jmp show_title_exit
4611 show_title_no_joystick:
4612 ldx #157 ; SPACE
4613 jsr check_key
4614 cpy #255
4615 bne show_title_wait_inner_loop
4617 lda #0 ; disable joystick support
4618 sta $577e
4620 show_title_exit:
4621 clc
4622 rts
4624 show_input_message:
4626 ldx #0
4627 show_input_message_loop:
4629 lda input_message,x
4630 jsr $ffee
4631 inx
4632 cpx #23
4633 bne show_input_message_loop
4635 rts
4637 wait_for_vsync:
4639 lda #19
4640 jmp $fff4 ; optimise away the rts
4642 game_over_vdu_bytes: .byte 28,4,17,15,15, 12, 26, 31,4,15, 17,2, "The journey", 31,9,17, "is over"
4644 delay:
4646 delay_loop:
4648 jsr wait_for_vsync
4649 dec $5785
4650 bne delay_loop
4652 rts
4654 show_game_over:
4656 lda #128
4657 sta $5785
4658 jsr delay
4660 ldx #0
4661 write_game_over_text_loop:
4662 lda game_over_vdu_bytes,x
4663 jsr $ffee
4664 inx
4665 cpx #33
4666 bmi write_game_over_text_loop
4668 lda #192
4669 sta $5785
4670 jsr delay
4672 rts
4674 end_of_level_bytes1: .byte 31,1,3, 17,3, "Exploration bonus", 31,11,5, "x 9"
4675 end_of_level_bytes2: .byte 31,0,28, 17,2, "My journey continues"
4677 show_end_of_level_screen:
4679 ; Draw a decorative room.
4681 jsr make_empty_room
4683 ldx #5
4684 end_of_level_h_walls_loop:
4686 lda #3
4687 sta $57b2,x
4688 sta $57e4,x
4689 dex
4690 bpl end_of_level_h_walls_loop
4692 ldx #30
4693 end_of_level_v_walls_loop:
4695 lda #3
4696 sta $57bc,x
4697 sta $57c1,x
4698 txa
4699 sec
4700 sbc #10
4701 tax
4702 bpl end_of_level_v_walls_loop
4704 jsr plot_room_tiles
4705 jsr set_standard_palette
4707 ldx #0
4708 end_of_level_text_loop1:
4710 lda end_of_level_bytes1,x
4711 jsr $ffee
4712 inx
4713 cpx #28
4714 bne end_of_level_text_loop1
4716 ; Count the number of rooms explored.
4717 ldx #0
4718 lda #0
4719 sta $8d
4720 sta $8e
4721 end_of_level_room_count_loop:
4723 lda $5200,x
4724 and #$80
4725 beq end_of_level_room_count_loop_next
4727 sed
4728 lda $8d
4729 adc #1
4730 sta $8d
4731 lda $8e
4732 adc #0
4733 sta $8e
4734 cld
4735 clc
4737 end_of_level_room_count_loop_next:
4738 inx
4739 cpx #121
4740 bne end_of_level_room_count_loop
4742 ; Position the player so that we can perform an animation.
4743 jsr position_player_set_up_plotting
4745 lda $8d
4746 sta $70
4747 lda $8e
4748 sta $71
4749 jsr write_bonus
4751 lda #0 ; reset motion counter
4752 sta $578e
4754 show_end_of_level_bonus_loop:
4756 jsr wait_for_vsync
4758 clc
4759 lda $578e
4760 and #15
4761 bne end_of_level_no_animation
4763 ; Animate the player.
4765 jsr reset_unplot_buffer
4766 jsr reset_plot_buffer
4768 ; $74,$75 should be unchanged
4769 jsr unplot_character
4771 lda $5281
4772 eor #1
4773 sta $5281
4774 jsr plot_character
4776 jsr plot_buffer
4778 end_of_level_no_animation:
4779 clc
4780 lda $578e
4781 and #3
4782 bne end_of_level_no_countdown
4784 ; Transfer the bonus to the score.
4786 sed
4787 sec
4788 lda $8d
4789 sbc #1
4790 sta $8d
4791 sta $70
4792 lda $8e
4793 sbc #0
4794 sta $8e
4795 sta $71
4796 cld
4797 clc
4799 jsr write_bonus
4801 lda #9
4802 sta $70
4803 jsr add_score
4805 lda $8d
4806 and #$3f
4807 asl
4808 ldy #1
4809 jsr play_note
4811 end_of_level_no_countdown:
4812 inc $578e ; update motion counter
4813 clc
4815 lda $8d
4816 cmp #0
4817 bne show_end_of_level_bonus_loop
4819 lda $8e
4820 cmp #0
4821 bne show_end_of_level_bonus_loop
4823 lda #64 ; initialise delay counter
4824 sta $5785
4825 jsr delay
4827 ldx #0
4828 end_of_level_text_loop2:
4830 lda end_of_level_bytes2,x
4831 jsr $ffee
4832 inx
4833 cpx #25
4834 bne end_of_level_text_loop2
4836 lda $578a
4837 cmp #3
4838 bpl show_end_of_level_screen_exit
4840 lda #192 ; initialise delay counter
4841 sta $5785
4842 jsr delay
4844 show_end_of_level_screen_exit:
4845 rts
4847 level_bonus_vdu_bytes: .byte 5,6,31, 1,17 ; reversed
4849 write_bonus: ; $70,$71=value
4850 ; $72,$73=address of VDU codes
4852 ldx #4
4853 write_bonus_vdu_bytes:
4855 lda level_bonus_vdu_bytes,x
4856 jsr $ffee
4857 dex
4858 bpl write_bonus_vdu_bytes
4860 ldy #1
4861 write_bonus_loop:
4863 tya
4864 tax ; temporary
4866 lda $70,x
4867 sta $80
4868 lsr
4869 lsr
4870 lsr
4871 lsr
4872 tax
4873 lda score_digits,x
4874 jsr $ffee
4876 lda $80
4877 and #$0f
4878 tax
4879 lda score_digits,x
4880 jsr $ffee
4882 dey
4883 bpl write_bonus_loop
4885 clc
4886 rts
4888 position_player_set_up_plotting:
4890 jsr reset_player_position
4891 jsr remove_characters
4893 jsr reset_unplot_buffer
4894 jsr reset_plot_buffer
4896 ; Run on into the next routine.
4898 plot_the_player:
4900 lda #$80 ; plot the player
4901 sta $74
4902 lda #$52
4903 sta $75
4904 jsr plot_character
4906 jsr plot_buffer
4907 rts
4909 complete_game_vdu_bytes1: .byte 12
4910 complete_game_vdu_bytes2: .byte 17,3, 31,2,20, "Congratulations!"
4911 complete_game_vdu_bytes3: .byte 17,2, 31,1,22, "Now journey onward"
4912 complete_game_vdu_bytes4: .byte 17,2, 31,1,24, "to a new adventure"
4914 show_complete_game:
4916 jsr blank_screen
4918 ldx #0
4919 show_complete_game_vdu_loop:
4921 lda complete_game_vdu_bytes1,x
4922 jsr $ffee
4923 inx
4924 cpx #68
4925 bne show_complete_game_vdu_loop
4927 jsr copy_completed_screen_up
4929 jsr set_complete_palette
4931 lda #255
4932 sta $5785
4934 show_complete_game_delay_loop:
4936 jsr wait_for_vsync
4938 dec $5785
4939 bne show_complete_game_no_message
4941 jsr colour1
4942 jsr show_input_message
4944 show_complete_game_no_message:
4946 lda #128
4947 ldx #0
4948 jsr $fff4
4949 cpx #0 ; fire button pressed?
4950 beq show_complete_game_no_joystick
4951 jmp show_complete_game_exit
4953 show_complete_game_no_joystick:
4955 ldx #157
4956 jsr check_key
4957 cpy #255
4958 bne show_complete_game_delay_loop
4960 show_complete_game_exit:
4961 clc
4962 rts
4964 check_high_scores:
4966 ; Start at the bottom of the table, moving scores down as necessary, and
4967 ; write in the current score at the appropriate place.
4969 lda #$86 ; current score
4970 sta $70
4971 lda #$57
4972 sta $71
4974 lda #$80
4975 sta $72
4976 lda #$51
4977 sta $73
4979 check_high_scores_loop:
4981 ldy #2
4982 check_high_scores_digits_loop:
4984 lda ($72),y
4985 cmp ($70),y ; existing score less than current score?
4986 bmi check_high_scores_move_down
4987 beq check_high_scores_digits_next ; keep checking digits if equal
4988 jmp check_high_scores_next
4990 check_high_scores_digits_next:
4991 dey
4992 bpl check_high_scores_digits_loop
4994 check_high_scores_next:
4995 clc
4996 lda $72
4997 adc #12
4998 sta $72
4999 cmp #$e0
5000 bne check_high_scores_loop
5002 ; The player's score didn't make it into the high score table.
5003 rts
5005 check_high_scores_move_down: ; $70,$71=pointer to current score
5006 ; $72,$73=pointer to old score
5008 ; The current score exceeded the existing entry. Make a note of the
5009 ; position in the high score table, insert the player's score, and take
5010 ; the old score
5012 lda $72 ; Record the position in the high score table of the
5013 sta $8d ; player's score.
5014 lda $73
5015 sta $8e
5017 lda #$e0
5018 sta $74
5019 lda #$51
5020 sta $75
5022 ldy #0
5023 insert_blank_player_name_loop:
5025 cpy #3
5026 bpl insert_blank_player_name_score_only
5028 lda ($70),y
5029 jmp insert_blank_player_name_store
5031 insert_blank_player_name_score_only:
5032 lda #32
5034 insert_blank_player_name_store:
5035 sta ($74),y
5036 iny
5037 cpy #12
5038 bne insert_blank_player_name_loop
5040 check_high_scores_move_down_loop:
5042 ldy #0
5043 check_high_scores_copy_score_and_name:
5045 lda ($72),y ; swap the current score with the score in the table
5046 tax
5047 lda ($74),y
5048 sta ($72),y
5049 txa
5050 sta ($74),y
5051 iny
5052 cpy #12
5053 bne check_high_scores_copy_score_and_name
5055 clc
5056 lda $72
5057 adc #12
5058 sta $72
5059 cmp #$e0
5060 bne check_high_scores_move_down_loop
5062 ; Draw a decorative room.
5064 jsr set_hidden_palette
5066 jsr make_empty_room
5068 lda #3
5069 sta $76
5070 sta $77
5071 jsr draw_top_line
5072 jsr draw_bottom_line
5073 jsr draw_left_line
5075 lda #0
5076 sta $77
5077 jsr draw_right_line
5079 jsr plot_room_tiles
5081 ; Add text characters to the room.
5082 jsr colour3
5084 lda #3 ; x
5085 sta $70
5086 lda #6 ; y
5087 sta $71
5089 lda #65
5090 sta $72
5092 ldx #3
5093 plot_text_characters_loop:
5095 jsr print_xy
5097 lda $70
5098 adc #4
5099 sta $70
5101 dex
5102 bpl plot_text_characters_next
5104 lda #3
5105 sta $70
5106 lda $71
5107 adc #3
5108 sta $71
5110 ldx #3
5112 plot_text_characters_next:
5114 inc $72
5115 lda $72
5116 cmp #91
5117 bne plot_text_characters_loop
5119 lda #11
5120 sta $70
5121 lda #95 ; _ representing a space
5122 sta $72
5123 jsr print_xy
5125 lda #15
5126 sta $70
5127 lda #60 ; < representing delete
5128 sta $72
5129 jsr print_xy
5131 ; Put the player in the centre of the room.
5132 jsr position_player_set_up_plotting
5134 lda #0 ; reset motion counter
5135 sta $578e
5137 lda #0 ; not on a character
5138 sta $578d
5140 lda #0 ; reset the level number so that the correct tiles are used
5141 sta $578a
5143 lda #3 ; cursor position in the high score entry held in $8d,$8e
5144 sta $8f
5146 jsr set_standard_palette
5148 ldx #0
5149 high_score_vdu_loop:
5151 lda high_score_vdu_bytes,x
5152 jsr $ffee
5153 inx
5154 cpx #39
5155 bne high_score_vdu_loop
5157 high_score_entry_loop:
5159 jsr reset_unplot_buffer
5160 jsr reset_plot_buffer
5162 jsr move_player
5163 ; Check if the player leaves the room.
5164 bcc high_score_entry_check_position
5165 jmp high_score_entry_after_loop
5167 high_score_entry_check_position:
5169 lda $5285 ; dx
5170 cmp #2
5171 beq high_score_entry_maybe_aligned
5172 jmp high_score_entry_not_aligned
5174 high_score_entry_maybe_aligned:
5176 lda $5282 ; y
5177 tay
5178 cmp #8
5179 bpl high_score_entry_not_aligned
5181 lda $5284 ; x
5182 tax
5183 cmp #9
5184 beq high_score_entry_not_aligned
5185 and #1
5186 beq high_score_entry_not_aligned
5188 lda $5283 ; dy
5189 cmp #2
5190 bmi high_score_entry_aligned
5191 jmp high_score_entry_not_aligned
5193 lda $5282 ; y again (don't apply the touching rule to the bottom
5194 cmp #7 ; row of characters)
5195 beq high_score_entry_not_aligned
5197 iny ; we are really touching the character below
5199 high_score_entry_aligned:
5201 lda $578d
5202 cmp #1
5203 beq high_score_entry_next
5205 ; The player is aligned with a letter.
5206 txa
5207 sec
5208 sbc #1
5209 lsr
5210 sta $7e ; record (x - 1) / 2
5212 tya ; recall y
5213 sec
5214 sbc #1
5215 asl
5216 asl ; (y - 1) * 4
5217 clc
5219 adc $7e ; (y - 1) * 4 + (x - 1) / 2
5220 adc #65
5221 sta $7e ; record the ASCII code
5223 cmp #91
5224 bmi insert_character
5226 cmp #92
5227 beq delete_character
5229 ; Insert a space.
5230 lda #32
5231 sta $7e
5233 insert_character:
5234 lda $8f
5235 cmp #12
5236 bpl high_score_entry_pressed
5238 tay ; insert the character
5239 lda $7e
5240 sta ($8d),y
5241 jsr print_high_score_character
5243 inc $8f
5244 jmp high_score_entry_pressed
5246 delete_character:
5247 lda $8f
5248 cmp #4
5249 bmi high_score_entry_pressed
5251 cmp #12
5252 beq high_score_delete_previous_character
5254 tay
5255 lda #32 ; insert a space
5256 sta ($8d),y
5257 jsr print_high_score_character
5259 high_score_delete_previous_character:
5260 dec $8f
5261 lda $8f
5262 tay ; insert a space
5263 lda #32
5264 sta ($8d),y
5265 jsr print_high_score_character
5267 high_score_entry_pressed:
5268 lda #1
5269 sta $578d
5270 jmp high_score_entry_next
5272 high_score_entry_not_aligned:
5273 lda #0
5274 sta $578d
5276 high_score_entry_next:
5278 jsr wait_for_vsync
5279 jsr plot_buffer
5281 jmp high_score_entry_loop
5283 inc $578e
5284 clc
5286 high_score_entry_after_loop:
5287 clc
5289 jsr cls
5290 jsr set_hidden_palette
5292 rts
5294 high_score_vdu_bytes: .byte 17,1, 31,2,3, "Enter your name!", 17,3, 31,5,30, "> <", 17,1
5296 cls:
5297 lda #12
5298 jsr $ffee
5299 rts
5301 colour1:
5302 lda #17
5303 jsr $ffee
5304 lda #1
5305 jsr $ffee
5306 rts
5308 colour3:
5309 lda #17
5310 jsr $ffee
5311 lda #3
5312 jsr $ffee
5313 rts
5315 print_high_score_character: ; A=ASCII code
5317 clc
5318 sta $72 ; store the character
5319 lda $8f
5320 adc #3
5321 sta $70 ; store the x position of the character
5322 lda #30
5323 sta $71
5324 ; Run on into the next routine.
5326 print_xy:
5328 lda #31
5329 jsr $ffee
5330 lda $70
5331 jsr $ffee
5332 lda $71
5333 jsr $ffee
5334 lda $72
5335 jsr $ffee
5336 rts
5338 disable_sound: ; X=1 (disable); X=0 (enable)
5340 lda #210
5341 ldy #0
5342 jmp $fff4 ; optimise away the rts
5344 status_vdu_bytes: .byte 31,2,0, 17,3, "Score", 31,11,0, 17,2, "Strength", 17,1
5345 ; TAB(1,0), COLOUR 3, "Score", TAB(12,0), COLOUR 2, "Strength", COLOUR 1
5347 start_new_game:
5349 ; Clear the screen.
5350 jsr cls
5352 ; Set the level.
5353 lda #0
5354 sta $578a
5356 ; Set the score.
5357 lda #0
5358 sta $5786
5359 lda #0
5360 sta $5787
5361 lda #0
5362 sta $5788
5364 ; Blank the screen now because it will be blanked before the room is shown
5365 ; and otherwise the strength bar will show briefly.
5366 jsr blank_screen
5368 ; Set the player's strength.
5369 lda #0
5370 sta $5784
5371 lda #64
5372 sta $70
5373 jsr add_strength
5375 ; Set the projectile type.
5376 lda #0
5377 sta $5789
5379 rts
5381 reset_player_position:
5383 lda #1 ; player
5384 sta $5280
5385 lda #6 ; down (first frame)
5386 sta $5281
5387 lda #4 ; y=4
5388 sta $5282
5389 lda #2 ; dy=2
5390 sta $5283
5391 lda #4 ; x=4
5392 sta $5284
5393 lda #3 ; dx=3
5394 sta $5285
5396 rts
5398 start_level:
5400 ; Clear the item/player flags.
5401 lda #0
5402 sta $5780
5404 ; Set current room.
5406 ldx $578a
5407 lda start_rooms_y,x
5408 sta $5782
5409 lda start_rooms_x,x
5410 sta $5783
5412 ; Set the player's position.
5414 jsr reset_player_position
5416 ; Reset the weapon counter.
5417 lda #0
5418 sta $577f
5420 ; Fill the treasure table with objects.
5421 ldx $578a ; level
5422 lda key_rooms,x
5423 sta $80
5425 ldx $578a ; level
5426 lda seeds,x
5427 adc #1
5428 and #31
5429 sta $7c
5430 clc
5431 lda seeds,x
5432 adc #2
5433 and #31
5434 sta $7d
5435 clc
5437 lda $578a ; create an upper limit on the weapon type found in this level
5438 adc #2
5439 sta $5781
5440 clc
5442 lda #$00
5443 sta $8e
5444 lda #$52
5445 sta $8f
5447 ldy #0
5448 start_level_add_treasure_loop:
5450 cpy $80 ; check for the key room
5451 bne start_level_add_treasure_item
5453 lda #5 ; the value to store is type + 1
5454 jmp start_level_add_treasure_store
5456 start_level_add_treasure_item:
5457 clc
5458 jsr unlimited_values
5459 and #$0f
5460 cmp #0
5461 beq start_level_add_treasure_none
5463 clc
5464 sta $8c
5465 tya
5466 adc $8c
5467 and #31
5468 clc
5469 tax
5470 lda treasure_table,x
5472 cmp #4
5473 bmi start_level_add_treasure_weapon
5475 clc
5476 adc #1
5477 jmp start_level_add_treasure_store
5479 start_level_add_treasure_weapon:
5481 ; Only add weapons with types that equal the level number or exceed it
5482 ; by one.
5483 cmp $5781
5484 bcs start_level_add_treasure_none
5486 clc
5487 adc #1 ; store values 0-8 as values 1-9
5488 jmp start_level_add_treasure_store
5490 start_level_add_treasure_none:
5491 clc
5492 lda #0 ; do not put treasure in this room
5494 start_level_add_treasure_store:
5495 clc
5496 sta ($8e),y ; add the item to the table
5498 iny
5499 cpy #121
5500 bmi start_level_add_treasure_loop
5502 ; Write the status text.
5503 ldx #0
5504 write_status_text_loop:
5505 lda status_vdu_bytes,x
5506 jsr $ffee
5507 inx
5508 cpx #25
5509 bmi write_status_text_loop
5511 jsr write_score
5513 clc
5514 rts
5516 main:
5517 jsr init
5519 main_loop:
5521 jsr show_title
5523 jsr start_new_game
5525 level_loop:
5527 jsr start_level
5529 game_loop:
5531 jsr remove_characters
5533 jsr reset_unplot_buffer
5534 jsr reset_plot_buffer
5536 lda $5782 ; current room (y)
5537 sta $78
5538 lda $5783 ; current room (x)
5539 sta $79
5540 jsr plot_room
5541 jsr set_room_palette
5542 jsr create_enemy_positions
5543 jsr add_treasure
5545 jsr plot_the_player
5547 lda #0 ; reset projectile counter
5548 sta $578d
5550 lda #0 ; reset motion counter
5551 sta $578e
5553 lda #63 ; reset generation counter
5554 sta $578f
5556 room_loop:
5557 jsr reset_unplot_buffer
5558 jsr reset_plot_buffer
5560 jsr move_characters
5561 jsr move_projectile
5563 lda $5780 ; is player out of strength ($40), leaving the
5564 and #$c2 ; level (0x80) or completing the game (0x02)?
5565 beq room_loop_player_move
5566 clc
5568 dec $5785 ; leave the loop when the delay
5569 bne room_loop_delay_next
5570 jmp after_room_loop ; counter is about to reset
5572 room_loop_delay_next:
5574 lda $5281 ; leave the loop when the player demise
5575 cmp #11 ; animation has finished
5576 beq room_loop_after_player_move
5577 clc
5579 lda $578e
5580 and #7
5581 bne room_loop_after_player_move
5583 lda $5780 ; skip the animation if leaving the level or
5584 and #$82 ; completing the game
5585 bne room_loop_after_player_move
5587 ; Show the demise animation when appropriate.
5589 lda #$80
5590 sta $74
5591 lda #$52
5592 sta $75
5594 jsr unplot_character
5596 inc $5281
5597 jsr plot_character
5598 jmp room_loop_after_player_move
5600 room_loop_player_move:
5602 ; See if it is time to generate a new enemy.
5603 lda $578f
5604 cmp #0
5605 bne no_emerge_characters
5606 jsr emerge_characters
5608 no_emerge_characters:
5609 clc
5611 jsr check_fire_key
5612 jsr move_player
5613 bcs after_room_loop ; check if we are leaving the level
5615 room_loop_after_player_move:
5616 clc
5618 lda #19
5619 jsr $fff4
5620 jsr plot_buffer
5622 ldx #143 ; Escape key check
5623 jsr check_key
5624 cpy #255
5625 beq main_loop_play_again
5627 ldx #174 ; S key check
5628 jsr check_key
5629 cpy #255
5630 bne no_set_sound
5632 ldx #0
5633 jsr disable_sound
5634 jmp after_sound_checks
5636 no_set_sound:
5638 ldx #239 ; Q key check
5639 jsr check_key
5640 cpy #255
5641 bne after_sound_checks
5643 ldx #1
5644 jsr disable_sound
5646 after_sound_checks:
5648 ldx #200 ; P key check
5649 jsr check_key
5650 cpy #255
5651 bne no_pause
5653 pause_loop:
5655 ldx #201 ; O key check
5656 jsr check_key
5657 cpy #255
5658 bne pause_loop
5660 no_pause:
5661 clc
5663 lda $578d
5664 cmp #0
5665 beq room_loop_no_update_projectile_counter
5667 dec $578d
5669 room_loop_no_update_projectile_counter:
5671 dec $578f ; update generation counter
5673 inc $578e ; update motion counter
5674 clc
5675 jmp room_loop
5677 after_room_loop:
5678 clc
5680 lda $5780
5681 and #$80
5682 bne exit_level
5684 lda $5780
5685 and #$40
5686 bne game_over
5688 lda $5780
5689 and #$02
5690 bne complete_game
5692 jmp game_loop
5694 exit_level:
5696 jsr show_end_of_level_screen
5698 inc $578a
5699 clc
5700 jmp level_loop
5702 game_over:
5703 jsr show_game_over
5704 jmp main_loop_play_again
5706 complete_game:
5707 jsr show_end_of_level_screen
5708 jsr show_complete_game
5709 jmp main_loop_play_again
5711 main_loop_play_again:
5712 jsr cls
5714 ; Check the score against the high scores.
5715 jsr check_high_scores
5717 jmp main_loop
5719 exit:
5720 clc
5721 rts