; various bits of code which have almost nothing to do with drones !

maxturn equ 1
dronek	equ	14000
droneq	equ	40000

.text

.if 0
Drone::	movem.l	d0-d4/a0,-(sp)
	tst.b	dronef.w
	beq	dex
	move.l	Dronea.w,a0	; address of list of white lines
	move.l	Dronec.w,d0	; drone item counter
	move.l	(a0)+,d1	; get limit for white lines
	asl.l	#5,d0		; scale offset to current 'next' target
	add.l	d0,a0		; apply offset
	move.l	d1,d0		; keep limit in d0
	subq.l	#1,d0		; reduce limit

.lp:	move.l	12(a0),d3	; true x offset
	move.l	20(a0),d4	; true z offset
	sub.l	xstart.w,d3
	sub.l	zstart.w,d4

	move.l	d3,d1
	move.l	d4,d2

	cmp.l	#dronek,d3
	bpl.b	nnext
	cmp.l	#dronek,d4
	bpl.b	nnext
	muls	d1,d1		; generate squared distance
	muls	d2,d2
	add.l	d2,d1
	cmp.l	#dronek*dronek,d1	; test for total 10000 distance
	bpl.b	nnext
	lea	32(a0),a0	; move to next object#
	move.l	Dronec.w,d1	; get current value
	addq.l	#1,d1
	cmp.l	d1,d0
	bmi.b	reset
.sok:	move.l	d1,Dronec.w
	bra	.lp		; try for next one being far enough away

nnext:	bsr	get_atan		; find arctan

	move.l	rstart.w,d1
	sub.w	d1,d0
	beq.b	.ok
	asr.w	#2,d0
	ext.w	d0
	asr.w	#2,d0
	bne.b	.ok
	moveq.l	#1,d0
.ok:	add.w	d1,d0
	and.w	#$3FF,d0	; fix to 10 bits
	move.l	d0,rstart.w	; and store
	bsr	get_sine	; update vectors
	move.l	xstart.w,d3	; get position again
	move.l	zstart.w,d4	; 
	muls	framect.w,d1
	muls	framect.w,d2
	asr.l	#7,d1
	asr.l	#7,d2
	add.l	d1,d3
	add.l	d2,d4
	move.l	d3,xstart.w
	move.l	d4,zstart.w
	movea.l	carsad.w,a0	; get address of drone car storage
	lea	32(a0),a0
	neg.w	d0
	move.w	d0,6(a0)
	move.l	d3,12(a0)
	move.l	d4,20(a0)
dex:	movem.l	(sp)+,d0-d4/a0
	rts

reset:	move.l	drx.w,xstart.w
	move.l	drz.w,zstart.w
	move.l	drr.w,rstart.w
	clr.l	Dronec.w
	bra	nnext	
.endif

find_segment_any::		; version for finding a segment number for a general car [for use in ai]
	move.l	12(a1),xstart.w
	move.l	20(a1),zstart.w
	movea.l	Genstr+20+(8*str_track),a0
	movem.l	d0-d6,-(sp)	; special version of search routine, uses pre-calculated knowledge of a close distance, to reduce checks
	move.l	d3,d5
	bra.b	go

findcl:	movem.l	d0-d6,-(sp)	; takes a0 as input, pointing to the list, and xstart/zstart as the position
	move.l	#$10000000,d5
go:	move.l	xstart.w,d3	; get position again
	move.l	zstart.w,d4	; 

	move.l	a0,-(sp)
	move.l	(a0)+,d0	; get limit for count down
	subq.l	#1,d0
	moveq.l	#0,d6		; to prevent wierd jumps through space
.lp:	move.l	d3,d1
	sub.l	12(a0),d1
	bpl.b	.nn1
	neg.l	d1
.nn1:	cmp.l	d1,d5
	ble.b	.out

	move.l	d4,d2
	sub.l	20(a0),d2
	bpl.b	.nn2
	neg.l	d2
.nn2:	cmp.l	d2,d5
	ble.b	.out

	cmp.l	d1,d2
	bpl.b	.ne
	exg	d1,d2
.ne:	asr.l	#1,d1
	add.l	d2,d1		; a 'weak' estimate of distance, but consistent

	cmp.l	d1,d5
	bmi.b	.out
	move.l	d1,d5
	move.l	d0,d6

	cmpi.l	#9000,d1	; check against the proposed auto-minimum value
	blt.b	.fin

.out:	lea	32(a0),a0
	dbra	d0,.lp

.fin:	move.l	(sp)+,a0
	move.l	(a0)+,d0

	move.l	d5,dh.w
	sub.l	d6,d0
	subq.l	#1,d0
	move.l	d0,Dronec.w
	asl.l	#5,d0
	adda.l	d0,a0
	move.l	12(a0),xstart.w
	move.l	20(a0),zstart.w
	move.l	6(a0),rstart.w
	movem.l	(sp)+,d0-d6
	rts

;============================================

point_at_car:
	moveq	#0,d0
	movea.l	carsad.w,a1		; points at the list of all cars
	move.b	grid_position.w,d0	; players car number is now grid position - colour is independent
	asl.w	#5,d0			; scale up
	adda.w	d0,a1			; finalise pointer
	rts

find_near_to_car:
	bsr	point_at_car
	move.l	12(a1),xstart.w
	move.l	20(a1),zstart.w
	move.l	Dronea.w,a0	; address of list of white lines
	bsr	findcl			; finds centre line nearest to (xstart,zstart)
	rts				; and returns position thereof in (xstart,zstart)

find_track_segment:
	bsr	point_at_car
	move.l	12(a1),xstart.w
	move.l	20(a1),zstart.w
	movea.l	Genstr+20+(8*str_track),a0		; address of list of track segments
	bsr	findcl			; finds track segment nearest to (xstart,zstart)
	rts				; and returns position thereof in (xstart,zstart)
					; also returns count for the segment in Dronec
					; and returns address of the 3d object (track segment) in a0

seg_distance:
	move.l	d0,-(sp)
	asl.w	#5,d0			; scale segment number up
	move.l	12(a0,d0.w),d1		; read segment x
	move.l	20(a0,d0.w),d0		; and segment z
	sub.l	12(a1),d1		; deduct car x
	bpl.b	.nn1
	neg.l	d1			; make absolute
.nn1:	sub.l	20(a1),d0		; similarly z
	bpl.b	.nn2
	neg.l	d0
.nn2:	cmp.l	d0,d1			; want to halve the smaller one
	bpl.b	.nsw
	exg	d0,d1			; swap if d1 smaller
.nsw:	lsr.l	d0			; halve
	add.l	d0,d1			; add on for final 'distance'
	move.l	(sp)+,d0
	rts

faster_find_segment:
	movem.l	d0-d4/a0,-(sp)
	move.w	current_segment.w,d0	; get segment number currently held
	movea.l	Genstr+20+(8*str_track),a0		; address of track list
	move.l	(a0)+,d2		; limit - make sure don't overrun or underrun
	bsr	seg_distance
	move.l	d1,d3			; keep distance for first (current) one
	subq.w	#1,d0			; try for previous segment
	bpl.b	.nowr
	add.w	d2,d0			; extend so that element -1 goes to last element
.nowr:	bsr	seg_distance
	move.l	d1,d4			; keep in case its the second 
	move.w	d0,second_segment.w
	cmp.l	d1,d3
	bmi.b	.nonr
	move.l	d3,d4			; if replacing neearest, then previous one becomes second
	move.w	current_segment.w,second_segment.w
	move.l	d1,d3
	move.w	d0,current_segment.w
.nonr:	addq.w	#2,d0			; start on next segment
	cmp.w	d2,d0
	bmi.b	.noos
	sub.w	d2,d0
.noos:	bsr	seg_distance
	cmp.l	d1,d3			; this time check for nearest first
	bmi.b	.nore
	move.l	d3,d4			; if nearer, then nearest becomes second
	move.w	current_segment,second_segment.w
	move.l	d1,d3
	move.w	d0,current_segment.w
	bra.b	.n2			; and we needn't worry about additional compares
.nore:	cmp.l	d1,d4			; check for second nearest if it wasn't nearest
	bmi.b	.n2
	move.l	d1,d4
	move.w	d0,second_segment.w
.n2:	cmpi.l	#20000,d3		; check distance
	bmi.b	.ok
	border	sky
	bsr	find_segment_any	; if too far away do a full check
	move.l	dh.w,d3
	border	white
	move.w	Dronec+2.w,current_segment.w
.ok:	move.l	d3,dh.w				; final separation value
	move.l	current_segment.w,Dronec+2.w	; final closest segment
	movem.l	(sp)+,d0-d4/a0
	rts

; explanation for curr-twist :
; when in inside view, the car has to be kept as near as possible flat, whilst
; when in outside view it simply stays level with the ground, and so needs no twist
; however, the twist applied must only ever take the form of an adjustment, because
; the actual twist of the car can be modified elsewhere - or at least could be.
; Thus, when the cockpit view is entered, the curr_twist is initialised to 0,
; and any changes are made to this.  So then when cockpit is left, we can just remove
; the effect of these cumulative changes.


write_twist:
	move.w	twdir.w,d0		; get twist direction
	sub.w	6(a1),d0		; subtract cars angle
	asl.w	#6,d0			; scale up to make 16bit
	move.w	d0,d2			; copy for use in tilt calcs
	asr.w	#6,d0			; extend so that $300 is in fact -$100
	bpl.b	.nn
	neg.w	d0			; get absolute angle
.nn:	sub.w	#$100,d0		; turn range 0-$200 into -$100 to +$100 (angular distance from direction of twist)
	move.w	twist.w,d1		; take twist amount
	muls	d1,d0			; multiply to give twist amount to apply
	asr.l	#8,d0			; scale down to sensible size
	asr.l	#3,d0
	tst.l	viewmove.w		; check for cockpit view
	beq.b	.norm

 ;	asr.w	#1,d0			; if in cockpit, half the twist output value
 ;	move.w	d0,d1			; copy for deducting from cars twist to prevent separation
;	asr.w	#2,d1			; quarter the copy amount - allow 25% freedom
;	sub.w	d0,d1			; gives -3/4 twist
 ;	neg.w	d1			; -twist because it works opposite way, instead of -3/4
 ;	sub.w	curr_twist.w,d1		; calc 'change' because cars twist can be changed by other routines
 ;	add.w	d1,10(a1)		; apply change
 ;	add.w	d1,curr_twist.w		; record modification
	moveq	#0,d0			; new to prevent nose shifts - NO TWIST in cockpit view
	asr.w	#2,d1			; also halve the up/down bit

.norm:	move.w	d0,Genstr+4		; write out actual twist amount

	add.w	#$100<<6,d2		; tilt calculation works off separate value
	asr.w	#6,d2			; unscale
	bpl.b	.nn2
	neg.w	d2			; absolute
.nn2:	sub.w	#$100,d2		; adjust
	muls	d1,d2			; multiply
	asr.l	#8,d2			; rescale
	asr.l	#3,d2
	sub.w	#$28,d2			; adjust
	tst.b	tview.w			; if in top view then no changes

	bne.b	.nc
	tst.l	viewmove.w
	beq.b	.noadd
	add.w	#$18,d2
.noadd:	move.w	d2,Genstr		; tilt view down as well
.nc:	tst.l	viewmove.w
	bne.b	.exit

	move.w	curr_twist.w,d0		; reset values if no longer in cockpit view
	sub.w	d0,10(a1)
	clr.w	curr_twist.w
.exit:	rts

update_targets:
	move.w	last_segment.w,d1
	move.w	twist_segment.w,d0	; get segment number
	cmp.w	d0,d1			; if no change then no change (!)
	beq.b	.exit
	move.w	d0,last_segment.w	; keep current as last
	asl.w	#3,d0
	movea.l	#track_table,a2
	move.w	(a2,d0.w),d1		; read twist target
	asl.w	#4,d1
	cmp.w	#5,view_last.w
	bne.b	.ok
	asr.w	#1,d1			; halve target when in view 5

.ok:	move.w	d1,twist_tgt.w		; store (modified) target
	sub.w	twist.w,d1		; generate increment value
	move.w	d1,twist_inc.w		; and store

	move.w	2(a2,d0.w),d1
	move.w	d1,twdir_tgt.w		; likewise for direction
	sub.w	twdir.w,d1
	move.w	d1,twdir_inc.w
.exit:	rts


update_values:
	movem.l	d0-d2,-(sp)
	move.w	twist.w,d2
	sub.w	twist_tgt.w,d2		; get current distance from target
	bpl.b	.nn1
	neg.w	d2			; make absolute
.nn1:	move.l	speed.w,d0
	move.w	twist_inc.w,d1
	muls	d0,d1
	swap	d1			; calc increment to apply
	add.w	twist.w,d1		; calc new twist
	move.w	d1,twist.w		; store it
	sub.w	twist_tgt.w,d1		; get new distance from target
	bpl.b	.nn2
	neg.w	d1			; make absolute
.nn2:	cmp.w	d1,d2			; see if old one is bigger than new (which it should be)
	bgt.b	.ok1
	move.w	twist_tgt.w,twist.w	; if not, then make target value the new value
	clr.w	twist_inc.w		; and remove the increment amount

.ok1:	move.w	twdir_inc.w,d1		; not currently bothering about target dir over-running, but probably should
	muls	d0,d1
	swap	d1
	add.w	d1,twdir.w

	movem.l	(sp)+,d0-d2
	rts

prevent_off_road:
	move.l	d0,-(sp)
	move.l	dh.w,d0
	cmp.l	#45000,d0		; test 
	blt.b	.ok

	move.l	#1,colhlt.w
	clr.l	speed.w
	clr.w	revs.w
	move.b	#1,gear.w
	st.b	god.w

.ok:	move.l	(sp)+,d0
	rts

test_twist::
	tst.b	game_over.w		; don't mess things up if the car has just finished
	bne.b	.ex
	move.w	twist_segment.w,current_segment.w
	bsr	faster_find_segment	; gets nearest piece to wherever a1 is pointing
	bsr	prevent_off_road
	move.w	current_segment.w,twist_segment.w
	bsr	update_targets		; changes target values if nearest piece has changed
	bsr	update_values		; applies increments
	bsr	write_twist		; converts values and applies to 3d world
.ex:	rts


off_track_test::			; computes distance from car pointed to by a1, and the two segments enumerated in twist_segment and second_segment
	movem.l	d0-d5/a0,-(sp)
	move.w	twist_segment.w,d0
	cmp.w	pit_end.w,d0
	ble	.fail
	cmp.w	pit_start.w,d0
	bge	.fail

	move.w	second_segment.w,d1
	cmp.w	d0,d1
	beq	.fail			; must return a zero distance

	asl.w	#5,d0
	asl.w	#5,d1
	movea.l	Genstr+20+(8*str_track),a0		; address of track list
	addq.l	#4,a0
	move.l	20(a1),d2		; Py
	sub.l	20(a0,d0),d2		; Py-Ay
	move.l	12(a1),d3		; Px
	sub.l	12(a0,d0),d3		; Px-Ax

	move.l	12(a0,d1),d4		; Bx
	sub.l	12(a0,d0),d4		; Bx-Ax

	move.l	20(a0,d1),d5		; By
	sub.l	20(a0,d0),d5		; By-Ay

	muls	d4,d2
	muls	d5,d3
	sub.l	d3,d2			; 2 * triangle area
	beq.b	.fail			; if zero, skip the slow(er) bit
	bpl.b	.ok
	neg.l	d2

.ok:	tst.l	d4			; make line end separations absolute
	bpl.b	.nn1
	neg.l	d4
.nn1:	tst.l	d5
	bpl.b	.nn2
	neg.l	d5

.nn2:	cmp.l	d4,d5			; test for larger (going to do fast approximation to length)
	blt.b	.nex
	exg	d4,d5
.nex:	asr.l	#1,d5
	add.l	d5,d4
	beq.b	.fail

	divu	d4,d2			; only low word is valid (rest is remainder)

	move.w	track_width.w,d0
	cmp.w	d0,d2			; check against current limit

	ble.b	.fail
	tas	off_track.w
	bne.b	.out			; only mess stuff around when first hit grass

	move.w	revs.w,d0
	asr.w	#4,d0
	move.w	slow_amount.w,d1
	mulu	d1,d0
	move.w	d0,revs.w
	move.l	speed.w,d0
	asr.l	#4,d0
	mulu	d1,d0
	move.l	d0,speed.w	
	bra.b	.exit

.out:	move.w	revs.w,d0
	asr.w	#4,d0
	sub.w	d0,revs.w
	move.l	speed.w,d0
	asr.l	#4,d0
	sub.l	d0,speed.w

.exit:	movem.l	(sp)+,d0-d5/a0
	rts

.fail:	clr.b	off_track.w
	clr.w	grass_count.w
	bra.b	.exit



