Add tools/ and manual/, move sources to src/
[dpadhero2.git] / src / game.asm
blob82761f1e2ee1ef849ea331a82649156ed0412b8c
2 ; Copyright (C) 2010 Kent Hansen.
4 ; This program is free software; you can redistribute it and/or modify
5 ; it under the terms of the GNU General Public License as published by
6 ; the Free Software Foundation; either version 3 of the License, or
7 ; (at your option) any later version.
9 ; This program is distributed in the hope that it will be useful,
10 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ; GNU General Public License for more details.
14 ; You should have received a copy of the GNU General Public License
15 ; along with this program. If not, see <http://www.gnu.org/licenses/>.
18 .include "common/fade.h"
19 .include "common/joypad.h"
20 .include "common/ldc.h"
21 .include "common/fixedpoint.h"
22 .include "common/palette.h"
23 .include "common/ppu.h"
24 .include "common/ppubuffer.h"
25 .include "common/ptr.h"
26 .include "sound/mixer.h"
27 .include "sound/sequencer.h"
28 .include "sound/sound.h"
29 .include "common/sprite.h"
30 .include "common/timer.h"
31 .include "player.h"
32 .include "target.h"
34 .ifdef MMC
35 .if MMC == 3
36 .include "mmc/mmc3.h"
37 .endif
38 .endif
40 .dataseg
42 play_count .dw
44 ; 0 = normal time, 1 = bullet time
45 time_mode .db
46 .public time_mode
48 ; 0 = full length, 1 = clip
49 play_mode .db
51 clip_index .db
53 displayed_energy_level .db[2]
55 display_letter_index .db
57 damage_blink_counter .db
58 screen_shake_counter .db
60 ; 0 - normal, 1 - dead, 2 - done
61 game_state .db
63 transition_timer .db
64 bullet_timer .db
66 ; Number of targets until the next heart should be spawned
67 heart_spawn_counter .db
68 HEART_SPAWN_INTERVAL .equ 32
69 spawned_heart_state .db
71 ; Damage levels
72 miss_damage .db
73 error_damage .db
74 skull_damage .db
76 ; Holds mapping from virtual to physical button, for 2 players.
77 button_mapping .byte[5*2]
78 .public button_mapping
80 ; The extent of the vertical area where hits are acknowledged, in pixels.
81 hit_extent .db
82 ; The Y position where the hit area begins.
83 hit_start_y .db
85 ; Mask of the lanes mapped to each player.
86 player_lanes .db[2]
88 normal_target_attributes .db[5]
90 ; Calculated each frame from joypad input.
91 lane_input_posedge .db[2]
92 lane_input .db[2]
94 LOCKED_LANES_MAX .equ 2
96 lockable_lanes .db
97 locked_lanes .db
98 locked_lane_timers .db[5]
100 ; array of targets, used to populate the linked list
101 targets_1 .target_1[MAX_TARGETS]
102 targets_2 .target_2[MAX_TARGETS]
103 .public targets_1
104 .public targets_2
106 ; linked lists
107 free_targets_list .db
108 active_targets_head .db
109 active_targets_tail .db
110 hit_targets_head .db
111 hit_targets_tail .db
112 missed_targets_head .db
113 missed_targets_tail .db
115 .public free_targets_list
116 .public active_targets_head
117 .public active_targets_tail
119 TARGET_DATA_DELAY_WIDTH .equ 3 ; number of bits for delay
121 target_data_speed .db ; frames per data timer decrement
122 target_data_timer .db
123 should_load_targets .db
124 target_data_chunk_length .db ; Number of targets per progress increment
126 begin_song_timer .dw
128 target_song .db
129 target_song_order_skip .db
130 target_song_row_skip .db
132 ; The player's state.
133 player .player_state
134 .public player
136 stat_changed .db ; b0: score, b1: top score, b2: progress, b3: energy, b4: lives, b5: points level, b6: letters
138 progress_level .db
139 progress_countdown .db
141 moving_bg_column .db
142 moving_bg_offset .db
144 selected_menu_item .db
146 lane_switch_request .db
147 lane_switcher_offset .db
149 speed_bump_request .db
151 ; temp variables
152 powable_lanes .db
153 saved_muted_channels .db
154 was_music_paused .db
155 tmp .db
156 checked_lanes .db
157 hit_lanes .db
158 hittable_lanes .db
159 error_lanes .db[2]
160 prev .db
161 menu_row .db
162 menu_col .db
164 ; division-related
165 ; ### move to its own file
166 AC0 .db ; initial dividend & resulting quotient
167 AC1 .db
168 AC2 .db
169 XTND0 .db ; remainder
170 XTND1 .db
171 XTND2 .db
172 AUX0 .db ; divisor
173 AUX1 .db
174 AUX2 .db
175 TMP0 .db
176 Count .db
178 .public AC0
179 .public AC1
180 .public AC2
181 .public AUX0
182 .public AUX1
183 .public AUX2
185 .dataseg zeropage
187 ; Pointer to the data that describes targets+timings
188 target_data .ptr
189 target_data_bit_ctr .db
190 target_data_bits .db
192 .codeseg
194 ;.define DEBUG_TARGET_DATA_TIMER
196 .public go_to_title_screen
197 .public go_to_game_type_select
199 .public setup_normal_play
200 .public setup_clip_play
201 .public is_clip_play
203 .public game_init
204 .public game_main
205 .public game_paused_main
207 .public game_palette
208 .public rock_score_table
209 .public draw_lane_indicator
211 .public set_default_button_mapping
212 .if 0
213 .public set_emu_button_mapping
214 .public set_guitar_button_mapping
215 .endif
217 .public wipeout
218 .public print_value
219 .public divide
220 .public count_bits
221 .public initialize_target_lists
222 .public move_target
223 .public add_to_active_targets_list
225 .extrn update_ampdisplay:proc
226 .extrn play_dmc_sample:proc
228 .extrn game_ui_data:label
229 .extrn pad3d_data:label
230 .extrn main_cycle:byte
231 .extrn selected_song:byte
232 .extrn target_data_table:label
233 .extrn frame_count:byte
234 .extrn bitmasktable:byte
235 .extrn global_transpose:byte
236 .extrn volume_table:byte
237 .extrn game_type:byte
239 .proc go_to_title_screen
240 lda #1 : sta main_cycle
241 lda #0 : jmp swap_bank
242 .endp
244 .proc go_to_game_type_select
245 lda #24 : sta main_cycle
246 lda #6 : jmp swap_bank
247 .endp
249 .proc setup_normal_play
250 lda #0
251 sta play_mode
253 .endp
255 .proc setup_clip_play
256 lda #0
257 sta clip_index
258 lda #1
259 sta play_mode
261 .endp
263 .proc is_clip_play
264 lda play_mode
266 .endp
268 ; Reads the next N bits from the target data stream.
269 ; In: A = number of bits to read (1..8)
270 ; Out: A = value of N bits (upper bits zero)
271 ; Destroys: Y
272 .proc read_target_data_bits
274 lda #0 ; output will be shifted into here
275 @@read_one_bit:
276 dec target_data_bit_ctr
277 bpl +
278 ; reset counter, read next byte
282 lda #7
283 sta target_data_bit_ctr
284 ldy #0
285 lda [target_data],y
286 sta target_data_bits
287 inc target_data.lo
288 bne ++
289 inc target_data.hi
290 ++ pla
293 + asl target_data_bits
296 bne @@read_one_bit
298 .endp
300 .proc fetch_target_data_byte
301 lda #8
302 jmp read_target_data_bits
303 .endp
305 .proc set_target_data_timer
306 sta target_data_timer
308 .endp
310 target_data_timer_table:
311 .db 1,2,4,8,12,16,24,32
313 .proc maybe_seek_one_target_pattern
314 lda target_song_order_skip
315 beq +
316 dec target_song_order_skip
317 lda #0 ; seek one pattern
318 jsr sequencer_seek_order_relative
319 + rts
320 .endp
322 .proc maybe_seek_to_target_pattern
323 lda current_song
324 cmp target_song
325 bne +
326 jsr maybe_seek_one_target_pattern
327 jsr maybe_seek_one_target_pattern
328 jsr maybe_seek_one_target_pattern
329 jsr maybe_seek_one_target_pattern
330 jsr maybe_seek_one_target_pattern
331 jsr maybe_seek_one_target_pattern
332 + rts
333 .endp
335 .proc init_begin_song_timer_lo
336 lda time_mode
338 lda target_data_speed
339 bcc +
341 + sta begin_song_timer+1
343 .endp
345 .proc maybe_begin_song
346 lda begin_song_timer+0
347 ora begin_song_timer+1
348 bne +
350 + jsr maybe_seek_to_target_pattern
351 dec begin_song_timer+1
352 beq +
354 + lda begin_song_timer+0
355 cmp #4
356 bne +
357 lda target_song
358 jsr start_song
359 jsr pause_music
360 + jsr on_pattern_row_change
361 dec begin_song_timer+0
362 beq +
363 jmp init_begin_song_timer_lo
364 + jsr unpause_music
365 ldcay on_pattern_row_change
366 jmp set_pattern_row_callback
367 .endp
369 game_palette:
370 ; bg
371 .db $0f,$10,$16,$27 ; logo, hearts, VU
372 .db $0f,$1B,$12,$22
373 .db $0f,$2B,$20,$10 ; points, progress bar
374 .db $0f,$38,$10,$00 ; pad, VU
375 ; sprites
376 ;.db $0f,$02,$12,$32 ; target
377 .db $0f,$02,$22,$30 ; target - blue
378 .db $0f,$0A,$2A,$30 ; target - green
379 ;.db $0f,$04,$24,$30 ; target - pink
380 .db $0f,$08,$28,$30 ; target - yellow
381 .db $0f,$06,$16,$30 ; target - red
382 ;.db $0f,$08,$28,$2A ; joypad indicator, points level indicator
383 ;.db $0f,$20,$20,$20 ; pause menu
384 ;.db $0f,$20,$20,$20 ; pause menu
386 .proc wipeout
387 jsr screen_off
388 jsr nmi_off
389 jsr reset_timers
390 lda #0
391 jsr fill_all_nametables
392 lda #0
394 jsr set_scroll_xy
395 lda #(PPU_CTRL0_SPRITE_SIZE_8x16 | PPU_CTRL0_BG_TABLE_0000 | PPU_CTRL0_SPRITE_TABLE_1000)
396 sta ppu.ctrl0
397 lda #(PPU_CTRL1_BG_CLIP_ON | PPU_CTRL1_SPRITE_CLIP_ON)
398 sta ppu.ctrl1
399 .ifdef MMC
400 .if MMC == 3
401 lda #MMC3_MIRROR_V
402 sta MMC3_MIRROR_REG
403 lda #0
404 sta chr_addr_toggle
405 .endif
406 .endif
407 jmp reset_sprites
408 .endp
410 .proc game_init
411 jsr wipeout
413 lda #0
414 jsr start_song ; mute
416 .ifdef MMC
417 .if MMC == 3
418 lda #16 : sta chr_banks[0]
419 lda #18 : sta chr_banks[1]
420 lda #20 : sta chr_banks[2]
421 lda #21 : sta chr_banks[3]
422 lda #22 : sta chr_banks[4]
423 lda #23 : sta chr_banks[5]
424 .endif
425 .endif
427 lda #5
428 jsr swap_bank ; for game ui data
429 ldcay game_ui_data
430 jsr write_ppu_data_at
431 ldcay pad3d_data
432 jsr write_ppu_data_at
434 ldcay game_palette
435 jsr load_palette
437 jsr initialize_target_lists
439 ; lda #2
440 ; sta game_type
442 ; reset stats
443 .if 0
444 lda player.checkpoint_score+0
445 sta player.score+0
446 lda player.checkpoint_score+1
447 sta player.score+1
448 lda player.checkpoint_score+2
449 sta player.score+2
450 .endif
451 lda #0
452 sta player.score+0
453 sta player.score+1
454 sta player.score+2
455 sta player.current_streak+0
456 sta player.current_streak+1
457 sta player.longest_streak+0
458 sta player.longest_streak+1
459 sta player.missed_count+0
460 sta player.missed_count+1
461 sta player.hit_count+0
462 sta player.hit_count+1
463 sta player.err_count+0
464 sta player.err_count+1
465 sta player.acquired_letters
466 sta player.skull_hit_count
467 sta player.pow_hit_count
468 sta player.star_hit_count
469 sta player.clock_hit_count
470 sta player.fake_skull_hit_count
471 sta player.heart_spawn_count
472 sta player.skull_miss_count
473 sta player.pow_miss_count
474 sta player.star_miss_count
475 sta player.clock_miss_count
476 sta player.fake_skull_miss_count
477 sta player.points_level
478 sta player.vu_level
479 sta player.letter_index
480 sta progress_level
481 sta lockable_lanes
482 sta locked_lanes
483 sta spawned_heart_state
484 sta stat_changed
485 sta global_transpose
486 sta time_mode
487 sta bullet_timer
488 sta display_letter_index
489 sta damage_blink_counter
490 sta screen_shake_counter
491 sta lane_switch_request
492 sta speed_bump_request
493 lda #$FF
494 sta lane_switcher_offset
495 lda #HEART_SPAWN_INTERVAL
496 sta heart_spawn_counter
497 lda player.difficulty
498 sta player.speed_level
500 ; damage levels
501 lda #3 : sta miss_damage
502 lda #2 : sta error_damage
503 lda #6 : sta skull_damage
505 lda play_mode
506 beq +
507 ; in clip mode, bump speed and double damage levels
508 inc player.speed_level
509 asl miss_damage
510 asl error_damage
511 asl skull_damage
513 + jsr game_type_init
515 jsr inc_play_count
517 lda #0
518 sta game_state
520 ; lda #2
521 ; sta player.difficulty
523 ; lda #6
524 ; sta player.speed_level
526 ; lda #1
527 ; sta time_mode
529 jsr sync_hit_area
531 ; lda #1
532 ; sta play_mode
534 lda play_mode
535 beq +
536 ldy player.difficulty
537 lda @@clip_mode_chunk_lengths,y
538 sta target_data_chunk_length
539 sta progress_countdown
540 lda clip_index
541 asl : tay
542 lda clips+0,y
543 sta selected_song
544 lda clips+1,y ; marker
545 + jsr init_target_data
547 lda #0
548 jsr mixer_set_muted_channels
549 lda #0
550 jsr start_song
552 inc main_cycle
554 jsr screen_on
555 jsr nmi_on
557 lda #0 : ldy #31
558 jsr set_fade_range
559 lda #6
560 jsr set_fade_delay
561 jmp start_fade_from_black
563 @@clip_mode_chunk_lengths:
564 .db 22 ; easy
565 .db 25 ; normal
566 .db 29 ; hard
567 .endp
569 clips:
570 ; song, marker
571 .db 0,3 ; 20-24 ocean, chorus
572 .db 2,1 ; 05-07 ripe, 2nd verse
573 .db 3,1 ; 0D-0F break, chorus
574 .db 4,1 ; 18-19 count, "bluesy" part
575 .db 5,1 ; 10-11 levva livet, chorus
577 .db 1,1 ; 0D-0E burn, "instrumental"
578 .db 0,2 ; 18-1C ocean, "a capella"
579 .db 3,2 ; 10-13 break, solo
580 .db 2,2 ; 0E-10 ripe, take-off
581 .db 5,2 ; 18-19 levva livet solo
582 .db 4,2 ; 1A-1D count, two guitars
584 .db 0,1 ; 10-14 ocean, solo
585 .db 2,3 ; 10-12 ripe, next-to-last part
586 .db 1,2 ; 15-18 burn, "hunk-a-hunk"
587 .db 4,3 ; 1E-22 count, chorus last time
589 .proc inc_play_count
590 inc play_count+0
591 bne +
592 inc play_count+1
593 + rts
594 .endp
596 .proc initialize_target_lists
597 lda #$FF
598 sta active_targets_head
599 sta active_targets_tail
600 sta hit_targets_head
601 sta hit_targets_tail
602 sta missed_targets_head
603 sta missed_targets_tail
604 ldx #0
605 stx free_targets_list
606 - txa
608 adc #sizeof target_1
609 sta targets_2.next,x
611 cpx #(sizeof target_1 * (MAX_TARGETS-1))
612 bne -
613 lda #$FF
614 sta targets_2.next,x
616 .endp
618 ; Destroys: A, Y
619 .proc sync_hit_area
620 ; set hit pos and extent according to speed level
621 ldy player.speed_level
622 lda @@hit_extent_table,y
623 sta hit_extent
624 lda @@hit_start_y_table,y
625 sta hit_start_y
627 @@hit_extent_table:
628 .db 14,16,18,21,24,28,32,34
629 @@hit_start_y_table:
630 .db 197,196,195,194,192,190,188,186
631 .endp
633 ; A = marker (0 = beginning)
634 .proc init_target_data
636 lda selected_song
637 ; lda #2
638 asl : asl : asl : asl ; each entry is 16 bytes
640 lda target_data_table+1,y
641 sta target_song
644 ora player.speed_level
646 lda target_data_table+2,x ; delay until song is started
648 lda target_data_table+0,y ; 16K bank to load @ $8000
651 ; set target data pointer based on difficulty
654 adc player.difficulty
655 adc player.difficulty
657 lda target_data_table+10,y
658 sta target_data.lo
659 lda target_data_table+11,y
660 sta target_data.hi
662 lda #0
663 sta target_data_bit_ctr
666 jsr swap_bank
668 ; Target data header: speed (1 byte), chunk length (1 byte)
669 jsr fetch_target_data_byte
670 sta target_data_speed
671 jsr fetch_target_data_byte
672 ldx play_mode
673 bne +
674 sta target_data_chunk_length
675 sta progress_countdown
677 + lda #1
678 jsr set_target_data_timer
680 lda #0
681 jsr mixer_set_muted_channels
682 ; the song is started later, to be in sync with the target data
684 sta begin_song_timer+0
685 jsr init_begin_song_timer_lo
687 pla ; marker
689 ; data base pointer
690 jsr fetch_target_data_byte
691 pha ; low
692 jsr fetch_target_data_byte
693 pha ; hi
695 ; marker data
697 asl : asl : tay
698 lda [target_data],y ; offset low
699 sta tmp
701 lda [target_data],y ; offset high
704 lda [target_data],y ; order start
705 sta target_song_order_skip
707 lda [target_data],y ; pattern row start
708 sta target_song_row_skip
710 sta target_data.hi
711 lda tmp
712 sta target_data.lo
714 ; divide by 8 (since the offset is in bits)
715 lsr target_data.hi
716 ror target_data.lo
717 lsr target_data.hi
718 ror target_data.lo
719 lsr target_data.hi
720 ror target_data.lo
722 ; add base pointer
723 pla ; hi
725 pla ; lo
727 adc target_data.lo
728 sta target_data.lo
730 adc target_data.hi
731 sta target_data.hi
733 lda tmp
734 and #7
735 beq +
736 jsr read_target_data_bits
737 + rts
738 .endp
740 ; Initialization that's specific to the game type.
741 .proc game_type_init
742 ; for 1-player, target attributes are fixed
743 ; for 2-player, they must be in sync with lane mapping
744 lda #0
745 sta normal_target_attributes+0 ; left
746 sta normal_target_attributes+1 ; right
747 ldx game_type
748 bne +
749 lda #2 ; 1 player: middle targets always yellow
750 + sta normal_target_attributes+2 ; middle
751 lda #3
752 sta normal_target_attributes+3 ; B
753 sta normal_target_attributes+4 ; A
755 lda #ENERGY_MAX
756 sta player.energy_level+0
757 sta displayed_energy_level+0
758 ldx game_type
759 cpx #2 ; versus?
760 beq +
761 lda #0
762 + sta player.energy_level+1
763 sta displayed_energy_level+1
765 cpx #2
766 beq + ; no score in versus
767 jsr print_score
768 .ifndef NO_TOP_SCORE
769 jsr print_top_score
770 .endif
771 .ifdef LIFE_SUPPORT
772 jsr print_life_count
773 .endif
775 + lda game_type
776 beq @@one_player_init
778 ; 2 players
779 lda #%00111
780 sta player_lanes+0 ; player 1 lanes
781 lda #%11000
782 sta player_lanes+1 ; player 2 lanes
784 lda game_type
785 cmp #1
786 beq @@write_normal_interface
787 ; versus
788 ; who starts with middle lane is determined by play count
789 lda play_count : and #2 : asl
790 eor player_lanes+0
791 sta player_lanes+0
792 and #4 : eor #4
793 eor player_lanes+1
794 sta player_lanes+1
795 lda play_count : and #1
796 beq +
797 ; swap the lanes
798 lda player_lanes+0
799 eor #%11111
800 sta player_lanes+0
801 lda player_lanes+1
802 eor #%11111
803 sta player_lanes+1
804 + jsr sync_normal_target_attributes
805 lda #$10
806 sta palette+5 ; gray instead of dark green
807 ldcay @@versus_interface_data
808 jmp write_ppu_data_at
810 @@one_player_init:
811 lda #%11111
812 sta player_lanes+0 ; player 1 lanes
813 lda #%00000
814 sta player_lanes+1 ; player 2 lanes
815 @@write_normal_interface:
816 ldcay @@normal_interface_data
817 jmp write_ppu_data_at
819 @@versus_interface_data:
820 ; progress indicator (initially "empty")
821 .db $20,$2B,$54,$0F
822 ; energy bars (initially full)
823 .db $20,$6B,$54,$0A
824 .db $20,$8B,$54,$0A
825 ; attributes
826 .db $23,$C2,$46,$5A
827 .db 0
829 @@normal_interface_data:
830 ; score: PTS-
831 .db $20,$4B,$03,$01,$02,$03
832 ; D-PAD HERO (letter placeholders)
833 .db $20,$55,$0A,$04,$8E,$05,$06,$04,$00,$07,$08,$09,$8D
834 .ifndef NO_TOP_SCORE
835 .db $20,$56,$03,$03,$04,$05 ; TOP
836 .endif
837 ; progress indicator (initially "empty")
838 .db $20,$6B,$54,$0F
839 ; energy bar (initially full)
840 .db $20,$8B,$54,$0A
841 .ifdef LIFE_SUPPORT
842 ; the X left of life count
843 .db $20,$67,$01,$1F
844 .endif
845 ; attributes
846 .db $23,$C3,$45,$AA
847 .db 0
848 .endp
850 .proc set_default_button_mapping
851 ldy #4
852 - lda @@mapping,y
853 sta button_mapping,x
856 bpl -
858 @@mapping:
859 ; LEFT, RIGHT, SELECT, B, A
860 .db 1, 0, 5, 6, 7
861 .endp
863 .if 0
864 .proc set_emu_button_mapping
865 ldy #4
866 - lda @@mapping,y
867 sta button_mapping,x
870 bpl -
872 @@mapping:
873 ; B, A, SELECT, LEFT, RIGHT
874 .db 6, 7, 5, 1, 0
875 .endp
877 .proc set_guitar_button_mapping
878 ldy #4
879 - lda @@mapping,y
880 sta button_mapping,x
883 bpl -
885 @@mapping:
886 .db 7, 6, 5, 0, 1
887 .endp
888 .endif
890 ; Y = lane index (0..4)
891 ; Destroys: A, X
892 .proc draw_lane_indicator
893 ; left half
894 jsr next_sprite_index
896 lda #$FD
897 sta sprites.tile,x
898 lda lane_slot_y_coords,y
899 sta sprites._y,x
900 lda lane_slot_x_coords,y
901 sta sprites._x,x
902 lda #2
903 sta sprites.attr,x
904 ; right half
905 jsr next_sprite_index
907 lda #$FD+2
908 sta sprites.tile,x
909 lda lane_slot_y_coords,y
910 sta sprites._y,x
911 lda lane_slot_x_coords,y
913 adc #8
914 sta sprites._x,x
915 lda #2
916 sta sprites.attr,x
918 .endp
920 lane_slot_x_coords:
921 ; LEFT, RIGHT, SELECT, B, A
922 .db 30-6,72+1,120,175-7,224-8
923 lane_slot_y_coords:
924 .db 207,207,207,207,207
926 ; Puts sprites that show which of the lanes are "pressed".
927 .proc draw_pressed_lanes
928 ; lda game_mode
929 ; beq + ; only draw buttons if we're in play mode
930 ; rts
932 ldy #4
933 - lda lane_input+0
934 ora lane_input+1
935 and bitmasktable,y
936 beq +
937 jsr draw_lane_indicator
938 + dey
939 bpl -
941 .endp
943 .proc on_pattern_row_change
944 dec target_data_timer
945 .ifdef DEBUG_TARGET_DATA_TIMER
947 txa : pha
948 tya : pha
949 jsr print_target_data_timer
950 pla : tay
951 pla : tax
953 .endif
954 beq +
956 + lda #1
957 sta should_load_targets
959 .endp
961 .proc maybe_load_targets
962 lda should_load_targets
963 bne +
965 + lda #0
966 sta should_load_targets
967 jmp process_target_data
968 .endp
970 ; X = offset of target being added
971 ; Destroys: A, Y
972 .proc add_to_active_targets_list
973 lda #$FF
974 sta targets_2.next,x
975 ldy active_targets_tail
976 stx active_targets_tail
977 cpy #$FF
978 bne +
979 stx active_targets_head
981 + txa
982 sta targets_2.next,y
984 .endp
986 ; Adds a target.
987 ; A = lane (bits 2..0), type (bits 5..3)
988 ; Y = duration
989 ; Returns: X = offset of added target
990 .proc add_target
991 ; grab target from free list
993 ldx free_targets_list
994 cpx #$FF
995 bne +
996 ; fatal, no more free targets
997 jmp reset
998 + lda targets_2.next,x
999 sta free_targets_list
1001 ; initialize the target
1002 sta targets_1.state,x
1004 sta targets_2.duration,x
1005 lda #0
1006 sta targets_1.pos_y.frac,x
1007 sta targets_1.pos_x.frac,x
1008 lda #48 ; initial Y position
1009 sta targets_1.pos_y.int,x
1010 lda targets_1.state,x
1011 and #7
1013 lda @@initial_x,y
1014 sta targets_1.pos_x.int,x
1015 ; X speed
1016 lda player.speed_level
1017 asl : asl : asl
1018 sta targets_2.speed_x.frac,x ; temp
1020 ora targets_2.speed_x.frac,x
1022 lda @@speed_x_lo,y
1023 sta targets_2.speed_x.frac,x
1024 lda @@speed_x_hi,y
1025 sta targets_2.speed_x.int,x
1026 ; Y speed
1027 lda player.speed_level
1030 lda @@speed_y_table+0,y
1031 sta targets_2.speed_y.int,x
1032 lda @@speed_y_table+1,y
1033 sta targets_2.speed_y.frac,x
1034 jmp add_to_active_targets_list
1035 ; LEFT, RIGHT, SELECT, B, A
1036 @@initial_x:
1037 .db 103,112,120,128,137
1038 @@speed_x_hi:
1039 ; level 0
1040 .db $FF,$FF,$00,$00,$00 : .db 0,0,0
1041 ; level 1
1042 .db $FF,$FF,$00,$00,$00 : .db 0,0,0
1043 ; level 2
1044 .db $FF,$FF,$00,$00,$01 : .db 0,0,0
1045 ; level 3
1046 .db $FE,$FF,$00,$00,$01 : .db 0,0,0
1047 ; level 4
1048 .db $FE,$FF,$00,$00,$01 : .db 0,0,0
1049 ; level 5
1050 .db $FE,$FF,$00,$00,$01 : .db 0,0,0
1051 ; level 6
1052 .db $FE,$FF,$00,$01,$02 : .db 0,0,0
1053 ; level 7
1054 .db $FD,$FE,$00,$01,$02 : .db 0,0,0
1055 @@speed_x_lo:
1056 ; level 0
1057 .db $80,$C0,$00,$40,$80 : .db 0,0,0
1058 ; level 1
1059 .db $40,$A0,$00,$60,$C0 : .db 0,0,0
1060 ; level 2
1061 .db $00,$80,$00,$80,$00 : .db 0,0,0
1062 ; level 3
1063 .db $C0,$60,$00,$A0,$40 : .db 0,0,0
1064 ; level 4
1065 .db $80,$40,$00,$C0,$80 : .db 0,0,0
1066 ; level 5
1067 .db $40,$20,$00,$E0,$C0 : .db 0,0,0
1068 ; level 6
1069 .db $00,$00,$00,$00,$00 : .db 0,0,0
1070 ; level 7
1071 .db $C0,$E0,$00,$20,$40 : .db 0,0,0
1073 @@speed_y_table:
1074 .db $01,$00 ; 1.0
1075 .db $01,$80 ; 1.5
1076 .db $02,$00 ; 2.0
1077 .db $02,$80 ; 2.5
1078 .db $03,$00 ; 3.0
1079 .db $03,$80 ; 3.5
1080 .db $04,$00 ; 4.0
1081 .db $04,$80 ; 4.5
1082 .endp
1084 .proc maybe_request_lane_switch
1085 lda game_type
1086 beq +
1087 ; 2-player
1088 lda lane_switcher_offset
1089 cmp #$FF
1090 bne + ; don't request lane switch if there is already a switcher
1091 lda #1
1092 sta lane_switch_request
1093 + rts
1094 .endp
1096 .proc maybe_request_speed_bump
1097 lda game_type
1098 cmp #2
1099 bne +
1100 ; versus
1101 lda progress_level
1102 and #$0F
1103 bne +
1104 lda player.speed_level
1105 cmp #7
1106 beq +
1107 lda #1
1108 sta speed_bump_request
1109 + rts
1110 .endp
1112 .proc play_speed_bump_sfx
1113 lda #9: ldx #4
1114 jmp start_sfx
1115 .endp
1117 ; Reads target data and adds targets to lanes accordingly.
1118 ; Sets the timer for the next data processing.
1119 .proc process_target_data
1120 lda #4
1121 jsr read_target_data_bits ; lanes specifier
1122 cmp #$0E
1123 bcc @@process_row
1124 beq @@end_of_clip
1125 ; 0F = end of data
1126 lda #0
1127 sta target_data.lo
1128 sta target_data.hi
1131 @@end_of_clip:
1132 lda play_mode
1133 beq process_target_data ; ignore if not in clip mode
1134 lda #0
1135 sta target_data.lo
1136 sta target_data.hi
1139 @@process_row:
1141 lda @@lanes_specifier_mask,y
1142 ldx #0
1143 @@lane_loop:
1145 bcc @@next
1146 pha ; save lanes mask
1147 lda #1
1148 jsr read_target_data_bits ; read normal/extended type bit
1149 lsr ; if it's zero, it's a normal target (type 0)
1150 bcc @@add_normal
1151 ; special type
1152 lda #3
1153 jsr read_target_data_bits ; type - 1
1154 clc : adc #1
1155 ldy game_type
1156 cpy #2 ; versus?
1157 beq +
1158 ldy play_mode
1159 bne + ; clip mode?
1160 beq ++
1161 + cmp #5
1162 bcc ++
1163 sbc #5 ; letter -> normal, fake skull -> skull
1164 ++ asl : asl : asl
1165 sta tmp
1166 txa ; lane index
1168 ora tmp
1169 ldy #1 ; duration
1170 jsr add_target
1171 jmp @@done_adding
1172 @@add_normal:
1173 txa ; lane index
1175 ; TODO - in boss mode, it becomes a skull (ora #$08) -- unless it is a lane switcher
1176 ldy #1 ; duration
1177 jsr add_target
1178 lda lane_switch_request
1179 beq @@done_adding
1180 pla ; lane index
1182 cmp #2 ; lane switcher only occurs in middle lane
1183 bne @@done_adding
1184 stx lane_switcher_offset ; this is the lane switcher target!
1185 lda #0
1186 sta lane_switch_request
1187 @@done_adding:
1189 tax ; restore lane index
1190 pla ; restore lanes mask
1191 @@next:
1193 cpx #5
1194 bne @@lane_loop
1196 dec progress_countdown
1197 bne @@set_next_delay
1198 inc progress_level
1199 jsr maybe_request_lane_switch
1200 jsr maybe_request_speed_bump
1201 lda stat_changed
1202 ora #4
1203 sta stat_changed
1204 lda target_data_chunk_length
1205 sta progress_countdown
1207 @@set_next_delay:
1208 lda #TARGET_DATA_DELAY_WIDTH
1209 jsr read_target_data_bits
1211 lda target_data_timer_table,y
1212 ldy speed_bump_request
1213 beq +
1214 sta tmp
1215 lda #0
1216 sta speed_bump_request
1217 ; Add the difference between next speed level and this one,
1218 ; in order to keep the target data in sync.
1219 lda selected_song
1220 asl : asl : asl : asl ; * 16
1221 ora player.speed_level
1222 inc player.speed_level
1224 lda target_data_table+2,y
1226 sbc target_data_table+3,y
1227 clc : adc tmp
1229 jsr sync_hit_area
1230 jsr play_speed_bump_sfx
1232 + jsr set_target_data_timer
1233 .ifdef DEBUG_TARGET_DATA_TIMER
1234 jmp print_target_data_timer
1235 .else
1237 .endif
1239 @@lanes_specifier_mask:
1240 .db %00000 ; 0 - none
1241 .db %00001 ; 1 - left
1242 .db %00010 ; 2 - right
1243 .db %00100 ; 3 - select
1244 .db %01000 ; 4 - B
1245 .db %10000 ; 5 - A
1246 .db %01001 ; 6 - left + B
1247 .db %10001 ; 7 - left + A
1248 .db %01010 ; 8 - right + B
1249 .db %10010 ; 9 - right + A
1250 .db %11000 ; 10 - B + A
1251 .endp
1253 .ifdef DEBUG_TARGET_DATA_TIMER
1254 .proc print_target_data_timer
1255 lda target_data_timer : sta AC0
1256 lda #0 : sta AC1 : sta AC2
1257 ldx #2 : lda #$22 : ldy #$10
1258 jmp print_value
1259 .endp
1260 .endif
1262 .proc toggle_time_mode
1263 lda time_mode
1264 eor #1
1265 sta time_mode
1266 lda global_transpose
1267 eor #$F4
1268 sta global_transpose
1269 jsr is_music_paused
1270 sta was_music_paused
1271 bne +
1272 jsr pause_music
1273 + jsr mixer_get_muted_channels
1274 sta saved_muted_channels
1275 lda #$1F
1276 jsr mixer_set_muted_channels
1277 lda time_mode
1278 ora #4
1279 ldx #4
1280 jsr start_sfx
1281 lda #80
1282 sta transition_timer
1284 .endp
1286 ; Counts number of 1 bits in A.
1287 ; Returns: X=number of 1 bits
1288 ; Destroys: A, Y
1289 .proc count_bits
1290 ldy #7
1291 ldx #0
1292 - lsr
1293 bcc +
1295 + dey
1296 bpl -
1298 .endp
1300 ; X = player (0 or 1)
1301 .proc check_for_errors
1302 lda hittable_lanes
1303 and player_lanes,x
1304 eor lane_input_posedge,x
1305 and lane_input_posedge,x
1306 sta error_lanes,x
1307 lda locked_lanes
1308 ora lockable_lanes
1309 eor #$FF
1310 and error_lanes,x
1311 sta error_lanes,x
1312 bne +
1314 + jsr deal_error_pain
1315 jsr inc_error_count
1316 jsr reset_points_level
1317 jsr reset_streak
1318 jsr dec_vu_level
1320 .endp
1322 ; The most important piece of game logic.
1323 ; Finds out which targets are hittable and hit,
1324 ; explodes hit targets unless no errors (cheating),
1325 ; updates stats.
1326 ; Moves missed targets to missed list.
1327 .proc process_active_targets
1328 lda #0
1329 sta checked_lanes
1330 sta hittable_lanes
1331 sta hit_lanes
1332 lda #$FF
1333 sta prev
1334 ldy active_targets_head
1336 @@loop:
1337 cpy #$FF ; end of list?
1338 bne @@do_target
1340 ldx #0
1341 jsr check_for_errors
1342 ldx #1
1343 jsr check_for_errors
1344 jmp sweep_active_targets
1346 @@do_target:
1347 jsr draw_target
1348 jsr move_target
1350 lda targets_1.state,y
1351 and #7 ; lane
1353 lda bitmasktable,x
1354 and checked_lanes
1355 beq +
1356 jmp @@next ; we already checked this lane, target can't possible be within hit range
1357 + lda bitmasktable,x
1358 ora checked_lanes
1359 sta checked_lanes
1360 ; not hittable, hittable or missed?
1361 lda targets_1.pos_y.int,y
1363 sbc hit_start_y
1364 bcc @@next ; not hittable
1365 sbc hit_extent
1366 bcs @@missed
1368 ; it's hittable
1369 lda bitmasktable,x
1370 ora hittable_lanes
1371 sta hittable_lanes
1372 ; is it actually hit?
1373 lda lane_input_posedge+0
1374 and bitmasktable,x
1375 bne @@hit_by_player_1
1376 - lda lane_input_posedge+1
1377 and bitmasktable,x
1378 bne @@hit_by_player_2
1379 ; if the lane is locked, hit anyway unless it's a skull
1380 -- lda bitmasktable,x
1381 and locked_lanes
1382 beq @@next
1383 lda targets_1.state,y
1384 and #$38 ; type
1385 cmp #$08
1386 beq @@next
1387 bne @@hit
1389 @@hit_by_player_1:
1390 lda player_lanes+0
1391 and bitmasktable,x
1392 beq - ; ignore, player 1 does not control this lane
1393 jmp @@hit
1395 @@hit_by_player_2:
1396 lda player_lanes+1
1397 and bitmasktable,x
1398 beq -- ; ignore, player 2 does not control this lane
1400 @@hit:
1401 lda bitmasktable,x
1402 ora hit_lanes
1403 sta hit_lanes
1405 @@next:
1406 lda targets_2.next,y
1407 sty prev
1409 jmp @@loop
1411 @@missed:
1412 lda targets_1.state,y
1413 and #$38 ; type
1414 beq @@miss_normal
1415 cmp #$08
1416 beq @@miss_skull
1417 cmp #$10
1418 beq @@miss_pow
1419 cmp #$18
1420 beq @@miss_star
1421 cmp #$20
1422 beq @@miss_clock
1423 cmp #$28
1424 beq @@miss_letter
1425 cmp #$30
1426 beq @@miss_fake_skull
1428 @@miss_skull:
1429 ; TODO - in boss mode, hurt the player!
1430 jmp @@move_to_missed_list
1432 @@miss_pow:
1433 inc player.pow_miss_count
1434 jmp @@move_to_missed_list
1436 @@miss_star:
1437 inc player.star_miss_count
1438 jmp @@move_to_missed_list
1440 @@miss_clock:
1441 inc player.clock_miss_count
1442 jmp @@move_to_missed_list
1444 @@miss_letter:
1445 jmp @@move_to_missed_list
1447 @@miss_fake_skull:
1448 inc player.fake_skull_miss_count
1449 tya : pha
1450 lda #13 : ldx #4
1451 jsr start_sfx
1452 pla : tay
1453 jmp @@move_to_missed_list
1455 @@miss_normal:
1456 ; missing a normal target is punished - if player(s) alive
1457 lda player.energy_level+0
1458 beq @@move_to_missed_list
1459 lda game_type
1460 eor #2
1461 ora player.energy_level+1 ; versus && player 2 dead
1462 beq @@move_to_missed_list
1463 cpy lane_switcher_offset
1464 bne +
1465 ; fake a hit, to enable automatic lane switch
1466 lda #4 ; middle lane mask
1467 ora hit_lanes
1468 sta hit_lanes
1469 lda #$FF
1470 sta lane_switcher_offset
1471 jsr switch_player_lane_mapping
1472 jmp @@next
1474 + jsr inc_missed_count
1475 jsr reset_points_level
1476 jsr reset_streak
1477 jsr dec_vu_level
1479 ldx #0 ; default: 1st player
1480 lda game_type
1481 cmp #2 ; versus?
1482 bne +
1483 ; in versus mode, hurt player is determined by lane
1484 lda targets_1.state,y
1485 and #7 ; lane
1487 jsr player_for_lane
1488 + lda miss_damage
1489 jsr sub_energy_with_pain
1491 ; turn off the sound channel
1492 jsr mixer_get_muted_channels
1493 ora #3
1494 jsr mixer_set_muted_channels
1496 @@move_to_missed_list:
1497 lda targets_2.next,y
1499 lda #$FF
1500 sta targets_2.next,y
1501 ldx missed_targets_tail
1502 sty missed_targets_tail
1503 cpx #$FF
1504 bne +
1505 sty missed_targets_head
1506 jmp ++
1507 + tya
1508 sta targets_2.next,x
1509 ++ pla
1510 ldx prev
1511 cpy active_targets_tail
1512 bne +
1513 stx active_targets_tail
1514 + tay
1515 cpx #$FF
1516 bne +
1517 sty active_targets_head
1518 jmp @@loop
1519 + sta targets_2.next,x
1520 jmp @@loop
1521 .endp
1523 ; In: X = lane index
1524 ; Out: X = player
1525 .proc player_for_lane
1526 lda bitmasktable,x
1527 ldx #0
1528 and player_lanes+0
1529 bne +
1531 + rts
1532 .endp
1534 ; X = player (0 or 1)
1535 .proc deal_error_pain
1536 ldy #0
1537 @@loop:
1538 lda bitmasktable,y
1539 and error_lanes,x
1540 beq @@next
1541 lda error_damage
1542 jsr sub_energy_with_pain
1543 @@next:
1545 cpy #5
1546 bne @@loop
1548 .endp
1550 ; process_active_targets() helper function.
1551 ; Explodes active targets that were hit and moves them to the hit list.
1552 .proc sweep_active_targets
1553 lda #$FF
1554 sta prev
1555 ldy active_targets_head
1556 @@loop:
1557 lda hit_lanes
1558 bne @@check_target
1561 @@check_target:
1562 lda targets_1.state,y
1563 and #7 ; lane
1565 lda bitmasktable,x
1566 and hit_lanes
1567 bne @@hit_target
1568 lda targets_2.next,y
1569 sty prev
1571 jmp @@loop
1573 @@hit_target:
1574 lda bitmasktable,x
1575 eor #$FF
1576 and hit_lanes
1577 sta hit_lanes
1579 ; type determines what happens
1580 lda targets_1.state,y
1581 and #$38 ; type
1582 bne +
1583 jmp @@hit_normal
1584 + cmp #$08
1585 beq @@hit_skull
1586 cmp #$10
1587 beq @@hit_pow
1588 cmp #$18
1589 beq @@hit_star
1590 cmp #$20
1591 beq @@hit_clock
1592 cmp #$28
1593 beq @@hit_letter
1594 cmp #$30
1595 beq @@hit_fake_skull
1597 @@hit_skull:
1598 inc player.skull_hit_count
1599 ; TODO - in boss mode, always subtract from 2nd player (boss), and shake screen
1600 ; @@hit_bad:
1601 lda targets_1.state,y
1602 and #7 ; lane
1604 jsr player_for_lane
1605 lda skull_damage
1606 jsr sub_energy_with_pain
1607 jmp @@loop
1609 @@hit_pow:
1610 lda #8
1611 jsr shake_screen
1612 inc player.pow_hit_count
1613 jsr sync_powable_lanes
1614 tya : pha
1615 lda #1: ldx #4
1616 jsr start_sfx
1617 pla : tay
1618 jmp pow_active_targets
1620 @@hit_star:
1621 inc player.star_hit_count
1622 lda #0
1623 sta locked_lanes
1624 lda #%11111
1625 sta lockable_lanes
1626 tya : pha
1627 lda #10: ldx #4
1628 jsr start_sfx
1629 pla : tay
1630 jmp @@explode_in_place
1632 @@hit_clock:
1633 inc player.clock_hit_count
1634 lda time_mode
1635 bne +
1638 jsr toggle_time_mode
1641 + jmp @@explode_in_place
1643 @@hit_letter:
1644 ldx player.letter_index
1645 cpx #8
1646 bcs + ; it's really an error in the mapping, there shouldn't be more than eight
1647 lda bitmasktable,x
1648 ora player.acquired_letters
1649 sta player.acquired_letters
1650 inc player.letter_index
1651 lda stat_changed
1652 ora #$40
1653 sta stat_changed
1654 tya : pha
1655 lda #12 : ldx #4
1656 jsr start_sfx
1657 pla : tay
1658 + jmp @@explode_in_place
1660 @@hit_fake_skull:
1661 inc player.fake_skull_hit_count
1662 tya : pha
1663 lda #11 : ldx #4
1664 jsr start_sfx
1665 pla : tay
1666 jmp @@explode_in_place
1668 @@hit_normal:
1669 ; TODO - in boss mode, hitting normal targets is bad
1670 ; jmp @@hit_bad
1671 jsr on_normal_target_hit
1672 cpy lane_switcher_offset
1673 bne +
1674 lda #$FF
1675 sta lane_switcher_offset
1676 jsr switch_player_lane_mapping
1677 jmp @@explode_in_place
1678 + lda game_type
1679 cmp #2 ; 2 player versus?
1680 beq @@explode_in_place ; if so, no hearts ever spawned
1681 lda targets_1.state,y
1682 and #7 ; lane
1684 jsr maybe_spawn_heart
1686 @@explode_in_place:
1687 lda #200
1688 sta targets_1.pos_y,y
1689 jsr explode_target
1690 jmp @@loop
1691 .endp
1693 ; Y = offset of POW target
1694 .proc sync_powable_lanes
1695 lda game_type
1696 cmp #2 ; versus?
1697 beq +
1698 ; in 1-player and co-op, all lanes are POWable
1699 lda player_lanes+0
1700 ora player_lanes+1
1701 sta powable_lanes
1703 ; in versus, only the lanes of the player that
1704 ; hit the POW are POWable
1705 + lda targets_1.state,y
1706 and #7 ; lane
1708 jsr player_for_lane
1709 lda player_lanes,x
1710 sta powable_lanes
1712 .endp
1714 ; sync attributes based on player 1 mapping
1715 ; (mapped to player 1 is blue, otherwise red)
1716 ; Destroys: A, X
1717 .proc sync_normal_target_attributes
1718 lda player_lanes
1719 ldx #0
1720 - pha
1721 and #1 : eor #1 : cmp #1 : rol ; 0 or 3
1722 sta normal_target_attributes,x
1726 cpx #5
1727 bne -
1729 .endp
1731 .proc switch_player_lane_mapping
1732 .if 0
1733 ; "random" switch (makes it very difficult)
1734 lda player_lanes+0
1735 and #4
1737 lda frame_count
1738 - and #7
1739 cmp #6
1740 bcc +
1741 sbc #6
1742 + tax
1743 lda @@player_1_lanes,x
1744 cmp player_lanes+0
1745 bne +
1748 jmp -
1749 + sta player_lanes+0
1750 lda @@player_2_lanes,x
1751 sta player_lanes+1
1754 ora player_lanes+1
1755 sta player_lanes+1
1757 eor #4
1758 ora player_lanes+0
1759 sta player_lanes+0
1760 .else
1761 lda player_lanes+0
1762 eor #%11111
1763 sta player_lanes+0
1764 lda player_lanes+1
1765 eor #%11111
1766 sta player_lanes+1
1767 .endif
1768 jsr sync_normal_target_attributes
1769 ; play switch SFX
1770 tya : pha
1771 lda #6 : ldx #4
1772 jsr start_sfx
1773 pla : tay
1775 .if 0
1776 @@player_1_lanes:
1777 .db %00011
1778 .db %11000
1779 .db %01001
1780 .db %10010
1781 .db %10001
1782 .db %01010
1783 @@player_2_lanes:
1784 .db %11000
1785 .db %00011
1786 .db %10010
1787 .db %01001
1788 .db %01010
1789 .db %10001
1790 .endif
1791 .endp
1793 .proc on_normal_target_hit
1794 lda player.energy_level
1795 bne +
1796 rts ; dead, don't care
1797 ; turn on the sound channel
1798 + jsr mixer_get_muted_channels
1799 and #$FC
1800 jsr mixer_set_muted_channels
1802 ; increase stats
1803 jsr inc_hit_count
1804 jsr inc_streak
1805 lda player.current_streak+0
1806 and #3
1807 bne +
1808 jsr inc_vu_level
1809 + lda game_type
1810 cmp #2 ; versus?
1811 bne +
1813 ; inc score
1814 + tya
1816 lda player.points_level
1819 lda @@scores+1,x
1821 lda @@scores+0,x
1822 jsr add_score
1827 @@scores:
1828 .dw 25, 50, 75, 100
1829 .endp
1831 ; Explodes target with offset in Y.
1832 ; Variable prev must contain the offset of the previous target,
1833 ; or $FF if it's the head of the list.
1834 ; Destroys: A, X, Y
1835 .proc explode_target
1836 lda targets_1.state,y
1837 ora #$80 ; bit 7 indicates that the target is exploded (used by draw routine)
1838 and #~$38 ; clear type bits
1839 sta targets_1.state,y
1840 ; move to hit list
1841 lda targets_2.next,y
1843 lda #$FF
1844 sta targets_2.next,y
1845 ldx hit_targets_tail
1846 sty hit_targets_tail
1847 cpx #$FF
1848 bne +
1849 sty hit_targets_head
1850 jmp ++
1851 + tya
1852 sta targets_2.next,x
1853 ++ pla ; next
1854 ldx prev
1855 cpy active_targets_tail
1856 bne +
1857 stx active_targets_tail
1858 + tay
1859 cpx #$FF
1860 bne +
1861 sty active_targets_head
1863 + sta targets_2.next,x
1865 .endp
1867 .proc pow_active_targets
1868 lda #$FF
1869 sta prev
1870 ldy active_targets_head
1871 @@loop:
1872 cpy #$FF ; end of list?
1873 bne +
1875 + lda targets_1.state,y
1876 and #$38 ; type
1877 cmp #$28
1878 bcc +
1879 ; don't pow letters and fake skulls
1880 @@skip:
1881 lda targets_2.next,y
1882 sty prev
1884 jmp @@loop
1885 + ora #0
1886 bne +
1887 cpy lane_switcher_offset
1888 beq @@skip
1889 lda targets_1.state,y
1890 and #7 ; lane
1892 lda bitmasktable,x
1893 and powable_lanes
1894 beq @@skip
1895 jsr on_normal_target_hit
1896 + jsr explode_target
1897 ; Y contains next pointer
1898 jmp @@loop
1899 .endp
1901 ; Draws a target.
1902 ; Y = offset of target to draw
1903 .proc draw_target
1904 ; left half
1905 jsr next_sprite_index
1907 lda targets_1.pos_x.int,y
1908 sta sprites._x,x
1909 lda targets_1.pos_y.int,y
1910 sta sprites._y,x
1911 lda targets_1.state,y
1912 bpl + ; jump if not exploding
1913 and #$70
1914 lsr : lsr ; explosion frame * 4
1915 adc #$A1
1916 jmp ++
1917 + lda targets_1.state,y
1918 and #$38 ; type
1919 cmp #$28 ; special orb?
1920 bcc +
1921 sbc #$28
1922 + asl
1923 asl ; type * 32
1924 sta sprites.tile,x
1925 lda targets_1.pos_y.int,y ; sprite ("size") is determined by Y
1927 sbc #48 ; initial Y pos
1930 and #$FC
1931 cmp #$20
1932 bcc +
1933 lda #$1C
1934 + ora #$1
1936 adc sprites.tile,x
1937 ++ sta sprites.tile,x
1940 lda targets_1.state,y
1941 bmi + ; jump if exploding
1942 and #$38 ; type
1943 beq +
1944 ; for special types, the attributes are determined by the type
1949 lda @@special_type_attributes-1,y
1950 jmp ++
1951 ; for normal targets, the attributes are determined by lane number
1952 ; -- unless it's a lane switch indicator, which is always 2
1953 + cpy lane_switcher_offset
1954 bne +
1955 lda #2
1956 bne ++
1957 + lda targets_1.state,y
1958 and #7 ; lane
1960 lda normal_target_attributes,y
1961 ++ sta sprites.attr,x
1964 ; right half
1965 jsr next_sprite_index
1967 lda targets_1.pos_x.int,y
1969 adc #8
1970 sta sprites._x,x
1971 lda targets_1.pos_y.int,y
1972 sta sprites._y,x
1973 lda targets_1.state,y
1974 bpl + ; jump if not exploding
1975 and #$70
1976 lsr : lsr ; explosion frame * 4
1977 adc #$A3
1978 jmp ++
1979 + lda targets_1.state,y
1980 and #$38 ; type
1981 cmp #$28 ; special orb?
1982 bcc +
1983 sbc #$28
1984 + asl
1985 asl ; type * 32
1986 sta sprites.tile,x
1987 lda targets_1.pos_y.int,y ; sprite ("size") is determined by Y
1989 sbc #48 ; initial Y position
1992 and #$FC
1993 cmp #$20
1994 bcc +
1995 lda #$1C
1996 + ora #$3
1998 adc sprites.tile,x
1999 ++ sta sprites.tile,x
2002 lda targets_1.state,y
2003 bmi + ; jump if exploding
2004 and #$38 ; type
2005 beq +
2006 ; for special types, the attributes are determined by the type
2011 lda @@special_type_attributes-1,y
2012 jmp ++
2013 ; for normal targets, the attributes are determined by lane number
2014 ; -- unless it's a lane switch indicator, which is always 2
2015 + cpy lane_switcher_offset
2016 bne +
2017 lda #2
2018 bne ++
2019 + lda targets_1.state,y
2020 and #7
2022 lda normal_target_attributes,y
2023 ++ sta sprites.attr,x
2028 @@special_type_attributes:
2029 .db 3 ; skull
2030 .db 3 ; POW
2031 .db 2 ; star
2032 .db 0 ; clock
2033 .db 1 ; letter
2034 .db $80 | 0 ; fake skull
2035 .endp
2037 ; Moves a target.
2038 ; Y = offset of target to move
2039 .proc move_target
2040 lda time_mode
2041 beq +
2043 ; temporarily divide speed by two
2044 lda targets_2.speed_y.int,y
2045 cmp #$80
2047 sta targets_2.speed_y.int,y
2048 lda targets_2.speed_y.frac,y
2050 sta targets_2.speed_y.frac,y
2051 lda targets_2.speed_x.int,y
2052 cmp #$80
2054 sta targets_2.speed_x.int,y
2055 lda targets_2.speed_x.frac,y
2057 sta targets_2.speed_x.frac,y
2060 + lda targets_1.pos_y.frac,y
2062 adc targets_2.speed_y.frac,y
2063 sta targets_1.pos_y.frac,y
2064 lda targets_1.pos_y.int,y
2065 adc targets_2.speed_y.int,y
2066 sta targets_1.pos_y.int,y
2068 lda targets_1.pos_x.frac,y
2070 adc targets_2.speed_x.frac,y
2071 sta targets_1.pos_x.frac,y
2072 lda targets_1.pos_x.int,y
2073 adc targets_2.speed_x.int,y
2074 sta targets_1.pos_x.int,y
2076 lda time_mode
2077 beq +
2078 ; restore speed (multiply by 2)
2079 lda targets_2.speed_y.frac,y
2081 sta targets_2.speed_y.frac,y
2082 lda targets_2.speed_y.int,y
2084 sta targets_2.speed_y.int,y
2085 lda targets_2.speed_x.frac,y
2087 sta targets_2.speed_x.frac,y
2088 lda targets_2.speed_x.int,y
2090 sta targets_2.speed_x.int,y
2091 + rts
2092 .endp
2094 .proc process_hit_targets
2095 lda #$FF
2096 sta prev
2097 ldy hit_targets_head
2098 @@loop:
2099 cpy #$FF
2100 bne +
2102 + jsr draw_target
2103 lda frame_count
2105 bcc +
2106 lda targets_1.state,y
2107 and #$70
2108 cmp #$70 ; reached last frame?
2109 beq @@evaporated
2110 lda targets_1.state,y
2112 adc #$10 ; advance to next frame
2113 sta targets_1.state,y
2114 + lda targets_2.next,y
2116 jmp @@loop
2118 @@evaporated:
2119 lda targets_2.next,y
2121 ; put on free list
2122 lda free_targets_list
2123 sta targets_2.next,y
2124 sty free_targets_list
2126 ; remove from hit targets list
2127 cpy hit_targets_tail
2128 bne +
2129 sta hit_targets_tail
2130 + tay
2131 ldx prev
2132 cpx #$FF
2133 bne +
2134 sty hit_targets_head
2135 jmp @@loop
2136 + sta targets_2.next,x
2137 jmp @@loop
2138 .endp
2140 .proc process_missed_targets
2141 lda #$FF
2142 sta prev
2143 ldy missed_targets_head
2144 @@loop:
2145 cpy #$FF
2146 bne +
2148 + jsr draw_target
2149 jsr move_target
2151 lda targets_1.pos_y.int,y
2152 cmp #240
2153 bcs @@fell_off
2154 lda targets_2.next,y
2155 sty prev
2157 jmp @@loop
2159 @@fell_off:
2160 lda targets_2.next,y
2162 ; put on free list
2163 lda free_targets_list
2164 sta targets_2.next,y
2165 sty free_targets_list
2167 ; remove from missed targets list
2168 cpy missed_targets_tail
2169 bne +
2170 sta missed_targets_tail
2171 + tay
2172 ldx prev
2173 cpx #$FF
2174 bne +
2175 sty missed_targets_head
2176 jmp @@loop
2177 + sta targets_2.next,x
2178 jmp @@loop
2179 .endp
2181 .proc inc_hit_count
2182 inc player.hit_count+0
2183 bne +
2184 inc player.hit_count+1
2185 + rts
2186 .endp
2188 .proc inc_missed_count
2189 inc player.missed_count+0
2190 bne +
2191 inc player.missed_count+1
2192 + rts
2193 .endp
2195 .proc inc_error_count
2196 inc player.err_count+0
2197 bne +
2198 inc player.err_count+1
2199 + rts
2200 .endp
2202 .proc inc_streak
2203 inc player.current_streak+0
2204 bne +
2205 inc player.current_streak+1
2206 + lda game_type
2207 cmp #2 ; versus?
2208 beq + ; no points level
2209 lda player.current_streak+1
2210 bne +
2211 lda player.current_streak+0
2212 cmp #8
2213 beq @@inc_points_level
2214 cmp #16
2215 beq @@inc_points_level
2216 cmp #24
2217 bne +
2218 @@inc_points_level:
2219 inc player.points_level
2220 lda stat_changed
2221 ora #$20
2222 sta stat_changed
2223 + jmp sync_longest_streak
2224 .endp
2226 .proc sync_longest_streak
2227 lda player.longest_streak+0
2229 sbc player.current_streak+0
2230 lda player.longest_streak+1
2231 sbc player.current_streak+1
2232 bcs +
2233 ; new longest streak
2234 lda player.current_streak+0
2235 sta player.longest_streak+0
2236 lda player.current_streak+1
2237 sta player.longest_streak+1
2238 + rts
2239 .endp
2241 .proc reset_points_level
2242 lda #0
2243 sta player.points_level
2244 lda stat_changed
2245 ora #$20
2246 sta stat_changed
2248 .endp
2250 .proc reset_streak
2251 lda #0
2252 sta player.current_streak+0
2253 sta player.current_streak+1
2255 .endp
2257 .proc inc_vu_level
2258 lda player.vu_level
2259 cmp #12
2260 bcs +
2261 inc player.vu_level
2262 + rts
2263 .endp
2265 .proc dec_vu_level
2266 lda player.vu_level
2267 beq +
2268 dec player.vu_level
2269 + rts
2270 .endp
2272 ; A = amount
2273 ; X = player (0 or 1)
2274 .proc sub_energy
2275 eor #$FF
2277 adc #1
2278 adc player.energy_level,x
2279 bcs @@set
2280 lda player.energy_level,x
2281 bne @@set_zero
2282 rts ; already dead
2283 @@set_zero:
2284 lda #0
2285 @@set:
2286 sta player.energy_level,x
2287 lda stat_changed
2288 ora #8
2289 sta stat_changed
2291 .endp
2293 ; A = amount
2294 ; X = player (0 or 1)
2295 .proc sub_energy_with_pain
2296 jsr sub_energy
2297 lda #4
2298 sta damage_blink_counter
2299 tya : pha
2300 lda #3
2301 jsr play_dmc_sample ; "ouch!"
2302 pla : tay
2304 .endp
2306 .proc add_energy
2308 adc player.energy_level
2309 bcs @@clip
2310 cmp #ENERGY_MAX
2311 bcc @@set
2312 @@clip:
2313 lda #ENERGY_MAX
2314 @@set:
2315 sta player.energy_level
2316 lda stat_changed
2317 ora #8
2318 sta stat_changed
2320 .endp
2322 .proc sub_score
2323 eor #$FF
2325 adc #1
2326 adc player.score+0
2327 sta player.score+0
2328 lda player.score+1
2329 adc #$FF
2330 sta player.score+1
2331 lda player.score+2
2332 adc #$FF
2333 sta player.score+2
2334 bcs +
2335 lda #0
2336 sta player.score+0
2337 sta player.score+1
2338 sta player.score+2
2339 + lda stat_changed
2340 ora #1
2341 sta stat_changed
2343 .endp
2345 ; Adds number in A,Y to score.
2346 ; Destroys: A, Y
2347 .proc add_score
2349 adc player.score+0
2350 sta player.score+0
2352 adc player.score+1
2353 sta player.score+1
2354 lda #0
2355 adc player.score+2
2356 sta player.score+2
2357 beq +
2358 cmp #$02
2359 bcs ++
2360 lda player.score+1
2361 cmp #$86
2362 bcc +
2363 bne ++
2364 lda player.score+0
2365 cmp #$A0
2366 bcc +
2367 ; clamp
2368 ++ lda #$9F : sta player.score+0
2369 lda #$86 : sta player.score+1
2370 lda #$01 : sta player.score+2
2371 + lda game_type
2372 cmp #2 ; versus?
2373 bne +
2375 + lda stat_changed
2376 ora #1
2377 sta stat_changed
2378 ; lda game_mode
2379 ; beq + ; only sync the top score if we're in play mode
2380 ; rts
2382 ; ### possibly award extra life
2383 .ifndef NO_TOP_SCORE
2384 jmp sync_top_score
2385 .else
2387 .endif
2388 .endp
2390 .ifndef NO_TOP_SCORE
2391 .proc sync_top_score
2392 lda player.top_score
2394 sbc player.score
2395 lda player.top_score+1
2396 sbc player.score+1
2397 lda player.top_score+2
2398 sbc player.score+2
2399 bcs +
2400 ; new top score
2401 lda player.score
2402 sta player.top_score
2403 lda player.score+1
2404 sta player.top_score+1
2405 lda player.score+2
2406 sta player.top_score+2
2407 lda stat_changed
2408 ora #2
2409 sta stat_changed
2410 + rts
2411 .endp
2412 .endif
2414 .proc draw_vu_pin
2415 ldy player.vu_level
2416 lda @@sprite_data_offsets,y
2418 - lda @@sprite_data+0,y
2419 bne +
2421 + jsr next_sprite_index
2423 lda @@sprite_data+0,y
2424 sta sprites._y,x
2425 lda @@sprite_data+1,y
2426 sta sprites.tile,x
2427 lda @@sprite_data+2,y
2428 sta sprites.attr,x
2429 lda @@sprite_data+3,y
2430 sta sprites._x,x
2435 jmp -
2436 @@sprite_data_offsets:
2437 .db @@l0-@@sprite_data
2438 .db @@l1-@@sprite_data
2439 .db @@l2-@@sprite_data
2440 .db @@l3-@@sprite_data
2441 .db @@l4-@@sprite_data
2442 .db @@l5-@@sprite_data
2443 .db @@l6-@@sprite_data
2444 .db @@l7-@@sprite_data
2445 .db @@l8-@@sprite_data
2446 .db @@l9-@@sprite_data
2447 .db @@l10-@@sprite_data
2448 .db @@l11-@@sprite_data
2449 .db @@l12-@@sprite_data
2450 @@sprite_data:
2451 @@l0:
2452 .db 170-99,$D7,0,194
2453 .db 170-99,$D9,0,194+8
2454 .db 170-99,$DB,0,194+16
2455 .db 0
2456 @@l1:
2457 .db 167-99,$DD,0,195
2458 .db 167-99,$DF,0,195+8
2459 .db 167-99,$E1,0,195+16
2460 .db 0
2461 @@l2:
2462 .db 163-99,$D1,0,198
2463 .db 163-99,$D3,0,198+8
2464 .db 163-99+8,$D5,0,198+16
2465 .db 0
2466 @@l3:
2467 .db 161-99,$E3,0,202
2468 .db 161-99+8,$E5,0,202+8
2469 .db 0
2470 @@l4:
2471 .db 160-99,$E7,0,205
2472 .db 160-99+16,$E9,0,205+8
2473 .db 0
2474 @@l5:
2475 .db 160-99,$EB,0,210
2476 .db 160-99+16,$ED,0,210
2477 .db 0
2478 @@l6:
2479 .db 159-99,$EF,0,215
2480 .db 159-99+16,$F1,0,215
2481 .db 0
2482 @@l7:
2483 .db 160-99,$EB,$40+0,210+3
2484 .db 160-99+16,$ED,$40+0,210+3
2485 .db 0
2486 @@l8:
2487 .db 160-99,$E7,$40+0,205+13
2488 .db 160-99+16,$E9,$40+0,205+13-8
2489 .db 0
2490 @@l9:
2491 .db 161-99,$E3,$40+0,202+19
2492 .db 161-99+8,$E5,$40+0,202+19-8
2493 .db 0
2494 @@l10:
2495 .db 163-99,$D1,$40+0,198+27
2496 .db 163-99,$D3,$40+0,198+27-8
2497 .db 163-99+8,$D5,$40+0,198+27-16
2498 .db 0
2499 @@l11:
2500 .db 167-99,$DD,$40+0,195+33
2501 .db 167-99,$DF,$40+0,195+33-8
2502 .db 167-99,$E1,$40+0,195+33-16
2503 .db 0
2504 @@l12:
2505 .db 170-99,$D7,$40+0,196+33
2506 .db 170-99,$D9,$40+0,196+33-8
2507 .db 170-99,$DB,$40+0,196+33-16
2508 .db 0
2509 .endp
2511 .proc draw_points_level_indicator
2512 lda player.points_level
2515 lda @@points_level_indicator_data_table+0,y
2517 lda @@points_level_indicator_data_table+1,y
2520 ldx #10
2521 jmp copy_bytes_to_ppu_buffer
2523 @@points_level_indicator_data_table:
2524 .dw @@points_level_0_data
2525 .dw @@points_level_1_data
2526 .dw @@points_level_2_data
2527 .dw @@points_level_3_data
2528 @@points_level_0_data:
2529 .db $21,$7A,$02,$00,$00
2530 .db $21,$9A,$02,$00,$00
2531 @@points_level_1_data:
2532 .db $21,$7A,$02,$BC,$BE
2533 .db $21,$9A,$02,$BD,$BF
2534 @@points_level_2_data:
2535 .db $21,$7A,$02,$BC,$C0
2536 .db $21,$9A,$02,$BD,$C1
2537 @@points_level_3_data:
2538 .db $21,$7A,$02,$BC,$C2
2539 .db $21,$9A,$02,$BD,$C3
2540 .endp
2542 .proc update_points_level_indicator
2543 lda stat_changed
2544 and #$20
2545 bne +
2547 + lda stat_changed
2548 and #~$20
2549 sta stat_changed
2550 jmp draw_points_level_indicator
2551 .endp
2553 .ifdef LIFE_SUPPORT
2554 .proc update_lives_display
2555 lda stat_changed
2556 and #$10
2557 bne +
2559 + lda stat_changed
2560 and #~$10
2561 sta stat_changed
2562 jmp print_life_count
2563 .endp
2565 .proc print_life_count
2566 ldy #$20 : lda #$68 : ldx #1
2567 jsr begin_ppu_string
2568 lda player.life_count
2569 ora #$D0
2570 jsr put_ppu_string_byte
2571 jmp end_ppu_string
2572 .endp
2573 .endif
2575 .proc update_score_displays
2576 lda stat_changed
2578 bcs @@update_score
2579 .ifndef NO_TOP_SCORE
2581 bcs @@update_top_score
2582 .endif
2584 @@update_score:
2586 sta stat_changed
2587 jmp print_score
2588 .ifndef NO_TOP_SCORE
2589 @@update_top_score:
2590 lda stat_changed
2591 and #~2
2592 sta stat_changed
2593 jmp print_top_score
2594 .endif
2595 .endp
2597 .proc print_score
2598 lda player.score+0 : sta AC0
2599 lda player.score+1 : sta AC1
2600 lda player.score+2 : sta AC2
2601 ldx #5 : lda #$20 : ldy #$4E
2602 jmp print_value
2603 .endp
2605 .ifndef NO_TOP_SCORE
2606 .proc print_top_score
2607 lda player.top_score+0 : sta AC0
2608 lda player.top_score+1 : sta AC1
2609 lda player.top_score+2 : sta AC2
2610 ldx #6 : lda #$20 : ldy #$59
2611 jmp print_value
2612 .endp
2613 .endif
2615 ; AC0, AC1, AC2 = value to print
2616 ; X = # of digits to output
2617 ; A = PPU high address
2618 ; Y = PPU low address
2619 .proc print_value
2620 stx Count
2621 ldx ppu_buffer_offset
2622 sta ppu_buffer,x
2625 sta ppu_buffer,x
2627 lda Count
2628 sta ppu_buffer,x
2630 lda #10
2631 sta AUX0
2632 lda #0
2633 sta AUX1
2634 sta AUX2
2635 ldy Count
2636 cpy #0
2637 bne +
2638 ; figure out how many digits to print
2639 - iny
2640 cpy #7
2641 beq +
2642 lda AC0
2644 sbc @@DecPos0-1,y
2645 lda AC1
2646 sbc @@DecPos1-1,y
2647 lda AC2
2648 sbc @@DecPos2-1,y
2649 bcs -
2650 + sty Count
2651 - jsr divide
2652 lda XTND0
2655 bne -
2656 - pla
2657 ora #$D0
2658 sta ppu_buffer,x
2661 cpy Count
2662 bne -
2663 jmp end_ppu_string
2664 @@DecPos0:
2665 .db $0A,$64,$E8,$10,$A0,$40
2666 @@DecPos1:
2667 .db $00,$00,$03,$27,$86,$42
2668 @@DecPos2:
2669 .db $00,$00,$00,$00,$01,$0F
2670 .endp
2672 .proc divide
2677 ldy #24 ; bitwidth
2678 lda #0
2679 sta XTND0
2680 sta XTND1
2681 sta XTND2
2682 - asl AC0 ;DIVIDEND/2, CLEAR QUOTIENT BIT
2683 rol AC1
2684 rol AC2
2685 rol XTND0
2686 rol XTND1
2687 rol XTND2
2688 lda XTND0 ;TRY SUBTRACTING DIVISOR
2690 sbc AUX0
2691 sta TMP0
2692 lda XTND1
2693 sbc AUX1
2695 lda XTND2
2696 sbc AUX2
2697 bcc + ;TOO SMALL, QBIT=0
2698 stx XTND1 ;OKAY, STORE REMAINDER
2699 sta XTND2
2700 lda TMP0
2701 sta XTND0
2702 inc AC0 ;SET QUOTIENT BIT = 1
2703 + dey ;NEXT STEP
2704 bne -
2710 .endp
2712 .proc update_progress_display
2713 lda stat_changed
2714 and #4
2715 bne +
2717 + lda stat_changed
2718 and #~4
2719 sta stat_changed
2720 lda progress_level
2721 cmp #41
2722 bcc +
2724 + sec
2725 sbc #1
2728 adc #$6B
2729 ldx game_type
2730 cpx #2 ; versus?
2731 bcc +
2732 sbc #$40 ; 2 rows up
2733 + ldy #$20
2734 ldx #$01 ; 1 tile
2735 jsr begin_ppu_string
2736 lda progress_level
2737 and #1 ; odd or even
2739 adc #$0D
2740 jsr put_ppu_string_byte
2741 jmp end_ppu_string
2742 .endp
2744 .proc update_energy_display
2745 lda stat_changed
2746 and #8
2747 bne +
2749 + lda stat_changed
2750 and #~8
2751 sta stat_changed
2752 ldy #0
2753 jsr update_player_energy_meter
2754 lda game_type
2755 cmp #2 ; versus?
2756 beq +
2758 + ldy #1
2759 jmp update_player_energy_meter
2760 .endp
2762 ; Y = player (0 or 1)
2763 .proc update_player_energy_meter
2764 lda player.energy_level,y
2765 cmp displayed_energy_level,y
2766 bcc @@less
2768 lda player.energy_level,y
2769 clc : adc #4
2771 sbc displayed_energy_level,y
2772 lsr : lsr : lsr
2773 beq @@draw_last
2775 ; fill full hearts on the left
2776 ora #$40 ; set RLE bit
2778 tya : pha ; save player index
2779 lda displayed_energy_level,y
2780 clc : adc #1
2781 lsr : lsr : lsr
2782 clc : adc #$6B
2783 cpy #0
2784 beq +
2785 clc : adc #$20
2786 + ldy game_type
2787 cpy #2
2788 beq +
2789 clc : adc #$20
2790 + ldy #$20
2791 jsr begin_ppu_string
2792 lda #$0A ; full heart
2793 jsr put_ppu_string_byte
2794 jsr end_ppu_string
2795 pla : tay ; restore player index
2796 jmp @@draw_last
2798 @@less:
2799 lda displayed_energy_level,y
2801 adc #7
2802 cmp #ENERGY_MAX
2803 bcc +
2804 lda #ENERGY_MAX
2805 + sec
2806 sbc player.energy_level,y
2807 lsr : lsr : lsr
2808 beq @@draw_last
2810 ; fill empty hearts on the right
2811 ora #$40 ; set RLE bit
2813 tya : pha ; save player index
2814 lda player.energy_level,y
2815 clc : adc #7
2816 lsr : lsr : lsr
2817 clc : adc #$6B
2818 cpy #0
2819 beq +
2820 clc : adc #$20
2821 + ldy game_type
2822 cpy #2
2823 beq +
2824 clc : adc #$20
2825 + ldy #$20
2826 jsr begin_ppu_string
2827 lda #$0C ; empty heart
2828 jsr put_ppu_string_byte
2829 jsr end_ppu_string
2830 pla : tay ; restore player index
2832 @@draw_last:
2833 tya : pha ; save player index
2834 lda player.energy_level,y
2835 lsr : lsr : lsr
2836 clc : adc #$6B
2837 cpy #0
2838 beq +
2839 clc : adc #$20
2840 + ldy game_type
2841 cpy #2
2842 beq +
2843 clc : adc #$20
2844 + ldy #$20 : ldx #$01
2845 jsr begin_ppu_string
2846 pla : tay ; restore player index
2847 pha ; save player index
2848 lda player.energy_level,y
2849 ldy #$0C ; empty heart
2850 and #7
2851 beq +
2852 dey ; half heart
2853 cmp #5
2854 bcc +
2855 dey ; full heart
2856 + tya
2857 jsr put_ppu_string_byte
2858 jsr end_ppu_string
2859 pla : tay ; restore player index
2860 lda player.energy_level,y
2861 sta displayed_energy_level,y
2863 .endp
2865 .proc update_letters_display
2866 lda stat_changed
2867 and #$40
2868 bne +
2870 + lda stat_changed
2871 and #~40
2872 sta stat_changed
2874 - ldy display_letter_index
2875 cpy player.letter_index
2876 bcc +
2878 + lda @@offsets,y
2880 adc #$55
2881 ldx #1
2882 cpy #1
2883 bne +
2884 inx ; for the hyphen
2885 + ldy #$20
2886 jsr begin_ppu_string
2887 ldy display_letter_index
2888 cpy #1
2889 bne +
2890 lda #$8F ; '-'
2891 jsr put_ppu_string_byte
2892 + lda @@tiles,y
2893 jsr put_ppu_string_byte
2894 jsr end_ppu_string
2895 inc display_letter_index
2896 bne -
2898 @@offsets:
2899 .db 0,1,3,4,6,7,8,9
2900 @@tiles:
2901 .db $99,$9A,$9B,$99,$9C,$9D,$9E,$9F
2902 .endp
2904 .proc check_pause
2905 lda joypad0_posedge
2906 and #JOYPAD_BUTTON_START
2907 bne @@pause
2909 @@pause:
2910 lda #0 : ldy #27
2911 jsr set_fade_range
2912 jsr palette_to_temp_palette
2913 jsr fade_out_step
2915 jsr is_music_paused
2916 sta was_music_paused
2917 bne +
2918 jsr pause_music
2919 + jsr mixer_get_muted_channels
2920 sta saved_muted_channels
2921 lda #$1F
2922 jsr mixer_set_muted_channels
2924 lda #3 : ldx #0
2925 jsr start_sfx
2927 lda #0
2928 sta selected_menu_item
2930 inc main_cycle ; game_paused_main
2931 pla : pla ; skip the rest of the game loop!
2933 .endp
2935 .proc game_paused_main
2936 jsr reset_sprites
2937 jsr draw_vu_pin
2938 ; jsr draw_pause_menu
2939 ; jsr draw_all_targets
2940 jmp check_pause_input
2941 .endp
2943 .proc check_pause_input
2944 lda joypad0_posedge
2945 and #(JOYPAD_BUTTON_START) ; | JOYPAD_BUTTON_A)
2946 bne @@select_menu_item
2948 .if 0
2949 lda joypad0_posedge
2950 and #(JOYPAD_BUTTON_UP | JOYPAD_BUTTON_DOWN)
2951 bne @@change_menu_item
2952 .endif
2955 .if 0
2956 @@change_menu_item:
2957 lda joypad0_posedge
2958 and #JOYPAD_BUTTON_UP
2959 bne @@prev_item
2960 ; next item
2961 lda selected_menu_item
2962 cmp #2
2963 bcs +
2964 inc selected_menu_item
2965 lda #0 : ldx #0
2966 jsr start_sfx
2967 + rts
2968 @@prev_item:
2969 lda selected_menu_item
2970 beq +
2971 dec selected_menu_item
2972 lda #0 : ldx #0
2973 jsr start_sfx
2974 + rts
2975 .endif
2976 @@select_menu_item:
2977 ldy selected_menu_item
2978 beq @@unpause
2979 .if 0
2981 beq @@restart
2982 jmp @@quit
2983 .endif
2985 @@unpause:
2986 jsr write_palette
2987 lda was_music_paused
2988 bne +
2989 jsr unpause_music
2990 + lda saved_muted_channels
2991 jsr mixer_set_muted_channels
2992 dec main_cycle ; game main
2995 .if 0
2996 @@restart:
2997 lda #0
2998 jsr mixer_set_muted_channels
2999 lda #0 ; no song
3000 jsr start_song
3001 jsr unpause_music
3003 lda #0
3004 sta main_cycle
3005 lda #7
3006 ldy #7
3007 jsr start_timer
3008 ldcay @@really_restart
3009 jsr set_timer_callback
3010 lda #0
3011 ldy #31
3012 jsr set_fade_range
3013 lda #7
3014 jsr set_fade_delay
3015 jmp start_fade_to_black
3017 @@quit:
3018 lda #0
3019 jsr mixer_set_muted_channels
3020 lda #0 ; no song
3021 jsr start_song
3022 jsr unpause_music
3024 lda #0
3025 sta main_cycle
3026 lda #7
3027 ldy #7
3028 jsr start_timer
3029 ldcay @@really_quit
3030 jsr set_timer_callback
3031 lda #0
3032 ldy #31
3033 jsr set_fade_range
3034 lda #7
3035 jsr set_fade_delay
3036 jmp start_fade_to_black
3038 @@really_restart:
3039 lda #7
3040 sta main_cycle
3043 @@really_quit:
3044 lda #0
3045 jsr swap_bank
3046 lda #5
3047 sta main_cycle
3049 .endif
3050 .endp
3052 .if 0
3053 .proc draw_pause_menu
3054 lda #0
3055 sta menu_row
3056 sta menu_col
3058 - lda @@text_data,y
3059 bne +
3061 lda @@text_data,y
3062 bne ++
3064 ++ inc menu_row
3065 lda #0
3066 sta menu_col
3067 jmp -
3068 + jsr next_sprite_index
3070 lda selected_menu_item
3071 cmp menu_row
3072 beq +
3074 bcc ++
3075 + sec
3076 ++ lda @@text_data,y
3077 bcs +
3078 adc #$20 ; dimmed
3079 + iny
3080 sta sprites.tile,x
3081 lda menu_row
3086 adc #96
3087 sta sprites._y,x
3088 lda #1
3089 sta sprites.attr,x
3090 lda menu_col
3094 adc #96
3095 sta sprites._x,x
3096 inc menu_col
3097 jmp -
3098 @@text_data:
3099 .charmap "data/pausemenu.tbl"
3100 .char "RESUME" : .db 0
3101 .char "RESTART" : .db 0
3102 .char "QUIT" : .db 0
3103 .db 0
3105 .endp
3106 .endif
3108 .proc check_if_done
3109 lda active_targets_head
3110 cmp #$FF
3111 beq +
3113 + lda hit_targets_head
3114 cmp #$FF
3115 beq +
3117 + lda missed_targets_head
3118 cmp #$FF
3119 beq +
3121 + lda target_data.lo
3122 ora target_data.hi
3123 beq +
3125 ; no more targets
3126 + jsr mixer_get_muted_channels
3127 and #$FC
3128 jsr mixer_set_muted_channels
3129 ldcay 0
3130 sta saved_muted_channels ; in case we are in bullet time
3131 jsr set_pattern_row_callback
3133 lda bullet_timer
3134 beq +
3135 ; make bullet time expire
3136 lda #1 : sta bullet_timer
3138 + lda game_type
3139 cmp #2 ; versus?
3140 bne +
3141 ; loop!
3142 ; wipe progress
3143 ldy #$20 : lda #$2B : ldx #$54
3144 jsr begin_ppu_string
3145 lda #$0F
3146 jsr put_ppu_string_byte
3147 jsr end_ppu_string
3148 lda target_data_chunk_length
3149 sta progress_countdown
3150 lda #0
3151 sta progress_level
3152 jsr init_target_data
3153 lda target_song
3154 jsr start_song
3155 jmp pause_music
3157 + lda play_mode
3158 beq +
3159 ; clip mode
3160 inc clip_index
3161 lda clip_index
3162 cmp #15 ; all clips played?
3163 beq +
3164 ; start next clip
3165 asl : tay
3166 lda clips+0,y
3167 sta selected_song
3168 lda clips+1,y ; marker
3169 jsr init_target_data
3170 lda #0
3171 jsr mixer_set_muted_channels
3172 lda #16
3173 jmp start_song
3175 + lda player.energy_level
3176 sta player.final_energy_level
3178 ; delay a bit
3179 lda #38 : ldy #6 ; ### customize delay for song?
3180 jsr start_timer
3181 ldcay @@add_points_for_energy
3182 jsr set_timer_callback
3183 ; lda player.energy_level
3184 ; ora #4
3185 ; and #~3 ; ### CHECKME
3186 ; sta player.energy_level
3187 lda #2
3188 sta game_state
3191 @@add_points_for_energy:
3192 lda #0
3193 jsr maybe_start_song ; mute
3194 lda player.energy_level
3195 beq @@done_adding_points_for_energy
3196 ldx #0
3197 lda #4
3198 jsr sub_energy
3199 ldy #0 : lda #100
3200 jsr add_score
3201 lda #3 : ldx #0
3202 jsr start_sfx
3203 lda #5 : ldy #1
3204 jsr start_timer
3205 ldcay @@add_points_for_energy
3206 jmp set_timer_callback
3208 @@done_adding_points_for_energy:
3209 lda #0
3210 sta time_mode
3211 sta global_transpose
3213 jsr compute_completed_challenges
3214 sta player.last_completed_challenges
3216 ; calculate new completed challenges
3217 ldy selected_song
3218 lda player.completed_challenges,y
3219 eor player.last_completed_challenges
3220 and player.last_completed_challenges
3221 sta player.new_completed_challenges
3223 ; calculate earned credit
3224 lda player.new_completed_challenges
3225 jsr count_bits
3226 stx player.won_credit
3228 ; delay a bit
3229 lda #12 : ldy #8
3230 jsr start_timer
3231 ldcay @@fade_out
3232 jmp set_timer_callback
3234 @@fade_out:
3235 lda #7 : ldy #7
3236 jsr start_timer
3237 ldcay @@goto_stats_screen
3238 jsr set_timer_callback
3239 lda #0 : ldy #31
3240 jsr set_fade_range
3241 lda #7
3242 jsr set_fade_delay
3243 jmp start_fade_to_black
3245 @@goto_stats_screen:
3246 lda #6
3247 jsr swap_bank
3248 lda #14
3249 sta main_cycle
3251 .endp
3253 ; Computes the set of challenges that were completed, based
3254 ; on the stats gathered from the game.
3255 ; Returns: A = set of completed challenges (1-bit = completed, 0-bit = not completed)
3256 .proc compute_completed_challenges
3257 lda #0
3258 ; 1. Make it to the end: unconditonal
3262 ; 2. High scorer: player.score > rock score
3264 lda player.difficulty
3265 asl : asl : asl : asl : asl ; 8*4=32 bytes per difficulty
3266 adc selected_song ; four
3267 adc selected_song ; bytes
3268 adc selected_song ; per
3269 adc selected_song ; score
3271 lda player.score+0
3273 sbc rock_score_table+0,y
3274 lda player.score+1
3275 sbc rock_score_table+1,y
3276 lda player.score+2
3277 sbc rock_score_table+2,y
3281 ; 3. Streaker: player.longest_streak > 100
3283 lda player.longest_streak+0
3285 sbc #100
3286 lda player.longest_streak+1
3287 sbc #0
3291 ; 4. Letters: player.acquired_letters == FF
3293 lda player.acquired_letters
3294 cmp #$FF
3298 ; 5. 3 fake skulls: fake_skull_hit_count == 3
3300 lda player.fake_skull_hit_count
3301 cmp #3
3305 ; 6. Blow up all POWs: pow_miss_count == 0
3307 lda player.pow_miss_count
3308 eor #$FF
3309 cmp #$FF
3313 ; 7. No special items: pow_hit_count | star_hit_count | clock_hit_count == 0
3315 lda player.pow_hit_count
3316 ora player.star_hit_count
3317 ora player.clock_hit_count
3318 eor #$FF
3319 cmp #$FF
3323 ; 8. finish with full energy: energy_level == ENERGY_MAX
3325 lda player.final_energy_level
3326 cmp #(ENERGY_MAX-2) ; -2 because that level is displayed as a full heart
3331 .endp
3333 rock_score_table:
3334 ; LED LOVE WHIP FREE DETH LIFE
3335 .dd 30000,20000,20000,20000,25000,25000,20000,20000 ; easy
3336 .dd 50000,25000,30000,30000,30000,40000,30000,30000 ; normal
3337 .dd 50000,30000,40000,35000,50000,50000,50000,50000 ; hard
3339 ; KILLME
3340 .proc game_done_main
3342 .endp
3344 .proc show_stats
3345 ; IMPLEMENTME
3346 jmp reset
3347 .endp
3349 .proc update_moving_background_step
3350 lda moving_bg_column
3351 cmp #12
3352 bne +
3353 lda #0
3354 sta moving_bg_column
3355 inc moving_bg_offset
3356 + inc moving_bg_column
3357 asl : asl
3359 lda @@bg_data+2,y
3361 lda @@bg_data+1,y
3363 lda @@bg_data+0,y
3366 jsr begin_ppu_string
3367 lda moving_bg_offset
3368 and #7
3369 ora #$80
3370 jsr put_ppu_string_byte
3371 jmp end_ppu_string
3372 @@bg_data:
3373 .db $22,$6E,$C4,0
3374 .db $22,$71,$C4,0
3375 .db $22,$6D,$C4,0
3376 .db $22,$72,$C4,0
3377 .db $22,$8C,$C3,0
3378 .db $22,$93,$C3,0
3379 .db $22,$89,$C3,0
3380 .db $22,$96,$C3,0
3381 .db $22,$A8,$C2,0
3382 .db $22,$B7,$C2,0
3383 .db $22,$C7,$C1,0
3384 .db $22,$D8,$C1,0
3385 .endp
3387 .proc update_moving_background
3388 jsr update_moving_background_step
3389 jsr update_moving_background_step
3390 jmp update_moving_background_step
3391 .endp
3393 .proc update_damage_blink
3394 lda damage_blink_counter
3395 bne +
3397 + cmp #4
3398 bne +
3399 ; start the blink - set palette red
3400 dec damage_blink_counter
3401 ldy #$3F : lda #$00 : ldx #$01
3402 jsr begin_ppu_string
3403 lda #$06
3404 jsr put_ppu_string_byte
3405 jmp end_ppu_string
3406 + dec damage_blink_counter
3407 beq +
3408 ; do nothing (palette remains red)
3410 ; end the blink - set palette black
3411 + ldy #$3F : lda #$00 : ldx #$01
3412 jsr begin_ppu_string
3413 lda #$0F
3414 jsr put_ppu_string_byte
3415 jmp end_ppu_string
3416 .endp
3418 ; X = lane to spawn in
3419 .proc maybe_spawn_heart
3420 dec heart_spawn_counter
3421 beq +
3423 + lda #HEART_SPAWN_INTERVAL
3424 sta heart_spawn_counter
3425 lda player.energy_level
3426 cmp #ENERGY_MAX
3427 bcc +
3429 ; spawn heart
3430 + inc player.heart_spawn_count
3432 ora #$80
3433 sta spawned_heart_state
3434 lda #8
3435 jsr add_energy
3436 tya : pha
3437 lda #6 : ldx #4
3438 jsr start_sfx
3439 pla : tay
3441 .endp
3443 .proc update_spawned_heart
3444 lda spawned_heart_state
3445 bmi +
3447 + and #7 ; lane
3449 jsr draw_big_heart
3450 lda frame_count
3451 and #7
3452 beq +
3454 ; next frame
3455 + lda spawned_heart_state
3456 and #$18 ; frame
3458 lda spawned_heart_state
3459 and #~$18
3460 sta spawned_heart_state
3463 adc #8 ; next frame
3464 and #$18
3466 ora spawned_heart_state
3467 sta spawned_heart_state
3469 bne +
3470 ; next iteration
3471 lda spawned_heart_state
3472 and #$60 ; iteration
3474 lda spawned_heart_state
3475 and #~$60
3476 sta spawned_heart_state
3479 adc #$20 ; next iteration
3480 and #$60
3481 ora spawned_heart_state
3482 sta spawned_heart_state
3483 + lda spawned_heart_state
3484 and #$78
3485 cmp #$48
3486 bne +
3487 ; kill the heart
3488 lda #0
3489 sta spawned_heart_state
3490 + rts
3491 .endp
3493 .proc draw_big_heart
3494 ; left half
3495 jsr next_sprite_index
3497 lda spawned_heart_state
3498 and #$18
3499 lsr ; frame * 4
3500 ora #$C1
3502 sta sprites.tile,x
3503 lda spawned_heart_state
3504 and #$78
3506 eor #$FF
3508 adc lane_slot_y_coords,y
3510 sbc #16
3511 sta sprites._y,x
3512 lda lane_slot_x_coords,y
3513 sta sprites._x,x
3514 lda #3
3515 sta sprites.attr,x
3516 ; right half
3517 jsr next_sprite_index
3520 ora #2
3521 sta sprites.tile,x
3522 lda spawned_heart_state
3523 and #$78
3525 eor #$FF
3527 adc lane_slot_y_coords,y
3529 sbc #16
3530 sta sprites._y,x
3531 lda lane_slot_x_coords,y
3533 adc #8
3534 sta sprites._x,x
3535 lda #3
3536 sta sprites.attr,x
3538 .endp
3540 .proc get_player_1_input
3541 lda #0
3542 sta lane_input_posedge+0
3543 sta lane_input+0
3544 ldx #4
3545 @@lane_loop:
3546 lda button_mapping,x
3548 lda bitmasktable,y
3550 and joypad0_posedge
3551 beq +
3552 lda bitmasktable,x
3553 ora lane_input_posedge+0
3554 sta lane_input_posedge+0
3555 + pla
3556 and joypad0
3557 beq @@next_lane
3558 lda bitmasktable,x
3559 ora lane_input+0
3560 sta lane_input+0
3561 @@next_lane:
3563 bpl @@lane_loop
3565 .endp
3567 .proc get_player_2_input
3568 lda #0
3569 sta lane_input_posedge+1
3570 sta lane_input+1
3571 lda game_type
3572 bne +
3573 ; one-player, no points in reading 2nd input
3575 + ldx #4
3576 @@lane_loop:
3577 lda button_mapping+5,x
3579 lda bitmasktable,y
3581 and joypad1_posedge
3582 beq +
3583 lda bitmasktable,x
3584 ora lane_input_posedge+1
3585 sta lane_input_posedge+1
3586 + pla
3587 and joypad1
3588 beq @@next_lane
3589 lda bitmasktable,x
3590 ora lane_input+1
3591 sta lane_input+1
3592 @@next_lane:
3594 bpl @@lane_loop
3596 .endp
3598 .proc process_locked_lanes
3599 lda locked_lanes
3600 bne +
3602 + ldx #4
3603 - lda bitmasktable,x
3604 and locked_lanes
3605 beq +
3606 lda frame_count
3608 bcc +
3609 dec locked_lane_timers,x
3610 bne +
3611 ; unlock
3612 lda bitmasktable,x
3613 eor #$FF
3614 and locked_lanes
3615 sta locked_lanes
3616 + dex
3617 bpl -
3619 .endp
3621 .proc process_lockable_lanes
3622 lda lockable_lanes
3623 bne +
3625 + ldx #4
3626 @@loop:
3627 lda lane_input_posedge+0
3628 ora lane_input_posedge+1
3629 and bitmasktable,x
3630 and lockable_lanes
3631 beq @@next
3632 ; lock it!
3633 ora locked_lanes
3634 sta locked_lanes
3635 lda bitmasktable,x
3636 eor #$FF
3637 and lockable_lanes
3638 sta lockable_lanes
3639 lda #$FF
3640 sta locked_lane_timers,x
3642 pha ; save lane index
3643 ; lda #6 : ldx #4
3644 ; jsr start_sfx
3645 lda locked_lanes
3646 jsr count_bits
3647 cpx #LOCKED_LANES_MAX
3648 bcc +
3649 ; no more lanes can be locked
3650 lda #0
3651 sta lockable_lanes
3652 + pla
3653 tax ; restore lane index
3654 @@next:
3656 bpl @@loop
3658 .endp
3660 .proc draw_lockable_lanes
3661 ldx #4
3662 - lda bitmasktable,x
3663 and lockable_lanes
3664 beq +
3667 lda frame_count
3668 bcc ++
3669 eor #$08
3670 ++ and #$08
3671 beq +
3675 jsr draw_lane_indicator
3678 + dex
3679 bpl -
3681 .endp
3683 .proc draw_locked_lanes
3684 ldx #4
3685 @@loop:
3686 lda bitmasktable,x
3687 and locked_lanes
3688 beq @@next
3689 lda locked_lane_timers,x
3690 cmp #$30
3691 bcs @@draw
3692 ; blink when it's about to time out
3693 lda frame_count
3694 and #2
3695 beq @@next
3696 @@draw:
3700 jsr draw_lane_indicator
3703 @@next:
3705 bpl @@loop
3707 .endp
3709 .proc draw_active_targets
3710 ldy active_targets_head
3711 draw_target_list:
3712 cpy #$FF ; end of list?
3713 beq @@out
3714 jsr draw_target
3715 lda targets_2.next,y
3717 jmp draw_target_list
3718 @@out:
3720 .endp
3722 .proc draw_hit_targets
3723 ldy hit_targets_head
3724 jmp draw_target_list
3725 .endp
3727 .proc draw_missed_targets
3728 ldy missed_targets_head
3729 jmp draw_target_list
3730 .endp
3732 .proc process_bullet_time
3733 lda bullet_timer
3734 bne +
3736 + lda frame_count
3738 bcs +
3740 + lsr
3741 bcs +
3743 + dec bullet_timer
3744 beq +
3746 + jmp toggle_time_mode
3747 .endp
3749 .proc draw_all_targets
3750 jsr draw_active_targets
3751 jsr draw_hit_targets
3752 jmp draw_missed_targets
3753 .endp
3755 ; Y = lane index
3756 .proc draw_player_lane_indicator
3757 jsr next_sprite_index
3759 lda #$F5
3760 sta sprites.tile,x
3761 lda lane_slot_y_coords,y
3762 clc : adc #17
3763 sta sprites._y,x
3764 lda lane_slot_x_coords,y
3765 clc : adc #4
3766 sta sprites._x,x
3767 lda bitmasktable,y
3768 and player_lanes+1
3769 beq +
3770 lda #3
3771 + sta sprites.attr,x
3773 .endp
3775 .proc maybe_draw_player_lane_indicators
3776 lda game_type
3777 bne + ; only if 2-player
3779 + ldy #4
3780 - jsr draw_player_lane_indicator
3782 bpl -
3784 .endp
3786 .proc check_if_dead
3787 lda player.energy_level
3788 beq @@die
3789 lda game_type
3790 eor #2
3791 ora player.energy_level+1
3792 beq @@die ; versus && player 2 health == 0
3794 @@die:
3795 lda #1
3796 sta game_state
3797 lda #42 : ldy #5
3798 jsr start_timer
3799 ldcay @@death_delay_done
3800 jsr set_timer_callback
3801 lda #$1F
3802 jsr mixer_set_muted_channels
3803 lda #1
3804 ldx #4
3805 jmp start_sfx
3807 @@death_delay_done:
3808 lda #12 : ldy #5
3809 jsr start_timer
3810 ldcay @@fade_out_done
3811 jsr set_timer_callback
3812 lda #0 : ldy #31
3813 jsr set_fade_range
3814 jmp start_fade_to_black
3816 @@fade_out_done:
3817 .ifdef LIFE_SUPPORT
3818 dec player.life_count
3819 bmi @@game_over
3820 ; start next life
3821 dec main_cycle ; game_init
3824 @@game_over:
3825 .endif
3826 lda #0
3827 sta time_mode
3828 sta global_transpose
3829 jsr start_song ; mute
3830 lda #0
3831 jsr mixer_set_muted_channels
3832 ldcay 0
3833 jsr set_pattern_row_callback
3835 lda #6
3836 jsr swap_bank
3837 lda #12 ; game over init
3838 ldx game_type
3839 cpx #2 ; versus?
3840 bne +
3841 lda #28 ; winner/loser screen
3842 + sta main_cycle
3844 .endp
3846 .proc update_screen_shake
3847 lda screen_shake_counter
3848 bne +
3850 + lda frame_count
3852 bcc +
3854 + dec screen_shake_counter
3855 lda screen_shake_counter
3856 and #1 : asl
3857 sta ppu.scroll_y
3859 .endp
3861 ; A = number of frames to shake
3862 .proc shake_screen
3863 sta screen_shake_counter
3865 .endp
3867 .proc update_palette_for_time_mode
3868 jsr palette_fade_in_progress
3869 beq + ; only if there is no fading in progress
3871 + lda transition_timer
3872 and #7
3873 beq +
3875 + lda time_mode
3876 bne @@fade_towards_green
3878 ; fade towards game palette
3879 ldy #15
3880 - lda palette,y
3881 cmp game_palette,y
3882 beq +
3883 bcc ++
3884 sec : sbc #1
3885 sta palette,y
3886 jmp +
3887 ++ clc : adc #1
3888 sta palette,y
3889 + dey
3890 bpl -
3891 jmp write_palette
3893 @@fade_towards_green:
3894 ldy #15
3895 - lda palette,y
3896 cmp #$0F
3897 beq +
3898 and #$0F
3899 cmp #9
3900 beq +
3901 lda palette,y
3902 bcc ++
3903 sec : sbc #1
3904 sta palette,y
3905 jmp +
3906 ++ clc : adc #1
3907 sta palette,y
3908 + dey
3909 bpl -
3910 jmp write_palette
3912 .if 0
3913 @@bullet_time_palette:
3914 ; bg
3915 .db $0f,$1A,$19,$2A ; logo, hearts, VU
3916 .db $0f,$1B,$12,$22 ; hearts
3917 .db $0f,$2A,$3A,$19 ; points, progress bar
3918 .db $0f,$39,$29,$09 ; pad, VU
3919 ; sprites
3920 .db $0f,$01,$21,$30 ; target - blue
3921 .db $0f,$0B,$2B,$30 ; target - green
3922 .db $0f,$07,$27,$30 ; target - yellow
3923 .db $0f,$05,$15,$30 ; target - red
3924 .endif
3925 .endp
3927 .proc set_palette_for_time_mode
3928 ; we need to fix up palette entry 5
3929 ; if we are in Versus mode...
3930 lda time_mode
3931 beq +
3933 + lda game_type
3934 cmp #2 ; versus?
3935 beq +
3937 + lda #$10
3938 sta palette+5 ; gray instead of dark green
3939 ldy #$3F : lda #$05 : ldx #1
3940 jsr begin_ppu_string
3941 lda palette+5
3942 jsr put_ppu_string_byte
3943 jmp end_ppu_string
3944 .endp
3946 .proc game_core
3947 jsr process_lockable_lanes
3948 jsr draw_lockable_lanes
3949 jsr process_locked_lanes
3950 jsr draw_locked_lanes
3951 jsr process_bullet_time
3952 jsr maybe_begin_song
3953 jsr maybe_load_targets
3954 jsr process_active_targets
3955 jsr process_hit_targets
3956 jsr process_missed_targets
3957 jsr update_score_displays
3958 jsr update_progress_display
3959 jsr update_energy_display
3960 jsr update_screen_shake
3961 .ifdef LIFE_SUPPORT
3962 jsr update_lives_display
3963 .endif
3964 jsr update_moving_background
3965 jsr update_ampdisplay
3966 jsr update_damage_blink
3967 jsr update_spawned_heart
3968 jsr update_points_level_indicator
3969 jsr update_letters_display
3970 jsr maybe_draw_player_lane_indicators
3971 jmp draw_vu_pin
3972 .endp
3974 ;.define PLAYER_2_CPU
3975 .ifdef PLAYER_2_CPU
3976 .proc lock_player_2_lanes
3977 lda player_lanes+1
3978 sta locked_lanes
3979 lda #0
3980 sta lockable_lanes
3981 lda #60
3982 sta locked_lane_timers+0
3983 sta locked_lane_timers+1
3984 sta locked_lane_timers+2
3985 sta locked_lane_timers+3
3986 sta locked_lane_timers+4
3988 .endp
3989 .endif
3991 .proc game_main
3992 jsr reset_sprites
3993 lda transition_timer
3994 bne @@update_transition
3995 lda game_state
3996 beq @@normal
3997 ; dead or done
3998 lda #0
3999 sta lane_input_posedge+0
4000 sta lane_input_posedge+1
4001 jmp game_core
4003 @@update_transition:
4004 jsr draw_all_targets
4005 jsr draw_locked_lanes
4006 jsr draw_vu_pin
4007 jsr maybe_draw_player_lane_indicators
4008 jsr update_palette_for_time_mode
4009 dec transition_timer
4010 beq +
4012 ; back to normal game mode
4013 + jsr set_palette_for_time_mode
4014 lda was_music_paused
4015 bne +
4016 jsr unpause_music
4017 + lda saved_muted_channels
4018 jsr mixer_set_muted_channels
4019 lda time_mode
4020 beq +
4021 lda #144
4022 sta bullet_timer ; how long bullet time shall last
4023 + rts
4025 @@normal:
4026 jsr get_player_1_input
4027 jsr get_player_2_input
4028 jsr check_pause
4029 .ifdef PLAYER_2_CPU
4030 jsr lock_player_2_lanes
4031 .endif
4032 jsr draw_pressed_lanes
4033 jsr game_core
4034 jsr check_if_done
4035 jsr check_if_dead
4036 ; turn on for dynamic "profiling" (the screen goes black when processing is done)
4037 .if 0
4038 lda ppu.ctrl1
4039 and #~PPU_CTRL1_BG_VISIBLE
4040 sta $2001
4041 .endif
4043 .endp
4045 .end