1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-12-23 18:31:08 +00:00
8bitworkshop/presets/apple2/tb_6502.s
2019-09-08 18:59:08 -05:00

4303 lines
74 KiB
ArmAsm

; From: http://www.deater.net/weave/vmwprod/tb1/tb_6502.html
.segment "INIT"
.segment "ONCE"
; don't use $800-$1fff :(
.segment "STARTUP"
jmp Start
; use $4000- :)
.segment "CODE"
.define EQU =
; blt = bcc
; bge = bcs
;; ZERO PAGE
CH EQU $24
CV EQU $25
BASL EQU $28
BASH EQU $29
H2 EQU $2C
COLOR EQU $30
YSAV EQU $34
YSAV1 EQU $35
RANDOM_SEED EQU $43
;; Our Zero Page Allocations
PADDLE_STATUS EQU $CA
HISCORE_1 EQU $CB
HISCORE_2 EQU $CC
HISCORE_3 EQU $CD
HISCORE_H EQU $CE
HISCORE_L EQU $CF
BOSS_X EQU $D0
BOSS_XADD EQU $D1
BOSS_COUNT EQU $D2
BOSS_SMOKE EQU $D3
BOSS_EXPLODING EQU $D4
BOSS_WAITING EQU $D5
BOSS_HITS EQU $D6
BOSS_SHOOTING EQU $D7
ENEMIES_SPAWNED EQU $D8
ENEMY_TYPE EQU $D9
ENEMY_WAVE EQU $DA
CURRENT_INIT_X EQU $DB
CURRENT_ENEMY_KIND EQU $DC
TOTAL_ENEMIES_OUT EQU $DD
SCROLL EQU $DE
SOUND_ON EQU $DF
SHIPX EQU $E0
SHIPXADD EQU $E1
ENEMY_PL EQU $E2
ENEMY_PH EQU $E3
MISSILE_PL EQU $E4
MISSILE_PH EQU $E5
GR_PAGE EQU $E6
LEVEL EQU $E7
SHIELDS EQU $E8
SCOREL EQU $E9
SCOREH EQU $EA
BONUS_FLAGS EQU $EB
BCD_BYTEH EQU $EC
BCD_BYTE EQU $ED
COL_X1 EQU $EC
COL_X2 EQU $ED
COL_X3 EQU $EE
COL_X4 EQU $EF
ENEMY_EXPLODING EQU $F0
ENEMY_KIND EQU $F1
ENEMY_X EQU $F2
ENEMY_Y EQU $F3
ENEMY_XADD EQU $F4
ENEMY_YADD EQU $F5
ENEMY_XMIN EQU $F6
ENEMY_XMAX EQU $F7
BETWEEN_DELAY EQU $F8
ENEMY_WAIT EQU $F9
STRINGL EQU $FA
STRINGH EQU $FB
PARAM2 EQU $FC
RESULT EQU $FD
LASTKEY EQU $FE
TEMP EQU $FF
;; VECTORS
BASIC EQU $3D0 ;; VECTOR for return to Applesoft
KEYPRESS EQU $C000
KEYRESET EQU $C010
SPEAKER EQU $C030
;; SOFT SWITCHES
GR EQU $C050
TEXT EQU $C051
FULLGR EQU $C052
TEXTGR EQU $C053
PAGE0 EQU $C054
PAGE1 EQU $C055
LORES EQU $C056
HIRES EQU $C057
PADDLE_BUTTON0 EQU $C061
PADDL0 EQU $C064
PTRIG EQU $C070
;; MONITOR ROUTINES
HLINE EQU $F819 ;; HLINE Y,$2C at A
VLINE EQU $F828 ;; VLINE A,$2D at Y
CLRSCR EQU $F832 ;; Clear low-res screen
CLRTOP EQU $F836 ;; clear only top of low-res screen
SETCOL EQU $F864 ;; COLOR=A
BASCALC EQU $FBC1 ;;
HOME EQU $FC58 ;; Clear the text screen
WAIT EQU $FCA8 ;; delay 1/2(26+27A+5A^2) us
SETINV EQU $FE80 ;; INVERSE
SETNORM EQU $FE84 ;; NORMAL
COUT1 EQU $FDF0 ;; output A to screen
;; GAME PARAMETERS
NUM_MISSILES EQU 2
NUM_ENEMIES EQU 6
UP_SHIELDS EQU 32
WAVE_SIZE EQU 16
WAVES_TILL_BOSS EQU 5
;; BONUS_FLAGS
PERFECT_SHIELDS EQU $80
PERFECT_KILLS EQU $40
PERFECT_AIM EQU $1
;==========================================================
; MAIN()
;==========================================================
;==============================
; back up part of the zero page
;==============================
Start:
lda #>zero_page_save
sta BASH
lda #<zero_page_save
sta BASL
ldy #0
save_zp_loop:
lda $C8,Y ; copy $C8-$FF
sta (BASL),Y ; to (zero_page_save)
iny
cpy #$38 ; we copy 56 bytes
bne save_zp_loop
lda #$ff
sta SOUND_ON
;==========================
; set graphics mode, page 0
;==========================
jsr HOME
jsr set_page0_gr
;=================
; clear the screen
;=================
jsr CLRTOP
;====================
; setup the high score
;=====================
lda #$01
sta HISCORE_H
lda #$00
sta HISCORE_L
sta PADDLE_STATUS
; modestly make me the high scorer
lda #$D6
sta HISCORE_1
lda #$CD
sta HISCORE_2
lda #$D7
sta HISCORE_3
lda #>(score_string+31)
sta STRINGH
lda #<(score_string+31)
sta STRINGL
jsr print_high_score
;=============
; put vmw logo
;=============
lda #$7 ; y=7
sta CV
lda #$8 ; x=8
sta CH
lda #>vmw_sprite
sta STRINGH
lda #<vmw_sprite
sta STRINGL
jsr blit ; blit the vmw sprite
;==================================
; Write "A VMW SOFTWARE PRODUCTION"
;==================================
lda #>vmw_string ; string = vmw_string
sta STRINGH
lda #<vmw_string
sta STRINGL
jsr print_text_xy ; print the string
;======================
; wait until keypressed
;======================
jsr wait_until_keypressed
;======================
; Opening Graphic
;======================
opener:
;=================
; clear the screen
;=================
jsr set_page0_gr
jsr HOME ; clear the screen
jsr CLRTOP
;=======================
; put opening graphic up
;=======================
lda #$0 ; y=0
sta CV
sta CH
lda #>opener_sprite
sta STRINGH
lda #<opener_sprite
sta STRINGL
jsr blit ; blit the opener sprite
lda #$A ; y=10 (we had to split in two)
sta CV
lda #>opener_sprite_2
sta STRINGH
lda #<opener_sprite_2
sta STRINGL
jsr blit ; blit the second half of sprite
;================================================
; Write "MERCILESS MALICIOUS MARAUDING MARKETERS"
;================================================
lda #>mercy_string ; string = MMMM
sta STRINGH
lda #<mercy_string
sta STRINGL
jsr print_text_xy ; print the string
jsr wait_until_keypressed ; wait until key pressed
;==========================================================
; The MAIN MENU
;==========================================================
main_menu:
jsr set_page0_text ; enter text mode
jsr HOME ; clear screen
lda #>help_string ; string = "H FOR HELP"
sta STRINGH
lda #<help_string
sta STRINGL
jsr print_text_xy ; print the string
lda #$5
sta PARAM2
jsr do_menu ; do the menu
lda RESULT ; load menu item from page0
cmp #$0 ; is it zero?
bne check_1 ; if not move ahead
jmp do_new_game ; yes, start new game
check_1:
cmp #$1 ; is it one?
bne check_2 ; if not, move ahead
jmp do_about ; else, show about into
check_2:
cmp #$2 ; is it two?
bne check_3 ; if not, move ahead
jmp do_story ; else, do the story info
check_3:
cmp #$3 ; is it three?
bne check_4 ; if not, move ahead
jmp do_hi_score ; else, show hi-score
check_4:
cmp #$4 ; is it four?
bne check_5 ; if not move ahead
jmp exit ; if so exit
check_5:
jsr do_help
jmp main_menu ; return to main_menu loop
;==========================================================
; EXIT back to BASIC
;==========================================================
exit:
jsr SETNORM ; NORMAL text
jsr set_page0_text
;======================
; restore the zero page
;======================
lda #>zero_page_save
sta BASH
lda #<zero_page_save
sta BASL
ldy #0
restore_zp_loop:
lda (BASL),Y ; copy (zero_page_save)
sta $C8,Y ; back to $C8-$FF
iny
cpy #$38 ; we copy 56 bytes
bne restore_zp_loop
jsr HOME ; clear screen
jmp (BASIC) ; return to BASIC
;==========================================================
; do_menu
;==========================================================
; draw a text-mode menu
do_menu:
lda #$0 ; start with menu=0
sta RESULT
menu:
lda #$8 ; y=8
sta CV
lda #>new_game_string ; string starts at "NEW GAME"
sta STRINGH
lda #<new_game_string
sta STRINGL
ldy #$0 ; clear string offset pointer
ldx #$0 ; clear line count
next_line:
lda #$8D ; carriage return
jsr COUT1
lda #$10 ; x=16
sta CH
sty TEMP ; save Y as NORM/INV changes it
jsr SETNORM ; set text style to normal
cpx RESULT ; are we at the selected entry?
bne menu_restore_y ; if not, move on
jsr SETINV ; if so, reverse text
menu_restore_y:
ldy TEMP ; restore Y we saved earlier
menu_char:
lda (STRINGL),Y ; get char from strings
beq done_line ; if 0, done this line
jsr COUT1 ; monitor char output line
iny ; indexY ++
jmp menu_char ; loop till done line
done_line:
inx ; move to next line
iny ; pointer after null
cpx PARAM2 ; are we past end of menu?
bne next_line ; if not, print next line
menu_wait:
jsr wait_until_keypressed
lda LASTKEY
cmp #('Q')
bne check_h
lda #$4
sta RESULT
rts
check_h:
cmp #('H')
bne check_i
lda #$5 ; if help, set RESULT=5
sta RESULT
rts
check_i:
cmp #('I')
bne check_m
dec RESULT
jmp check_menu_values
check_m:
cmp #('M')
bne check_cr
inc RESULT
jmp check_menu_values
check_cr:
cmp #(13)
bne menu_wait
rts
check_menu_values:
lda RESULT
bpl check_menu_over
lda PARAM2
sbc #$1
sta RESULT
check_menu_over:
cmp PARAM2
bne menu
lda #$0
sta RESULT
jmp menu
;==========================================================
; do_about
;==========================================================
; print the "about" info
do_about:
bit GR
jsr CLRTOP
lda #$0 ; x,y= 12,0
sta CV
lda #$C
sta CH
lda #>vince_sprite
sta STRINGH
lda #<vince_sprite
sta STRINGL
jsr blit ; blit the pic of vince
lda #>about_lines
sta STRINGH
lda #<about_lines
sta STRINGL
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr wait_until_keypressed
lda #$6 ; only want to clear bottom 3 lines
sta BASH ; so set pointer to $6D0
lda #$D0
sta BASL
ldx #$01 ; set X already to 1
jsr bottom_y ; and jump midway into clear_bottom
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr wait_until_keypressed
jmp opener
;==========================================================
; do_help
;==========================================================
; print the "help" info
do_help:
jsr set_page0_text
jsr HOME
lda #>help_lines
sta STRINGH
lda #<help_lines
sta STRINGL
ldx #$14
jsr print_x_strings ; print text
jsr wait_until_keypressed
rts
;==========================================================
; do_story
;==========================================================
; the story routine
do_story:
bit GR
jsr CLRTOP
;
; draw the mars map
;
lda #$0 ; y=0
sta CV
sta CH
lda #>phobos_sprite
sta STRINGH
lda #<phobos_sprite
sta STRINGL
jsr blit ; blit the phobos sprite
lda #>story_lines
sta STRINGH
lda #<story_lines
sta STRINGL
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr wait_until_keypressed
;
; animate the droid launch
;
jsr clear_bottom
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
lda #$12 ; x=18
sta CH
lda #$7
sta CV ; y=7
phobos_loop:
lda #>evil_ship_sprite
sta STRINGH
lda #<evil_ship_sprite
sta STRINGL
jsr blit ; blit the droid sprite
; delay
; wait 1/2 (26+27A+5A^2) us
lda #$8B ; 107 = 30080us = 30ms
jsr WAIT
lda #$0 ; set color to zero
jsr SETCOL
; HLINE H1,H2 at V1
lda CH ; get x value
tay ; move it to H1
adc #$3 ; add 3
sta H2 ; move it to H2
lda #$e ; set V1
jsr HLINE
ldy CH ; reset H1
lda #$f ; set V1 to bottom value
jsr HLINE
; move ship
inc CH ; incrememnt X
lda CH
cmp #$25 ; have we reached 37? (edge)
bne phobos_loop
jsr wait_until_keypressed
;
; "you are tom..."
;
jsr clear_bottom
jsr CLRTOP
lda #$1 ; y=0
sta CV
lda #$C ; x=12
sta CH
lda #>tom_sprite
sta STRINGH
lda #<tom_sprite
sta STRINGL
jsr blit ; blit the tom sprite
lda #>you_are_tom
sta STRINGH
lda #<you_are_tom
sta STRINGL
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr wait_until_keypressed
jmp opener
;==========================================================
; do_ending
;==========================================================
; the ending you get after level 1
do_ending:
jsr set_page0_gr ; set graphics mode
jsr CLRTOP
jsr clear_bottom
;
; draw the earth
;
lda #$7 ; y=7
sta CV
lda #$F ; x=15
sta CH
lda #>earth_sprite
sta STRINGH
lda #<earth_sprite
sta STRINGL
jsr blit ; blit the earth sprite
lda #>ending_lines
sta STRINGH
lda #<ending_lines
sta STRINGL
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
ldx #30
jsr wait_X_100msec ; pause for 3 seconds
bit KEYRESET ; clear keyboard
jsr wait_until_keypressed
;
; second page
;
jsr clear_bottom
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr print_text_xy ; print text
jsr wait_until_keypressed
;
; third page
;
jsr CLRTOP
jsr clear_bottom
;
; draw Susie
;
lda #$7 ; y=7
sta CV
lda #$A ; x=10
sta CH
lda #>susie_sprite
sta STRINGH
lda #<susie_sprite
sta STRINGL
jsr blit ; blit the susie sprite
lda #>susie_lines
sta STRINGH
lda #<susie_lines
sta STRINGL
jsr print_text_xy ; print text
jsr wait_until_keypressed
;
; fourth page
;
jsr CLRTOP
jsr clear_bottom
;
; draw Tom's head
;
lda #$7 ; y=7
sta CV
lda #$F ; x=15
sta CH
lda #>tom_head_sprite
sta STRINGH
lda #<tom_head_sprite
sta STRINGL
jsr blit ; blit Tom's head
lda #>tom_sigh
sta STRINGH
lda #<tom_sigh
sta STRINGL
jsr print_text_xy ; print text
jsr wait_until_keypressed
jmp no_ending
;==========================================================
; START NEW GAME
;==========================================================
do_new_game:
;; set up struct pointers
lda #>missile_0 ; clear the missile struct
sta MISSILE_PH ; should make this clear all BSS
lda #<missile_0 ; at some point
sta MISSILE_PL
lda #>enemy_0
sta ENEMY_PH
lda #<enemy_0
sta ENEMY_PL
;; Clear BSS
ldy #$0
lda #$0
clear_bss:
sta start_bss,Y
iny
cpy #end_bss-start_bss
bne clear_bss
;; Init one-time vars
lda #$8
sta SHIELDS ; shields start at 8
jsr update_shields
lda #$12
sta SHIPX ; shipx at start is 18
lda #$1
sta LEVEL ; start at level 1
lda #$0
sta SCOREL
sta SCOREH
jsr print_score
new_level:
;========================
; Setup various variables
;========================
lda #(PERFECT_AIM|PERFECT_SHIELDS|PERFECT_KILLS)
sta BONUS_FLAGS ; set perfect shot/shield/enemies
lda #$14
sta ENEMY_WAIT
lda #$0
sta BETWEEN_DELAY
sta SHIPXADD ; clear shipxadd
sta ENEMY_WAVE
sta TOTAL_ENEMIES_OUT
sta ENEMIES_SPAWNED
sta ENEMY_TYPE
;=======================
; Print "LEVEL X"
;=======================
jsr set_page0_text
jsr HOME
;===================
; set level to level
;===================
lda #>(level_string+9)
sta STRINGH
lda #<(level_string+9)
sta STRINGL
lda #0
sta BCD_BYTEH
lda LEVEL
sta BCD_BYTE
jsr print_bcd_byte
;======================
; Print level on screen
;======================
lda #>(level_string_xy)
sta STRINGH
lda #<(level_string_xy)
sta STRINGL
jsr print_text_xy
ldx #20
jsr wait_X_100msec ; pause for 3 seconds
bit KEYRESET ; clear keyboard
;==================================
; Enter graphics mode, clear screen
;==================================
jsr set_page0_gr ; set graphics mode
jsr clear_screen ; clear screen
draw_stars:
;=====================
; Setup star field
;=====================
lda #>(star_field)
sta STRINGH
lda #<(star_field)
sta STRINGL
ldy #$0
star_init:
jsr random_number
and #$9f
clc
adc #$4
sta (STRINGL),Y
iny
lda #$0
sta (STRINGL),Y
iny
bne star_init
lda #$0
sta SCROLL
;/========================\
;+ +
;+ MAIN GAME LOOP +
;+ +
;\========================/
main_game_loop:
jsr clear_screen ; clear screen
jsr show_stars
done_scrolling:
; ================================
; put out new enemies (if needed)
; ================================
inc BETWEEN_DELAY ; inc how long we've delayed
lda BETWEEN_DELAY ; load it in
cmp ENEMY_WAIT ; have we waited long enough?
beq reset_delay
jmp move_enemies ; if not, go on to movement
reset_delay:
; delay==wait, so attempt to put out new enemy
lda BETWEEN_DELAY
and #$1
sta BETWEEN_DELAY ; reset delay
; special case for boss
lda #$9 ; if boss, don't keep track of
cmp ENEMY_TYPE ; how many enemies were spawned
bne not_boss_dont_clear
lda #$1 ; store 1 so we don't increment wave
sta ENEMIES_SPAWNED
not_boss_dont_clear:
; see if we are at a new wave
; basically, if 16 have been spawned, change
lda ENEMIES_SPAWNED
and #$0f
bne same_enemy_type ; if not 16 gone by, move on
;=======================
; change the enemy type
inc ENEMIES_SPAWNED
jsr random_number
and #$7 ; get a random number 0-7
sta ENEMY_TYPE
inc ENEMY_WAVE
lda ENEMY_WAVE ; have we gone enough waves to reach boss?
cmp #WAVES_TILL_BOSS
bne not_boss_yet
lda #$8
sta ENEMY_TYPE
not_boss_yet:
; set various constants
; these may be overriden later
lda #20
sec
sbc LEVEL
sta ENEMY_WAIT ; enemy_wait=20-level
; set kind and init x to be random by default
lda #$ff
sta CURRENT_ENEMY_KIND
sta CURRENT_INIT_X
same_enemy_type:
; find empty enemy slot
ldy #$0 ; point to enemies[0]
tya
find_empty_enemy:
pha
lda (ENEMY_PL),Y ; get enemy[y].out
beq add_enemy
pla
clc
adc #$9
tay
cpy #(NUM_ENEMIES*9)
bne find_empty_enemy
jmp move_enemies ; no empty, slots, move on
add_enemy:
pla
;==============================================
; First see if we must wait for enemy to clear
; types 2 and 8
lda ENEMY_TYPE
cmp #$2
bne check_type_8
lda TOTAL_ENEMIES_OUT
beq change_to_type_3
jmp move_enemies
change_to_type_3:
lda #$3
sta ENEMY_TYPE
jsr random_number
and #$8
sta CURRENT_ENEMY_KIND
jsr random_number
and #$1F ; mask off so 0-31
clc
adc #$2
asl A
sta CURRENT_INIT_X
jmp setup_enemy_defaults
check_type_8:
cmp #$8
beq before_boss_stuff
jmp check_type_9
before_boss_stuff:
;======================
; before boss stuff
lda TOTAL_ENEMIES_OUT
beq prepare_for_boss
jmp move_enemies
prepare_for_boss:
;===============
; HANDLE BONUSES
;===============
; Set text mode
jsr set_page0_text
jsr HOME
; Print "BONUS POINTS"
lda #>bonus_string
sta STRINGH
lda #<bonus_string
sta STRINGL
jsr print_text_xy ; print text
; Check to see if we had any bonuses
lda #$C1
bit BONUS_FLAGS
beq no_bonus
; Check if we had no hits on shields
perfect_shields:
bpl perfect_kills
jsr score_plus_50
lda #>bonus_shields
sta STRINGH
lda #<bonus_shields
sta STRINGL
jsr print_text_xy ; print text
; See if we killed all the enemies
perfect_kills:
bit BONUS_FLAGS
bvc perfect_aim
jsr score_plus_50
lda #>bonus_kills
sta STRINGH
lda #<bonus_kills
sta STRINGL
jsr print_text_xy ; print text
; See if no missiles missed
perfect_aim:
lda #$01
bit BONUS_FLAGS
beq done_bonus
jsr score_plus_50
lda #>bonus_aim
sta STRINGH
lda #<bonus_aim
sta STRINGL
jsr print_text_xy ; print text
jmp done_bonus
; we had no bonuses
no_bonus:
lda #>no_bonus_string
sta STRINGH
lda #<no_bonus_string
sta STRINGL
jsr print_text_xy ; print text
; Wait until a keypress, and return to graphics mode
done_bonus:
ldx #30
jsr wait_X_100msec ; pause for 3 seconds
bit KEYRESET ; clear keyboard
jsr wait_until_keypressed
jsr set_page0_gr
;======================
; setup boss
lda #$0C
sta BOSS_X ; boss_x = 13
lda #$1
sta BOSS_XADD ; boss_xadd=1
sta BOSS_WAITING ; boss_waiting=1
jsr random_number
and #$1f
sta BOSS_COUNT ; boss_count = rand%32
lda #$0
sta BOSS_SMOKE ; boss_smoke=0
sta BOSS_EXPLODING ; boss_exploding=0
sta BOSS_SHOOTING ; boss_shooting=0
lda LEVEL
asl A
clc
adc #$10
sta BOSS_HITS ; boss_hits=(level*2)+20
lda #$9
sta ENEMY_TYPE ; enemy_type=9
jmp move_enemies
check_type_9:
; if boss, and he's waiting,
; don't produce enemies
cmp #$9
bne setup_enemy_defaults
lda BOSS_WAITING
beq setup_enemy_defaults
jmp move_enemies
;========================
; setup enemy defaults
setup_enemy_defaults:
inc ENEMIES_SPAWNED
inc TOTAL_ENEMIES_OUT
lda #$1
sta (ENEMY_PL),Y ; enemy[i].out=1
lda #$0
iny ; exploding
sta (ENEMY_PL),Y ; enemy[i].exploding=0
iny ; kind
lda CURRENT_ENEMY_KIND ; if kind <0 then random
bpl store_enemy_kind
jsr random_number
and #$38
jmp store_enemy_kind
store_enemy_kind:
sta (ENEMY_PL),Y
; determine enemy _x
; if < 0, make random between 2->34
lda CURRENT_INIT_X
bpl store_init_x
jsr random_number
and #$1f
clc
adc #$2
asl
store_init_x:
iny ; X
sta (ENEMY_PL),Y
; enemy_y is always 0 by default
iny ; Y
lda #$0
sta (ENEMY_PL),Y
lda #$0
iny
sta (ENEMY_PL),Y ; xadd
iny
sta (ENEMY_PL),Y ; yadd
lda #$2
iny
sta (ENEMY_PL),Y ; xmin
iny
lda #$24
sta (ENEMY_PL),Y ; ymin
dey ; xmin
dey ; yadd
dey ; xadd
;===========================================
; Enemy specific inits
lda ENEMY_TYPE
beq enemy_type_0
cmp #$1
beq enemy_type_1
jmp enemy_type_2
enemy_type_0:
enemy_type_1:
;================================
; ENEMY TYPE 0 and 1
; diagonal, no wait
; movement proportional to level
lda LEVEL ; xadd = level
sta (ENEMY_PL),Y
iny
lsr A
ora #$1
sta (ENEMY_PL),Y ; yadd = level/2
jmp move_enemies
enemy_type_2:
;=====================
; Enemy Type 2
; just a place-holder
; waits for enemies to die then moves on to 3
cmp #$2
bne enemy_type_3
jmp move_enemies
enemy_type_3:
cmp #$3
bne enemy_type_4
;======================
; Enemy type 3
lda #$1
sta (ENEMY_PL),Y ; xadd=1
iny
lda LEVEL
sta (ENEMY_PL),Y ; yadd=level
jmp move_enemies
enemy_type_4:
cmp #$4
bne enemy_type_5
;=========================
; Enemy Type 4
; Horizontal, then fall
lda #$2
sta (ENEMY_PL),Y ; xadd = 2
iny
jsr random_number
ora #$80 ; set negative
sta (ENEMY_PL),y ; yadd = -(random%128)
; this means bop back and forth a random
; time, then drop
jmp move_enemies
enemy_type_5:
cmp #$5
bne enemy_type_6
;========================
; Enemy Type 5
; "wiggle"
lda #$1
sta (ENEMY_PL),y ; xadd=1
iny
lda LEVEL
sta (ENEMY_PL),y ; yadd=2
iny
jsr random_number
and #$0f
clc
adc #$2
sta (ENEMY_PL),y ; xmin=(rand%16)+2
dey ; yadd
dey ; xadd
dey ; y
dey ;x
asl A
sta (ENEMY_PL),y
iny ;y
iny ; xadd
iny ; yadd
iny ; xmin
jsr random_number
and #$0f
clc
adc (ENEMY_PL),Y
adc #$02
iny
sta (ENEMY_PL),Y ; xmax = xmin+(rand%16)+2
jmp move_enemies
enemy_type_6:
cmp #$6
beq enemy_type_7
cmp #$7
beq enemy_type_7
jmp enemy_type_8
enemy_type_7:
;=====================
; Enemy Types 6+7
; "Rain"
jsr random_number
and #6
bne no_use_own_x
dey ; y
dey ; x
lda SHIPX
cmp #$2
bpl shipx_ok
lda #$2 ; stupid bug where gets stuck is < xmin
shipx_ok:
asl A
sta (ENEMY_PL),Y ; one-in-four chance we use shipx as X
iny ; y
iny ; xadd
no_use_own_x:
lda #$0
sta (ENEMY_PL),Y ; xadd=0
iny
lda #$1
sta (ENEMY_PL),Y ; yadd = 1
jmp move_enemies
enemy_type_8:
enemy_type_9:
;======================
; Things flung by boss
dey ; y
dey ; x
lda BOSS_X
clc
adc #$5
asl A
sta (ENEMY_PL),Y ; enemy_x=boss_x+5
iny
lda #$3
asl A
asl A
sta (ENEMY_PL),Y ; enemy_y=3
iny
lda #$0
sta (ENEMY_PL),Y ; xadd=0
iny
lda #$2
sta (ENEMY_PL),Y ; yadd=2
move_enemies:
;==============================================
; Move Enemies! (first thing, if no new added)
;==============================================
ldy #$0 ; point to enemies[0]
handle_enemies:
tya
pha ; store y on stack
lda (ENEMY_PL),Y ; get enemy[y].out
bne load_enemy_zero_page ; if enemy.out then we are good
jmp skip_to_next_enemy ; enemy is not out, so skip to next
;==========================================
; load this enemy stuff into zero page for
; easier access
;==========================================
load_enemy_zero_page:
ldx #ENEMY_EXPLODING
load_to_zero_page:
iny ; point to exploding
lda (ENEMY_PL),Y
sta 0,X ; store to zero page
inx
cpx #(ENEMY_XMAX+1) ; see if reached end
bne load_to_zero_page ; if not keep copying
;================================
; skip all movement and collision
; if exploding
;================================
lda ENEMY_EXPLODING
beq move_enemy_x
jmp draw_enemy
;================================
; Start the enemy movement engine
;================================
;========
; Move X
;========
move_enemy_x:
clc
lda ENEMY_X ; X
adc ENEMY_XADD ; x+=xadd
sta ENEMY_X
lsr A
cmp ENEMY_XMIN ; are we less than xmin?
bmi switch_dir_enemy_x ; if so, switch direction
cmp ENEMY_XMAX ; are we greater than xmax?
bpl switch_dir_enemy_x ; if so, switch direction
jmp move_enemy_y
switch_dir_enemy_x:
; switch X direction
lda #$0 ; load zero
sec
sbc ENEMY_XADD ; 0 - ENEMY_XADD
sta ENEMY_XADD ; store it back out, negated
jmp move_enemy_x ; re-add it in
;========
; Move Y
;========
move_enemy_y:
lda #$0 ; load in zero
cmp ENEMY_YADD ; compare to YADD
bmi no_y_special_case ; if minus, we have special case
inc ENEMY_YADD
bne done_enemy_y
lda #$0
sta ENEMY_XADD
lda #$2
sta ENEMY_YADD
; increment y
; is it > 0?
; if not keep going
; if so, yadd=level*2
jmp done_enemy_y
no_y_special_case:
clc
lda ENEMY_Y ; get Y
adc ENEMY_YADD ; y+=yadd
sta ENEMY_Y ; store back out
lsr A
lsr A
cmp #$12 ; is y<=12?
bmi done_enemy_y ; if so no need to do anything
beq done_enemy_y
; off screen
pla ; pop saved Y off stack
tay
pha ; push y back on stack
lda #$0
sta (ENEMY_PL),Y ; set enemy[i].out=0
dec TOTAL_ENEMIES_OUT
lda BONUS_FLAGS
and #<(~PERFECT_KILLS)
sta BONUS_FLAGS
jmp skip_to_next_enemy ; skip to next enemy
done_enemy_y:
;===============
; Done Movement
;===============
;======================
; Check for Collisions
;======================
;==================================
; Check ENEMY <> MISSILE collision
;==================================
check_enemy_missile_collision:
ldy #$0
sty YSAV
check_missile_loop:
lda (MISSILE_PL),Y
beq missile_not_out
iny ; point to missile.x
lda (MISSILE_PL),Y ; load missile.x
sta COL_X1
sta COL_X2
lda ENEMY_X
lsr A
sta COL_X3
clc
adc #3
sta COL_X4
jsr check_inside
bcc missile_done
x_in_range:
iny
lda (MISSILE_PL),Y ; load missile.y
sta COL_X3
clc
adc #2
sta COL_X4
lda ENEMY_Y
lsr A
lsr A
sta COL_X1
clc
adc #1
sta COL_X2
jsr check_inside
bcc missile_done
horrible_explosion:
; clear missile
ldy YSAV
lda #$0
sta (MISSILE_PL),Y
; clear enemy
lda #$1
sta ENEMY_EXPLODING
lda #$40
sta ENEMY_KIND
jsr inc_score
jmp draw_enemy
missile_done:
missile_not_out:
ldy YSAV
iny
iny
iny
sty YSAV
cpy #(NUM_MISSILES*3)
bne check_missile_loop
;=================================
; Done missile <> enemy collision
;=================================
;====================================
; check for ship <-> enemy collision
;====================================
lda SHIPX
sta COL_X3
clc
adc #8
sta COL_X4 ; big check is shipx - shipx+8
lda ENEMY_X
lsr A
sta COL_X1
clc
adc #2
sta COL_X2 ; small check enemy_x - enemy_x+2
jsr check_inside ; check if overlap
bcc draw_enemy ; if not, move ahead
lda #16
sta COL_X3
lda #18
sta COL_X4 ; big check is 16 - 18
lda ENEMY_Y
lsr A
lsr A
sta COL_X1
clc
adc #$1
sta COL_X2 ; little check is enemy_y - enemy_y+1
jsr check_inside ; check if overlap
bcc draw_enemy ; if not, move ahead
; make the enemy explode
lda #$1
sta ENEMY_EXPLODING
lda #$40
sta ENEMY_KIND
dec SHIELDS
jsr update_shields ; move shields down
lda #<(~PERFECT_SHIELDS) ; (~PERFECT_SHIELDS)
and BONUS_FLAGS ; remove perfect shield bonus
sta BONUS_FLAGS
;=====================================
; Done ship <> enemy collision detect
;=====================================
draw_enemy:
; See if the enemy is currently exploding
; if so, do explosion stuff
check_enemy_explode:
lda ENEMY_EXPLODING ; load enemy[i].exploding
beq not_exploding ; if 0 then not exploding
handle_exploding:
jsr click ; make some noise
clc
lda ENEMY_KIND ; move to next step in explosion
adc #$4
sta ENEMY_KIND
cmp #$58 ; have we cycles through explosion?
bne draw_enemy_sprite ; if not, we are still exploding
dec TOTAL_ENEMIES_OUT ; total_enemies_out--
pla
tay ; load y
pha
lda #$0 ; enemy[i].out=0
sta (ENEMY_PL),Y
jmp skip_to_next_enemy
; point to enemies_x
; goto enemies_xy
not_exploding:
draw_enemy_sprite:
; point to proper sprite
lda #>enemy_sprite0 ; point to the missile sprite
sta STRINGH
lda #<enemy_sprite0
sta STRINGL
lda ENEMY_KIND ; get kind
and #$F8
clc
adc STRINGL
sta STRINGL
lda #0
adc STRINGH
sta STRINGH
enemies_xy:
lda ENEMY_X ; get X
lsr A
sta CH
lda ENEMY_Y ; load it
lsr A
lsr A
sta CV
jsr blit ; blit the missile sprite
save_zp_enemy_back:
; save zero page copy back to RAM
ldx #ENEMY_EXPLODING
pla
tay ; restore y pointer
pha
save_from_zero_page:
iny ; point to exploding
lda 0,X
sta (ENEMY_PL),Y
inx
cpx #(ENEMY_XMAX+1) ; see if reached end
bne save_from_zero_page ; if not keep copying
skip_to_next_enemy:
pla ; get saved value of Y
clc
adc #$9 ; add 9 to point to next
tay
cpy #NUM_ENEMIES*9 ; have we looped through them all?
beq draw_the_boss ; if not, loop
jmp handle_enemies
;===================================================
;===================================================
; BOSS STUFF
draw_the_boss:
;=======================
; if enemy_type==9
; we have a boss out
lda ENEMY_TYPE
cmp #$9
beq check_boss_exploding
jmp done_with_boss
check_boss_exploding:
;================================
; if not exploding, draw the boss
lda BOSS_EXPLODING
bne skip_draw_boss
lda #$0 ; boss_y=0
sta CV
lda BOSS_X
sta CH ; boss_x
lda #>boss_sprite
sta STRINGH
lda #<boss_sprite
sta STRINGL
jsr blit ; blit the ship sprite
skip_draw_boss:
;================================
; Draw Smoke
lda BOSS_SMOKE
beq skip_draw_smoke
; point to proper sprite
lda #>smoke_sprite0 ; point to the missile sprite
sta STRINGH
lda #<smoke_sprite0
sta STRINGL
lda BOSS_SMOKE ; get kind
and #$fc ; mask off bottom 2 bits
clc
adc STRINGL
sta STRINGL
lda #0
adc STRINGH
sta STRINGH
lda BOSS_X ; get X
clc
adc #$5
sta CH
lda #$3 ; load it
sta CV
jsr blit ; blit the missile sprite
lda BOSS_X
clc
adc #$5
sec
sbc BOSS_XADD
sta CH
lda #$4
sta CV
jsr blit
dec BOSS_SMOKE
skip_draw_smoke:
;======================
; BOSS Laser Shoot
lda BOSS_SHOOTING
beq skip_boss_shooting
dec BOSS_SHOOTING
jsr click
ldx #$0
boss_shoot_loop:
txa
pha
; point to proper sprite
lda #>laser_sprite0 ; point to the missile sprite
sta STRINGH
lda #<laser_sprite0
sta STRINGL
lda BOSS_SHOOTING ; get shooting
and #$1
beq got_right_laser
clc
lda #$5
adc STRINGL
sta STRINGL
lda #0
adc STRINGH
sta STRINGH
got_right_laser:
lda BOSS_X
sta CH
txa
asl
clc
adc #$3
sta CV
jsr blit ; blit the laser sprite
lda BOSS_X
clc
adc #$C
sta CH
pla
pha
asl
clc
adc #$3
sta CV
jsr blit
pla
tax
inx
cpx #$8
bne boss_shoot_loop
jsr click
skip_boss_shooting:
;=============================
; boss is dead
lda BOSS_EXPLODING
beq boss_is_not_exploding
lda #$1
sta BOSS_WAITING
ldx #$20
big_explosion:
txa
pha
; point to proper sprite
lda #>smoke_sprite0 ; point to the missile sprite
sta STRINGH
lda #<smoke_sprite0
sta STRINGL
lda BOSS_EXPLODING ; get kind
lsr A
lsr A
and #$0c ; mask off bottom 2 bits
clc
adc STRINGL
sta STRINGL
lda #0
adc STRINGH
sta STRINGH
jsr random_number
and #$03
sta CV
jsr random_number
and #$07
clc
adc BOSS_X
sta CH
jsr blit ; blit the missile sprite
pla
tax
dex
bne big_explosion
jsr click
dec BOSS_EXPLODING
bne not_dead_yet
lda LEVEL ; only show ending after level 1
cmp #$1
bne no_ending
jmp do_ending
no_ending:
inc SCOREH ; add 100 to score
jsr print_score
lda LEVEL
cmp #$7 ; level can't be higher than 7
beq start_new_level
inc LEVEL
inc SHIELDS
inc SHIELDS
lda #$A
cmp SHIELDS
bpl start_new_level
sta SHIELDS
start_new_level:
jsr update_shields
jmp new_level
not_dead_yet:
jmp move_boss
boss_is_not_exploding:
dec BOSS_COUNT
bne move_boss
;=========================================
; Toggle boss waiting state if count is up
lda BOSS_WAITING
beq make_boss_wait
stop_boss_waiting:
lda #$0
sta BOSS_WAITING ; boss_waiting=0
jsr random_number
sta BOSS_COUNT ; boss_count=rand%256
jmp move_boss
make_boss_wait:
lda #$1
sta BOSS_WAITING
jsr random_number
and #$01f
clc
adc #$30
sta BOSS_COUNT
lda #$20
sta BOSS_SHOOTING
move_boss:
lda BOSS_WAITING
bne laser_collision
lda BOSS_X
clc
adc BOSS_XADD
sta BOSS_X
cmp #26
bpl boss_reverse
boss_under:
cmp #$0
bpl laser_collision
boss_reverse:
lda #$0 ; load zero
sec
sbc BOSS_XADD ; 0 - ENEMY_XADD
sta BOSS_XADD ; store it back out, negated
jmp move_boss ; re-add it in
laser_collision:
;================================
; Collision detection for lasers
;
lda BOSS_SHOOTING
beq done_with_boss
left_laser:
lda BOSS_X
sta COL_X1
sta COL_X2
lda SHIPX
sta COL_X3
lda #$6
clc
adc SHIPX
sta COL_X4
jsr check_inside
bcs laser_hit
right_laser:
lda BOSS_X
clc
adc #$C
sta COL_X1
sta COL_X2
jsr check_inside
bcc done_with_boss
laser_hit:
lda BOSS_SHOOTING
and #$3 ; only take damage 1/8 the time
bne done_with_boss
dec SHIELDS
jsr update_shields
done_with_boss:
ldy #$0 ; point to missile[0]
move_missiles:
lda (MISSILE_PL),Y ; get missile[y]
beq loop_move_missiles ; if missile.out==0 skip
iny ; move to missile.y
iny
clc ; clear carry
lda (MISSILE_PL),Y ; get missile.y
adc #$FF ; move up (subtract 1)
sta (MISSILE_PL),Y ; store missile.y
bpl missile_collision_detection ; if not off screen, contine
dey ; back up to missile.out
dey
lda #$0
sta (MISSILE_PL),Y ; set missile.out=0
lda #<(~PERFECT_AIM) ; shot missed!
and BONUS_FLAGS ; clear perfect shot flag
sta BONUS_FLAGS
jmp loop_move_missiles ; continue
missile_collision_detection:
check_missile_boss:
lda ENEMY_TYPE
cmp #$9
bne done_missile_collision
dey ; missile x
lda (MISSILE_PL),Y
iny ; fix y
sta COL_X1
sta COL_X2
lda BOSS_X
sta COL_X3
clc
adc #$0d
sta COL_X4
jsr check_inside
bcc done_missile_collision
check_boss_y:
lda (MISSILE_PL),Y
sta COL_X1
clc
adc #$2
sta COL_X2
lda #$0
sta COL_X3
lda #$3
sta COL_X4
jsr check_inside
bcc done_missile_collision
hit_the_boss:
dey
dey
lda #$0
sta (MISSILE_PL),Y ; missile_out=0
lda #$B
sta BOSS_SMOKE
dec BOSS_HITS
bne loop_move_missiles
lda #$2F
sta BOSS_EXPLODING
lda #$0
sta BOSS_SHOOTING
jmp loop_move_missiles
done_missile_collision:
jmp loop_move_at_y
loop_move_missiles:
iny
iny
loop_move_at_y:
iny
cpy #NUM_MISSILES*3 ; have we checked all missiles?
bne move_missiles ; if not, loop
done_move_missiles:
ldy #$0 ; point to missiles[0]
draw_missiles:
lda (MISSILE_PL),Y ; get missile[y]
beq loop_draw_missiles ; if missile.out==0 skip
iny ; point to missile.x
lda (MISSILE_PL),Y ; load it
sta CH
iny ; point to missile.y
lda (MISSILE_PL),Y ; load it
sta CV
sty YSAV1 ; save Y
lda #>missile_sprite ; point to the missile sprite
sta STRINGH
lda #<missile_sprite
sta STRINGL
jsr blit ; blit the missile sprite
ldy YSAV1 ; restore Y
jmp loop_draw_missiles_noadd
loop_draw_missiles:
iny
iny
loop_draw_missiles_noadd:
iny
cpy #NUM_MISSILES*3 ; have we looped through them all?
bne draw_missiles ; if not, loop
game_read_keyboard:
jsr get_key
lda LASTKEY
bne game_q
jmp move_ship ; if no keypressed, move the ship
game_q:
cmp #'Q'
bne game_j
;; call verify_quit
jmp done_game
;; jmp set_pause_flag
game_j:
cmp #'J'
bne game_k
lda SHIPXADD ; load xadd
beq game_j_sub
bpl game_j_0 ; is switch dir, then 0 it
game_j_sub:
dec SHIPXADD ; else, dec XADD
jmp move_ship
game_j_0:
lda #$0
sta SHIPXADD
jmp move_ship
game_k:
cmp #'K'
bne game_c
lda SHIPXADD ; load xadd
bmi game_j_0 ; if we are switching dirs, set to zero
inc SHIPXADD ; else xadd++
jmp move_ship
game_c:
cmp #'C'
bne game_p
lda PADDLE_STATUS
eor #$80
sta PADDLE_STATUS
jmp move_ship
game_p:
cmp #'P'
bne game_s
bit KEYRESET
jsr wait_until_keypressed
jmp move_ship
game_s:
cmp #'S'
bne game_h
lda SOUND_ON
eor #$ff
sta SOUND_ON
jmp move_ship
game_h:
cmp #'H'
bne game_space
jsr do_help
jsr set_page0_gr
game_space:
cmp #' '+128 ; +128 because of get_key 'feature'
bne game_unknown
ldy #$0 ; point to missile[y]
fire_missiles:
lda (MISSILE_PL),Y ; get missile[y].out
bne end_fire_loop ; if not out, skip ahead
lda #$1 ; set missile[y].out=1
sta (MISSILE_PL),Y
iny ; point to missile[y].x
lda #$3
clc
adc SHIPX ; missile[y].x=shipx+3
sta (MISSILE_PL),Y
iny ; point to missile[y].y
lda #$10 ; set to 16
sta (MISSILE_PL),Y
jmp done_fire_missiles
end_fire_loop:
iny
iny
iny
cpy #NUM_MISSILES*3 ; see if we have more missiles
bne fire_missiles ; if so, loop
done_fire_missiles:
jmp move_ship
game_unknown:
move_ship:
clc ; Clear carry
lda SHIPX ; load ship_x
adc SHIPXADD ; ship_x+=xadd
sta SHIPX ; store it back
check_x_under:
bpl check_x_over ; if positive, keep going
lda #$0 ; we were below zero
sta SHIPX ; so shipx=0
sta SHIPXADD ; xadd=0
jmp blit_ship ; go to blit
check_x_over:
cmp #$21 ; are we over 33?
bmi blit_ship ; if not, blit ship
lda #$0 ; shipxadd=0
sta SHIPXADD
lda #$21 ; shipx=33
sta SHIPX
blit_ship:
lda #$10 ; shipy=16
sta CV
lda SHIPX
sta CH ; load shipx
lda #>ship_sprite
sta STRINGH
lda #<ship_sprite
sta STRINGL
jsr blit ; blit the ship sprite
jsr clear_bottom
lda #>shields_string
sta STRINGH
lda #<shields_string
sta STRINGL
clc
lda #$2
adc GR_PAGE
sta BASH
lda #$50
sta BASL
ldy #$0
shield_print_loop:
;=============================
; CHECK TO SEE IF GAME IS OVER
;=============================
lda SHIELDS
bmi done_game
lda (STRINGL),Y
sta (BASL),Y
iny
cpy #$1E ; string is 30 long
bne shield_print_loop
inc BASH ; move to line 23
lda #>score_string
sta STRINGH
lda #<score_string
sta STRINGL
ldy #$0
score_print_loop:
lda (STRINGL),Y
sta (BASL),Y
iny
cpy #$26 ; string is 38 long
bne score_print_loop
clc
lda #$80
adc BASL
sta BASL ; move to line 24
;OPTIMIZE
lda #>level_string
sta STRINGH
lda #<level_string
sta STRINGL
ldy #$0
level_print_loop:
lda (STRINGL),Y
sta (BASL),Y
iny
cpy #$C ; string is 12 long
bne level_print_loop
;==========
; Flip Pages
lda #$4
bit GR_PAGE
bne gr_page_1
gr_page_0:
bit PAGE1 ; switch to page 0
lda #$4
jmp write_out_gr_page
gr_page_1:
bit PAGE0 ; switch to page 1
lda #$8
write_out_gr_page:
sta GR_PAGE
; lda #$8B ; 107 = 30080us = 30ms
lda #$65
jsr WAIT
jmp main_game_loop
done_game:
ldx #30
jsr wait_X_100msec ; pause for 3 seconds
bit KEYRESET ; clear keyboard
jsr set_page0_text
jsr HOME
lda #>game_over_string
sta STRINGH
lda #<game_over_string
sta STRINGL
jsr print_text_xy
jsr wait_until_keypressed
jsr set_page0_text
see_if_new_hi_score:
sed
lda SCOREH
cmp HISCORE_H
cld
beq too_close
bpl new_high
jmp do_hi_score
too_close:
sed
lda SCOREL
cmp HISCORE_L
cld
bpl new_high
jmp do_hi_score
new_high:
; Actually set the high score
lda SCOREL
sta HISCORE_L
lda SCOREH
sta HISCORE_H
lda #>(score_string+31)
sta STRINGH
lda #<(score_string+31)
sta STRINGL
jsr print_high_score
jsr HOME
; print new high score message
lda #>new_high_score_string
sta STRINGH
lda #<new_high_score_string
sta STRINGL
jsr print_text_xy
jsr print_text_xy
; set high score to AAA
lda #$C1
sta HISCORE_1
sta HISCORE_2
sta HISCORE_3
; load initials address
lda #$06
sta STRINGH
lda #$12
sta STRINGL
; load pointer address
lda #$06
sta BASH
lda #$92
sta BASL
ldy #$0
ldx #$0
initials_loop:
; erase old pointer
ldy #$0
lda #$A0
sta (BASL),Y
iny
sta (BASL),Y
iny
sta (BASL),Y
txa
tay
; draw pointer
lda #$DE ; '^'
sta (BASL),Y
ldy #$0
; draw initials
lda HISCORE_1
sta (STRINGL),Y
iny
lda HISCORE_2
sta (STRINGL),Y
iny
lda HISCORE_3
sta (STRINGL),Y
in_key:
jsr wait_until_keypressed
lda LASTKEY
beq in_key
cmp #$D
beq do_hi_score
cmp #'I'
bne in_down
inc HISCORE_1,X
in_down:
cmp #'M'
bne in_left
dec HISCORE_1,X
in_left:
cmp #'K'
bne in_right
inx
in_right:
cmp #'J'
bne fix_limits
dex
fix_limits:
; Make sure X is between 0 and 2
cpx #$0
bpl x_high
ldx #$2
x_high:
cpx #$3
bmi x_lo
ldx #$0
x_lo:
jmp initials_loop
do_hi_score:
jsr HOME
lda #>high_score_string
sta STRINGH
lda #<high_score_string
sta STRINGL
jsr print_text_xy
; go to screen co-ords 15x12
lda #$06
sta STRINGH
lda #$37
sta STRINGL
; put the initials up
lda HISCORE_1
ldy #$0
sta (STRINGL),Y
lda HISCORE_2
iny
sta (STRINGL),Y
lda HISCORE_3
iny
sta (STRINGL),Y
; Print score to screen
;
lda #$06
sta STRINGH
lda #$3D
sta STRINGL
jsr print_high_score
jsr wait_until_keypressed
jmp opener
;=========================================================
; CLICK
;=========================================================
click:
lda SOUND_ON
beq no_click
bit SPEAKER
no_click:
rts
;==========================================================
; Wait X 100 msec
;==========================================================
;
wait_X_100msec:
lda #$86 ; constant ~ 100msec
jsr WAIT
dex
bne wait_X_100msec
rts
;==========================================================
; Update Shields
;==========================================================
;
update_shields:
lda #>shields_string
sta STRINGH
lda #<shields_string
sta STRINGL
ldy #0
lda SHIELDS
bne normal_shields
flash_shields:
lda #$7f
and (STRINGL),Y
sta (STRINGL),Y
iny
cpy #$7
bne flash_shields
jmp shields_line
normal_shields:
lda #$80
ora (STRINGL),Y
sta (STRINGL),Y
iny
cpy #$7
bne normal_shields
shields_line:
ldy #$A
ldx #$0
shield_line_loop:
cpx SHIELDS
bmi shield_box
lda #'_'+128
jmp shield_char
shield_box:
lda #' '
shield_char:
sta (STRINGL),Y
iny
iny
inx
cpx #$A
bne shield_line_loop
rts
;==========================================================
; Random Number Generator
;==========================================================
; from dlyons@Apple.COM (David A Lyons)
; posting to comps.sys.apple2 24 November 1992
; algorithm from Pop Science ~1980s
; when seeded with non-zero, will generate all 255 values
; before repeating
random_number:
lda RANDOM_SEED
bne random_not_zero
lda #$D
random_not_zero:
asl A
bcc random_num_done
eor #$87
random_num_done:
sta RANDOM_SEED
rts
;==========================================================
; Wait until keypressed
;==========================================================
;
wait_until_keypressed:
inc RANDOM_SEED ; seed random num counter
lda KEYPRESS ; check if keypressed
bpl wait_until_keypressed ; if not, loop
jmp figure_out_key
;==========================================================
; Get Key
;==========================================================
;
get_key:
check_paddle_button:
; check for paddle button
bit PADDLE_BUTTON0
bpl no_button
lda #' '+128
jmp save_key
no_button:
lda KEYPRESS
bpl no_key
figure_out_key:
cmp #' '+128 ; the mask destroys space
beq save_key ; so handle it specially
and #$5f ; mask, to make upper-case
check_right_arrow:
cmp #$15
bne check_left_arrow
lda #'K'
check_left_arrow:
cmp #$08
bne check_up_arrow
lda #'J'
check_up_arrow:
cmp #$0B
bne check_down_arrow
lda #'I'
check_down_arrow:
cmp #$0A
bne check_escape
lda #'M'
check_escape:
cmp #$1B
bne save_key
lda #'Q'
jmp save_key
no_key:
bit PADDLE_STATUS
bpl no_key_store
; check for paddle action
; code from http://web.pdx.edu/~heiss/technotes/aiie/tn.aiie.06.html
inc PADDLE_STATUS
lda PADDLE_STATUS
and #$03
beq check_paddles
jmp no_key_store
check_paddles:
lda PADDLE_STATUS
and #$80
sta PADDLE_STATUS
ldx #$0
LDA PTRIG ;TRIGGER PADDLES
LDY #0 ;INIT COUNTER
NOP ;COMPENSATE FOR 1ST COUNT
NOP
PREAD2: LDA PADDL0,X ;COUNT EVERY 11 uSEC.
BPL RTS2D ;BRANCH WHEN TIMED OUT
INY ;INCREMENT COUNTER
BNE PREAD2 ;CONTINUE COUNTING
DEY ;COUNTER OVERFLOWED
RTS2D: ;RETURN W/VALUE 0-255
cpy #96
bmi paddle_left
cpy #160
bmi no_key_store
lda #'K'
jmp save_key
paddle_left:
lda #'J'
jmp save_key
no_key_store:
lda #0 ; no key, so save a zero
save_key:
sta LASTKEY ; save the key to our buffer
bit KEYRESET ; clear the keyboard buffer
rts
;==========================================================
; score_plus_50
;==========================================================
;
score_plus_50:
sed ; enter decimal mode
clc
lda SCOREL
adc #$50
sta SCOREL ; score+=50
lda SCOREH
adc #$0
sta SCOREH ; carry into high byte if needed
cld ; leave decimal mode
jmp print_score
;==========================================================
; inc_score
;==========================================================
;
inc_score:
sed ; enter decimal mode
clc
lda SCOREL
adc #$5
sta SCOREL ; score+=5
lda SCOREH
adc #$0
sta SCOREH ; carry into high byte if needed
cld ; leave decimal mode
lda SCOREL ; if score /100 =0 then inc shields
bne print_score
lda SHIELDS
cmp #$0A ; don't raise shields higher than 10
bpl print_score
inc SHIELDS
jsr update_shields
print_score:
lda #>(score_string+7)
sta STRINGH
lda #<(score_string+7)
sta STRINGL
tya
pha ; save Y on stack
ldy #$0
lda SCOREH
sta BCD_BYTEH
lda SCOREL
sta BCD_BYTE
jsr print_bcd_word
pla ; restore Y
tay
rts
;======================
; print high_score
;======================
; location to output to in STRINGH/STRINGL
print_high_score:
tya
pha ; save Y on stack
ldy #$0
lda HISCORE_H
sta BCD_BYTEH
lda HISCORE_L
sta BCD_BYTE
jsr print_bcd_word
pla ; restore Y
tay
rts
;==========================================================
; print_bcd_word
;==========================================================
; string to output in STRINGH/STRINGL
; byte to output in BCD_BYTE
print_bcd_word:
lda BCD_BYTEH
lsr A
lsr A
lsr A
lsr A
and #$f ; mask low nybble
bne to_ascii_thou
lda #$A0 ; load a space
jmp write_thousands
to_ascii_thou:
adc #$B0 ; covert to ascii
write_thousands:
sta (STRINGL),Y ; store output
iny
lda BCD_BYTEH
and #$f
bne to_ascii_hun
cmp BCD_BYTEH
bne to_ascii_hun
lda #$A0
jmp write_hundreds
to_ascii_hun:
adc #$B0
write_hundreds:
sta (STRINGL),Y
iny
print_bcd_byte:
lda BCD_BYTE
lsr A
lsr A
lsr A
lsr A
and #$f ; mask low nybble
bne to_ascii_tens ; if not zero, convert to ascii
cmp BCD_BYTEH
bne to_ascii_tens
lda #$A0
jmp write_tens
to_ascii_tens:
adc #$B0 ; covert to ascii
write_tens:
sta (STRINGL),Y ; store output
iny ; point one lower
lda BCD_BYTE
clc
and #$f
adc #$B0
sta (STRINGL),Y
rts
;==========================================================
; check inside
;==========================================================
; Simple collision detection. Have small line x1<->x2
; Want to see if it overlaps long line x3<---------->x4
; so:
; if ((x1>x3)&&(x1<x4)) || ((x2>x3) && (x2<x4)) inside
; else outside
check_inside:
lda COL_X1
cmp COL_X3
bmi check_higher
cmp COL_X4
bmi inside
check_higher:
lda COL_X2
cmp COL_X3
bmi outside
cmp COL_X4
bpl outside
inside:
sec
rts
outside:
clc
rts
;==========================================================
; set_page0_text
;==========================================================
;
set_page0_text:
bit PAGE0 ; set page0
bit TEXT ; set text mode
rts
;==========================================================
; set_page0_gr
;==========================================================
;
set_page0_gr:
lda #4
sta GR_PAGE
bit PAGE0 ; set page 0
bit LORES ; Lo-res graphics
bit TEXTGR ; mixed gr/text mode
bit GR ; set graphics
rts
;==========================================================
; clear bottom
;==========================================================
;
clear_bottom:
lda #$2
clc
adc GR_PAGE
sta BASH ; point to line 21
lda #$50
sta BASL
ldx #$00 ; line counter
bottom_y:
lda #' '+128 ; want to put a space
ldy #$0 ; column count
bottom_loop:
sta (BASL),Y ; store a space
iny ; incrememnt
cpy #$28 ; are we > 40?
bmi bottom_loop ; if not, loop
lda #$80 ; go to next line [they are $80 apart]
clc
adc BASL ; increment base
sta BASL ; store it out
lda #$0 ; load 0 into A
adc BASH ; carry into top byte if need be
sta BASH ; and store out
inx ; increment line count
cpx #$4 ; have we done 4
bcc bottom_y ; if not, loop
rts
;==========================================================
; print X strings
;==========================================================
;
;
print_x_strings:
stx TEMP
jsr print_text_xy
ldx TEMP
dex
bne print_x_strings
rts
;==========================================================
; Print text x,y
;==========================================================
; x=ch y=cv
; string=string_addr
print_text_xy:
ldy #$0 ; clear IY
lda (STRINGL),Y ; load x from memory
sta CH ; store to CH
iny ; point to next value
lda (STRINGL),Y ; load y from memory
sta CV ; store to CV
; point to beginning of string
clc
lda #$2
adc STRINGL
sta STRINGL
lda #$0
adc STRINGH
sta STRINGH
print_text:
ldy #$0
lda CV
jsr BASCALC ; get the address of y in BASH:BASL
clc ; clear the carry
lda BASL ; load BASL
adc CH ; add x
sta BASL ; store BASL back out
output_loop:
lda (STRINGL),Y ; load char from string_addr+y
beq print_done ; if null terminated, done
sta (BASL),Y ; store to BASH:BASL
iny ; IY++
jmp output_loop ; loop
print_done:
iny
tya ; transfer y to accumulator
adc STRINGL ; add y and stringl
sta STRINGL ; and store it out
lda #$0 ; clear accumulator
adc STRINGH ; add with carry from prev stringh
sta STRINGH ; and save it
rts
;==========================================================
; clear_screen
;==========================================================
;
clear_screen:
ldx #$0
clear_0:
cpx #$0
bne clear_1
lda GR_PAGE
sta BASH
lda #$0
sta BASL
ldy #$78
jmp clear_it
clear_1:
cpx #$1
bne clear_2
lda #$80
sta BASL
ldy #$78
jmp clear_it
clear_2:
cpx #$2
bne clear_3
clc
lda #$1
adc GR_PAGE
sta BASH
ldy #$78
jmp clear_it
clear_3:
cpx #$3
bne clear_4
lda #$0
sta BASL
ldy #$78
jmp clear_it
clear_4:
cpx #$4
bne clear_5
clc
lda #$2
adc GR_PAGE
sta BASH
ldy #$50
jmp clear_it
clear_5:
cpx #$5
bne clear_6
lda #$80
sta BASL
ldy #$50
jmp clear_it
clear_6:
cpx #$6
bne clear_7
clc
lda #$3
adc GR_PAGE
sta BASH
ldy #$50
jmp clear_it
clear_7:
cpx #$7
bne clear_8
lda #$0
sta BASL
ldy #$50
jmp clear_it
clear_8:
rts
clear_it:
lda #$00
clear_loop:
dey
sta (BASL),Y
bne clear_loop
inx
jmp clear_0
;==========================================================
; show_stars
;==========================================================
;
show_stars:
lda #>star_field ; Load the star offsets
sta STRINGH ; array into
lda #<star_field ; STRINGH/STRINGL
sta STRINGL
lda BETWEEN_DELAY
and #$1
beq star_7
dec SCROLL ; decrement the scroll count
star_7:
ldy SCROLL ; load the scroll offset into Y
ldx #$8 ; We initially repeat 8 times
lda #$0 ; And have L of 0
sta TEMP ; This is stupid interlace stuff
sta COL_X1
star_4:
lda GR_PAGE ; we loop here, it resets
sta BASH ; to the proper page
star_0:
lda (STRINGL),Y ; get star offset
beq star_5
pha ; save for later
bmi light_star ; check color
lda #$5
jmp done_star
light_star:
lda #$A
done_star:
sta COL_X2 ; save color for later
pla ; restore offset
clc
and #$7f ; clear color flag
adc TEMP ; add in offset
sta BASL ; store as offset
tya ; save y on stack
pha ;
lda COL_X2
ldy #$0
sta (BASL),Y ; plot star
pla ; restore y from stack
tay
star_5:
iny ; increase y (offset pointer)
lda (STRINGL),Y ; get star offset
beq star_6
pha ; save for later
bmi light_star2 ; check color
lda #$50
jmp done_star2
light_star2:
lda #$A0
done_star2:
sta COL_X2 ; save color for later
pla ; restore offset
clc
and #$7f ; clear color flag
adc TEMP ; add in offset
sta BASL ; store as offset
tya ; save y on stack
pha ;
lda COL_X2
ldy #$0
sta (BASL),Y ; plot star
pla ; restore y from stack
tay
star_6:
iny ; increase y (offset pointer)
lda TEMP ; get offset
clc
adc #$80 ; increment to next line
sta TEMP ; and save back
bcc overflow_line ; if overflow, increase BASH
inc BASH
overflow_line:
dex ; repeat X times
bne star_0
inc COL_X1 ; check if first time through
lda #$1
cmp COL_X1
star_1:
bne star_2 ; reload for second 8 lines
ldx #$8
lda #$28
sta TEMP
jmp star_4
star_2: ; check if second time through
lda #$2
cmp COL_X1
bne star_3
ldx #$4 ; reload for another 4 lines
lda #$50
sta TEMP
jmp star_4
star_3:
rts
;==========================================================
; blit
;==========================================================
; x=ch y=cv
; string=addr of sprite
; only works on sprites < 256 bytes!!!
blit:
ldy #$00 ; clear IY
big_blit_loop:
lda CV ; Load y
jsr BASCALC ; we only do 40x20 so just use text mode
lda #$4
bit GR_PAGE
bne keep_blitting
clc
adc BASH
sta BASH
keep_blitting:
clc ; clear the carry
lda BASL ; load BASL
adc CH ; add x
sta BASL ; store BASL back out
bcc blit_loop ; if carry we overflowed
inc BASH ; add overflow into BASH
blit_loop:
lda (STRINGL),Y ; load char from string_addr+y
beq blit_x_done ; if null terminated, done this row
sty YSAV ; save IY
pha ; save run/color on stack
jsr SETCOL ; make low/high both col
; and save in in COLOR
pla ; restore run/color
lsr
lsr
lsr
lsr ; shift A right by 4 to get run-length
tax ; store in IX
ldy #$0 ; clear IY
lda COLOR ; load back COLOR
bne rle_loop ; if not zero, plot it
skip_color:
inc BASL ; increment pointer
dex ; count down IX
bne skip_color ; and skip ahead
jmp rle_loop_done ; done
rle_loop:
sta (BASL),Y ; store our color to the line
inc BASL ; increment output pointer
dex ; decrement count
bne rle_loop ; until done
rle_loop_done:
ldy YSAV ; restore SPRITE pointer
iny ; IY++
jmp blit_loop ; loop until row done
blit_x_done:
iny ; point past 0
lda (STRINGL),Y ; get next
beq blit_done ; if 0 as well, done with sprite
inc CV ; otherwise y++
jmp big_blit_loop ; and loop
blit_done:
rts
;; *********************
;; BSS
;; *********************
.bss
start_bss:
missile_0: .res NUM_MISSILES*3
enemy_0: .res NUM_ENEMIES*9
end_bss:
star_field: .res 255
zero_page_save: .res 56
;; *********************
;; DATA
;; *********************
.data
; SHIELDS: plus 22 spaces (30 total)
shields_string:
.byte $D3,$C8,$C9,$C5,$CC,$C4,$D3,$BA
.byte $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
.byte $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
.byte $A0,$A0
; SCORE and HISCORE: (38 Total)
score_string:
.byte $D3,$C3,$CF,$D2,$C5,$BA,$A0,$A0,$A0,$A0
.byte $A0
.byte $A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
.byte $C8,$C9,$D3,$C3,$CF,$D2,$C5,$BA,$A0,$A0,$A0,$A0
.byte $B5,$B0,$B0,$A0,$A0,$A0
; LEVEL:
level_string_xy:
.byte $0E,$0A
level_string:
.byte $CC,$C5,$D6,$C5,$CC,$BA,$A0,$A0,$A0,$A0,$B1,$A0,$00
; A VMW SOFTWARE PRODUCTION
vmw_string: .byte $07,$14
.byte $C1,$A0,$D6,$CD,$D7,$A0,$D3,$CF,$C6,$D4,$D7,$C1,$D2
.byte $C5,$A0,$D0,$D2,$CF,$C4,$D5,$C3,$D4,$C9,$CF,$CE,$00
; MERCILESS MARAUDING MALICIOUS MARKETERS
mercy_string: .byte $00,$14
.byte $CD,$C5,$D2,$C3,$C9,$CC,$C5,$D3,$D3,$A0,$CD,$C1,$D2
.byte $C1,$D5,$C4,$C9,$CE,$C7,$A0,$CD,$C1,$CC,$C9,$C3,$C9
.byte $CF,$D5,$D3,$A0,$CD,$C1,$D2,$CB,$C5,$D4,$C5,$D2,$D3
.byte $00
; GAME OVER
game_over_string:
.byte $0F,$0A
.byte $C7,$C1,$CD,$C5,$A0,$CF,$D6,$C5,$D2,$00
; NEW GAME
new_game_string: .byte $CE,$C5,$D7,$A0,$C7,$C1,$CD,$C5,$00
; ABOUT
about_string: .byte $C1,$C2,$CF,$D5,$D4,$00
; STORY
story_string: .byte $D3,$D4,$CF,$D2,$D9,$00
; HISCORE
hiscore_string: .byte $C8,$C9,$A0,$D3,$C3,$CF,$D2,$C5,$00
; QUIT
quit_string: .byte $D1,$D5,$C9,$D4,$00
; H FOR HELP
help_string: .byte $0,$14
.byte $C8,$A0,$C6,$CF,$D2,$A0,$C8,$C5,$CC,$D0,$00
; QUIT? ARE YOU SURE?
quit_conf_string: .byte $D1,$D5,$C9,$D4,$BF,$A0,$C1,$D2,$C5,$A0,$D9,$CF,$D5
.byte $A0,$D3,$D5,$D2,$C5,$BF,$00
; YES
yes_string: .byte $D9,$C5,$D3,$00
; NO
no_string: .byte $CE,$CF,$00
about_lines:
; TOM BOMBEM BY VINCE WEAVER (PIC ABOVE)
.byte $0,$14
.byte $D4,$CF,$CD,$A0,$C2,$CF,$CD,$C2,$C5,$CD
.byte $A0,$A0,$C2,$D9,$A0,$D6,$C9,$CE,$C3,$C5
.byte $A0,$D7,$C5,$C1,$D6,$C5,$D2,$A0,$A8,$D0
.byte $C9,$C3,$A0,$C1,$C2,$CF,$D6,$C5,$A9,$00
; BASED ON LINUX TB_ASM - APPLE II FOREVER
.byte $0,$16
.byte $C2,$C1,$D3,$C5,$C4,$A0,$CF,$CE,$A0,$CC
.byte $C9,$CE,$D5,$D8,$A0,$D4,$C2,$DF,$C1,$D3
.byte $CD,$A0,$AD,$A0,$C1,$D0,$D0,$CC,$C5,$A0
.byte $C9,$C9,$A0,$C6,$CF,$D2,$C5,$D6,$C5,$D2,$00
; VINCE@DEATER.NET
.byte $0,$16
.byte $D6,$C9,$CE,$C3,$C5,$C0,$C4,$C5,$C1,$D4
.byte $C5,$D2,$AE,$CE,$C5,$D4,$00
; HTTP://WWW.DEATER.NET/WEAVE/VMWPROD/TB1/
.byte $0,$17
.byte $C8,$D4,$D4,$D0,$BA,$AF,$AF,$D7,$D7,$D7
.byte $AE,$C4,$C5,$C1,$D4,$C5,$D2,$AE,$CE,$C5
.byte $D4,$AF,$D7,$C5,$C1,$D6,$C5,$AF,$D6,$CD
.byte $D7,$D0,$D2,$CF,$C4,$AF,$D4,$C2,$B1,$AF,$00
ending_lines:
; *** MESSAGE FROM EARTH ***
.byte $7,$14
.byte $AA,$AA,$AA,$A0,$CD,$C5,$D3,$D3,$C1,$C7
.byte $C5,$A0,$C6,$D2,$CF,$CD,$A0,$C5,$C1,$D2
.byte $D4,$C8,$A0,$AA,$AA,$AA,$00
; CONGRATULATIONS TOM, YOU'VE DESTROYED
.byte $0,$16
.byte $C3,$CF,$CE,$C7,$D2,$C1,$D4,$D5,$CC,$C1
.byte $D4,$C9,$CF,$CE,$D3,$A0,$D4,$CF,$CD,$AC
.byte $A0,$D9,$CF,$D5,$A7,$D6,$C5,$A0,$C4,$C5
.byte $D3,$D4,$D2,$CF,$D9,$C5,$C4,$00
; THE MENACE!
.byte $2,$17
.byte $D4,$C8,$C5,$A0,$CD,$C5,$CE,$C1,$C3,$C5
.byte $A1,$00
; BUT WAIT! SENSORS ARE DETECTING NEW
.byte $0,$14
.byte $C2,$D5,$D4,$A0,$D7,$C1,$C9,$D4,$A1,$A0
.byte $A0,$D3,$C5,$CE,$D3,$CF,$D2,$D3,$A0,$C1
.byte $D2,$C5,$A0,$C4,$C5,$D4,$C5,$C3,$D4,$C9
.byte $CE,$C7,$A0,$CE,$C5,$D7,$00
; INCOMING TARGETS.
.byte $2,$15
.byte $C9,$CE,$C3,$CF,$CD,$C9,$CE,$C7,$A0,$D4
.byte $C1,$D2,$C7,$C5,$D4,$D3,$AE,$00
; REMEMBER, YOU DON'T GET PAID UNTIL ALL
.byte $0,$16
.byte $D2,$C5,$CD,$C5,$CD,$C2,$C5,$D2,$AC,$A0
.byte $D9,$CF,$D5,$A0,$C4,$CF,$CE,$A7,$D4,$A0
.byte $C7,$C5,$D4,$A0,$D0,$C1,$C9,$C4,$A0,$D5
.byte $CE,$D4,$C9,$CC,$A0,$C1,$CC,$CC,$00
; ARE DESTROYED
.byte $2,$17
.byte $C1,$D2,$C5,$A0,$C4,$C5,$D3,$D4,$D2,$CF
.byte $D9,$C5,$C4,$00
susie_lines:
; PS. YOUR PET GUINEA PIG IS DOING FINE
.byte $0,$14
.byte $D0,$D3,$AE,$A0,$A0,$D9,$CF,$D5,$D2,$A0
.byte $D0,$C5,$D4,$A0,$C7,$D5,$C9,$CE,$C5,$C1
.byte $A0,$D0,$C9,$C7,$A0,$C9,$D3,$A0,$C4,$CF
.byte $C9,$CE,$C7,$A0,$C6,$C9,$CE,$C5,$00
tom_sigh:
; TOM: *SIGH*
.byte $0,$14
.byte $D4,$CF,$CD,$BA,$A0,$AA,$D3,$C9,$C7,$C8,$AA,$00
story_lines:
; IT IS THE YEAR 2025.
.byte $0,$14
.byte $C9,$D4,$A0,$C9,$D3,$A0,$D4,$C8,$C5,$A0
.byte $D9,$C5,$C1,$D2,$A0,$B2,$B0,$B2,$B5,$AE,$00
; ALL TELEMARKETERS AND UNSOLICITED
.byte $2,$15
.byte $C1,$CC,$CC,$A0,$D4,$C5,$CC,$C5,$CD,$C1
.byte $D2,$CB,$C5,$D4,$C5,$D2,$D3,$A0,$C1,$CE
.byte $C4,$A0,$D5,$CE,$D3,$CF,$CC,$C9,$C3,$C9
.byte $D4,$C5,$C4,$00
; BULK E-MAILERS HAVE BEEN EXILED
.byte $4,$16
.byte $C2,$D5,$CC,$CB,$A0,$C5,$AD,$CD,$C1,$C9
.byte $CC,$C5,$D2,$D3,$A0,$C8,$C1,$D6,$C5,$A0
.byte $C2,$C5,$C5,$CE,$A0,$C5,$D8,$C9,$CC,$C5
.byte $C4,$00
; TO PHOBOS.
.byte $6,$17
.byte $D4,$CF,$A0,$D0,$C8,$CF,$C2,$CF,$D3,$AE,$00
; RIGHT BEFORE BEING TRAPPED FOREVER
.byte $0,$14
.byte $D2,$C9,$C7,$C8,$D4,$A0,$C2,$C5,$C6,$CF
.byte $D2,$C5,$A0,$C2,$C5,$C9,$CE,$C7,$A0,$D4
.byte $D2,$C1,$D0,$D0,$C5,$C4,$A0,$C6,$CF,$D2
.byte $C5,$D6,$C5,$D2,$00
; THEY MANAGE TO LAUNCH ONE LAST
.byte $2,$15
.byte $D4,$C8,$C5,$D9,$A0,$CD,$C1,$CE,$C1,$C7
.byte $C5,$A0,$D4,$CF,$A0,$CC,$C1,$D5,$CE,$C3
.byte $C8,$A0,$CF,$CE,$C5,$A0,$CC,$C1,$D3,$D4,$00
; MARKETING DROID.
.byte $4,$16
.byte $CD,$C1,$D2,$CB,$C5,$D4,$C9,$CE,$C7,$A0
.byte $C4,$D2,$CF,$C9,$C4,$AE,$00
help_lines:
; TOM BOMBEM
.byte $A,$0
.byte $D4,$CF,$CD,$A0,$C2,$CF,$CD,$C2,$C5,$CD,$00
; BY
.byte $E,$1
.byte $C2,$D9,$00
; VINCE WEAVER
.byte $9,$2
.byte $D6,$C9,$CE,$C3,$C5,$A0,$D7,$C5,$C1,$D6
.byte $C5,$D2,$00
; KEY BINDINGS:
.byte $0,$4
.byte $CB,$C5,$D9,$A0,$C2,$C9,$CE,$C4,$C9,$CE
.byte $C7,$D3,$BA,$00
; UP OR 'I' : MOVE MENU UP
.byte $2,$6
.byte $D5,$D0,$A0,$CF,$D2,$A0,$A7,$C9,$A7,$A0
.byte $A0,$A0,$A0,$BA,$A0,$CD,$CF,$D6,$C5,$A0
.byte $CD,$C5,$CE,$D5,$A0,$D5,$D0,$00
; DOWN OR 'M' : MOVE MENU DOWN
.byte $2,$7
.byte $C4,$CF,$D7,$CE,$A0,$CF,$D2,$A0,$A7,$CD
.byte $A7,$A0,$A0,$BA,$A0,$CD,$CF,$D6,$C5,$A0
.byte $CD,$C5,$CE,$D5,$A0,$C4,$CF,$D7,$CE,$00
; ENTER : SELECTS CURRENT OPTION
.byte $2,$8
.byte $C5,$CE,$D4,$C5,$D2,$00
.byte $F,$8
.byte $BA,$A0,$D3,$C5,$CC,$C5,$C3,$D4,$D3,$A0
.byte $C3,$D5,$D2,$D2,$C5,$CE,$D4,$A0,$CF,$D0
.byte $D4,$C9,$CF,$CE,$00
; RIGHT OR 'K' : MOVES SHIP RIGHT
.byte $2,$A
.byte $D2,$C9,$C7,$C8,$D4,$A0,$CF,$D2,$A0,$A7
.byte $CB,$A7,$A0,$BA,$A0,$CD,$CF,$D6,$C5,$D3
.byte $A0,$D3,$C8,$C9,$D0,$A0,$D2,$C9,$C7,$C8
.byte $D4,$00
; LEFT OR 'J' : MOVES SHIP LEFT
.byte $2,$B
.byte $CC,$C5,$C6,$D4,$A0,$CF,$D2,$A0,$A7,$CA
.byte $A7,$A0,$A0,$BA,$A0,$CD,$CF,$D6,$C5,$D3
.byte $A0,$D3,$C8,$C9,$D0,$A0,$CC,$C5,$C6,$D4,$00
; SPACEBAR : SHOOTS
.byte $2,$C
.byte $D3,$D0,$C1,$C3,$C5,$C2,$C1,$D2,$A0,$A0
.byte $A0,$A0,$A0,$BA,$A0,$D3,$C8,$CF,$CF,$D4
.byte $D3,$00
; 'H' : DISPLAYS HELP
.byte $2,$E
.byte $A7,$C8,$A7,$00
.byte $F,$E
.byte $BA,$A0,$C4,$C9,$D3,$D0,$CC,$C1,$D9,$D3
.byte $A0,$C8,$C5,$CC,$D0,$00
; ESC OR 'Q' : QUITS
.byte $2,$F
.byte $C5,$D3,$C3,$A0,$CF,$D2,$A0,$A7,$D1,$A7
.byte $A0,$A0,$A0,$BA,$A0,$D1,$D5,$C9,$D4,$D3,$00
; 'P' : PAUSES
.byte $2,$10
.byte $A7,$D0,$A7,$00
.byte $F,$10
.byte $BA,$A0,$D0,$C1,$D5,$D3,$C5,$D3,$00
; 'S' : TOGGLES SOUND
.byte $2,$11
.byte $A7,$D3,$A7,$00
.byte $F,$11
.byte $BA,$A0,$D4,$CF,$C7,$C7,$CC,$C5,$D3,$A0
.byte $D3,$CF,$D5,$CE,$C4,$00
; 'C' : ENABLES PADDLES
.byte $2,$12
.byte $A7,$C3,$A7,$00
.byte $F,$12
.byte $BA,$A0,$C5,$CE,$C1,$C2,$CC,$C5,$D3,$A0
.byte $D0,$C1,$C4,$C4,$CC,$C5,$D3,$00
you_are_tom:
; YOU ARE TOM BOMBEM.
.byte $0,$14
.byte $D9,$CF,$D5,$A0,$C1,$D2,$C5,$A0,$D4,$CF
.byte $CD,$A0,$C2,$CF,$CD,$C2,$C5,$CD,$AE,$00
; YOU DREW THE SHORT STRAW
.byte $1,$15
.byte $D9,$CF,$D5,$A0,$C4,$D2,$C5,$D7,$A0,$D4
.byte $C8,$C5,$A0,$D3,$C8,$CF,$D2,$D4,$A0,$D3
.byte $D4,$D2,$C1,$D7,$00
; IT IS UP TO YOU TO DESTROY THE EVIL
.byte $2,$16
.byte $C9,$D4,$A0,$C9,$D3,$A0,$D5,$D0,$A0,$D4
.byte $CF,$A0,$D9,$CF,$D5,$A0,$D4,$CF,$A0,$C4
.byte $C5,$D3,$D4,$D2,$CF,$D9,$A0,$D4,$C8,$C5
.byte $A0,$C5,$D6,$C9,$CC,$00
; AND RESTORE PEACE TO THE SOL SYSTEM.
.byte $3,$17
.byte $C1,$CE,$C4,$A0,$D2,$C5,$D3,$D4,$CF,$D2
.byte $C5,$A0,$D0,$C5,$C1,$C3,$C5,$A0,$D4,$CF
.byte $A0,$D4,$C8,$C5,$A0,$D3,$CF,$CC,$A0,$D3
.byte $D9,$D3,$D4,$C5,$CD,$AE,$00
bonus_string:
; BONUS POINTS
.byte $E,$0
.byte $C2,$CF,$CE,$D5,$D3,$A0,$D0,$CF,$C9,$CE
.byte $D4,$D3,$00
no_bonus_string:
; NONE
.byte $12,$2
.byte $CE,$CF,$CE,$C5,$00
bonus_shields:
; PERFECT SHIELDS +50
.byte $9,$2
.byte $D0,$C5,$D2,$C6,$C5,$C3,$D4,$A0,$D3,$C8
.byte $C9,$C5,$CC,$C4,$D3,$A0,$A0,$A0,$AB,$B5
.byte $B0,$00
bonus_aim:
; PERFECT AIM +50
.byte $9,$3
.byte $D0,$C5,$D2,$C6,$C5,$C3,$D4,$A0,$C1,$C9
.byte $CD,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$AB,$B5
.byte $B0,$00
bonus_kills:
; PERFECT KILLS +50
.byte $9,$4
.byte $D0,$C5,$D2,$C6,$C5,$C3,$D4,$A0,$CB,$C9
.byte $CC,$CC,$D3,$A0,$A0,$A0,$A0,$A0,$AB,$B5
.byte $B0,$00
high_score_string:
; HIGH SCORE
.byte $F,$A
.byte $C8,$C9,$C7,$C8,$A0,$D3,$C3,$CF,$D2,$C5,$00
new_high_score_string:
; NEW HIGH SCORE
.byte $D,$0
.byte $CE,$C5,$D7,$A0,$C8,$C9,$C7,$C8,$A0,$D3
.byte $C3,$CF,$D2,$C5,$00
; USE ARROWS TO ENTER INITIALS
.byte $6,$2
.byte $D5,$D3,$C5,$A0,$C1,$D2,$D2,$CF,$D7,$D3
.byte $A0,$D4,$CF,$A0,$C5,$CE,$D4,$C5,$D2,$A0
.byte $C9,$CE,$C9,$D4,$C9,$C1,$CC,$D3,$00
vmw_sprite:
.byte $71,$14,$72,$14,$72,$00
.byte $71,$14,$72,$14,$72,$00
.byte $10,$51,$34,$52,$34,$52,$00
.byte $10,$51,$34,$52,$34,$52,$00
.byte $20,$31,$54,$32,$54,$32,$00
.byte $20,$31,$54,$32,$54,$32,$00
.byte $30,$11,$74,$12,$74,$12,$00
.byte $30,$11,$74,$12,$74,$12,$00
.byte $00
opener_sprite:
.byte $36,$10,$36,$10,$16,$30,$16,$10,$29,$20,$39,$10,$19,$30,$19,$10,$29,$20,$29,$10,$19,$30,$19,$00
.byte $10,$16,$20,$16,$10,$16,$10,$26,$10,$26,$10,$19,$10,$19,$10,$19,$10,$19,$10,$29,$10,$29,$10,$19,$10,$19,$10,$19,$20,$29,$10,$29,$00
.byte $10,$16,$20,$16,$10,$16,$10,$16,$10,$16,$10,$16,$10,$29,$20,$19,$10,$19,$10,$19,$10,$19,$10,$19,$10,$29,$20,$29,$10,$19,$10,$19,$10,$19,$00
.byte $10,$16,$20,$16,$10,$16,$10,$16,$30,$16,$10,$19,$10,$19,$10,$19,$10,$19,$10,$19,$30,$19,$10,$19,$10,$19,$10,$19,$20,$19,$30,$19,$00
.byte $10,$16,$20,$36,$10,$16,$30,$16,$10,$29,$20,$39,$10,$19,$30,$19,$10,$29,$20,$29,$10,$19,$30,$19,$00
.byte $F0,$F0,$00
.byte $F0,$A0,$1A,$A0,$1A,$00
.byte $30,$1A,$70,$1F,$F0,$40,$15,$00
.byte $F0,$F0,$00
.byte $50,$1A,$A0,$15,$C0,$1F,$00
.byte $00
opener_sprite_2:
.byte $50,$2A,$F0,$1A,$D0,$1E,$00
.byte $10,$1D,$30,$3A,$F0,$E0,$1E,$21,$00
.byte $10,$3D,$16,$8F,$36,$F0,$60,$1E,$29,$00
.byte $2D,$11,$19,$16,$1F,$11,$14,$16,$14,$16,$2F,$46,$F0,$40,$1E,$10,$29,$00
.byte $10,$2D,$19,$16,$1F,$11,$14,$16,$14,$16,$2F,$56,$60,$11,$D0,$29,$00
.byte $30,$1D,$16,$8A,$6F,$40,$1D,$4A,$A0,$29,$00
.byte $F0,$90,$11,$80,$1F,$40,$21,$00
.byte $40,$15,$50,$1A,$F0,$00
.byte $10,$1F,$F0,$1F,$90,$15,$00
.byte $F0,$F0,$80,$1A,$00
.byte $00
vince_sprite:
.byte $20,$15,$8F,$15,$00
.byte $10,$15,$1A,$4F,$1A,$4F,$2A,$00
.byte $15,$5A,$15,$1A,$1F,$2A,$3F,$1A,$00
.byte $1A,$15,$10,$15,$3A,$8F,$15,$00
.byte $1A,$10,$15,$CF,$1A,$00
.byte $15,$10,$1A,$7F,$1A,$1F,$2A,$25,$00
.byte $25,$9F,$25,$10,$15,$1A,$00
.byte $15,$1A,$4F,$1A,$3F,$1A,$10,$15,$10,$15,$1A,$00
.byte $1A,$25,$1A,$1F,$15,$10,$15,$1A,$1F,$1A,$40,$15,$00
.byte $10,$1A,$10,$15,$1F,$20,$15,$10,$15,$1F,$15,$30,$15,$00
.byte $10,$1A,$15,$1A,$1F,$15,$20,$1A,$2F,$1A,$30,$1A,$00
.byte $10,$1F,$15,$3F,$2A,$4F,$30,$1A,$00
.byte $10,$1F,$1A,$25,$1A,$5F,$35,$2A,$00
.byte $10,$2F,$15,$10,$1A,$4F,$1A,$10,$3A,$00
.byte $10,$2F,$1A,$15,$2A,$3F,$1A,$10,$2A,$15,$00
.byte $10,$2A,$10,$15,$20,$2A,$20,$1F,$15,$1A,$00
.byte $10,$15,$2F,$15,$2F,$1A,$20,$15,$2A,$15,$00
.byte $20,$1F,$3A,$1F,$2A,$25,$1F,$1A,$00
.byte $20,$1A,$4F,$25,$10,$15,$1F,$15,$00
.byte $30,$25,$50,$1A,$1F,$15,$00
.byte $00
phobos_sprite:
.byte $F0,$30,$1A,$F0,$00
.byte $F0,$F0,$60,$1F,$00
.byte $F0,$F0,$00
.byte $50,$1A,$4F,$F0,$00
.byte $40,$11,$69,$E0,$1F,$00
.byte $30,$11,$59,$11,$29,$F0,$00
.byte $30,$11,$89,$F0,$00
.byte $30,$11,$39,$11,$49,$50,$15,$18,$F0,$00
.byte $30,$11,$89,$50,$18,$F0,$00
.byte $30,$11,$59,$11,$29,$F0,$40,$1F,$00
.byte $40,$11,$69,$F0,$1A,$00
.byte $50,$1A,$4F,$F0,$00
.byte $F0,$F0,$00
.byte $F0,$F0,$00
.byte $30,$1F,$D0,$1A,$C0,$1A,$00
.byte $00
evil_ship_sprite:
.byte $17,$1E,$17,$00
.byte $00
tom_sprite:
.byte $20,$62,$46,$00
.byte $20,$22,$40,$25,$26,$00
.byte $20,$22,$40,$25,$26,$00
.byte $20,$22,$40,$25,$26,$00
.byte $20,$22,$40,$25,$26,$00
.byte $40,$42,$26,$00
.byte $82,$86,$00
.byte $22,$26,$42,$26,$29,$22,$26,$00
.byte $22,$26,$42,$46,$22,$26,$00
.byte $22,$26,$42,$46,$22,$26,$00
.byte $22,$26,$42,$46,$22,$26,$00
.byte $22,$26,$42,$46,$22,$26,$00
.byte $27,$2E,$22,$26,$22,$26,$27,$2E,$00
.byte $40,$22,$26,$22,$26,$00
.byte $40,$22,$26,$22,$26,$00
.byte $40,$22,$26,$22,$26,$00
.byte $40,$27,$2E,$27,$2E,$00
.byte $40,$25,$2A,$25,$2A,$00
.byte $00
ship_sprite:
.byte $20,$36,$00
.byte $10,$1A,$3F,$1A,$00
.byte $2A,$1F,$1A,$1F,$2A,$00
.byte $30,$1D,$00
.byte $00
missile_sprite:
.byte $1A,$00
.byte $1A,$00
.byte $1D,$00
.byte $00
enemy_sprites:
enemy_sprite0:
.byte $2F,$11,$00
.byte $3F,$00
.byte $00,$00,$00
enemy_sprite1:
.byte $16,$10,$16,$00
.byte $10,$16,$00
.byte $00
enemy_sprite2:
.byte $17,$28,$00
.byte $17,$28,$00
.byte $00,$00
enemy_sprite3:
.byte $10,$1D,$00
.byte $1D,$10,$1D,$00
.byte $00
enemy_sprite4:
.byte $19,$2F,$00
.byte $19,$2A,$00
.byte $00,$00
enemy_sprite5:
.byte $14,$1C,$14,$00
.byte $34,$00
; .byte $14,$1C,$14,$00
.byte $00,$00
enemy_sprite6:
.byte $1F,$20,$00
.byte $3C,$00
.byte $00,$00,$00
enemy_sprite7:
.byte $33,$00
.byte $13,$10,$13,$00
.byte $00,$00
explosion_sprites:
explosion_sprite0:
.byte $2D,$19,$00
.byte $19,$1D,$15,$00
.byte $00
explosion_sprite1:
.byte $2A,$11,$00
.byte $11,$1A,$00
.byte $00,$00
explosion_sprite2:
.byte $25,$00
.byte $10,$25,$00
.byte $00
smoke_sprites:
smoke_sprite0:
.byte $10,$15,$00
.byte $00
smoke_sprite1:
.byte $25,$1A,$00
.byte $00
smoke_sprite2:
.byte $2A,$11,$00
.byte $00
boss_sprite:
.byte $1F,$1A,$11,$79,$11,$1A,$1F,$00
.byte $1F,$15,$1A,$21,$17,$1E,$17,$21,$1A,$15,$1F,$00
.byte $1F,$10,$15,$1A,$17,$1E,$1D,$1E,$17,$1A,$15,$10,$1F,$00
.byte $00
laser_sprites:
laser_sprite0:
.byte $1B,$00
.byte $13,$00
.byte $00
laser_sprite1:
.byte $13,$00
.byte $1B,$00
.byte $00
tom_head_sprite:
.byte $10,$32,$26,$00
.byte $10,$12,$20,$15,$16,$00
.byte $10,$12,$20,$15,$16,$00
.byte $10,$12,$20,$15,$16,$00
.byte $10,$12,$20,$15,$16,$00
.byte $20,$22,$16,$00
.byte $42,$36,$00
.byte $00
earth_sprite:
.byte $10,$1A,$2F,$00
.byte $14,$2C,$26,$00
.byte $12,$1C,$36,$00
.byte $12,$16,$2C,$16,$00
.byte $12,$16,$1C,$26,$00
.byte $10,$1A,$2F,$00
.byte $00
susie_sprite:
.byte $BA,$15,$10,$2F,$10,$3A,$00
.byte $2A,$90,$15,$20,$15,$20,$2A,$00
.byte $1A,$F0,$20,$1A,$00
.byte $1A,$F0,$20,$1A,$00
.byte $1A,$F0,$3A,$00
.byte $2A,$C0,$5A,$00
.byte $4A,$35,$5A,$35,$4A,$00