mirror of
https://github.com/deater/tb1.git
synced 2024-12-22 13:29:48 +00:00
2650 lines
40 KiB
ArmAsm
2650 lines
40 KiB
ArmAsm
; Level 1
|
|
|
|
;; Memory areas
|
|
extra_sprite = $600
|
|
|
|
;; GAME PARAMETERS
|
|
NUM_MISSILES = 2
|
|
NUM_ENEMIES = 6
|
|
UP_SHIELDS = 32
|
|
WAVE_SIZE = 16
|
|
WAVES_TILL_BOSS = 5
|
|
|
|
;; BONUS_FLAGS
|
|
PERFECT_SHIELDS = $80
|
|
PERFECT_KILLS = $40
|
|
PERFECT_AIM = $1
|
|
|
|
|
|
; Page zero locations
|
|
shipx = $02
|
|
star_scroll = $03
|
|
star_scroll_h = $04 ; 0004 too, 16-bit
|
|
RANDOM_SEED = $05
|
|
YSAV = $06
|
|
YSAV_H = $07
|
|
|
|
joypad1_raw = $08
|
|
joypad1_raw_h = $09
|
|
joypad1_pressed = $0a
|
|
joypad1_pressed_h = $0b
|
|
joypad1_held = $0c
|
|
joypad1_held_h = $0d
|
|
|
|
sprite_l = $10
|
|
sprite_h = $11
|
|
|
|
SPRITE_HIGH_LOOKUP = $20
|
|
SHL2 = $21
|
|
SHL3 = $22
|
|
SHL4 = $23
|
|
|
|
HISCORE_1 = $cb
|
|
HISCORE_2 = $cc
|
|
HISCORE_3 = $cd
|
|
HISCORE_H = $ce
|
|
HISCORE_L = $cf
|
|
|
|
BOSS_X = $d0
|
|
BOSS_XADD = $d1
|
|
BOSS_COUNT = $d2
|
|
BOSS_SMOKE = $d3
|
|
BOSS_EXPLODING = $d4
|
|
BOSS_WAITING = $d5
|
|
BOSS_HITS = $d6
|
|
BOSS_SHOOTING = $d7
|
|
ENEMIES_SPAWNED = $d8
|
|
ENEMY_TYPE = $d9
|
|
ENEMY_WAVE = $da
|
|
CURRENT_INIT_X = $db
|
|
CURRENT_ENEMY_KIND = $dc
|
|
TOTAL_ENEMIES_OUT = $dd
|
|
SCROLL = $de
|
|
SOUND_ON = $df
|
|
|
|
SHIPXADD = $e1
|
|
ENEMY_PL = $e2
|
|
ENEMY_PH = $e3
|
|
MISSILE_PL = $e4
|
|
MISSILE_PH = $e5
|
|
GR_PAGE = $e6
|
|
LEVEL = $e7
|
|
SHIELDS = $e8
|
|
SCOREL = $e9
|
|
SCOREH = $ea
|
|
BONUS_FLAGS = $eb
|
|
BCD_BYTEH = $ec
|
|
BCD_BYTE = $ed
|
|
|
|
COL_X1 = $ec
|
|
COL_X2 = $ed
|
|
COL_X3 = $ee
|
|
COL_X4 = $ef
|
|
|
|
ENEMY_EXPLODING = $f0
|
|
ENEMY_KIND = $f1
|
|
ENEMY_X = $f2
|
|
ENEMY_Y = $f3
|
|
ENEMY_XADD = $f4
|
|
ENEMY_YADD = $f5
|
|
ENEMY_XMIN = $f6
|
|
ENEMY_XMAX = $f7
|
|
|
|
BETWEEN_DELAY = $f8
|
|
ENEMY_WAIT = $f9
|
|
|
|
STRINGL = $fa
|
|
STRINGH = $fb
|
|
PARAM2 = $fc
|
|
RESULT = $fd
|
|
LASTKEY = $fe
|
|
TEMP = $ff
|
|
|
|
|
|
.setcpu "65816"
|
|
|
|
.segment "STARTUP"
|
|
|
|
;================================================
|
|
; LEVEL 1
|
|
;================================================
|
|
|
|
level_1:
|
|
|
|
sep #$20 ; mem/A = 8 bit
|
|
.a8
|
|
rep #$10 ; X/Y = 16 bit
|
|
.i16
|
|
|
|
;==========================
|
|
; Setup Background
|
|
;==========================
|
|
|
|
; we want the BG1 Tilemap to start at VRAM $f000
|
|
; Format is
|
|
; aaaa aass a is shifted by 10 for address
|
|
; ss = size of screen in tiles 00 = 32x32
|
|
;
|
|
; 0111 1000
|
|
|
|
lda #$78 ; BG1 Tilemap starts at VRAM $f000/2
|
|
sta $2107 ; bg1 src
|
|
|
|
; we want the BG2 Tilemap to start at VRAM $d000
|
|
; Format is
|
|
; aaaa aass a is shifted by 10 for address
|
|
; ss = size of screen in tiles 10 = 32x64
|
|
;
|
|
; 0110 1010
|
|
|
|
lda #$6a ; BG2 Tilemap starts at VRAM $d000/2
|
|
sta $2108 ; bg2 src
|
|
|
|
|
|
; aaaa bbbb a= BG2 tiles, b= BG1 tiles
|
|
; bbbb<<13
|
|
; 0000 0000
|
|
; our BG1 tiles are stored starting in VRAM $0000
|
|
|
|
lda #$32 ; bg2 tile data starts at VRAM 5000/2
|
|
sta $210b ; bg1 tile data starts at VRAM 4000/2
|
|
|
|
|
|
;===============================
|
|
; Load Level1 Background Palette
|
|
;===============================
|
|
stz $2121 ; start with color 0
|
|
ldy #(16*2) ; we have 16 colors
|
|
lda #^level1_background_palette
|
|
ldx #.LOWORD(level1_background_palette)
|
|
jsr svmw_load_palette
|
|
|
|
;======================
|
|
; Load Level1 Tile Data
|
|
;======================
|
|
ldx #$2000 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
; multiply by 2, so 0x4000
|
|
|
|
lda #^level1_background_tile_data
|
|
ldx #.LOWORD(level1_background_tile_data)
|
|
ldy #1824 ; Copy 57 tiles, which are 32 bytes each
|
|
; 8x8 tile with 4bpp
|
|
; (57*32) = 1824 = ????
|
|
|
|
jsr svmw_load_vram
|
|
|
|
;===================================
|
|
; Load Level1 Tile Map
|
|
;===================================
|
|
ldx #$7800 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
; multiply by 2, so 0xe000
|
|
|
|
lda #^level1_background_tilemap
|
|
ldx #.LOWORD(level1_background_tilemap)
|
|
ldy #$0700 ; 32x28 = 896 * 2 = 0x700
|
|
jsr svmw_load_vram
|
|
|
|
|
|
|
|
|
|
;===============================
|
|
; Load Level1 Star Palette
|
|
;===============================
|
|
lda #16
|
|
sta $2121 ; start with color 16
|
|
ldy #(16*2) ; we have 16 colors
|
|
lda #^star_background_palette
|
|
ldx #.LOWORD(star_background_palette)
|
|
jsr svmw_load_palette
|
|
|
|
;======================
|
|
; Load Level1 Star Data
|
|
;======================
|
|
ldx #$3000 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
; multiply by 2, so 0x4000
|
|
|
|
lda #^star_background_tile_data
|
|
ldx #.LOWORD(star_background_tile_data)
|
|
ldy #$4420 ; Copy 545 tiles, which are 32 bytes each
|
|
; 8x8 tile with 4bpp
|
|
; (545*32) = 17,440 = 0x4420
|
|
|
|
jsr svmw_load_vram
|
|
|
|
;===================================
|
|
; Load Level1 Star Tile Map
|
|
;===================================
|
|
ldx #$6800 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
; multiply by 2, so 0xd000
|
|
|
|
lda #^star_background_tilemap
|
|
ldx #.LOWORD(star_background_tilemap)
|
|
ldy #$1000 ; 32x64 = 2048 * 2 = 0x1000
|
|
jsr svmw_load_vram
|
|
|
|
|
|
|
|
;==========================
|
|
; Setup Sprites
|
|
;==========================
|
|
|
|
; Load Palette for our sprite
|
|
|
|
; Sprite Palettes start at color 128
|
|
|
|
; Load palette 0
|
|
|
|
lda #128 ; start with color 128
|
|
sta $2121 ;
|
|
ldy #(16*2) ; we have 16 colors
|
|
lda #^level1_pal0_palette
|
|
ldx #.LOWORD(level1_pal0_palette)
|
|
jsr svmw_load_palette
|
|
|
|
; Load palette 2
|
|
|
|
lda #160 ; start with color 128
|
|
sta $2121 ;
|
|
ldy #(16*2) ; we have 16 colors
|
|
lda #^level1_pal2_palette
|
|
ldx #.LOWORD(level1_pal2_palette)
|
|
jsr svmw_load_palette
|
|
|
|
|
|
;=========================
|
|
; Load sprite data to VRAM
|
|
;=========================
|
|
|
|
lda #$80 ; increment after writing $2119
|
|
sta $2115
|
|
|
|
; Pal0 Sprites
|
|
|
|
ldx #$0000 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
; multiply by 2, so 0x0000
|
|
|
|
lda #^level1_pal0_data
|
|
ldx #.LOWORD(level1_pal0_data)
|
|
ldy #$0800 ; 32 bytes * 64 tiles
|
|
|
|
jsr svmw_load_vram
|
|
|
|
; Pal2 Sprites
|
|
|
|
; 0x0000 + 32*0x60 / 2 = 0x600
|
|
ldx #$0600 ;
|
|
stx $2116 ; set adddress for VRAM read/write
|
|
|
|
lda #^level1_pal2_data
|
|
ldx #.LOWORD(level1_pal2_data)
|
|
ldy #$0400 ; 32 bytes * 32 tiles
|
|
|
|
jsr svmw_load_vram
|
|
|
|
|
|
;=============================
|
|
; Init sprites to be offscreen
|
|
|
|
jsr svmw_move_sprites_offscreen
|
|
|
|
;=============================
|
|
; Set our sprite active
|
|
; assume 544 byte sprite table in $0200
|
|
|
|
sep #$20 ; mem/A = 8 bit
|
|
.a8
|
|
|
|
;==================
|
|
; setup ship sprite
|
|
|
|
; Xxxxxxxxx yyyyyyy cccccccc vhoo pppN
|
|
;
|
|
|
|
lda #104 ; set shipx to 104
|
|
sta $0200 ;
|
|
|
|
lda #192 ; set shipy to 192
|
|
sta $0201
|
|
|
|
stz $0202 ; set ship sprite to 0
|
|
|
|
lda #$20 ; no flip, priority 2, N=0 palette=0 ($20)
|
|
sta $0203
|
|
|
|
; X high bit = 0 for sprite 0
|
|
; sprite size = 1 (larger)
|
|
lda #%01010110
|
|
sta $0400
|
|
|
|
;=====================================
|
|
; set sprites 8,9,10,11 to be missiles
|
|
|
|
lda #12 ; sprite location 13
|
|
sta $0202 + 4*8
|
|
sta $0202 + 4*9
|
|
sta $0202 + 4*10
|
|
sta $0202 + 4*11
|
|
|
|
lda #$20 ; pal=0, priority=2, flip=none
|
|
sta $0203 + 4*8
|
|
sta $0203 + 4*9
|
|
sta $0203 + 4*10
|
|
sta $0203 + 4*11
|
|
|
|
|
|
;=========================
|
|
;=========================
|
|
; Enable sprites
|
|
;=========================
|
|
;=========================
|
|
; sssnnbbb
|
|
; sss = size (011 = 16x16 and 32x32)
|
|
; nn = name
|
|
; bbb = base selection
|
|
lda #%01100000
|
|
sta $2101
|
|
|
|
jsr svmw_transfer_sprite
|
|
|
|
|
|
;======================
|
|
; Setup the Video Modes
|
|
;======================
|
|
level1_setup_video:
|
|
|
|
sep #$20 ; mem/A = 8 bit
|
|
.a8
|
|
rep #$10 ; X/Y = 16 bit
|
|
.i16
|
|
|
|
lda #$01 ; 8x8 tiles, Mode 1
|
|
sta $2105
|
|
|
|
lda #$13 ; Enable BG1,BG2, and sprites
|
|
sta $212c
|
|
|
|
stz $212d ; disable subscreen
|
|
|
|
|
|
|
|
lda #$00 ; Disable NMI (VBlank Interrupt) and joypads
|
|
sta $4200 ;
|
|
|
|
;==========================
|
|
; Setup VBLANK routine
|
|
;==========================
|
|
|
|
ldx #level1_vblank
|
|
stx vblank_vector
|
|
|
|
lda #$81 ; Enable NMI (VBlank Interrupt) and joypads
|
|
sta $4200 ;
|
|
|
|
jsr svmw_fade_in
|
|
|
|
|
|
;===========================
|
|
; init lookup tables
|
|
;===========================
|
|
|
|
lda #$01
|
|
sta SPRITE_HIGH_LOOKUP
|
|
lda #$04
|
|
sta SHL2
|
|
lda #$10
|
|
sta SHL3
|
|
lda #$40
|
|
sta SHL4
|
|
|
|
;====================
|
|
; setup the high score
|
|
;=====================
|
|
|
|
lda #$01
|
|
sta HISCORE_H
|
|
lda #$00
|
|
sta HISCORE_L
|
|
|
|
; modestly make me the high scorer
|
|
lda #'V'
|
|
sta HISCORE_1
|
|
lda #'M'
|
|
sta HISCORE_2
|
|
lda #'W'
|
|
sta HISCORE_3
|
|
|
|
|
|
;==========================================================
|
|
; START NEW GAME
|
|
;==========================================================
|
|
|
|
|
|
do_new_game:
|
|
|
|
;; Clear BSS
|
|
|
|
; ldx #$0
|
|
;clear_bss:
|
|
; stz start_bss,X
|
|
; inx
|
|
; cpx #end_bss-start_bss
|
|
; bne clear_bss
|
|
|
|
;; Init one-time vars
|
|
|
|
stz star_scroll
|
|
stz star_scroll_h
|
|
|
|
lda #$8
|
|
sta SHIELDS ; shields start at 8
|
|
; jsr update_shields
|
|
|
|
lda #104
|
|
sta shipx ; shipx at start is 104
|
|
|
|
lda #$1
|
|
sta LEVEL ; start at level 1
|
|
|
|
stz SCOREL
|
|
stz 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 ; ???
|
|
|
|
stz BETWEEN_DELAY
|
|
stz SHIPXADD ; clear shipxadd
|
|
stz ENEMY_WAVE
|
|
stz TOTAL_ENEMIES_OUT
|
|
stz ENEMIES_SPAWNED
|
|
stz ENEMY_TYPE
|
|
|
|
;======================
|
|
; 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
|
|
|
|
|
|
;/========================\
|
|
;+ +
|
|
;+ MAIN LEVEL1 LOOP +
|
|
;+ +
|
|
;\========================/
|
|
.a8
|
|
.i16
|
|
|
|
level1_loop:
|
|
|
|
wai ; wait for interrupt
|
|
|
|
; ================================
|
|
; 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 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 #$80 ; point to enemies[0] $20 * 4
|
|
find_empty_enemy:
|
|
jsr is_sprite_active
|
|
bcc add_enemy
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
cpy #($80+4*NUM_ENEMIES)
|
|
bne find_empty_enemy
|
|
|
|
jmp move_enemies ; no empty, slots, move on
|
|
|
|
add_enemy:
|
|
|
|
;==============================================
|
|
; 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
|
|
;===============
|
|
|
|
; 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
|
|
|
|
jsr activate_sprite ; enemy[i].out=1
|
|
|
|
; lda #$0
|
|
; iny ; exploding
|
|
; sta (ENEMY_PL),Y ; enemy[i].exploding=0
|
|
|
|
lda CURRENT_ENEMY_KIND ; if kind <0 then random
|
|
bpl store_enemy_kind
|
|
|
|
jsr random_number
|
|
and #$8
|
|
|
|
store_enemy_kind:
|
|
|
|
; Xxxxxxxxx yyyyyyy cccccccc vhoo pppN
|
|
|
|
clc
|
|
adc #$60 ; Use pal2 enemies for now
|
|
|
|
pha ; store type for later
|
|
|
|
; Y = $20+enemies
|
|
|
|
; want to store to $200 + (Y*4)
|
|
|
|
tyx ; copy Y to X
|
|
|
|
; 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:
|
|
|
|
sta $200,Y ; store x value at $200+(Y*4)
|
|
|
|
; enemy_y is always 0 by default
|
|
lda #$0
|
|
sta $201,Y ; store y value at $201+(Y*4)
|
|
|
|
|
|
pla ; pull enemy type off stack
|
|
|
|
sta $202,Y ; store SPRITE value to $202+(Y*4)
|
|
|
|
lda #$24 ; noflip, pal2, priority=2
|
|
sta $203,Y ; store paramaters to $203+(Y*4)
|
|
|
|
lda #$0
|
|
sta extra_sprite,Y ; xadd
|
|
sta extra_sprite+1,Y ; yadd
|
|
|
|
lda #2
|
|
sta extra_sprite+2,Y ; xmin
|
|
lda #100
|
|
sta extra_sprite+3,Y ; xmax
|
|
|
|
|
|
;===========================================
|
|
; 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 extra_sprite,Y
|
|
|
|
lsr A
|
|
ora #$1
|
|
sta extra_sprite+1,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 #$80 ; point to enemies[0] (4*$20)
|
|
handle_enemies:
|
|
|
|
jsr is_sprite_active ; set if enemy[y].out
|
|
bcs 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:
|
|
|
|
|
|
lda extra_sprite,Y
|
|
sta ENEMY_XADD
|
|
lda extra_sprite+1,Y
|
|
sta ENEMY_YADD
|
|
lda extra_sprite+2,Y
|
|
sta ENEMY_XMIN
|
|
lda extra_sprite+3,Y
|
|
sta ENEMY_XMAX
|
|
|
|
lda $200,Y
|
|
sta ENEMY_X
|
|
lda $201,Y
|
|
sta ENEMY_Y
|
|
|
|
; 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 #50 ; is y<=12?
|
|
bmi done_enemy_y ; if so no need to do anything
|
|
beq done_enemy_y
|
|
|
|
; off screen
|
|
|
|
jsr deactivate_sprite ; 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
|
|
|
|
lda ENEMY_XADD
|
|
sta extra_sprite,Y
|
|
|
|
lda ENEMY_YADD
|
|
sta extra_sprite+1,Y
|
|
|
|
lda ENEMY_XMIN
|
|
sta extra_sprite+2,Y
|
|
|
|
lda ENEMY_XMAX
|
|
sta extra_sprite+3,Y
|
|
|
|
lda ENEMY_X
|
|
sta $200,Y
|
|
|
|
lda ENEMY_Y
|
|
sta $201,Y
|
|
|
|
|
|
; 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
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #($80+4*NUM_ENEMIES) ; 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:
|
|
|
|
;====================
|
|
; Move Missiles
|
|
;====================
|
|
; Missiles are 8,9,10,11 in sprite table
|
|
|
|
|
|
ldy #$20 ; point to missile[0] (8*4)
|
|
move_missiles:
|
|
jsr is_sprite_active
|
|
bcc loop_move_missiles ; if not active, skip
|
|
|
|
; phy
|
|
; tya
|
|
; asl
|
|
; asl
|
|
; tay
|
|
|
|
lda $0201,Y
|
|
dea
|
|
sta $0201,Y
|
|
|
|
; ply
|
|
|
|
cmp #200
|
|
|
|
; bge
|
|
bcc missile_collision_detection ; if not off screen, contine
|
|
|
|
jsr deactivate_sprite
|
|
|
|
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
|
|
iny
|
|
iny
|
|
cpy #($20+4*NUM_MISSILES) ; have we checked all missiles?
|
|
bne move_missiles ; if not, loop
|
|
|
|
done_move_missiles:
|
|
|
|
;===============================
|
|
; handle joypad input
|
|
;===============================
|
|
|
|
game_read_keyboard:
|
|
ldx joypad1_pressed
|
|
bne key_start
|
|
jmp move_ship ; if no keypressed, move the ship
|
|
|
|
key_start:
|
|
lda joypad1_pressed_h
|
|
bit #$10 ; start button
|
|
beq key_left
|
|
|
|
; pause game
|
|
; ask for resume/save/toggle_sound/help/quit
|
|
|
|
key_left:
|
|
bit #$02
|
|
beq key_right
|
|
|
|
lda SHIPXADD ; load xadd
|
|
beq game_l_sub
|
|
bpl game_l_0 ; is switch dir, then 0 it
|
|
game_l_sub:
|
|
dec SHIPXADD ; else, dec XADD
|
|
jmp move_ship
|
|
game_l_0:
|
|
lda #$0
|
|
sta SHIPXADD
|
|
jmp move_ship
|
|
|
|
key_right:
|
|
bit #$01
|
|
beq key_A
|
|
|
|
lda SHIPXADD ; load xadd
|
|
bmi game_l_0 ; if we are switching dirs, set to zero
|
|
inc SHIPXADD ; else xadd++
|
|
jmp move_ship
|
|
|
|
key_A:
|
|
lda joypad1_pressed
|
|
bit #$80
|
|
beq game_unknown
|
|
|
|
ldy #$20 ; point to missile[y] (8*4)
|
|
fire_missiles:
|
|
jsr is_sprite_active
|
|
bcs end_fire_loop ; if active, skip to next
|
|
|
|
; phy
|
|
; tya
|
|
; asl
|
|
; asl
|
|
; tay
|
|
|
|
lda #8
|
|
clc
|
|
adc shipx ; missile[y].x=shipx+8
|
|
sta $0200,Y ; $220 + 4*(Y-8)
|
|
|
|
lda #190 ; set to 190
|
|
sta $0201,Y
|
|
|
|
|
|
; ply
|
|
jsr activate_sprite
|
|
|
|
bra done_fire_missiles ; done firing missile
|
|
|
|
end_fire_loop:
|
|
iny ; point to next missile
|
|
iny
|
|
iny
|
|
iny
|
|
|
|
cpy #($20+4*NUM_MISSILES) ; 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
|
|
bra update_shields2 ; go to blit
|
|
|
|
check_x_over:
|
|
cmp #$70 ; are we over 33?
|
|
bmi update_shields2 ; if not, blit ship
|
|
lda #$0 ; shipxadd=0
|
|
sta SHIPXADD
|
|
lda #$70 ; shipx=33
|
|
sta shipx
|
|
|
|
; Update shields
|
|
update_shields2:
|
|
|
|
; 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
|
|
|
|
; 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
|
|
|
|
|
|
;========================
|
|
; scroll background
|
|
;========================
|
|
|
|
lda star_scroll
|
|
sta $2110
|
|
lda star_scroll_h
|
|
sta $2110
|
|
|
|
rep #$20 ; A/mem=16 bit
|
|
.a16
|
|
dec star_scroll
|
|
sep #$20 ; A/mem=8 bit
|
|
.a8
|
|
|
|
|
|
;========================
|
|
; update OAM
|
|
;========================
|
|
|
|
lda shipx
|
|
sta $0200 ; set sprite 0 X to shipx
|
|
|
|
|
|
jmp level1_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
|
|
|
|
|
|
|
|
;=============================
|
|
; Level 1 VBLank Routine
|
|
;=============================
|
|
|
|
level1_vblank:
|
|
php ; save status register
|
|
rep #$30 ; Set A/mem=16 bits, X/Y=16 bits (to push all 16 bits)
|
|
.a16 ; tell assembler the A is 16-bits
|
|
.i16
|
|
phb ; save b
|
|
pha ; save A
|
|
phx ; save X
|
|
phy ; save Y
|
|
phd ; save zero page
|
|
|
|
sep #$20 ; A/mem=8 bit
|
|
.a8
|
|
|
|
joypad_read:
|
|
lda $4212 ; get joypad status
|
|
and #$01 ; if joy is not ready
|
|
bne joypad_read ; wait
|
|
|
|
rep #$20 ; A 16-bit
|
|
.a16
|
|
|
|
ldx joypad1_raw ; load previous raw value
|
|
|
|
lda $4218 ; load 2 bytes of joypad status
|
|
sta joypad1_raw ; save new raw value
|
|
|
|
txa ; transfer old raw into A
|
|
|
|
eor joypad1_raw ; set the bits that have changed
|
|
|
|
and joypad1_raw ; set the bits just pressed
|
|
|
|
sta joypad1_pressed ; store the pressed value
|
|
txa ; transfer back prev value
|
|
and joypad1_raw ; find buttons being held
|
|
sta joypad1_held ; store held down buttons
|
|
|
|
sep #$20 ; A=8bit
|
|
.a8
|
|
|
|
|
|
done_joypad:
|
|
|
|
;=======================================
|
|
; Update the sprite info structure (OAM)
|
|
;=======================================
|
|
|
|
jsr svmw_transfer_sprite
|
|
|
|
done_vblank:
|
|
|
|
lda $4210 ; Clear NMI flag
|
|
|
|
rep #$30 ; A/Mem=16 bits, X/Y=16 bits
|
|
.a16
|
|
.i16
|
|
pld ; restore saved vaules from stack
|
|
ply
|
|
plx
|
|
pla
|
|
plb
|
|
|
|
plp
|
|
rti ; return from interrupt
|
|
|
|
|
|
|
|
;==========================================================
|
|
; "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
|
|
.a8
|
|
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
|
|
|
|
|
|
;==========================================================
|
|
; 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
|
|
|
|
|
|
|
|
;==========================================================
|
|
; 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
|
|
|
|
;==========================================================
|
|
; 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
|
|
|
|
|
|
|
|
|
|
;; *********************
|
|
;; BSS
|
|
;; *********************
|
|
.bss
|
|
|
|
;start_bss:
|
|
;extra_sprite: .res 256
|
|
;end_bss:
|
|
|
|
|
|
;============================================================================
|
|
; Sprite/Tile Data
|
|
;============================================================================
|
|
|
|
.segment "HIGHROM"
|
|
|
|
; sprite data
|
|
.include "level1_pal0.sprites"
|
|
.include "level1_pal2.sprites"
|
|
.include "level1_background.tiles"
|
|
.include "star_background.tiles"
|
|
|
|
|
|
|
|
|
|
|