	.include	'eq.s'
	.include	'externs.s'

	.text
start::
	move.l	#$00004000,a7
	bsr		initonce				;initialize everything
	jsr		init_snd				;load DSP code, start it running

restart::
	move.l	#$00004000,a7
	jsr		sndoff				;turn off sounds
	jsr		gotitle				;go to title screen

mainloop::
	clr.w	d0
	move.b	gamemode,d0			;get current game mode
	lsl.w	#2,d0				;4 bytes per game mode
	lea		looptable,a0			;list of loop addresses
	move.l	(a0,d0.w),a1
	jsr		(a1)					;do one of the loops
	bsr		random				;change the seed values
	bsr		wait_int				;wait for vertical interrupt before continuing
	bra.b	mainloop


gameloop::
	bsr		set_background			;set up background tiles

	tst.b	pause_flag			;see if pause_flag is 0 (not paused)
	bne		.60					;skip following stuff if paused

	jsr		chk_voices			;set voicestatus table

	bsr		anim_plr				;player animation
	bsr		anim_explosions		;explosions for enemies and player

	bsr		shot_collisions		;player shots with enemies
	bsr		bomb_collisions		;bombs with enemies
	bsr		spec_collisions		;special weapons with enemies
	bsr		plr_collisions			;player with enemies, shots, powerup
	bsr		c_sh_col				;cutter shots with enemies

	bsr		move_pwrup			;powerup
	bsr		move_shots			;move player bullets
	bsr		move_bomb				;move player bomb
	bsr		move_spec				;move special weapon

	bsr		move_en_shots			;move enemy shots
	move.l	#$FFFFFFFF,BORD1
	bsr		move_en				;move enemies
	move.l	#0,BORD1
	bsr		mv_stat				;animate and move station if visible

	bsr		grnd_obj				;create ground enemies or objects if necessary
	bsr		mk_form				;make formation if necessary
	bsr		create_en				;create new enemies
	bsr		get_en_distance		;get horiz and vert distances from player, set direction if necessary

	bsr		anim_enemies			;enemy animation
	bsr		adjbspos				;adjust positions of boss enemies with multiple parts

	bsr		an_en_shots			;enemy shot animation

	bsr		mv_cutr				;move cutter's ship
	bsr		mv_cutsh				;move cutter's shots
	bsr		cutinput				;make cutter move and fire if necessary

	tst.b	gameover
	bne.b	.60					;if game has ended, don't scroll

	bsr		scrolling				;scroll background tiles
	bsr		mk_front				;make new foreground object if necessary
	bsr		mv_front				;move foreground objects

.60:
	bsr		conv_score			;convert hex to decimal digits

	tst.b	pause_flag			;see if pause_flag is 0 (not paused)
	bne.b	.70					;don't need to redraw info if paused
	bsr		draw_info				;make icon bar, score bar objects
	bsr		run_counters			;color cycling, delays, etc
.70:
	move.l	#gameobjs,FIRSTOBJ_ADR	;address of first object header
	move.l	#GAME_OBJS,TOTOBJS_ADR	;total objects in list
	bsr		do_build				;build packed object list

	bsr		input				;check the controller
	bsr		gameinput				;process the results of input
	tst.b	levflag				;see if level should change
	beq.b	.80					;if level should not change, exit
	jsr		sndoff				;turn off sounds
	move.w	level,d0				;if level should change, see if this is the last level
	cmp.w	#FINAL_LEVEL,d0
	bne		.72					;if you completed the last level, congratulations!
	jmp		go_cong
.72:
	cmp.w	#FINAL_LEVEL,d0
	bge		.75					;if bonus level was just played
	and.w	#1,d0				;see if level number is even or odd
	bne.b	.75					;if odd, you just completed a planet level
	addq.w	#1,level				;if even, go from space to planet
	jmp		go_intro				;display intro, initialize new level
.75:
	add.b	#1,lvlsdone
	move.w	level,d0				;get current level number
	lsr.w	#1,d0				;there is one flag for every 2 levels
	lea		finished,a0			;which worlds have been completed
	move.b	#1,(a0,d0.w)			;set the flag for a completed world
	jmp		goselect				;go to level selection screen
.80:	rts

clearscr::						;cover screen with black, wait until it is displayed
	cmp.w	#FLASH,specweap+O_DESC
	beq.b	.20
	move.w	#FLASH,specweap+O_DESC
	bsr		draw_flsh				;make sure flash data in in ram before using it
.20:
	move.l	#scrcover,FIRSTOBJ_ADR	;address of first object header
	move.l	#1,TOTOBJS_ADR			;total objects in list
	bsr		do_build				;build packed object list
	bsr		wait_int
	rts

scrolling::
	cmp.b	#2,levstatus			;2 if scrolling after end of level
	bne.b	.10
	cmp.w	#END_LEVEL_DELAY,endlvdel	;there is a delay after the boss is destroyed
	beq.b	.05
	add.w	#1,endlvdel			;increase delay counter
	rts
.05:	addq.w	#1,scrlspd			;if levstatus is 2, speed up scrolling
	cmp.w	#MAX_SCROLLSPD,scrlspd
	blt.b	.10
	move.w	#MAX_SCROLLSPD,scrlspd	;set maximum scrolling speed
.10:	move.w	odomend,d1			;limit for odomback
	move.w	odomback,d0			;current odometer reading
	add.w	scrlspd,d0			;add background scrolling speed
	cmp.w	d1,d0				;compare end to current odometer
	bcs.b	.40					;branch if end > current
;at this point, the odometer has reached its limit
	cmp.b	#0,levstatus			;playing the level
	beq.b	.20					;if odometer reached the first end point, set the second end point
	cmp.b	#1,levstatus			;already stopped at first stop position
	beq.b	.60					;if scrolling has stopped, exit
	cmp.b	#2,levstatus			;scrolling fast to get to second end point
	bne.b	.20
	move.b	#1,levflag			;change level at end of loop
	rts
.20:	move.b	#1,levstatus			;now at first stop point
	lea		od_end1,a0			;list of the first end points
	lea		od_end2,a1			;list of the end points after level is completed
	move.w	level,d0				;get current level
	lsl.w	#1,d0				;level * 2
	move.w	(a0,d0.w),odomback		;set stopped odometer position
	move.w	(a1,d0.w),odomend		;get new odometer end
	clr.w	scrlspd				;0 speed until enemies are gone
	clr.w	scrlspdf				;stop foreground scrolling
	rts
.40:	move.w	d0,odomback			;update new odometer reading
	move.w	odomfrnt,d0
	add.w	scrlspdf,d0			;update foreground odometer
	cmp.w	#MAX_ODOM_FRONT,d0
	bcs.b	.50
	move.w	#MAX_ODOM_FRONT,d0
.50:	move.w	d0,odomfrnt
.60:	rts

initgame::
;stuff done at the start of a game
	move.b	#0,lvlsdone
	move.b	#STARTING_LIVES,lives	;default number of lives
	move.l	#0,score				;erase score
	clr.b	score_dec+6			;make sure last digit is 0
	moveq.l	#MAX_SPEC_WEAPONS-1,d0
	lea		spec_tot,a0
.10:	clr.w	(a0)+				;erase supply of each special weapon
	dbra		d0,.10

	moveq.l	#TOTAL_WORLDS-1,d0		;6 worlds, 1 final level
	lea		finished,a0			;status of each level
.20:	clr.b	(a0)+				;make sure all levels are not completed
	dbra		d0,.20

	moveq.l	#MAX_SPEC_WEAPONS-1,d0
	lea		spec_tot,a0
.30:	move.w	#1,(a0)+				;start with 1 of each special weapon
	dbra		d0,.30

	move.w	#MAGNET,spec_type		;default special weapon
	rts

startlev::
	move.l	#0,joyold
	clr.w	joyhold

	clr.b	pause_flag			;make sure game is not paused when level starts
	clr.b	levflag				;reset level change flag
	move.w	level,d0
	lsl.w	#1,d0
	move.w	d0,levelx2			;level * 2
	lsl.w	#1,d0
	move.w	d0,levelx4			;level * 4
	lsl.w	#4,d0
	move.w	d0,levelx64			;level * 64

	move.w	#SCROLL_SPEED,scrlspd
	move.w	#SCROLL_SPEEDF,scrlspdf
	move.w	level,d0
	lsl.w	#1,d0				;level * 2
	lea		od_end1,a0			;table of first odometer end points
	move.w	(a0,d0.w),odomend
	clr.b	levstatus
	clr.b	bossmade				;boss character not created yet
	clr.w	endlvdel				;clear end of level delay counter

	lea		palette,a0			;get address of palette
	jsr		set_palette

	move.w	levelx4,d0
	lea		scoreclr,a0
	move.l	(a0,d0.w),a0
	movea.l	#(CLUT+$B8+$B8),a1		;start at color $B8
	move.w	#7,d0				;set 8 colors
.10:	move.w	(a0)+,(a1)+
	dbra		d0,.10

	clr.b	gameover				;clear game over flag
	clr.w	odomback				;init odometer for background
	clr.w	odomfrnt				;init odometer for foreground

	moveq.l	#(TOTAL_ENEMIES-1),d0
	lea		enemy0,a0				;first enemy
	bsr		objsoff

	moveq.l	#(MAX_ENEMY_SHOTS-1),d0
	lea		en_shot0,a0			;first enemy shot
	bsr		objsoff

	moveq.l	#(MAX_BULLETS-1),d0
	lea		bullet0,a0			;first player shot
	bsr		objsoff

	moveq.l	#(TOTAL_FRONT_OBJS-1),d0
	lea		front0,a0				;first foreground object
	bsr		objsoff

	moveq.l	#(CUTR_BULLETS-1),d0
	lea		cutshot0,a0			;first cutter bullet object
	bsr		objsoff

	or.b		#DELETE_OBJ,cutter+O_TYPE	;turn off cutter
	or.b		#DELETE_OBJ,bomb+O_TYPE		;make sure bomb is off
	or.b		#DELETE_OBJ,specweap+O_TYPE	;make sure special weapon is off
	or.b		#DELETE_OBJ,specflsh+O_TYPE	;make sure flash is off
	or.b		#DELETE_OBJ,powerup+O_TYPE	;make sure powerup is off
	or.b		#DELETE_OBJ,statn+O_TYPE		;make sure station is off
	or.b		#DELETE_OBJ,statnflg+O_TYPE	;make sure station flag is off
	move.w	#$7FFF,specweap+O_DESC		;make sure first special weapon will get blitted (can't be a negative number)
	move.w	#$FFFF,bomb+O_DESC			;make sure first bomb will get blitted

	or.b		#DELETE_OBJ,message+O_TYPE	;turn off game over message

	bsr		init_plr				;initialize player stuff
	move.b	#LEV_DELAY_TIME,levdelay	;so starting the game doesn't cause weapons to be fired

	bsr		ld_decmp				;load decompression code into GPU
	bsr		load_en				;load enemy graphic data for current level
	bsr		loadshts				;blit shots for enemies
	bsr		loadobjs				;blit any other objects for current level
	bsr		ld_decmp				;some of decomp code was erased by uncomp code, so load it back in
	move.l	#q65,a3				;starting address of dq_table
	bsr		load_dq
	bsr		loadcutr				;load cutter ship
;need to ld_decmp if any decompression is to be done after loadcutr

;******************************
.if	RANDOM_LEVEL = 1
	bsr		rand_lev				;make random level
.endif
;******************************

	bsr		ld_decmp				;load decompression code into GPU
	move.w	level,d0
	lsl.w	#2,d0
	lea		tile_q,a0				;which quality table to use
	move.l	(a0,d0.w),a3			;get address of dq table
	bsr		load_dq

	clr.b	firstbuf				;buf0 is on the left side of the screen
	clr.w	curbktile				;index for tilelist table
	clr.w	oldbktile

	move.l	#8,Out_Width			;width of tile buffer / 8
	move.l	#WID64,Out_E_Width
	lea		tilebufs,a0			;list of tile data addresses
	move.w	levelx4,d1
	lea		til_tbl,a2
	move.l	(a2,d1.w),a2			;list of tiles for current level
.30:
	move.l	(a2)+,In_Adr			;address of source data
	beq.b	.35					;exit if 0
	move.l	(a0)+,Out_Adr			;get address of buffer to write to
	bsr		decomp				;start decompression
	bra.b	.30

.35:
	move.l	#screen,A1_BASE		;destination address
	move.l	#PITCH1|PIXEL32|WID256|XADDPHR,A1_FLAGS	;destination
	move.l	#PITCH1|PIXEL32|WID32|XADDPHR,A2_FLAGS	;source
	move.l	#$0001FFE0,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#$0001FFE0,A2_STEP				;1 in Y step size, negative width in X step size

	move.l	#0,d2
	move.w	#7,d7				;do first 8 tiles
	lea		tilebufs,a3			;list of buffers containing tile data
	move.w	levelx4,d1
	lea		tlisttbl,a4
	move.l	(a4,d1.w),a4			;list of tile numbers for current level
	move.l	#$00000000,d1			;Y,X position in destination
.40:	move.b	(a4)+,d2				;get tile type
	lsl.w	#2,d2				;get 4 * tile number (1 long per tile)
	move.l	(a3,d2.w),A2_BASE		;address of source data
	move.l	#0,A2_PIXEL			;start at 0,0 of source image
	move.l	#$01200020,B_COUNT		;inner loop = 288, outer loop = 32
	move.l	d1,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#UPDA1|UPDA2|SRCEN|LFU_A|LFU_AN,B_CMD		;start blitter
	add.l	#$00000020,d1
	dbra		d7,.40

	move.l	#screen,bkground+O_DATA	;initialize background object data pointer
	move.w	#SCRN_TOP,bkground+O_YPOS	;assume normal ypos
	cmp.b	#1,pal_ntsc
	beq.b	.60						;if pal, don't need to adjust ypos
	move.w	levelx2,d0
	lea		bk_ypos,a0
	move.w	(a0,d0.w),bkground+O_YPOS	;set background ypos for NTSC for each level

;ANYTHING THAT USES A MASK MUST BE DONE BEFORE THE BACKGROUND TILES ARE BLITTED ONTO THE SCREEN
;BECAUSE SCREEN RAM IS USED FOR UNCOMPRESSING ALL MASKS
.60:	bsr		erase_info
	bsr		draw_lives			;draw lives once
	bsr		draw_icns
	bsr		draw_score
	move.l	#$FFFFFFFF,oldscore		;make sure score gets drawn when level starts

	bsr		ld_build				;load object list builder code into GPU

	lea		max_gtbl,a0
	move.w	level,d0
	move.b	(a0,d0.w),d0			;get byte from table
	move.w	d0,max_g_en			;store word, highest enemy number for ground enemies for this level

	rts

objsoff::
;d0 = total object - 1
;a0 = address of first object header
.10:	or.b		#DELETE_OBJ,O_TYPE(a0)	;turn off object
	move.w	#0,O_DESC(a0)			;this is only needed to clear negative bit for enemy objects, but let's do it for all objects anyway
	adda.l	#OBJ_SIZE,a0			;next object header
	dbra		d0,.10
	rts


;************************************
.if	RANDOM_LEVEL = 1
rand_lev::
	move.w	levelx4,d0
	lea		rndtbl0,a0
	move.l	(a0,d0.w),a0

	move.l	#screen,a2			;write table in screen ram
	move.l	#screen+256,a3			;set end address
	moveq.l	#0,d1				;first tile type
	move.b	d1,(a2)+				;make first tile 0
.10:	move.b	d1,d2
	and.w	#$FF,d2				;clear high byte
	lsl.w	#4,d2				;multiply * 16
	jsr		random
	and.l	#$F,d0				;0 - 15
	add.w	d0,d2				;add to tile type * 16
	move.b	(a0,d2.w),d1			;get next tile type, put it in d1 for the top of the loop
	move.b	d1,(a2)+				;store next tile in tilelist table
	cmpa.l	a3,a2				;end of tilelist table
	bne.b	.10
	rts
rndtbl0:						;addresses of tables to use for making random backgrounds
	dc.l		rnd_til1,rnd_til2
	dc.l		rnd_til1,rnd_til0
	dc.l		rnd_til1,rnd_til3
	dc.l		rnd_til1,rnd_til0
	dc.l		rnd_til1,rnd_til4
rnd_til0::
;tiles that can go on the right of each tile for swamp level
	dc.b		$01,$02,$03,$0D,$0E,$0F,$01,$02,$03,$0D,$0E,$0F,$01,$02,$03,$0D	;tile $00
	dc.b		$02,$03,$0D,$0E,$0F,$02,$03,$0D,$0E,$0F,$02,$03,$0D,$0E,$0F,$02	;tile $01
	dc.b		$01,$03,$0D,$0E,$0F,$01,$03,$0D,$0E,$0F,$01,$03,$0D,$0E,$0F,$01	;tile $02
	dc.b		$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00	;tile $03
	dc.b		$00,$05,$06,$0C,$00,$05,$06,$0C,$00,$05,$06,$0C,$00,$05,$06,$0C	;tile $04
	dc.b		$00,$04,$06,$0C,$00,$04,$06,$0C,$00,$04,$06,$0C,$00,$04,$06,$0C	;tile $05
	dc.b		$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07	;tile $06
	dc.b		$08,$09,$0A,$0B,$08,$09,$0A,$0B,$08,$09,$0A,$0B,$08,$09,$0A,$0B	;tile $07
	dc.b		$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07,$09,$0A,$07	;tile $08
	dc.b		$07,$08,$0A,$0B,$07,$08,$0A,$0B,$07,$08,$0A,$0B,$07,$08,$0A,$0B	;tile $09
	dc.b		$07,$08,$09,$0B,$07,$08,$09,$0B,$07,$08,$09,$0B,$07,$08,$09,$0B	;tile $0A
	dc.b		$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00	;tile $0B
	dc.b		$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01	;tile $0C
	dc.b		$01,$02,$03,$0E,$0F,$01,$02,$03,$0E,$0F,$01,$02,$03,$0E,$0F,$02	;tile $0D
	dc.b		$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00,$04,$05,$06,$0C,$00	;tile $0E
	dc.b		$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01,$02,$0D,$01	;tile $0F
rnd_til1::
;tiles that can go on the right of each tile for space level
	dc.b		$01,$01,$01,$01,$04,$04,$04,$04,$04,$04,$04,$05,$05,$05,$05,$05	;tile $00
	dc.b		$02,$02,$02,$02,$07,$07,$07,$07,$08,$08,$08,$08,$09,$09,$09,$09	;tile $01
	dc.b		$00,$03,$06,$0A,$0B,$0C,$0D,$00,$03,$06,$0A,$0B,$0C,$0D,$0B,$0C	;tile $02
	dc.b		$01,$01,$01,$01,$01,$01,$04,$04,$04,$04,$04,$05,$05,$05,$05,$05	;tile $03
	dc.b		$01,$01,$01,$01,$01,$01,$01,$01,$05,$05,$05,$05,$05,$05,$05,$05	;tile $04
	dc.b		$00,$03,$06,$0A,$0B,$0C,$0D,$00,$03,$06,$0A,$0B,$0C,$0D,$0B,$0C	;tile $05
	dc.b		$02,$07,$08,$09,$02,$07,$08,$09,$02,$07,$08,$09,$02,$07,$08,$09	;tile $06
	dc.b		$02,$02,$02,$02,$02,$02,$08,$08,$08,$08,$08,$09,$09,$09,$09,$09	;tile $07
	dc.b		$02,$02,$02,$02,$02,$07,$07,$07,$07,$07,$09,$09,$09,$09,$09,$09	;tile $08
	dc.b		$00,$03,$06,$0A,$0B,$0C,$0D,$00,$03,$06,$0A,$0B,$0C,$0D,$0B,$0C	;tile $05
	dc.b		$00,$03,$06,$0B,$0C,$0D,$00,$03,$06,$0B,$0C,$0D,$00,$03,$06,$0B	;tile $0A
	dc.b		$00,$03,$06,$0A,$0C,$0D,$00,$03,$06,$0A,$0C,$0D,$00,$0C,$0D,$0D	;tile $0B
	dc.b		$00,$03,$06,$0A,$0B,$0D,$00,$03,$06,$0A,$0B,$0D,$00,$03,$06,$0A	;tile $0C
	dc.b		$00,$03,$06,$0A,$0B,$0C,$00,$03,$06,$0A,$0B,$0C,$00,$03,$06,$0A	;tile $0D
rnd_til2::
;desert
	dc.b		$01,$02,$03,$04,$05,$06,$07,$01,$02,$03,$04,$05,$06,$07,$01,$02	;tile 00
	dc.b		$00,$02,$04,$06,$07,$00,$02,$04,$06,$07,$00,$02,$04,$06,$07,$00	;tile 01
	dc.b		$00,$01,$03,$04,$06,$07,$00,$01,$03,$04,$06,$07,$00,$01,$03,$04	;tile 02
	dc.b		$01,$04,$05,$06,$07,$01,$04,$05,$06,$07,$01,$04,$05,$06,$07,$01	;tile 03
	dc.b		$00,$02,$05,$06,$07,$00,$02,$05,$06,$07,$00,$02,$05,$06,$07,$00	;tile 04
	dc.b		$00,$03,$04,$06,$00,$03,$04,$06,$00,$03,$04,$06,$00,$03,$04,$06	;tile 05
	dc.b		$08,$09,$0A,$0C,$08,$09,$0A,$0C,$08,$09,$0A,$0C,$08,$09,$0A,$0C	;tile 06
	dc.b		$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D	;tile 07
	dc.b		$00,$02,$03,$05,$07,$00,$02,$03,$05,$07,$00,$02,$03,$05,$07,$00	;tile 08
	dc.b		$08,$0A,$0C,$08,$0A,$0C,$08,$0A,$0C,$08,$0A,$0C,$08,$0A,$0C,$08	;tile 09
	dc.b		$08,$09,$0C,$08,$09,$0C,$08,$09,$0C,$08,$09,$0C,$08,$09,$0C,$08	;tile 10
	dc.b		$08,$09,$0A,$0C,$08,$09,$0A,$0C,$08,$09,$0A,$0C,$08,$09,$0A,$0C	;tile 11
	dc.b		$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D,$0E,$0F,$0D	;tile 12
	dc.b		$00,$01,$02,$03,$04,$05,$06,$00,$01,$02,$03,$04,$05,$06,$00,$01	;tile 13
	dc.b		$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B,$0B	;tile 14
	dc.b		$0D,$0E,$0D,$0E,$0D,$0E,$0D,$0E,$0D,$0E,$0D,$0E,$0D,$0E,$0D,$0E	;tile 15
rnd_til3::
;air
	dc.b		$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01	;tile00
	dc.b		$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02	;tile01
	dc.b		$03,$04,$05,$06,$0A,$03,$04,$05,$06,$0A,$03,$04,$05,$06,$0A,$03	;tile02
	dc.b		$00,$03,$04,$05,$06,$0A,$00,$03,$04,$05,$06,$0A,$00,$03,$04,$05	;tile03
	dc.b		$00,$03,$05,$06,$0A,$00,$03,$05,$06,$0A,$00,$03,$05,$06,$0A,$03	;tile04
	dc.b		$03,$04,$06,$03,$04,$06,$03,$04,$06,$03,$04,$06,$03,$04,$06,$03	;tile05
	dc.b		$07,$08,$09,$0D,$0E,$07,$08,$09,$0D,$0E,$07,$08,$09,$0D,$0E,$07	;tile06
	dc.b		$08,$09,$0D,$0E,$08,$09,$0D,$0E,$08,$09,$0D,$0E,$08,$09,$0D,$0E	;tile07
	dc.b		$07,$09,$0D,$0E,$07,$09,$0D,$0E,$07,$09,$0D,$0E,$07,$09,$0D,$0E	;tile08
	dc.b		$00,$03,$04,$05,$06,$0A,$00,$03,$04,$05,$06,$0A,$03,$04,$05,$06	;tile09
	dc.b		$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B	;tile10
	dc.b		$0C,$0F,$0C,$0F,$0C,$0F,$0C,$0F,$0C,$0F,$0C,$0F,$0C,$0F,$0C,$0F	;tile11
	dc.b		$07,$08,$09,$0D,$0E,$07,$08,$09,$0D,$0E,$07,$08,$09,$0D,$0E,$07	;tile12
	dc.b		$07,$08,$09,$0E,$07,$08,$09,$0E,$07,$08,$09,$0E,$07,$08,$09,$0E	;tile13
	dc.b		$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B,$0C,$0F,$0B	;tile14
	dc.b		$03,$04,$05,$06,$03,$04,$05,$06,$03,$04,$05,$06,$03,$04,$05,$06	;tile15
rnd_til4::
;city
	dc.b		$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B	;tile00
	dc.b		$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B	;tile01
	dc.b		$03,$0A,$0B,$0D,$10,$03,$0A,$0B,$0D,$10,$03,$0A,$0B,$0D,$10,$03	;tile02
	dc.b		$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07	;tile03
	dc.b		$05,$06,$07,$0C,$0F,$05,$06,$07,$0C,$0F,$05,$06,$07,$0C,$0F,$05	;tile04
	dc.b		$04,$06,$07,$0C,$0F,$04,$06,$07,$0C,$0F,$04,$06,$07,$0C,$0F,$04	;tile05
	dc.b		$04,$05,$07,$0C,$0F,$04,$05,$07,$0C,$0F,$04,$05,$07,$0C,$0F,$04	;tile06
	dc.b		$01,$08,$09,$0E,$11,$01,$08,$09,$0E,$11,$01,$08,$09,$0E,$11,$01	;tile07
	dc.b		$01,$09,$0E,$11,$01,$09,$0E,$11,$01,$09,$0E,$11,$01,$09,$0E,$11	;tile08
	dc.b		$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B	;tile09
	dc.b		$02,$03,$0B,$0D,$10,$02,$03,$0B,$0D,$10,$02,$03,$0B,$0D,$10,$02	;tile10
	dc.b		$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07	;tile11
	dc.b		$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B	;tile12
	dc.b		$01,$08,$09,$0E,$11,$01,$08,$09,$0E,$11,$01,$08,$09,$0E,$11,$01	;tile13
	dc.b		$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07,$0C,$0F,$04,$05,$06,$07	;tile14
	dc.b		$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B,$0D,$10,$02,$03,$0A,$0B	;tile15
	dc.b		$02,$03,$0A,$0B,$0D,$02,$03,$0A,$0B,$0D,$02,$03,$0A,$0B,$0D,$02	;tile16
	dc.b		$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00	;tile17


.endif
;******************************************************

load_dta::
;load the four different bullet graphics that will always be in ram
;copy 416 bytes
	move.l	#PITCH1|PIXEL32|WID8|XADDPHR,d0
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#ramobjs,A1_BASE				;destination address
	move.l	#bullet0r,A2_BASE				;source address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$000D0008,B_COUNT
	move.l	#$0001FFF8,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

;copy the level 3 bullet 2 more times
;each bullet is 16 x 11, 176 bytes
	move.l	#PITCH1|PIXEL32|WID4|XADDPHR,A1_FLAGS	;destination
	move.l	#PITCH1|PIXEL32|WID4|XADDPHR,A2_FLAGS	;source
	move.l	#bulletl4,A1_BASE				;destination address
	move.l	#bullet3r,A2_BASE				;source address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$000B0004,B_COUNT
	move.l	#$0001FFFC,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

	move.l	#bulletl5,A1_BASE				;destination address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$000B0004,B_COUNT
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter
	rts

loadcutr::
	move.w	levelx4,d0
	lea		cutrshps,a0
	move.l	(a0,d0.w),In_Adr		;address of compressed data (skip 8 byte header)
	move.l	#cutrdata,Out_Adr		;set destination address
	move.l	#8,Out_Width			;number of 8 pixel blocks in destination area
	move.l	#WID64,Out_E_Width		;setting for blitter
	bsr		decomp

	move.l	#cutrdata,ADJBLACK_START
	move.l	#cutrdata+(64*24*2),ADJBLACK_END
	bsr		adjblak

	bsr		ld_uncmp

	move.l	#cutrdata,A1_BASE		;destination address
	move.l	#PITCH1|PIXEL16|WID64|XADDPIX,A1_FLAGS
	move.l	#PITCH1|PIXEL1|WID56|XADDPIX,A2_FLAGS
	move.l	#$00180038,B_COUNT		;height, width of source data
	move.l	#$0001FFC8,A1_STEP		;1 in Y step size, negative width in X step size
	move.l	#$0001FFC8,A2_STEP		;1 in Y step size, negative width in X step size
	move.w	levelx4,d0
	lea		cutrmsks,a0
	move.l	(a0,d0.w),UNCOMP_START	;address of mask data
	move.l	#screen+(56*24/8),UNCOMP_END
	bsr		blitmask
	rts

loadgrph::

	move.l	#dcmpgame,a0			;table with decompression info
	move.w	#8,d0				;number of objects to decompress
	bsr		dodecomp

	move.l	#player00,ADJBLACK_START
	move.l	#player00+(48*165*2),ADJBLACK_END
	bsr		adjblak
	move.l	#shield00,ADJBLACK_START
	move.l	#shield00+(64*264*2),ADJBLACK_END
	bsr		adjblak
	move.l	#station0,ADJBLACK_START
	move.l	#statflg6+(48*56*2),ADJBLACK_END
	bsr		adjblak
	move.l	#exp_a0,ADJBLACK_START
	move.l	#exp_d7+(80*64*2),ADJBLACK_END
	bsr		adjblak

	bsr		ld_uncmp

	move.l	#msk_game,a0			;address of table of mask info
	move.w	#8,d0				;number of masks
	bsr		do_mask

	move.l	#q65,a3
	bsr		load_dq				;restore quality table
	rts

dcmpgame:
	dc.l		plrship,	player00,		6,	WID48		;player ships
	dc.l		shlds,	shield00,		8,	WID64		;shields
	dc.l		station,	station0,		24,	WID192		;station
	dc.l		flags,	statflg0,		6,	WID48		;station flag
	dc.l		expa,	exp_a0,		2,	WID16		;explosion A
	dc.l		expb,	exp_b0,		4,	WID32		;explosion B
	dc.l		expc,	exp_c0,		6,	WID48		;explosion C
	dc.l		expd,	exp_d0,		10,	WID80		;explosion D
msk_game:
	dc.l		player00,		WID48,	$00A50030,	$0001FFD0,	plrshpm,	(48*165/8)
	dc.l		shield00,		WID64,	$01090040,	$0001FFC0,	shld_m,	(64*265/8)
	dc.l		station0,		WID192,	$006800C0,	$0001FF40,	statnm,	(192*104/8)
	dc.l		statflg0,		WID48,	$01880030,	$0001FFD0,	flags_m,	(48*392/8)
	dc.l		exp_a0,		WID16,	$00380010,	$0001FFF0,	expa_m,	(16*56/8)
	dc.l		exp_b0,		WID32,	$00A80020,	$0001FFE0,	expb_m,	(32*168/8)
	dc.l		exp_c0,		WID48,	$01190030,	$0001FFD0,	expc_m,	(48*281/8)
	dc.l		exp_d0,		WID80,	$01C00050,	$0001FFB0,	expd_m,	(80*448/8)


loadshts::
	lea		shload,a0				;table of shots to load for each level
	move.l	#0,d0
	move.w	levelx4,d0			;level * 4
	lsl.w	#2,d0				;make it level * 16
	adda.l	d0,a0
	move.l	(a0)+,d0				;address of source data
	beq.b	.90					;if 0, no shots to load
	move.l	d0,A2_BASE			;source address
	move.l	(a0)+,A1_BASE			;destination address
	move.l	(a0)+,B_COUNT
	move.l	(a0)+,A1_STEP			;1 in Y step size, negative width in X step size
	move.l	#PITCH1|PIXEL8|WID8|XADDPHR,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL8|WID8|XADDPHR,A2_FLAGS	;description of source area
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter
.90:	rts

loadobjs::
	lea		objload,a0			;table of objects to load for each level
	move.l	#0,d0
	move.w	levelx4,d0			;level * 4
	move.l	(a0,d0.w),a0
.10:	move.l	(a0)+,d0				;address of source data
	beq.b	.90					;if 0, no objects to load
	move.l	d0,A2_BASE			;source address
	move.l	(a0)+,A1_BASE			;destination address
	move.l	(a0)+,B_COUNT
	move.l	(a0)+,A1_STEP			;destination
	move.l	(a0)+,A2_STEP			;source
	move.l	(a0)+,A1_PIXEL			;Y,X position to write data in destination area
	move.l	#0,A2_PIXEL			;start at 0,0 of source image
	move.l	(a0)+,d0
	move.l	d0,A1_FLAGS			;description of destination area
	move.l	d0,A2_FLAGS			;description of source area
	move.l	#UPDA1|UPDA2|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter
	bra.b	.10					;check for next object
.90:	rts

load_en::
	move.l	#0,a2				;make sure compression quality table gets copied
	move.w	levelx4,d0			;level * 4
	lea		enload,a0				;list of tables for loading enemies
	move.l	(a0,d0.w),a0			;get address of table to use
.10:	move.l	(a0)+,In_Adr			;address of compressed data (skipping 8 byte header)
	beq		.30
	move.l	(a0)+,Out_Adr			;set destination address
	move.l	(a0)+,Out_Width		;number of 8 pixel blocks in destination area
	move.l	(a0)+,Out_E_Width		;setting for blitter
	move.l	(a0)+,a3				;compression quality table
	cmpa.l	a3,a2				;compare to the one that was used last
	beq.b	.20					;if it's the same table, don't need to copy it again
	movea.l	a3,a2				;save address in a2 so it can be checked for next enemy
	bsr		load_dq
.20:	bsr		decomp
	bra.b	.10

.30:
	move.l	#0,d0
	move.w	levelx4,d0
	lsl.w	#1,d0				;make it level * 8
	lea		adblktbl,a0			;list of start and end addresses for adjblack
	adda.l	d0,a0
	move.l	(a0)+,ADJBLACK_START	;start address for adjblack
	beq.b	.40
	move.l	(a0),ADJBLACK_END
	bsr		adjblak

.40:	bsr		ld_uncmp

	move.w	levelx4,d0
	lea		enloadm,a6			;information for blitting masks
	move.l	(a6,d0.w),a6			;get address of table to use
.50:	move.l	(a6)+,A1_BASE			;destination address
	beq.b	.90					;exit if 0
	move.l	#screen,A2_BASE
	move.l	(a6)+,d0				;destination window width
	move.l	d0,d1				;save it for A2_FLAGS
	or.l		#PITCH1|PIXEL16|XADDPIX,d0
	move.l	d0,A1_FLAGS
	or.l		#PITCH1|PIXEL1|XADDPIX,d1
	move.l	d1,A2_FLAGS
	move.l	(a6)+,B_COUNT			;height, width of source data
	move.l	(a6)+,d0
	move.l	d0,A1_STEP			;1 in Y step size, negative width in X step size
	move.l	d0,A2_STEP			;1 in Y step size, negative width in X step size
	move.l	(a6)+,UNCOMP_START
	move.l	(a6)+,d0
	add.l	#screen,d0
	move.l	d0,UNCOMP_END
	bsr		blitmask
	bra.b	.50
.90:	rts

adjblak::
	move.l	#ADJBLACK_PRG,G_PC		;set program counter
	move.l	#$00000011,G_CTRL		;start GPU
.10:	cmp.l	#1,ADJBLACK_DONE		;wait until finished
	bne.b	.10
	rts

blitmask::
;these must be set already:
;uncomp GPU code must be in GPU ram
;A1_BASE		destination address
;A1_FLAGS		pitch,pixel,wid,xadd for destination
;A2_FLAGS		pitch,pixel,wid,xadd for source
;B_COUNT		height, width of source data
;A1_STEP		1, negative width
;A2_STEP		1, negative width

	move.l	#screen,UNCOMP_DEST
	move.l	#UNCOMP_PRG,G_PC		;set program counter
	move.l	#$00000011,G_CTRL		;start GPU
.30:	cmp.l	#1,UNCOMP_DONE			;wait until uncomp is finished
	bne.b	.30

	move.l	#screen,A2_BASE		;source address
	move.l	#$00000000,B_PATD		;low word is color to write if bit is set in source data
	move.l	#0,A2_PIXEL			;start at 0,0 of source data
	move.l	#0,A1_PIXEL			;X,Y position to write data in destination area
	move.l	#UPDA1|UPDA2|SRCEN|BCOMPEN|PATDSEL|LFU_A|LFU_AN,B_CMD
	rts

init_plr::
;make the player object into the player at the default starting position
	move.w	#PLR_XPOS,player+O_XPOS			;default xpos for player
	move.w	#PLR_YPOS,player+O_YPOS			;default ypos for player
	move.w	#PLR_OHEIGHT,player+O_HEIGHT		;height of player object
	move.w	#PLR_DWIDTH,player+O_DWIDTH		;player dwidth
	move.w	#PLR_IWIDTH,player+O_IWIDTH		;player iwidth
	move.b	#PLR_DEPTH,player+O_DEPTH		;player pixel depth
	move.w	#PLR_PLAY,player+O_DESC			;player object is now the player, not explosion
	and.b	#$7F,player+O_TYPE				;make sure player object is on

	move.w	#SHIP_NEUTRAL,d2
	bsr		load_ship

	clr.b	bulpower				;reset bullet power level
	clr.w	bomb_power			;reset bomb power level

	rts

run_counters::
	tst.b	levdelay				;check delay at the start of a level
	beq.b	.10
	subq.b	#1,levdelay			;no firing until levdelay = 0
.10:	tst.b	shot_delay			;see if shot_delay is 0
	beq.b	.20
	subq.b	#1,shot_delay			;no firing shots by holding down A button until shot_delay = 0
.20:	tst.b	spec_delay			;see if spec_weap_delay is 0
	beq.b	.24
	subq.b	#1,spec_delay			;no firing special weapon by holding down C button until spec_delay = 0
.24:	tst.b	cutshdel
	beq.b	.30
	subq.b	#1,cutshdel			;decrease delay timer for cutter bullets
.30:
	tst.b	gameover
	beq.b	.35
	cmp.b	#CONT_DELAY,cont_del
	beq.b	.32
	addq.b	#1,cont_del			;delay until you can start a continued game
.32:	addq.b	#1,cont_cnt			;counter that determines when to change signs
	cmp.b	#CONT_TOGGLE,cont_cnt	;when to change signs
	blt.b	.35
	clr.b	cont_cnt
	eor.b	#1,cont_sign			;switch signs (game over, press fire to continue)
	cmp.b	#1,cont_sign
	beq.b	.34					;if 1, load continue sign
.33:	bsr		ld_gmovr				;if 0, load game over sign
	bra.b	.35
.34:	bsr		ld_cont				;load press fire to continue sign
.35:
do_colors::
;color cycle for powerups (colors $F0 - $FF)
	move.w	CLUT+$FF+$FF,d0		;save last color
	lea		CLUT+$FE+$FE,a0		;next to last color
.40:	move.w	(a0),2(a0)			;move color forward 1 spot in palette
	suba.l	#2,a0				;step back to previous color
	cmpa.l	#(CLUT+$EF+$EF),a0		;stop at color $F0 * 2
	bne.b	.40
	move.w	d0,CLUT+$F0+$F0		;put last color in first color position

	rts

set_background::
	move.w	odomback,d0			;get current odometer reading
	move.w	d0,d1				;save odometer value so it can be subtracted later
	lsr.w	#6,d0				;divide by width of one tile (64)
	move.w	d0,curbktile			;save offset for list of tiles as current background tile
	lsl.w	#6,d0				;tile number * width of one tile
	sub.w	d1,d0				;(tile number * width) - odometer = a number between 0 and -63 for xpos
	move.w	d0,bkground+O_XPOS		;X position of background object is how much of first tile is off left side of screen

	neg.w	d0					;change xpos from negative to positive
	lsr.w	#2,d0				;positive xpos divided by 4 (4 pixels per phrase) = 0-15 phrases that are off screen
	add.w	#113,d0				;add minimum IWIDTH for background
	move.w	d0,bkground+O_IWIDTH	;draw just enough phrases to reach the right edge of the screen

	clr.b	newtilfl				;initialize new tile flag
	move.w	curbktile,d0
	cmp.w	oldbktile,d0
	beq		.90					;if left tile hasn't changed, don't need to blit a new one
	move.w	d0,oldbktile			;update oldbktile with curbktile
	move.b	#1,newtilfl			;set new tile flag so ground object will be created
	move.l	bkground+O_DATA,A1_BASE	;blit the new tile into here
	add.l	#128,bkground+O_DATA	;move data pointer ahead 64 pixels

	move.w	levelx4,d1
	lea		tlisttbl,a4
	move.l	(a4,d1.w),a4			;list of tile numbers for current level
	addq.w	#7,d0				;move ahead 7 files from first tile (d0 is curbktile)
	clr.w	d2
	move.b	(a4,d0.w),d2			;get tile type to blit
	lsl.w	#2,d2				;get 4 * tile number (1 long per tile)
	lea		tilebufs,a3
	move.l	(a3,d2.w),A2_BASE		;source address of tile data
	move.l	#0,A2_PIXEL			;start at 0,0 of source image
	move.l	#$01200020,B_COUNT		;height, width of tile
	move.l	#PITCH1|PIXEL32|WID256|XADDPHR,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL32|WID32|XADDPHR,A2_FLAGS	;description of source
	move.l	#$00010000,A1_PIXEL				;Y,X position to write data in destination area
	move.l	#$0001FFE0,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#$0001FFE0,A2_STEP		;1 in Y step size, negative width in X step size
	move.l	#UPDA1|UPDA2|SRCEN|LFU_A|LFU_AN,B_CMD				;start blitter
.90:
	rts

mk_front::
	move.w	odomfrnt,d0			;get odometer reading for foreground
	lsr.w	#6,d0				;divide by 64
	cmp.w	oldfront,d0			;compare oldfront to current
	beq		.90
	move.w	d0,oldfront			;updata oldfront with current

	move.w	levelx4,d1
	lea		flisttbl,a4
	move.l	(a4,d1.w),a4			;address of list of foreground objects for current level
	cmp.l	#0,a4
	beq		.90					;no foreground objects if 0
	move.b	(a4,d0.w),d1			;get the type of object
	cmp.b	#$FF,d1				;if $FF, don't create any object
	beq		.90
	move.b	d1,d4				;get object type
	and.w	#$7F,d4				;remove flip bit from object number if it is set
	lsl.w	#1,d4				;object type * 2

	move.w	levelx4,d0
	lea		frinftbl,a0
	move.l	(a0,d0.w),a5			;A5 = DATA (address of list of data addresses for foreground objects)
	movea.l	a5,a0				;need to set a0 to address of heights
	adda.l	#64,a0				;A0 = HEIGHT (skip 16 data addresses * 4 bytes each)
	movea.l	a0,a3				;need to set a3 to address of widths
	adda.l	#32,a3				;A3 = WIDTH (skip 16 heights * 2 bytes each)
	movea.l	a3,a2				;need to set a2 to address of dwidths
	adda.l	#32,a2				;A2 = DWIDTH (skip 16 widths * 2 bytes each)
	movea.l	a2,a1				;need to set a1 to addres of heights
	adda.l	#32,a1				;A1 = YPOS (skip 16 dwidths * 2 bytes each)
	lea		front0,a6				;first foreground object header
	move.w	#TOTAL_FRONT_OBJS-1,d0
.30:	tst.b	O_TYPE(a6)			;object is turned on if positive
	bpl.b	.40					;need to find an object that is turned off
	move.b	#TRANS_ON,O_FLAGS(a6)	;assume object is not flipped
	move.w	#SCRN_RIGHT,O_XPOS(a6)	;assume object will start just off screen
	tst.b	d1					;check number of tile to use
	bpl.b	.35					;tile is flipped if > $80
	move.w	(a3,d4.w),d2			;get width of object
	subq.w	#1,d2				;make it width - 1
	add.w	d2,O_XPOS(a6)			;add object width - 1 to current xpos if flipped
	or.b		#HFLIP_ON,O_FLAGS(a6)	;set flip bit for object
.35:	and.b	#$7F,O_TYPE(a6)		;turn object on
	move.w	(a0,d4.w),O_HEIGHT(a6)
	move.w	(a1,d4.w),O_YPOS(a6)
	move.w	(a2,d4.w),O_DWIDTH(a6)
	move.w	O_DWIDTH(a6),O_IWIDTH(a6)
	lsl.w	#1,d4				;change 2 * object number to 4 * object number (1 long per object)
	move.l	(a5,d4.w),O_DATA(a6)	;save address in foreground object header
	rts
.40:	adda.l	#OBJ_SIZE,a6			;next foreground object
	dbra		d0,.30
.90:	rts

mv_front::
	lea		front0,a6				;first foreground object header
	moveq.l	#TOTAL_FRONT_OBJS-1,d0
.30:	tst.b	O_TYPE(a6)			;see if foreground object is on
	bmi.b	.80					;if not, go to next one
	move.w	O_DWIDTH(a6),d2		;get width in phrases
	lsl.w	#2,d2				;convert to pixels
	neg.w	d2					;use negative xpos as width
	move.w	O_XPOS(a6),d1
	sub.w	scrlspdf,d1			;subtract foreground scrolling speed
	move.w	d1,O_XPOS(a6)
	cmp.w	d2,d1				;turn off object when it gets off screen
	bge.b	.80
	or.b		#DELETE_OBJ,O_TYPE(a6)	;turn off foreground object when far enough off screen
.80:	adda.l	#OBJ_SIZE,a6			;next foreground object
	dbra		d0,.30
	rts



plr_left::
	sub.w	#PLR_HSPEED,player+O_XPOS
	bmi.b	.20
	cmp.w	#PLR_LEFT_LIMIT,player+O_XPOS
	bge.b	.50
.20:	move.w	#PLR_LEFT_LIMIT,player+O_XPOS
.50:	rts
plr_right::
	add.w	#PLR_HSPEED,player+O_XPOS
	cmp.w	#PLR_RIGHT_LIMIT,player+O_XPOS
	blt.b	.10
	move.w	#PLR_RIGHT_LIMIT,player+O_XPOS
.10:	rts
plr_up::
	sub.w	#(PLR_VSPEED*2),player+O_YPOS
	cmp.w	#PLR_TOP_LIMIT,player+O_YPOS
	bge.b	.10
	move.w	#PLR_TOP_LIMIT,player+O_YPOS
.10:
	move.l	joyedge,d2
	btst.l	#JOY_UP,d2
	beq.b	.15
	clr.w	joyhold
	bra.b	.40
.15:	move.l	joyold,d2
	btst.l	#JOY_UP,d2
	beq.b	.40
	cmp.w	#MAX_JOYHOLD,joyhold
	beq.b	.20
	add.w	#1,joyhold
	cmp.w	#MAX_JOYHOLD,joyhold
	blt.b	.40
.20:	move.w	#SHIP_UPMAX,d2
	bra.b	.60
.40:	move.w	#SHIP_UPMID,d2
.60:	bsr		load_ship
.90:	rts
plr_down::
	add.w	#(PLR_VSPEED*2),player+O_YPOS
	cmp.w	#PLR_BOT_LIMIT,player+O_YPOS
	blt.b	.10
	move.w	#PLR_BOT_LIMIT,player+O_YPOS
.10:
	move.l	joyedge,d2
	btst.l	#JOY_DOWN,d2
	beq.b	.15
	clr.w	joyhold
	bra.b	.40
.15:	move.l	joyold,d2
	btst.l	#JOY_DOWN,d2
	beq.b	.40
	cmp.w	#MAX_JOYHOLD,joyhold
	beq.b	.20
	add.w	#1,joyhold
	cmp.w	#MAX_JOYHOLD,joyhold
	blt.b	.40
.20:	move.w	#SHIP_DNMAX,d2
	bra.b	.60
.40:	move.w	#SHIP_DNMID,d2
.60:	bsr		load_ship
.90:	rts

fire_shot::
	moveq.l	#(MAX_BULLETS-1),d6
	lea		bullet0,a0			;first bullet object
.10:
	tst.b	O_TYPE(a0)
	bmi.b	.50					;if -, bullet is object is available
.20:	adda.l	#OBJ_SIZE,a0
	dbra		d6,.10				;try another bullet object
	rts							;no bullets available, so don't fire
.50:
	move.b	#SHOT_DELAY_TIME,shot_delay
	and.b	#$7F,O_TYPE(a0)		;turn on the bullet object
	move.w	player+O_XPOS,O_XPOS(a0)
	add.w	#BULLET_XPOS,O_XPOS(a0)	;object xpos
	move.l	#0,d0
	move.b	bulpower,d0			;get current bullet power
	move.w	d0,O_DESC(a0)
	lea		bulfirst,a1
	move.b	(a1,d0.w),O_FIRSTPIX(a0)
	lsl.w	#1,d0				;bulpower * 2
	lea		bulyoff,a1
	move.w	player+O_YPOS,d2
	add.w	(a1,d0.w),d2
	move.w	d2,O_YPOS(a0)			;object ypos
	lea		bulheight,a1
	move.w	(a1,d0.w),O_HEIGHT(a0)	;bullet height
	lea		buldwid,a1
	move.w	(a1,d0.w),O_DWIDTH(a0)
	move.w	(a1,d0.w),O_IWIDTH(a0)
	lsl.w	#1,d0				;change bulpower * 2 to bulpower * 4
	lea		buldata,a1
	move.l	(a1,d0.w),O_DATA(a0)
	move.b	#3,O_DEPTH(a0)			;8 bits per pixel
	move.w	#PLRFIRE_SND,d0
	move.w	player+O_XPOS,d1		;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos
	rts

fire_bomb::
	tst.b	bomb+O_TYPE
	bpl		.90					;if positive, bomb is already active
	and.b	#$7F,bomb+O_TYPE		;turn on the bomb object
	move.w	bomb_power,d0
	cmp.w	bomb+O_DESC,d0
	beq.b	.10
	bsr		loadbomb
.10:
	move.l	#bombdata,bomb+O_DATA
	move.w	#2,bomb+O_DWIDTH
	move.w	#2,bomb+O_IWIDTH
	move.w	#13,bomb+O_HEIGHT
	move.b	#3,bomb+O_DEPTH
	clr.b	bomb_an_step			;reset bomb anim step
	move.w	player+O_XPOS,bomb+O_XPOS
	add.w	#BOMB_XPOS,bomb+O_XPOS
	move.w	player+O_YPOS,bomb+O_YPOS
	add.w	#BOMB_YPOS,bomb+O_YPOS
	move.w	#BOMB_SND,d0
	move.w	bomb+O_XPOS,d1			;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos
.90:	rts

loadbomb::
;d0 is bomb_power
	move.w	d0,bomb+O_DESC
	lsl.w	#2,d0						;get bomb type * 4
	lea		bombsrom,a0
	move.l	(a0,d0.w),A2_BASE				;get source address
	move.l	#PITCH1|PIXEL32|WID4|XADDPHR,d0
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#bombdata,A1_BASE				;destination address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$000D0004,B_COUNT				;inner loop = 13, outer loop = 16
	move.l	#$0001FFFC,A1_STEP				;negative width in X step size, 1 in Y step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter
	rts

move_shots::
	move.w	#(MAX_BULLETS-1),d6
	lea		bullet0,a1
	move.w	#$FFE8,d2				;left limit
	move.w	#SCRN_RIGHT,d3			;right limit
	move.w	#SCRN_TOP-10,d4		;top limit
	move.w	#SCRN_BOTTOM,d5		;bottom limit
.10:	tst.b	O_TYPE(a1)
	bmi.b	.80					;if negative, bullet is not active
	tst.w	O_DESC(a1)
	bpl.b	.50					;if negative, bullet is an explosion
	move.l	#(12*2),d0			;direction 12 * 2 bytes for each direction in spds_h and spds_v tables
	bsr		move_obj				;scroll with background
	bra.b	.60
.50:	move.l	#(4*2)+(BULLET_SPEED*32),d0	;direction 4 * 2 bytes for each direction in spds_h and spds_v tables + 1 extra speed * 32
	bsr		mv_obj2				;don't scroll with background
.60:	tst.b	limitflag
	beq.b	.80
.70:	or.b		#DELETE_OBJ,O_TYPE(a1)	;turn off bullet

.80:	adda.l	#OBJ_SIZE,a1			;next bullet object
	dbra		d6,.10
	rts

move_bomb::
	tst.b	bomb+O_TYPE
	bmi		.90					;if negative, bomb is not active
	tst.w	bomb+O_DESC
	bpl.b	.20					;if negative, bomb is an explosion
	move.l	#(12*2),d0			;direction 12 * 2 bytes for each direction in spds_h and spds_v tables
	bsr		move_obj				;scroll with background
	tst.b	limitflag
	beq.b	.80
	bra.b	.40
.20:
	lea		bomb_hpos_chg,a2
	lea		bomb_vpos_chg,a3
	clr.w	d0
	clr.w	d1
	move.b	bomb_an_step,d0		;get animation step
	move.b	(a2,d0.w),d1			;get hpos change
	add.w	d1,bomb+O_XPOS
	move.b	(a3,d0.w),d1			;get vpos change
	add.w	d1,bomb+O_YPOS
	cmp.w	#SCRN_BOTTOM,bomb+O_YPOS
	blt.b	.50
.40:	or.b		#DELETE_OBJ,bomb+O_TYPE	;turn off bomb
	move.w	#BOMB_SND,d0
	jsr		sndoffd0				;turn off bomb sound
	rts
.50:	add.b	#1,bomb_an_step		;increase bomb anim step
.80:
	move.w	bomb+O_YPOS,d2
	sub.w	#SCRN_TOP,d2
	move.w	d2,d3				;save result for modulator calculation
	mulu		#$330,d2				;pitch range / ypos range
	move.l	#$60000,d0			;maximum pitch
	sub.l	d2,d0				;set new pitch in D0
	mulu		#$6E0,d3				;modulator range / ypos range
	move.l	#$D0000,d1			;maximum modulator
	sub.l	d3,d1				;set new modulator value in D1
	jsr		bombchg				;needs D0 and D1 set
.90:	rts

move_pwrup::
	tst.b	powerup+O_TYPE
	bmi.b	.90					;if negative, powerup is not active
	move.w	#$FFF0,d2				;left limit
	move.w	#SCRN_RIGHT,d3			;right limit
	move.w	#SCRN_TOP-20,d4		;top limit
	move.w	#SCRN_BOTTOM,d5		;bottom limit
	moveq.l	#32,d0				;speed of 1, * 16 directions for each speed, * 2 bytes for each direction
	move.l	#0,d1
	move.b	pwr_dir,d1			;get powerup direction
	cmp.w	#4,d1				;see if powerup is moving straight to the right
	bne.b	.50
	cmp.w	#1,scrlspd			;if powerup is moving right and background is scrolling at the same speed, it would appear to stand still
	bne.b	.50
	moveq.l	#64,d0				;give powerup a speed of 2, which will change to 1 when scrolling speed is subtracted in move_obj
.50:	add.w	d1,d0				;add direction to speed * 32
	add.w	d1,d0				;add direction again because each direction uses 2 bytes
	lea		powerup,a1			;powerup object
	bsr		move_obj
	tst.b	limitflag
	beq.b	.90
	or.b		#DELETE_OBJ,powerup+O_TYPE	;turn off powerup if it went off screen
.90:	rts

make_pwrup::
;a1 points to the object header for the object that got hit
	tst.b	powerup+O_TYPE				;see if powerup object is active
	bpl		.90						;if object is being used, exit
	and.b	#$7F,powerup+O_TYPE			;turn on powerup object
	move.w	O_XPOS(a1),powerup+O_XPOS	;use old object xpos
	move.w	O_YPOS(a1),powerup+O_YPOS	;use old object ypos
	move.l	seed,d0
	and.l	#$7F,d0
	lea		pwrtable,a0
	move.b	(a0,d0.w),d0			;get powerup type from table
	cmp.b	#P_BULL1,d0			;bullet powerup
	bne.b	.30
	move.b	bulpower,d0
	cmp.b	#MAX_BULLET_POWER-1,d0
	beq.b	.40					;if bullets are at max power, make a points powerup
	bra.b	.50
.30:	cmp.b	#P_BOMB1,d0			;bomb powerup
	bne.b	.50
	move.w	bomb_power,d0
	add.w	#P_BOMB1,d0
	cmp.w	#P_BOMB2+1,d0
	bne.b	.50
.40:	move.w	#P_POINTS,d0			;if bombs are at max power, make a points powerup
.50:
	move.w	d0,powerup+O_DESC
	lsl.w	#2,d0						;get powerup type * 4
	lea		pwr_data,a0
	move.l	(a0,d0.w),A2_BASE				;get source address
	move.l	#PITCH1|PIXEL32|WID4|XADDPHR,d0
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#pwrupdata,A1_BASE				;destination address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$000F0004,B_COUNT				;inner loop counter, outer loop counter
	move.l	#$0001FFFC,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

	move.b	seed+3,pwr_dir			;get a random number for the direction
	and.b	#3,pwr_dir			;make it 0 - 3
	cmp.w	#(SCRN_RIGHT/2),powerup+O_XPOS
	blt.b	.70					;if powerup is on left side, move it right
	add.b	#8,pwr_dir			;direction will be 8 - 15
	cmp.w	#((SCRN_BOTTOM-SCRN_TOP)/2),powerup+O_YPOS
	blt.b	.90					;powerup is in lower right, use directions 8-11
	bra.b	.75					;powerup is in upper right, add 4 so directions will be 12-15
.70:	cmp.w	#((SCRN_BOTTOM-SCRN_TOP)/2),powerup+O_YPOS
	bge.b	.90					;powerup is in lower left, use directions 0-3
.75:	add.b	#4,pwr_dir			;powerup is in upper left, use directions 4-7
.90:	rts

got_pwrup::
;player collided with powerup
	move.w	#PICKUP_SND,d0
	move.w	powerup+O_XPOS,d1		;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos
	move.w	powerup+O_DESC,d0		;get type of powerup
	lsl.w	#2,d0				;powerup * 4
	lea		pw_coll,a0			;table of powerup collision subroutines
	move.l	(a0,d0.w),a0			;get address of subroutine
	jmp		(a0)

pw_bull::							;increase bullet power
	addq.b	#1,bulpower
	cmp.b	#MAX_BULLET_POWER,bulpower
	blt.b	.90
	clr.b	bulpower
.90:	rts
pw_bomb::							;increase bomb power
	addq.w	#1,bomb_power
	cmp.w	#MAX_BOMB_POWER,bomb_power
	blt.b	.90
	clr.w	bomb_power
.90:	rts
pw_mag::
	moveq.l	#(MAGNET*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_ring::
	moveq.l	#(RING*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_trace::
	moveq.l	#(TRACER*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_miss::
	moveq.l	#(MISSILE*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_flash::
	moveq.l	#(FLASH*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_beam::
	moveq.l	#(BEAM*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_shld::
	moveq.l	#(SHIELD*2),d1
	moveq.l	#1,d2
	bra.b	add_spec
pw_bolt::
	moveq.l	#(BOLT*2),d1
	moveq.l	#1,d2
;	bra.b	add_spec
add_spec::						;add the special weapon that was picked up
;d0 is the special weapon type * 2
	lea		spec_tot,a0
	add.w	d2,(a0,d1.w)
	cmp.w	#5,(a0,d1.w)
	blt.b	.90					;maximum of 5 in reserve
	move.w	#5,(a0,d1.w)
.90:	rts
pw_life::							;give player another life
	addq.b	#1,lives
	cmp.b	#MAX_LIVES,lives
	blt		draw_lives
	move.b	#MAX_LIVES,lives
	bra		draw_lives
pw_pts::
	move.l	#500,d0				;give player 5000 points
	bra		addscore

;a1 points to object being moved
;d0 is set to the offset for spds_h and spds_v, which is (speed * 32) + (direction * 2)
;d2 is left limit
;d3 is right limit
;d4 is top limit
;d5 is bottom limit
mv_obj2::							;ignore the background scrolling speed
;d0 is speed * 16 + direction
	clr.b	limitflag				;initialize flag
	move.l	#0,d1
	lea		spds_v,a0
	move.w	(a0,d0.w),d1			;get vertical speed
	swap		d1					;move vertical speed to high word
	lea		spds_h,a0
	move.w	(a0,d0.w),d1			;get amount to move horizontally
	bra		mv_horiz

;a1 points to object being moved
;d0 is set to the offset for spds_h and spds_v, which is (speed * 32) + (direction * 2)
;d2 is left limit
;d3 is right limit
;d4 is top limit
;d5 is bottom limit
move_obj::
;d0 is speed * 16 + direction
	clr.b	limitflag				;initialize flag
	move.l	#0,limitall			;clear limittop,limitbot,limitlf,limitrt bytes all at once
	move.l	#0,d1
	lea		spds_v,a0
	move.w	(a0,d0.w),d1			;get vertical speed
	swap		d1					;move vertical speed to high word
	lea		spds_h,a0
	move.w	(a0,d0.w),d1			;get amount to move horizontally
	sub.w	scrlspd,d1			;scroll with background
mv_horiz:
	beq.b	mv_vert				;if 0, don't move horizontally
	bmi.b	.10
	bsr		move_right
	bra.b	mv_vert
.10:	neg.w	d1					;make speed positive, move_left will subtract it
	bsr		move_left
mv_vert:
	swap		d1					;put vertical speed in low word of d1
	tst.w	d1
	beq.b	.90					;if 0, don't move
	bmi.b	.30					;if negative, move up
	bra		move_down
.30:	neg.w	d1					;make speed positive, move_up will subtract it
	bra		move_up
.90:	rts

move_left::
	move.w	O_XPOS(a1),d0
	sub.w	d1,d0
	tst.w	d2					;check left limit
	bpl.b	.30					;if left limit is positive, see if xpos < left limit
	cmp.w	d2,d0
	bge.b	.50					;if xpos > a negative left limit, move is ok
	cmp.w	#$8000,d0
	blt.b	.50
	bra.b	hitleft
.30:	cmp.w	d2,d0				;compare left limit to xpos
	blt.b	hitleft				;if xpos < positive left limit, set hitlimit
	tst.w	d0
	bmi.b	hitleft				;set hitlimit if left limit is positive and xpos is negative
.50:	move.w	d0,O_XPOS(a1)
	rts
move_right::
	add.w	O_XPOS(a1),d1
	cmp.w	d3,d1				;right limit
	bge.b	hitright
	move.w	d1,O_XPOS(a1)
	rts
move_up::
	move.w	O_YPOS(a1),d0
	sub.w	d1,d0
	tst.w	d4					;check top limit
	bpl.b	.30					;if top limit is positive, see if ypos < top limit
	cmp.w	d4,d0
	bge.b	.50					;if ypos > a negative top limit, move is ok
	cmp.w	#$8000,d0
	blt.b	.50
	bra.b	hittop
.30:	cmp.w	d4,d0				;compare top limit to ypos
	blt.b	hittop				;if ypos < positive top limit, set hitlimit
	tst.w	d0
	bmi.b	hittop				;set hitlimit if top limit is positive and ypos is negative
.50:	move.w	d0,O_YPOS(a1)
	rts
move_down::
	add.w	O_YPOS(a1),d1
	cmp.w	d5,d1				;bottom limit
	bge.b	hitbot
	move.w	d1,O_YPOS(a1)
	rts

hittop::
	move.b	#1,limittop
	bra.b	hitlimit
hitbot::
	move.b	#1,limitbot
	bra.b	hitlimit
hitleft::
	move.b	#1,limitlf
	bra.b	hitlimit
hitright::
	move.b	#1,limitrt
;	bra		hitlimit
hitlimit::						;moving object reached its limit
	move.b	#1,limitflag
	rts


anim_plr::
	cmp.w	#PLR_PLAY,player+O_DESC	;see if player is playing the game
	beq.b	.40
	cmp.w	#PLR_EXP,player+O_DESC	;see if player is an explosion
	beq.b	.15
	cmp.w	#PLR_FLASH,player+O_DESC	;see if player is flashing
	bne.b	.15
	add.b	#1,plrflash			;add 1 to timer
	cmp.b	#PLR_FLASH_TIME,plrflash
	blt.b	.10
	move.w	#PLR_PLAY,player+O_DESC
	bra.b	.20					;make sure player object is turned on
.10:	move.b	plrflash,d0
	and.b	#3,d0
	cmp.b	#2,d0
	blt.b	.20
	or.b		#DELETE_OBJ,player+O_TYPE
.15:	rts
.20:	and.b	#$7F,player+O_TYPE		;turn on player object
.40:
	rts

load_ship::
;change the data address for player ship
;d2 = type of ship to display
	move.w	d2,curship
	lsl.w	#2,d2
	lea		shipdata,a0
	move.l	(a0,d2.w),player+O_DATA
	rts

ld_gmovr::
;load game over message (192 x 18)
	move.l	#PITCH1|PIXEL32|WID48|XADDPHR,d0	;description of destination area
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#msgdata,A1_BASE				;destination address
	move.l	#gmoverrm,A2_BASE				;source address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$00120030,B_COUNT				;inner loop = 18, outer loop = 48
	move.l	#$0001FFD0,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

	and.b	#$7F,message+O_TYPE		;turn on object to display message
	move.w	#GAMEOVER_XPOS,message+O_XPOS
	move.w	#GAMEOVER_YPOS,message+O_YPOS
	move.w	#GAMEOVER_DWIDTH,message+O_DWIDTH
	move.w	#GAMEOVER_DWIDTH,message+O_IWIDTH
	move.w	#GAMEOVER_HT,message+O_HEIGHT
	rts

ld_cont::
;load continue message (192 x 18)
	move.l	#PITCH1|PIXEL32|WID48|XADDPHR,d0	;description of destination area
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#msgdata,A1_BASE				;destination address
	move.l	#controm,A2_BASE				;source address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$00120030,B_COUNT				;inner loop = 18, outer loop = 48
	move.l	#$0001FFD0,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

	and.b	#$7F,message+O_TYPE		;turn on object to display message
	move.w	#CONTINUE_XPOS,message+O_XPOS
	move.w	#CONTINUE_YPOS,message+O_YPOS
	move.w	#CONTINUE_DWIDTH,message+O_DWIDTH
	move.w	#CONTINUE_DWIDTH,message+O_IWIDTH
	move.w	#CONTINUE_HT,message+O_HEIGHT
	rts

ld_pause::
;load pause message (64 x 13)
	move.l	#PITCH1|PIXEL32|WID16|XADDPHR,d0	;description of destination area
	move.l	d0,A1_FLAGS					;destination
	move.l	d0,A2_FLAGS					;source
	move.l	#msgdata,A1_BASE				;destination address
	move.l	#pauserm,A2_BASE				;source address
	move.l	#0,A2_PIXEL					;start at 0,0 of source image
	move.l	#0,A1_PIXEL					;Y,X position to write data in destination area
	move.l	#$00120010,B_COUNT				;inner loop = 18, outer loop = 16
	move.l	#$0001FFF0,A1_STEP				;1 in Y step size, negative width in X step size
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter

.if	SHOW_PAUSED = 1				;see if pause sign should be displayed
	and.b	#$7F,message+O_TYPE		;turn on object to display message
.endif
	move.w	#PAUSED_XPOS,message+O_XPOS
	move.w	#PAUSED_YPOS,message+O_YPOS
	move.w	#PAUSED_DWIDTH,message+O_DWIDTH
	move.w	#PAUSED_DWIDTH,message+O_IWIDTH
	move.w	#PAUSED_HT,message+O_HEIGHT
	rts


shot_collisions::
	lea		bullet0,a0
	lea		en_collwh,a2
	lea		en_coladd,a3			;add to enemy xpos and ypos to get edges
	lea		bulcolht,a4
	lea		bulwidth,a5
	clr.w	bulnum				;count bullets
.05:	tst.b	O_TYPE(a0)
	bmi		.90					;if negative, bullet is not active

	move.w	O_DESC(a0),d4
	bmi		.90					;if negative, bullet is an explosion
	lsl.w	#1,d4
	move.w	O_XPOS(a0),d0			;get shot xpos
	move.w	d0,d1				;xpos will be left edge
	add.w	(a5,d4.w),d0			;add amount to get right edge
	move.w	O_YPOS(a0),d2			;get shot ypos
	move.w	d2,d3				;ypos will be top edge
	add.w	(a4,d4.w),d2			;add shot height * 2 (half lines)

	lea		enemy0,a1				;first enemy object
	clr.w	d6					;count enemies
.10:
	tst.b	O_TYPE(a1)			;see if enemy is active
	bmi		.50					;check next enemy if not active
	move.w	O_DESC(a1),d5			;enemy is an explosion if >= $80
	bmi		.50
	cmp.w	#GEYSER,d5
	beq		.50					;shots don't collide with geyser
	lsl.w	#2,d5				;4 bytes for each width and height

	move.w	O_XPOS(a1),d4			;get enemy xpos
	add.w	(a3,d5.w),d4			;add amount to get left edge
	cmp.w	d0,d4				;compare shot xpos + width (d0) - overlap to enemy xpos (d4)
	bge		.50					;if enemy xpos >= shot xpos + width, exit

	add.w	(a2,d5.w),d4			;add width of enemy to its left edge
	cmp.w	d1,d4				;compare shot xpos - overlap (d1) to enemy xpos + width (d4)
	blt		.50					;if enemy xpos + width < shot xpos - overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy ypos
	add.w	2(a3,d5.w),d4			;add amount to get top edge
	cmp.w	d2,d4				;compare shot ypos + height - overlap (d2) to enemy ypos (d4)
	bge		.50					;if enemy ypos >= shot ypos + height - overlap, exit

	add.w	2(a2,d5.w),d4			;add height of enemy to its top edge (d5 is already enemy type * 4)
	cmp.w	d3,d4				;compare shot ypos - overlap (d3) to enemy ypos + height
	blt.b	.50					;if enemy ypos + height < shot ypos - overlap, exit

	lea		bull_dmg,a6
	move.w	O_DESC(a0),d5			;get bullet type
	lsl.w	#1,d5				;bullet type * 2
	move.w	(a6,d5.w),d7			;amount of damage to enemy
	bsr		damage_enemy
	cmp.w	#1,d7				;1 if enemy was destroyed
	beq.b	.40
	bsr		start_bul_exp			;change bullet into explosion
	bra.b	.90

.40:	or.b		#DELETE_OBJ,O_TYPE(a0)	;turn off bullet if enemy was destroyed
	bra.b	.90					;check next bullet
.50:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_ENEMIES,d6
	blt		.10

.90:	adda.l	#OBJ_SIZE,a0			;next bullet object
	add.w	#1,bulnum
	cmp.w	#MAX_BULLETS,bulnum
	blt		.05					;check next bullet
	rts

bomb_collisions::
	tst.b	bomb+O_TYPE
	bmi		.90					;if negative, bomb is not active
	tst.w	bomb+O_DESC
	bmi		.90
	move.w	bomb+O_XPOS,d0			;get bomb xpos
	move.w	d0,d1
	add.w	#BOMB_COLL_R,d0		;add amount to get right edge
	add.w	#BOMB_COLL_L,d1		;add amount to get left edge
	move.w	bomb+O_YPOS,d2			;get bomb ypos
	move.w	d2,d3
	add.w	#BOMB_COLL_B,d2		;add amount to get bottom edge
	add.w	#BOMB_COLL_T,d3		;add amount to get top edge
	lea		enemy0,a1				;first enemy object
	lea		en_collwh,a2
	lea		en_coladd,a3
	clr.w	d6					;count enemies
.10:
	tst.b	O_TYPE(a1)			;see if enemy is active
	bmi		.50					;check next enemy if not active
	move.w	O_DESC(a1),d5			;enemy is an explosion if >= $80
	bmi		.50
	lsl.w	#2,d5				;4 bytes for each width and height

	move.w	O_XPOS(a1),d4			;get enemy xpos
	add.w	(a3,d5.w),d4			;add amount to get left edge
	cmp.w	d0,d4				;compare bomb xpos + width (d0) - overlap to enemy xpos (d4)
	bge		.50					;if enemy xpos >= bomb xpos + width, exit

	add.w	(a2,d5.w),d4			;add width of enemy to its xpos
	cmp.w	d1,d4				;compare bomb xpos - overlap (d1) to enemy xpos + width (d4)
	blt		.50					;if enemy xpos + width < bomb xpos - overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy ypos
	add.w	2(a3,d5.w),d4			;add amount to get top edge
	cmp.w	d2,d4				;compare bomb ypos + height - overlap (d2) to enemy ypos (d4)
	bge		.50					;if enemy ypos >= bomb ypos + height - overlap, exit

	add.w	2(a2,d5.w),d4			;add height of enemy to its top edge (d5 is already enemy type * 4)
	cmp.w	d3,d4				;compare bomb ypos - overlap (d3) to enemy ypos + height
	blt.b	.50					;if enemy ypos + height < bomb ypos - overlap, exit

	move.w	#BOMB_SND,d0
	jsr		sndoffd0				;turn off bomb sound
	lea		bomb_dmg,a0
	move.w	bomb+O_DESC,d0			;get bomb type
	lsl.w	#1,d0				;bomb type * 2
	move.w	(a0,d0.w),d7			;amount of damage to enemy
	bsr		damage_enemy
	cmp.w	#1,d7				;1 if enemy was destroyed
	beq.b	.40
	move.w	#$FFFF,bomb+O_DESC		;set it to negative for explosion
	move.w	#12,bomb+O_HEIGHT
	move.w	#4,bomb+O_DWIDTH
	move.w	#4,bomb+O_IWIDTH
	move.b	#4,bomb+O_DEPTH
	move.l	#exp_a0,bomb+O_DATA
	add.w	#8,bomb+O_YPOS
	clr.b	exp_cntb				;reset explos_count for bomb
	clr.b	exp_stpb				;reset explos_step for bomb
	bra.b	.90

.40:	or.b		#DELETE_OBJ,bomb+O_TYPE	;turn off bomb if enemy was destroyed
	bra.b	.90					;check next bomb

.50:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_ENEMIES,d6
	blt		.10
.90:	rts

plr_collisions::
	cmp.w	#PLR_EXP,player+O_DESC	;see if player is playing the game
	beq		.90					;if player is an explosion or flashing, exit
	move.w	player+O_XPOS,d0		;get player xpos
	move.w	d0,d1
	add.w	#PLR_COLL_R,d0			;add amount to get right edge
	add.w	#PLR_COLL_L,d1			;add amount to get left ledge
	move.w	player+O_YPOS,d2		;get player ypos
	move.w	d2,d3
	add.w	#PLR_COLL_B,d2			;add amount to get bottom edge
	add.w	#PLR_COLL_T,d3			;add amount to get top edge

	cmp.w	#PLR_FLASH,player+O_DESC	;see if player is flashing
	beq		.75					;if player is flashing, only check for powerup collisions

	cmp.w	#SHIELD,specweap+O_DESC
	bne.b	.05					;if special weapon is not the shield, check for collisions with enemies
	tst.b	specweap+O_TYPE		;if special weapon is the shield, see if it is on
	bpl		.55					;shield is turned on, don't check enemies, but check enemy shots


.05:	lea		enemy0,a1				;first enemy object
	lea		en_collwh,a2			;table of enemy widths and heights
	lea		en_coladd,a3
	lea		en_action,a4
	clr.w	d6					;count enemies
.10:
	tst.b	O_TYPE(a1)			;see if enemy is active
	bmi.b	.20					;check next enemy if not active
	move.w	O_DESC(a1),d5			;enemy is an explosion if >= $80
	bmi.b	.20
	cmp.b	#EN_APPEAR,(a4,d6.w)
	beq.b	.20					;no collisions with player if enemy is appearing
	cmp.w	#GEYSER,d5
	bne.b	.15
	bsr		geyscoll
	cmp.w	#0,d7
	bne.b	.18
	bra.b	.20
.15:
	lsl.w	#2,d5				;4 bytes for each width and height in the table
	move.w	O_XPOS(a1),d4			;get enemy xpos
	add.w	(a3,d5.w),d4			;add amount to get left edge
	cmp.w	d0,d4				;compare player xpos + width - overlap (d0) to enemy xpos (d4)
	bge.b	.20					;if enemy xpos > player xpos + width - overlap, exit

	add.w	(a2,d5.w),d4			;add width of enemy to its xpos
	cmp.w	d1,d4				;compare player + overlap (d1) to enemy xpos + enemy width (d4)
	blt.b	.20					;if enemy xpos + width < player xpos + overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy ypos
	add.w	2(a3,d5.w),d4			;add amount to get top edge
	cmp.w	d2,d4				;compare player ypos + height - overlap to enemy ypos
	bge.b	.20					;if enemy ypos >= player + height - overlap, exit

	add.w	2(a2,d5.w),d4			;add height of enemy to its top edge (d5 is already enemy type * 4)
	cmp.w	d3,d4				;compare player ypos + overlap (d3) to enemy ypos + enemy height (d4)
	blt.b	.20					;if enemy ypos + enemy height < player ypos + overlap, exit

.18:	move.w	#PLR_COLL_DAMAGE,d7		;amount of damage to inflict on enemy
	bsr		damage_enemy
	bra		start_plr_explosion
.20:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_ENEMIES,d6
	blt		.10


	move.w	level,d4
	lea		frontcol,a1
	cmp.b	#1,(a1,d4.w)			;if 1, check for collisions with foreground objects in this level
	bne.b	.55
	cmp.w	#FINAL_LEVEL+1,level
	bne.b	.30
	bsr		rng_coll
	bra.b	.35
.30:	bsr		fr_coll
.35:	cmp.w	#1,d7
	beq		start_plr_explosion

.55:	move.w	#(MAX_ENEMY_SHOTS-1),d6	;count enemy shots
	lea		en_shot0,a1			;first enemy shot object
	lea		en_sh_width,a2			;table of shot widths
	lea		en_sh_ht,a3			;table of shot heights
.60:
	tst.b	O_TYPE(a1)			;see if enemy shot is active
	bmi.b	.70					;check next enemy shot if not active

	move.w	O_XPOS(a1),d4			;get enemy shot xpos
	cmp.w	d0,d4				;compare player xpos + width - overlap (d0) to enemy shot xpos (d4)
	bge.b	.70					;if enemy shot xpos > player xpos + width - overlap, exit

	move.w	O_DESC(a1),d5			;get enemy shot type
	lsl.w	#1,d5				;2 bytes for each width in the table
	add.w	(a2,d5.w),d4			;add width of enemy shot to its xpos
	cmp.w	d1,d4				;compare player + overlap (d1) to enemy shot xpos + shot width (d4)
	blt.b	.70					;if enemy shot xpos + width < player xpos + overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy shot ypos
	cmp.w	d2,d4				;compare player ypos + height - overlap to enemy shot ypos
	bge.b	.70					;if enemy shot ypos >= player + height - overlap, exit

	add.w	(a3,d5.w),d4			;add height of enemy shot to its ypos (d5 is already shot type * 2)
	add.w	(a3,d5.w),d4			;add height again to make it halflines
	cmp.w	d3,d4				;compare player ypos + overlap (d3) to enemy shot ypos + enemy height (d4)
	blt.b	.70					;if enemy shot ypos + shot height < player ypos + overlap, exit

	or.b		#DELETE_OBJ,O_TYPE(a1)	;turn off enemy shot
	cmp.w	#SHIELD,specweap+O_DESC
	bne		start_plr_explosion		;if special weapon is not the shield, explode player
	tst.b	specweap+O_TYPE		;if special weapon is the shield, see if it is on
	bmi		start_plr_explosion		;special weapon is the shield, but it is not turned on

.70:
	adda.l	#OBJ_SIZE,a1			;next object header
	dbra		d6,.60				;enemy shot counter

.75:
	tst.b	powerup+O_TYPE			;see if powerup is active
	bmi.b	.90					;exit if powerup is not active

	move.w	powerup+O_XPOS,d4		;get powerup xpos
	cmp.w	d0,d4				;compare player xpos + width - overlap (d0) to powerup xpos (d4)
	bge.b	.90					;if powerup xpos > player xpos + width - overlap, exit

	add.w	#16,d4				;add width of powerup to its xpos
	cmp.w	d1,d4				;compare player + overlap (d1) to powerup xpos + width (d4)
	blt.b	.90					;if powerup xpos + width < player xpos + overlap, exit

	move.w	powerup+O_YPOS,d4		;get powerup ypos
	cmp.w	d2,d4				;compare player ypos + height - overlap to powerup ypos
	bge.b	.90					;if powerup ypos >= player + height - overlap, exit

	add.w	#30,d4				;add 2 * powerup height (half lines)
	cmp.w	d3,d4				;compare player ypos + overlap (d3) to powerup ypos + height (d4)
	blt.b	.90					;if powerup ypos + height < player ypos + overlap, exit

	or.b		#DELETE_OBJ,powerup+O_TYPE	;turn off powerup
	bra		got_pwrup
.90:	rts

fr_coll::
	lea		front0,a1				;first foreground object
	clr.w	d6					;count foreground objects
.30:
	tst.b	O_TYPE(a1)			;see if object is on
	bmi.b	.40					;check next object if turned off

	move.w	O_XPOS(a1),d4			;get foreground object xpos
	add.w	#24,d4				;add something so it is harder to collide
	cmp.w	d0,d4				;compare player xpos + width (d0) to object xpos (d4)
	bge.b	.40					;if enemy xpos > player xpos + width - overlap, exit

	move.w	O_DWIDTH(a1),d7
	lsl.w	#2,d7				;dwidth * 4 = width in pixels
	add.w	d7,d4				;add width of object to its xpos
	sub.w	#48,d4				;subtract twice what was added before
	cmp.w	d1,d4				;compare player (d1) to object xpos + object width (d4)
	blt.b	.40					;if object xpos + width < player xpos, exit

	move.w	O_YPOS(a1),d4			;get object ypos
	add.w	#32,d4				;add something to it is harder to collide
	cmp.w	d2,d4				;compare player ypos + height to object ypos
	bge.b	.40					;if object ypos >= player + height, exit

	add.w	O_HEIGHT(a1),d4		;add height of object to its top edge
	add.w	O_HEIGHT(a1),d4		;add height of object again to make it half lines
	sub.w	#64,d4				;subtract twice what was added before
	cmp.w	d3,d4				;compare player ypos (d3) to object ypos + object height (d4)
	blt.b	.40
	move.w	#1,d7				;collision occurred
	rts							;return to plr_collisions
.40:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_FRONT_OBJS,d6
	blt		.30
	clr.w	d7					;no collision
	rts

rng_coll::
	lea		front0,a1				;first foreground object
	lea		rngcldta,a2
	clr.w	d6					;count foreground objects
.10:
	tst.b	O_TYPE(a1)			;see if object is on
	bmi.b	.80					;check next object if turned off
	move.w	O_DESC(a1),d7
	lsl.w	#4,d7				;object number * 16

	move.w	O_XPOS(a1),d4			;get foreground object xpos
	add.w	(a2,d7),d4			;add something so it is harder to collide
	cmp.w	d0,d4				;compare player xpos + width (d0) to object xpos (d4)
	bge.b	.40					;if object xpos > player xpos + width - overlap, exit

	add.w	2(a2,d7),d4			;add width of object to its left edge
	cmp.w	d1,d4				;compare player (d1) to object xpos + object width (d4)
	blt.b	.40					;if object xpos + width < player xpos, exit

	move.w	O_YPOS(a1),d4			;get object ypos
	add.w	4(a2,d7.w),d4			;add something to it is harder to collide
	cmp.w	d2,d4				;compare player ypos + height to object ypos
	bge.b	.40					;if object ypos >= player + height, exit

	add.w	6(a2,d7.w),d4			;add height of object to its top edge
	cmp.w	d3,d4				;compare player ypos (d3) to object ypos + object height (d4)
	bge.b	.60
.40:
	move.w	O_XPOS(a1),d4			;get foreground object xpos
	add.w	8(a2,d7),d4			;add something so it is harder to collide
	cmp.w	d0,d4				;compare player xpos + width (d0) to object xpos (d4)
	bge.b	.80					;if object xpos > player xpos + width - overlap, exit

	add.w	10(a2,d7),d4			;add width of object to its left edge
	cmp.w	d1,d4				;compare player (d1) to object xpos + object width (d4)
	blt.b	.80					;if object xpos + width < player xpos, exit

	move.w	O_YPOS(a1),d4			;get object ypos
	add.w	12(a2,d7.w),d4			;add something to it is harder to collide
	cmp.w	d2,d4				;compare player ypos + height to object ypos
	bge.b	.80					;if object ypos >= player + height, exit

	add.w	14(a2,d7.w),d4			;add height of object to its top edge
	cmp.w	d3,d4				;compare player ypos (d3) to object ypos + object height (d4)
	blt.b	.80

.60:	move.w	#1,d7				;collision occurred
	rts							;return to plr_collisions
.80:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_FRONT_OBJS,d6
	blt		.10
	clr.w	d7					;no collision
	rts

rngcldta::
	dc.w		0,105,0,50			;top of large ring
	dc.w		0,105,318,50			;bottom of large ring
	dc.w		0,79,0,34				;top of medium ring
	dc.w		0,79,206,234			;bottom of medium ring
	dc.w		0,52,0,24				;top of small ring
	dc.w		0,52,152,24			;bottom of small ring

geyscoll::
;A1 = enemy object
;A2 = en_collwh
;A3 = en_coladd
;A4 = en_action
;d6 = enemy counter
;d5 = enemy desc
	lsl.w	#2,d5				;4 bytes for each width and height in the table
	move.w	O_XPOS(a1),d4			;get enemy xpos
	add.w	(a3,d5.w),d4			;add amount to get left edge
	cmp.w	d0,d4				;compare player xpos + width - overlap (d0) to enemy xpos (d4)
	bge.b	.90					;if enemy xpos > player xpos + width - overlap, exit

	add.w	(a2,d5.w),d4			;add width of enemy to its xpos
	cmp.w	d1,d4				;compare player + overlap (d1) to enemy xpos + enemy width (d4)
	blt.b	.90					;if enemy xpos + width < player xpos + overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy ypos
	add.w	2(a3,d5.w),d4			;add amount to get top edge
	cmp.w	d2,d4				;compare player ypos + height - overlap to enemy ypos
	bge.b	.90					;if enemy ypos >= player + height - overlap, exit

	add.w	O_HEIGHT(a1),d4		;add height of enemy to its top edge (d5 is already enemy type * 4)
	add.w	O_HEIGHT(a1),d4		;add height again to make it half line
	sub.w	#30,d4				;subtract some so you don't collide with dirt part of geyser
	cmp.w	d3,d4				;compare player ypos + overlap (d3) to enemy ypos + enemy height (d4)
	blt.b	.90					;if enemy ypos + enemy height < player ypos + overlap, exit
.80:	move.w	#PLR_COLL_DAMAGE,d7
	rts							;return to plr_coll
.90:	clr.w	d7
	rts							;return to plr_coll


c_sh_col::
;collision detection for cutter shots
	lea		cutshot0,a0
	lea		en_collwh,a2
	lea		en_coladd,a3			;add to enemy xpos and ypos to get edges

.05:	tst.b	O_TYPE(a0)
	bmi		.90					;if negative, bullet is not active

	move.w	O_DESC(a0),d4
	lsl.w	#1,d4
	move.w	O_XPOS(a0),d0			;get shot xpos
	move.w	d0,d1				;xpos will be left edge
	add.w	#7,d0				;add amount to get right edge
	move.w	O_YPOS(a0),d2			;get shot ypos
	move.w	d2,d3				;ypos will be top edge
	add.w	#14,d2				;add shot height * 2 (half lines)

	lea		enemy0,a1				;first enemy object
	clr.w	d6					;count enemies
.10:
	tst.b	O_TYPE(a1)			;see if enemy is active
	bmi.b	.50					;check next enemy if not active
	move.w	O_DESC(a1),d5			;enemy is an explosion if >= $80
	bmi.b	.50
	lsl.w	#2,d5				;4 bytes for each width and height

	move.w	O_XPOS(a1),d4			;get enemy xpos
	add.w	(a3,d5.w),d4			;add amount to get left edge
	cmp.w	d0,d4				;compare shot xpos + width (d0) - overlap to enemy xpos (d4)
	bge.b	.50					;if enemy xpos >= shot xpos + width, exit

	add.w	(a2,d5.w),d4			;add width of enemy to its left edge
	cmp.w	d1,d4				;compare shot xpos - overlap (d1) to enemy xpos + width (d4)
	blt.b	.50					;if enemy xpos + width < shot xpos - overlap, exit

	move.w	O_YPOS(a1),d4			;get enemy ypos
	add.w	2(a3,d5.w),d4			;add amount to get top edge
	cmp.w	d2,d4				;compare shot ypos + height - overlap (d2) to enemy ypos (d4)
	bge.b	.50					;if enemy ypos >= shot ypos + height - overlap, exit

	add.w	2(a2,d5.w),d4			;add height of enemy to its top edge (d5 is already enemy type * 4)
	cmp.w	d3,d4				;compare shot ypos - overlap (d3) to enemy ypos + height
	blt.b	.50					;if enemy ypos + height < shot ypos - overlap, exit

	or.b		#DELETE_OBJ,O_TYPE(a0)	;turn off bullet
	move.w	#CUTR_SHOT_DMG,d7		;amount of damage to enemy
	bsr		damage_enemy
	bsr		start_bul_exp			;change bullet into explosion
	bra.b	.90					;check next bullet
.50:
	adda.l	#OBJ_SIZE,a1			;next object header
	add.w	#1,d6
	cmp.w	#TOTAL_ENEMIES,d6
	blt.b	.10

.90:	adda.l	#OBJ_SIZE,a0			;next bullet object
	cmpa.l	#cutshot0+(OBJ_SIZE*CUTR_BULLETS),a0
	bne		.05					;check next bullet
	rts


start_explosion::
;a1 points to enemy object
;d6 is the enemy number that was hit
	movem.l	a2-a4,-(sp)
	lea		exp_count,a2
	lea		exp_step,a3
	clr.b	(a2,d6.w)				;reset explos_count for this enemy
	clr.b	(a3,d6.w)				;reset explos_step for this enemy
	move.w	O_DESC(a1),d0			;get enemy type
	lea		en_expl,a4			;type of explosion for each type of enemy
	clr.w	d1
	move.b	(a4,d0.w),d1			;get explosion type
	move.w	d1,O_DESC(a1)			;get explosion type
	or.w		#$FF00,O_DESC(a1)		;set negative bit for explosion
	lea		exp_otyp,a4			;scaled or unscaled
	move.b	(a4,d1.w),O_TYPE(a1)
	move.b	#4,O_DEPTH(a1)			;set pixel depth for explosion
	lsl.w	#1,d1				;multiply explosion type * 2
	lea		exp_dw,a4				;dwidth,iwidth
	move.w	(a4,d1.w),O_DWIDTH(a1)	;set explosion dwidth
	move.w	(a4,d1.w),O_IWIDTH(a1)	;set explosion iwidth
	lsl.w	#1,d1				;change explosion type * 2 to explosion type * 4
	lea		exp_scl,a4			;scale size
	move.l	(a4,d1.w),O_SCALE(a1)
	lsl.w	#2,d1				;explosion type * 4 to explosion type * 16 (8 steps * 2 bytes per step)
	lea		exp_ht,a4
	move.w	(a4,d1.w),O_HEIGHT(a1)	;set explosion height
	lsl.w	#1,d1				;explosion type * 16 to explosion type * 32 (8 steps * 4 bytes per step)
	lea		exp_data,a4
	move.l	(a4,d1.w),O_DATA(a1)	;get address of data for first animation step
	lsl.w	#2,d0				;enemy type * 4
	lea		en_ex_pos,a4			;adjustment to hpos
	move.w	(a4,d0.w),d1
	add.w	d1,O_XPOS(a1)
	move.w	2(a4,d0.w),d1			;adjustment to ypos
	add.w	d1,O_YPOS(a1)

	move.w	O_DESC(a1),d1			;get explosion type
	and.w	#$FF,d1				;clear negative bit
	lea		exp_snd,a4			;table of sounds to play
	clr.w	d0
	move.b	(a4,d1.w),d0			;get sound number
	move.w	O_XPOS(a1),d1			;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos

	movem.l	(sp)+,a2-a4
	rts

start_plr_explosion::
.if	COLLISIONS = 0					;see if collision detection is on
	rts
.endif
	move.w	#EXPLOS0_SND,d0
	move.w	player+O_XPOS,d1		;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos
	move.w	#CAT_SND,d0
	move.w	player+O_XPOS,d1		;xpos to determine pan value
	jsr		playsnd				;d0 = sample number, d1 = sound xpos

	move.w	exp_ht+(EXP_D*16),player+O_HEIGHT		;height of player explosion object
	move.w	exp_dw+(EXP_D*2),player+O_DWIDTH		;player explosion dwidth
	move.w	player+O_DWIDTH,player+O_IWIDTH		;player explosion iwidth
	move.l	plr_exdt,player+O_DATA
	move.w	#PLR_EXP,player+O_DESC				;player object is now an explosion
	sub.w	#16,player+O_XPOS					;player 48 x 33, explosion 80 x 64
	sub.w	#62,player+O_YPOS					;player 48 x 33, explosion 80 x 64
 	clr.b	p_expcnt							;reset explosion animation counter
	clr.b	p_expstp							;reset explosion animation step
	move.w	#SHIELD_TIME,shldtime				;make sure shield will turn off
	cmp.w	#RING,specweap+O_DESC
	beq.b	.70
	cmp.w	#BEAM,specweap+O_DESC
	bne.b	.90
.70:	or.b		#DELETE_OBJ,specweap+O_TYPE			;turn off ring special weapon
.90:
	rts

start_bul_exp::
;A0 = bullet object
	move.w	#$FFFF,O_DESC(a0)		;set it to negative for explosion
	move.w	#12,O_HEIGHT(a0)
	move.w	#4,O_DWIDTH(a0)
	move.w	#4,O_IWIDTH(a0)
	move.b	#4,O_DEPTH(a0)
	move.l	#exp_a0,O_DATA(a0)
	add.w	#5,O_XPOS(a0)
	sub.w	#8,O_YPOS(a0)
	clr.b	O_FIRSTPIX(a0)
	lea		exp_cnts,a6
	lea		exp_stps,a1			;ok to change a1 now that enemy was hit
	move.w	bulnum,d0
	clr.b	(a6,d0.w)				;reset explos_count for this shot
	clr.b	(a1,d0.w)				;reset explos_step for this shot
	rts

erase_info::								;erase the icon bar and score bar
;80 x 15 for icon bar, 8 bit
;80 x 12 for score bar, 8 bit
	move.l	#PITCH1|PIXEL32|WID20|XADDPHR,A1_FLAGS
	move.l	#iconbar,A1_BASE				;destination address
	move.l	#0,A1_PIXEL					;get rectangle Y,X
	move.l	#$0001FFEC,A1_STEP				;high = Y step, low = negative width
	move.l	#$000F0014,B_COUNT				;high = height, low = width
	move.l	#0,B_PATD						;write 0's to clear the info bars
	move.l	#0,B_PATD+4
	move.l	#PATDSEL|UPDA1,B_CMD			;turn on blitter

;use same A1_FLAGS, A1_STEP, B_PATD, B_PATD+4
	move.l	#scorebar,A1_BASE				;destination address
	move.l	#0,A1_PIXEL					;get rectangle Y,X
	move.l	#$000C0014,B_COUNT				;high = height, low = width
	move.l	#PATDSEL|UPDA1,B_CMD
	rts

draw_info::
	bsr		draw_icns
	move.l	score,d0				;get current score
	cmp.l	oldscore,d0
	beq.b	.30					;don't need to draw score digits if they didn't change
	move.l	d0,oldscore			;update old score
	bsr		draw_score
.30:	rts

draw_score::
;draw score numbers
;find the first digit that is not 0 so leading 0's are not displayed
	move.l	#PITCH1|PIXEL8|WID80|XADDPIX,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL8|XADDPIX,A2_FLAGS		;description of source data
	move.l	#scorebar,A1_BASE		;destination address
	move.l	#$0001FFF6,A1_STEP		;1 for Y step, negative width for x step
	move.l	#0,d5				;Y,X position of first char
	lea		score_dec,a3			;first decimal score digit
.20:	tst.b	(a3)					;see if this digit is 0
	bne.b	.40					;this is the first non zero digit, so start printing digits
	add.l	#$0000000A,d5			;move starting x position to next digit
	adda.l	#1,a3				;point to next score digit
	cmpa.l	#score_dec+SCORE_DIGITS-1,a3	;see if we're at the last digit
	bne.b	.20					;if score is 0, print the last digit
.40:								;now d5 is X,Y of first digit to print, a3 points to first digit
	lea		num_addr,a5
.60:	clr.w	d0
	move.b	(a3)+,d0				;get score digit, increase pointer
	lsl.w	#2,d0				;4 bytes per character address
	move.l	(a5,d0.w),A2_BASE		;source address
	move.l	#$000C000A,B_COUNT		;height, width of source image
	move.l	d5,A1_PIXEL			;Y,X position in destination area
	move.l	#0,A2_PIXEL			;start at 0,0 of source image
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD	;turn on blitter
	add.l	#$0000000A,d5			;add width + space
	cmpa.l	#score_dec+SCORE_DIGITS,a3
	bne.b	.60
	rts

draw_icns::
;draw special weapon icon

	move.l	#iconbar,A1_BASE				;destination address
	move.l	#$0001FFFC,A1_STEP				;high = Y step, low = negative width
	move.l	#$000F0004,B_COUNT		;height = 15, width = 16 (4 because it blits 32 bit)
	move.l	#$0000000A,A1_PIXEL		;Y,X position in destination (actual X position is 40)
	move.w	spec_type,d0
	lsl.w	#2,d0
	lea		spec_icons,a0
	move.l	(a0,d0.w),A2_BASE		;source address
	move.l	#PITCH1|PIXEL32|WID20|XADDPHR,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL32|XADDPHR,A2_FLAGS		;description of source data
	move.l	#0,A2_PIXEL						;start at 0,0 of source image
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD		;turn on blitter

	lea		spec_tot,a0
	move.w	spec_type,d0			;get the current special weapon
	lsl.w	#1,d0
	move.w	(a0,d0.w),d0			;get the supply of the current special weapon
	lsl.w	#2,d0				;4 bytes per character address
	lea		num_addr,a5
	move.l	(a5,d0.w),A2_BASE		;source address
	move.l	#$0001003A,A1_PIXEL		;Y,X position in destination
	move.l	#$000C000A,B_COUNT		;height, width of source image
	move.l	#$0001FFF6,A1_STEP		;1 for Y step, negative width for x step
	move.l	#PITCH1|PIXEL8|WID80|XADDPIX,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL8|XADDPIX,A2_FLAGS		;description of source data
	move.l	#0,A2_PIXEL						;start at 0,0 of source image
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD		;turn on blitter
	rts

draw_lives::
	move.l	#iconbar,A1_BASE		;destination address
	move.l	#lifeicn,A2_BASE		;address of source data
	move.l	#$00000000,A1_PIXEL		;1st life icon position
	move.l	#$000F0004,B_COUNT		;height, width of source image
	move.l	#$0001FFFC,A1_STEP		;1 for Y step, negative width for x step
	move.l	#PITCH1|PIXEL32|WID20|XADDPHR,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL32|XADDPHR,A2_FLAGS		;description of source data
	move.l	#0,A2_PIXEL						;start at 0,0 of source image
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD		;turn on blitter

	lea		num_addr,a5
	clr.w	d0
	move.b	lives,d0				;get number of lives
	lsl.w	#2,d0				;4 bytes per character address
	move.l	(a5,d0.w),A2_BASE		;source address
	move.l	#$00010012,A1_PIXEL		;Y,X position in destination
	move.l	#$000C000A,B_COUNT		;height, width of source image
	move.l	#$0001FFF6,A1_STEP		;1 for Y step, negative width for x step
	move.l	#PITCH1|PIXEL8|WID80|XADDPIX,A1_FLAGS	;description of destination area
	move.l	#PITCH1|PIXEL8|XADDPIX,A2_FLAGS		;description of source data
	move.l	#0,A2_PIXEL						;start at 0,0 of source image
	move.l	#UPDA1|SRCEN|LFU_A|LFU_AN,B_CMD		;turn on blitter
	rts

addscore::
;add the value in d0 to the hex score
	add.l	d0,score
	rts

conv_score::
;score is really the current score / 10
	move.l	#16,d1				;for shifting division result
	clr.b	score_dec				;initialize millions digit
	move.l	score,d0				;get current score in hex
.10:	sub.l	#100000,d0			;see if score is over 1 million
	bmi.b	.20					;if negative, millions digit is set now
	addq.b	#1,score_dec			;increase millions digit
	bra.b	.10					;check score again 
.20:	add.l	#100000,d0			;make d0 positive again
	divu		#10000,d0				;score without millions / 100000
	move.b	d0,score_dec+1			;result is hundred thousand digit
	lsr.l	d1,d0				;move remainder from high word to low word, clear high word
	divu		#1000,d0
	move.b	d0,score_dec+2			;result is ten thousand digit
	lsr.l	d1,d0				;move remainder from high word to low word, clear high word
	divu		#100,d0
	move.b	d0,score_dec+3			;result is thousand digit
	lsr.l	d1,d0				;move remainder from high word to low word, clear high word
	divu		#10,d0
	move.b	d0,score_dec+4			;result is hundreds digit
	swap		d0					;move remainder to low word
	move.b	d0,score_dec+5			;tens digit
;ones digit is always 0
	rts

anim_explosions::
	move.w	#TOTAL_ENEMIES-1,d6
	lea		exp_count,a0
	lea		exp_step,a1
	lea		enemy0,a2				;first enemy/explosion object
	lea		exp_data,a3			;table of data addresses
	lea		exp_stp,a4			;max anim steps for type of each explosion
	lea		exp_chg,a5			;when to change exp_step
	lea		exp_ht,a6
.10:
	tst.b	O_TYPE(a2)
	bmi.b	.40					;if explosion is not active, check next one
	move.w	O_DESC(a2),d0			;enemy is an explosion if >= $80
	bpl.b	.40					;if not an explosion, skip it
	addq.b	#1,(a0)
	move.b	(a0),d2				;get exp_count
	and.w	#$FF,d0				;cancel negative bit for explosion
	cmp.b	(a5,d0.w),d2			;when to change anim step for this type of explosion
	bne.b	.30					;not time to change yet
	clr.b	(a0)					;reset exp_count
	addq.b	#1,(a1)				;increase exp_step
	move.b	(a1),d2				;get exp_step
	cmp.b	(a4,d0.w),d2			;get max anim steps for this type of explosion
	bne.b	.30
	clr.b	(a1)					;reset animation step
	move.b	#DELETE_OBJ,O_TYPE(a2)	;turn off enemy/explosion and set to unscaled object type
	clr.w	O_DESC(a2)			;make sure negative bit is turned off
	bra.b	.40
.30:
	lsl.w	#4,d0				;explosion type * 8 steps * 2 bytes per step
	clr.w	d1
	move.b	(a1),d1				;get animation step for current explosion
	lsl.b	#1,d1				;animation step * 2
	move.w	d1,d5				;save anim step * 2
	add.w	d0,d1				;add explosion type * 16 to anim step * 2
	move.w	(a6,d1.w),O_HEIGHT(a2)

	lsl.w	#1,d0				;explosion type * 8 steps * 4 bytes per step
	lsl.w	#1,d5				;change anim step * 2 to anim step * 4 bytes for each data address in table
	add.w	d0,d5				;add explosion type * 32 to anim step * 4
	move.l	(a3,d5.w),O_DATA(a2)
.40:
	adda.l	#OBJ_SIZE,a2			;next explosion object
	adda.l	#1,a0				;next exp_count
	adda.l	#1,a1				;next exp_step
	dbra		d6,.10

	move.w	#MAX_BULLETS-1,d6
	lea		exp_cnts,a0
	lea		exp_stps,a1
	lea		bullet0,a2			;first bullet/explosion object
;	lea		exp_data,a3			;table of data addresses
;	lea		exp_stp,a4			;max anim steps for type of each explosion
;	lea		exp_chg,a5			;when to change exp_step
;	lea		exp_ht,a6
.42:
	tst.b	O_TYPE(a2)
	bmi.b	.46					;if explosion is not active, check next one
	move.w	O_DESC(a2),d0			;bullet is an explosion if >= $80
	bpl.b	.46					;if not an explosion, skip it
	addq.b	#1,(a0)
	move.b	(a0),d2				;get exp_count
	cmp.b	(a5),d2				;when to change anim step for this type of explosion
	bne.b	.44					;not time to change yet
	clr.b	(a0)					;reset exp_cnts
	addq.b	#1,(a1)				;increase exp_step
	move.b	(a1),d2				;get exp_stps
	cmp.b	(a4),d2				;get max anim steps for explosion type A
	bne.b	.44
	clr.b	(a1)					;reset animation step
	or.b		#DELETE_OBJ,O_TYPE(a2)	;turn off bullet/explosion
	clr.w	O_DESC(a2)			;make sure negative bit is turned off
	bra.b	.46
.44:
	clr.w	d1
	move.b	(a1),d1				;get animation step for current explosion
	lsl.b	#1,d1				;animation step * 2
	move.w	d1,d5				;save anim step * 2
	move.w	(a6,d1.w),O_HEIGHT(a2)
	lsl.w	#1,d5				;change anim step * 2 to anim step * 4 bytes for each data address in table
	move.l	(a3,d5.w),O_DATA(a2)
.46:
	adda.l	#OBJ_SIZE,a2			;next explosion object
	adda.l	#1,a0				;next exp_cntb
	adda.l	#1,a1				;next exp_stpb
	dbra		d6,.42

;	lea		exp_data,a3			;table of data addresses
;	lea		exp_stp,a4			;max anim steps for type of each explosion
;	lea		exp_chg,a5			;when to change exp_step
;	lea		exp_ht,a6
	tst.b	bomb+O_TYPE
	bmi.b	.50					;if explosion is not active, check next one
	move.w	bomb+O_DESC,d0			;bomb is an explosion if >= $80
	bpl.b	.50					;if not an explosion, skip it
	addq.b	#1,exp_cntb
	move.b	exp_cntb,d2			;get exp_count
	cmp.b	(a5),d2				;when to change anim step for this type of explosion
	bne.b	.50					;not time to change yet
	clr.b	exp_cntb				;reset exp_cntb
	addq.b	#1,exp_stpb			;increase exp_step
	move.b	exp_stpb,d2			;get exp_stpb
	cmp.b	(a4),d2				;get max anim steps for explosion type A
	bne.b	.48
	clr.b	exp_stpb				;reset animation step
	or.b		#DELETE_OBJ,bomb+O_TYPE	;turn off bomb/explosion
	bra.b	.50
.48:
	clr.w	d1
	move.b	exp_stpb,d1			;get animation step for current explosion
	lsl.b	#1,d1				;animation step * 2
	move.w	d1,d5				;save anim step * 2
	move.w	(a6,d1.w),bomb+O_HEIGHT
	lsl.w	#1,d5				;change anim step * 2 to anim step * 4 bytes for each data address in table
	move.l	(a3,d5.w),bomb+O_DATA

.50:
	tst.b	gameover
	bne		.90					;don't animate player explosion if game has ended
	cmp.w	#PLR_EXP,player+O_DESC
	bne		.90					;if player is not an explosion, exit
	addq.b	#1,p_expcnt
	cmp.b	#PLR_EXPLOS_CHANGE,p_expcnt
	bne		.80
	clr.b	p_expcnt
	addq.b	#1,p_expstp
	cmp.b	#PLR_EXPLOS_STEPS,p_expstp
	bne.b	.80
	clr.b	p_expstp				;reset animation step
	or.b		#DELETE_OBJ,player+O_TYPE	;turn off player until he is ready to reappear
	tst.b	lives
	bne.b	.70

	move.b	#1,gameover			;turn on game over flag
	clr.b	cont_cnt				;reset continue sign counter
	clr.b	cont_sign				;set to game over sign
	clr.b	cont_del				;delay before you can continue
	bsr		ld_gmovr
	clr.w	scrlspd
	clr.w	scrlspdf
	move.w	#CUTR_TIME,cutrtime		;make cutter leave
	bsr		bssndoff				;turn off boss sounds
	rts

.70:	bsr		init_plr
	move.w	#PLR_FLASH,player+O_DESC	;player ready to return from explosion
	clr.b	plrflash				;reset player flash timer
	sub.b	#1,lives
	bsr		draw_lives
	rts
.80:	clr.w	d0
	move.b	p_expstp,d0			;get animation step for current explosion
	lsl.b	#1,d0				;animation step * 2
	move.w	d0,d5				;save anim step * 2
	add.w	#(EXP_D*16),d0			;add explosion type * 16 to anim step * 2
	move.w	(a6,d0.w),player+O_HEIGHT
	lsl.w	#1,d5				;change anim step * 2 to anim step * 4 bytes for each data address in table
	add.w	#(EXP_D*32),d5			;add explosion type * 32 to anim step * 4
	move.l	(a3,d5.w),player+O_DATA

.90:	rts

