;===============================================
;	ROUTINES FOR MOVEMENT AND CONTROL
;===============================================

in			equ	1
out			equ	0
right			equ	0
left			equ	1
manual			equ	1
automatic		equ	0
down_revs_per_tick	equ	1000
wheel_base		equ	1500

swing_speed		equ	80	;32
return_speed		equ	160	;80
swing_angle_limit	equ	20	; put any figure here in degrees
swing_limit		equ	swing_angle_limit * 16384 / 360	

tight			equ	1	;2
standard		equ	1	;2
loose			equ	1	;2


.text

do_dennis_routines::
	tst.b	pre_race.w
	bne.b	.e1
	bsr	test_if_car_in_collision; both checks for crashes and performs all necessary math
.e1:	bsr	get_controls		; check key presses
	tst.b	pre_race.w
	bne.b	.e2
	bsr	get_gear_offset		; calculate offset value for gear-referenced tables
	bsr	do_steering		; check steering keys and modify directions etc
.e2:	bsr	do_gears
	tst.b	pre_race.w
	bne.b	.e3
	bsr	calculate_speed_of_car
	bsr	calculate_true_speed
;	bsr	get_yaw_velocity	; value generated is never used anyway
.ok:	bsr	turn_car
	bsr.b	switch_skids
.e3:	bsr 	do_engine_sound
	bsr	do_swing_camera
;	trace.w	#"St"
;	trace.w	steer.w
.ex:	rts

switch_skids:				; used
	move.w	speed+2.w,d1
	cmpi.w	#5250,d1		; 5250 = 44 mph
	blt.b	.not
	muls	steer.w,d1
	bpl.b	.nn
	neg.l	d1
.nn:	cmpi.l	#200000,d1		; ie full steer at 44 mph
	blt.b	.not

	tst.l	skidfx.w
	bne.b	.ok

	sfx	skid,$2fff
	move.l	d0,skidfx.w
	rts

.not:	tst.b	short_skid.w
	beq.b	.kil
	clr.b	short_skid.w
	bra.b	.ok

.kil:	move.l	skidfx.w,d0
	beq.b	.ok
	kill_sfx
	clr.l	skidfx.w
.ok:	rts

test_if_car_in_collision:		; used
;	move.l	joy_edge.w,d0
;	btst.l	#KEY_7,d0
;	beq.b	.f1
;	addq.w	#1,crash_type.w
;	andi.w	#15,crash_type.w 	;@ prevent wrap
.f1:	tst.b	start_crash.w		;@ THIS SECTION REORDERED
	bne.b	initialise_crash_routine;@ test for initialise first, so that crash flag (direction) can be set in advance
	tst.b	crash_flag.w		;@ 
	bne.b	continue_crash		;@ if not start, then either no crash or a continuation
	rts


initialise_crash_routine:		; used
	clr.b	start_crash		;@ new
;@	clr.l	revs
;@	clr.l	speed
;@	move.b	#1,gear
	move.w	6(a1),car_direction.w	;@
	move.l	#KEY_S0H|ANY_JOY|PAUSEx,d0
	move.l	d0,key_mask.w		;@ prevent any user interaction during crash sequence
	and.l	d0,joy_cur.w
	and.l	d0,joy_edge.w		; thereby killing any pending key presses !!!

	bsr 	do_engine_sound
	moveq	#15,d1
	and.w	crash_type.w,d1
	asl.w	#2,d1
	move.l	#crash_list,a4
	move.l	(a4,d1.w),a5
	bsr	Zap_shadow

	tst.w	spark_count.w		; only trigger sparks if not already running
	bne.b	.nsp
	addq.w	#1,spark_count.w

.nsp:	bra.b	spin_car

continue_crash:				; used
	move.l 	crash_pointer.w,a5
	cmp.w	#$8000,(a5)
	beq.b	terminate_crash
	cmp.w	#$8002,(a5)
	bne.b	spin_car
	bsr	return_control
spin_car::
	cmp.b	#2,crash_flag.w
	beq.b	spin_right
spin_left:				; used
t1:	move.w	(a5)+,d1
	move.w	(a5)+,d2
	move.w	(a5)+,d3
	move.w	(a5)+,d4
	add.w	d1,10(a1)		;roll
	add.w	d2,2(a1)		;pitch
	ext.l	d4
	move.l	d4,16(a1)		;height
	move.l	a5,crash_pointer.w
	and.w	viewmove.w,d3		;yaw only used when in cockpit
	add.w	d3,6(a1)		; safe - cockpit only
	sub.w	d3,Genstr+2
	rts

spin_right:				;used
	move.w	(a5)+,d1
	move.w	(a5)+,d2
	move.w	(a5)+,d3
	move.w	(a5)+,d4
	sub.w	d1,10(a1)		;roll
	add.w	d2,2(a1)		;pitch
	ext.l	d4
	move.l	d4,16(a1)		;height
	move.l	a5,crash_pointer.w
	and.w	viewmove.w,d3		;yaw only used in cockpit
	sub.w	d3,6(a1)		; safe - cockpit only
	add.w	d3,Genstr+2
	rts

terminate_crash:			; used
	tst.b	out_of_control.w 	;@ changed to work better with my stuff
	bne.b	.nokey		 	;@
	moveq	#-1,d1		 	;@
	move.l	d1,key_mask.w	 	;@ re-engage keys
.nokey:	moveq	#0,d1		 	;@
	move.b	d1,crash_flag.w	 	;@
;	move.w	last_view,d1
;	bsr	Request_viewpoint	;@ was dennis_view
	bsr.b	prevent_sideways
	rts

prevent_sideways:
.if 0			; change such that there is no loss of speed associated with direction change during a crash
	move.w	6(a1),d1
	sub.w	car_direction.w,d1	;@ get difference from original direction to new one
	asl.w	#6,d1			;@
	asr.w	#6,d1			;@ extend so that value is -$200 to $200
	bpl.b	.nn			;@
	neg.w	d1			;@ make absolute
.nn:	cmpi.w	#$c0,d1			;@ check that is not too far away from original
	bmi.b	.ok			;@
	move.b	#1,gear.w		;@
	clr.w	revs.w			;@ if it is, stop the car, so as to prevent strange looking drifts
.endif
;	trace.w	#'Ze'
;	trace.w	car_direction.w
;	trace.w	6(a1)
;	trace.w	d1
	move.w	6(a1),car_direction.w	; makes any new acceleration in right direction
.ok:	bsr	Unzap_shadow		; want shadow back regardless
	rts

return_control::			; used
	addq.l	#2,a5			; skip marker
;	tst.b	out_of_control.w
;	bne.b	exit
;	move.l	#(ANY_FIRE|PAUSEx|KEY_S0H|ANY_JOY),d1
	moveq	#-1,d1
	move.l	d1,key_mask.w
	bsr	prevent_sideways
exit:	rts

do_swing_camera::			; used
	tst.b	camera_lock_switch	; check in case want no return
	bne	exit			; quit when no changes required [for end of race sequence]
	move.l	joy_cur.w,d0		; read joystick
	moveq	#0,d2			; initialise the change amount to 0
	moveq	#0,d3			; make a 'limit' value which also is initialised to zero
	move.w	swing_camera.w,d1	; test current setting

	beq.b	no_limits		; no need to check if currently 0, since won't over-shoot in one frame
	bmi	currently_left

	cmp.w	#swing_limit,d1
	bgt.b	cut_fast_to_limit

	tst.l	speed.w
	beq.b	.od
	btst	#JOY_RIGHT,d0
	bne.b	allow_up_to_limit
.od:	btst	#JOY_LEFT,d0
	bne.b	cut_fast_to_0

	move.w	#-return_speed,d2
	bra.b	apply_to_lower_limit

no_limits:
	tst.l	speed.w
	beq.b	.od
	btst	#JOY_LEFT,d0
	bne	allow_down_to_limit
	btst	#JOY_RIGHT,d0
	bne.b	allow_up_to_limit
.od:	moveq	#0,d1
	bra.b	output

cut_fast_to_0:
	move.w	#-return_speed-swing_speed,d2
	bra.b	apply_to_lower_limit

allow_up_to_limit:
	move.w	#swing_speed,d2
	move.w	#swing_limit,d3
	bra.b	apply_to_upper_limit

cut_fast_to_limit:
	move.w	#swing_limit,d3
	btst	#JOY_RIGHT,d0
	bne.b	less_rapid_cut
	btst	#JOY_LEFT,d0
	bne.b	more_rapid_cut

	move.w	#-return_speed*2,d2
	bra.b	apply_to_lower_limit

less_rapid_cut:
	move.w	#-(return_speed*3/2),d2
	bra.b	apply_to_lower_limit

more_rapid_cut:
	move.w	#-return_speed*3,d2
	bra.b	apply_to_lower_limit

apply_to_upper_limit:
	muls	framect.w,d2
	asr.w	#2,d2
	add.w	d2,d1
	cmp.w	d1,d3
	bge.b	output
	move.w	d3,d1
output:	move.w	d1,swing_camera.w
	asr.w	#4,d1
	move.w	d1,swing_camera_angle.w
	rts

apply_to_lower_limit:
	muls	framect.w,d2
	asr.w	#2,d2
	add.w	d2,d1
	cmp.w	d1,d3
	ble	output
	move.w	d3,d1
	bra	output

currently_left:
	cmp.w	#-swing_limit,d1
	blt.b	up_fast_to_limit

	tst.l	speed.w
	beq.b	.od
	btst	#JOY_LEFT,d0
	bne.b	allow_down_to_limit
.od:	btst	#JOY_RIGHT,d0
	bne.b	up_fast_to_0

	move.w	#return_speed,d2
	bra.b	apply_to_upper_limit

up_fast_to_0:
	move.w	#return_speed+swing_speed,d2
	bra.b	apply_to_upper_limit

allow_down_to_limit:
	move.w	#-swing_speed,d2
	move.w	#-swing_limit,d3
	bra.b	apply_to_lower_limit

up_fast_to_limit:
	move.w	#-swing_limit,d3
	btst	#JOY_RIGHT,d0
	bne.b	less_rapid_up
	btst	#JOY_LEFT,d0
	bne.b	more_rapid_up

	move.w	#return_speed*2,d2
	bra.b	apply_to_upper_limit

less_rapid_up:
	move.w	#return_speed*3/2,d2
	bra.b	apply_to_upper_limit

more_rapid_up:
	move.w	#return_speed*3,d2
	bra.b	apply_to_upper_limit





turn_car::				; used
	bsr	roll_wheels
	tst.w	steer.w
	beq	not_turning
	bsr	get_original_degrees_to_turn
;	bsr	get_alternative_degrees_to_turn
 	rts

;brdr	equ	$20			; braking when drifting (no acceleration or braking)
brdr	equ	133			; braking when drifting (no acceleration or braking);test
brin	equ	66			; initial braking when first hit brake	
brst	equ	41			; step per frame
brmax	equ	300			; limit of braking

get_lateral_acceleration::		; used
	move.l	speed.w,d1		; maximum value < $6000
	move.l	d1,d2
	mulu	d1,d2			; V^2 < $24000000
	move.l	d2,d3			; d3=(speed/2)^2 as above
	lsr.l	#7,d3
	lsr.l	#6,d3			; div $4000, don't know why, but it gives maximum $9000
	mulu	understeer.w,d3 	; understeer is $9a4c, so could be $56cac000 - still no overflow !
	add.l	#11211200,d3		;d3=(g*l)+kus*(speed/2)2/$4000

;	lsr.l	#5,d3
;	lsr.l	#5,d3			;div $400

	swap	d3			; equivalent to div $10000 or $40 times previous amount
;	ext.l	d3			; giving max $56ca
	beq.b	.fail

	divu	d3,d2			; max $6a30
;	asr.w	#2,d2
	muls	steer.w,d2		; signed because of steering angle
	divs	#81<<4,d2		;20,d2	;steering 0-$400 and radians 57.3 / 2
	rts				;d2=lateral acceleration

.fail:	moveq	#50,d2
	rts

get_lateral_movement:			; used
	move.w	car_sine.w,d3
	move.w	car_cos.w,d4
	muls	d2,d3			;lateral z
	muls	d2,d4			;lateral x
	asr.l	#7,d3
	asr.l	#7,d3
	asr.l	#7,d4
	asr.l	#7,d4
t3:	move.l	d3,lateral_z.w
	move.l	d4,lateral_x.w
	rts

move_car_to_new_car_x_z:		; used
t6:	move.l	z_offset.w,d4
	add.l	lateral_z.w,d4
	move.l	20(a1),d0
	add.l	d4,d0
	move.l	d0,20(a1)		;car z
	move.l	d0,Gpu_zpos

	move.l	x_offset.w,d5
	add.l	lateral_x.w,d5
      	move.l	12(a1),d0		; get car x-coordinate
	add.l	d5,d0
	move.l	d0,12(a1)		;car x
	move.l	d0,Gpu_xpos

	tst.l	viewmove.w		; check whether to make viewpoint follow same path as car (ie in-cockpit view)
	beq.b	.exit			; no changes if in outside view, as camera view is recalculated every frame

	add.l	d5,Genstr+12		; modify position of camera
	add.l	d4,Genstr+20

.exit:	rts

calculate_true_speed:			; used
	move.w	speed+2.w,d1
	lsr.w	#4,d1
	mulu	framect.w,d1

	move.l	splim.w,d0		; RCD modification -
	cmp.w	d0,d1			; stops car in event of collision
	blo.b	.ok			; against the object hit,
	move.l	d0,d1			; and also clears to zero
;	clr.l	speed.w			; the speed
;	clr.w	revs.w			; the revs
;	move.b	#1,gear.w		; and resets the gear
.ok:	move.w	d1,true_speed.w
	add.l	#1100,d1		;@ CHANGED THIS VALUE TO NEW CAR SIZE 6-6-94
;	asl.l	#1,d1			; changed to double Aug 94, to try to combat wierd collisions, removed again to stop frame rate dying
	move.l	d1,Gpu_dist
	rts

get_original_degrees_to_turn:		; used
	bsr	get_car_turning_radius
	bsr	calculate_degrees_to_move
	tst.w	d4
	beq	not_turning
	bsr	calculate_new_car_x_z
	bsr	get_lateral_acceleration
	bsr	get_lateral_movement
	bsr	calc_sideways_effect	; special from collisions
	bsr	move_car_to_new_car_x_z
	rts

calc_sideways_effect::			; used
	tst.w	sidecount.w
	beq.b	.ok
	subq.w	#1,sidecount.w
.if	Trace_on=1
	bne.b	.st			; debug code only
	trace.w	#0
	trace.w	#'So'
	trace.l	#0
.endif
.st:	move.w	sideways.w,d0
	trace.w	#'Si'
	trace.w	d0
	asr.w	sideways.w
	add.w	d0,tcx.w
.ok:	rts

get_car_turning_radius:			; used
	move.w	steer.w,d0
	beq.b	.fail			; ZERO PROTECTION
	bsr	get_sine; get sine and cosine d1=sine d2=cosine
	move.l	#2288*$100,d3		;wheel base
	divs	d1,d3
	muls	d2,d3
	asr.l	#8,d3
	asr.l	#4,d3
	bne.b	.ok
	moveq	#1,d3
.ok:	move.w	d3,radius_temp.w
.fail:	rts				;d3 now contains turning radius

calculate_degrees_to_move:		; used
	move.l	#$a3,d4			;$400/(2*pi)
	mulu	true_speed.w,d4
	tst.w	d3
	beq.b	.sk
	divs	d3,d4
.sk:	asr.w	#4,d4
	rts				;d4 now contains degrees to move

calculate_new_car_x_z:			; used
	bsr	get_z
	bsr	get_x
	move.w	d4,d0			;dtm
	bsr	get_sine
	bsr	add_yaw_velocity
	and.w	viewmove.w,d4
	sub.w	d4,Genstr+2
	bsr	get_new_car_z
	bsr	get_new_car_x
	rts

add_yaw_velocity:			; used - doesn't do what it says in the name !!!!
	move.w	d4,d7
;	tst.w	yaw_velocity.w
;	beq.b	.f1
;	muls.w	yaw_velocity.w,d7
	trace.w	#'Yw'
	trace.w	d7
.f1:	add.w	d7,6(a1)		; steering related - should be safe but trace added anyway
	lsr.w	#1,d7			; allow reduced changes to in-crash type things
	add.w	d7,car_direction.w
	rts

get_z:	move.w	car_direction.w,d0	;@ used
	tst.b	crash_flag.w		;@ check for crash underway
	bne.b	.f1			;@
	move.w	6(a1),d0		;car angle
.f1:	bsr	get_sine
	move.w	d1,car_sine.w
	move.w	d2,car_cos.w
	muls	radius_temp.w,d1
	asr.l	#8,d1
	asr.l	#6,d1			;r*sin(a); radius is div by 16
	move.w	d1,tcz.w		;save z=r*sin(a)
	rts

get_x:	muls	radius_temp.w,d2	; used
	asr.l	#8,d2
	asr.l	#6,d2			;r*cos(a);radius / 16
	move.w	d2,tcx.w		;save x=r*cos(a)	
	rts

get_new_car_z:				; used
	move.w	tcx.w,d0		;save x
	move.w	tcz.w,d4		;save z
	muls	d2,d4			;z*cos(dtm)
	muls	d1,d0			;x*sin(dtm)
	add.l	d0,d4			;nz=z*cos(dtm)+x*sin(dtm)
	asr.l	#8,d4
	asr.l	#6,d4			;new car x
	sub.w	tcz.w,d4
	ext.l	d4
	asl.l	#4,d4
	move.l	d4,z_offset.w
	rts

get_new_car_x:				; used
	move.w	tcx.w,d5		;save x
	move.w	tcz.w,d6		;save z
	muls	d2,d5			;x*cos(dtm)
	muls	d1,d6			;z*sin(dtm)
	sub.l	d6,d5			;nx=x*cos(dtm)-z*sin(dtm)
	asr.l	#8,d5
	asr.l	#6,d5			;new car z
	sub.w	tcx.w,d5
	ext.l	d5
	asl.l	#4,d5
	move.l	d5,x_offset.w
	rts

not_turning::				; used
	move.w	car_direction.w,d0	;@
	tst.b	crash_flag.w		;@
	bne.b	.f1			;@
	move.w	6(a1),d0
.f1:	bsr	get_sine		;d1=sine d2=cosine
	move.w	true_speed.w,d6
;	lsr.w	#1,d6
	bsr	calc_move_bits
	sub.l	d1,12(a1);car x
	add.l	d2,20(a1);car z

	move.l	12(a1),d0		; get car x-coordinate
	move.l	d0,Gpu_xpos

	move.l	20(a1),d0
	move.l	d0,Gpu_zpos

	and.l	viewmove.w,d1
	and.l	viewmove.w,d2
	sub.l	d1,Genstr+12		; position of camera
	add.l	d2,Genstr+20
	rts

calc_move_bits::		; converts d6 = speed, sideways if set, and d1=sine,d2=cosine into d1=x offset,d2=z offset
	movem.l	d0/d3/d4,-(sp)
	moveq	#0,d0
	tst.w	sidecount.w
	beq.b	.nz
	subq.w	#1,sidecount.w
	move.w	sideways.w,d0
	asr.w	sideways.w
	trace.w	#'Si'
	trace.w	d0
.nz:	move.l	d1,d3
	move.l	d2,d4
	
	muls	d6,d1
	asl.l	#2,d1
	swap	d1
	ext.l	d1			; d1 = v sine

	muls	d6,d2
	asl.l	#2,d2
	swap	d2
	ext.l	d2			; d2 = v cos

      	muls	d0,d3
	asl.l	#2,d3
	swap	d3
	ext.l	d3			; d3 = w sine

      	muls	d0,d4
	asl.l	#2,d4
	swap	d4
	ext.l	d4			; d4 = w cos

	sub.l	d4,d1
	add.l	d3,d2

	movem.l	(sp)+,d0/d3/d4
	rts

do_gears:				; used
	cmp.b	#automatic,gear_type.w
	beq.b	.f1
	bsr	do_manual_gear
	bsr	do_accelerator
	rts
.f1:	bsr	do_automatic_gears
	rts

do_manual_gear:				; used
	tst.b	gear_up_pressed.w
	bne.b	.f1
	tst.b	gear_down_pressed.w
	beq.b	.ex

	cmp.b	#1,gear.w		; change down if not in 1
	beq.b	.ex
	subq.b	#1,gear.w
	subq.w	#2,gear_offset.w
	tst.b	pre_race.w
	bne.b	.ex
	bsr	get_new_down_revs
.ex:	rts

.f1:	cmp.b	#6,gear.w		; change up if not in top
	beq.b	.ex
	addq.b	#1,gear.w
	addq.w	#2,gear_offset.w
	tst.b	pre_race.w
	bne.b	.ex
	bsr	get_new_revs
	rts

do_accelerator:				; used
	tst.b	pre_race.w
	beq.b	nrm
prea:	tst.b	engine_on.w		; can't rev an engine thats off
	beq.b	.ok
	tst.b	accelerator_pressed.w
	beq.b	.nac
	addi.w	#800,revs.w
	cmp.w	#13500,revs.w
	ble.b	.ok
	move.w	#13500,revs.w
.ok:	rts
.nac:	sub.w	#800,revs.w
	bpl.b	.ex
	clr.w	revs.w
.ex:	rts


nrm:	cmp.w	#13500,revs.w
	ble.b	.f3
	bsr	reduce_revs
	rts

.f3:	tst.b	brake_pressed.w
	bne	apply_manual_brake
	tst.b	accelerator_pressed.w
	beq.b	.f1			;accelerator not pressed
	tst.w	true_speed.w		; see if standing
	bne.b	.mvg

	tst.w	spark_count.w		; only trigger sparks if not already running
	bne.b	.spo
	addq.w	#1,spark_count.w
	addq.w	#1,smoke_count.w

.spo:	tst.l	skidfx.w
	bne.b	.mvg

	sfx	skid,$2fff		; trigger a brief skid noise as well
	move.l	d0,skidfx.w
	st	short_skid.w

.mvg:	cmp.w	#13500,revs.w
	bhs.b	.ex
	cmp.w	#12500,revs.w
	bhi.b	.f2
	bsr	get_up_revs
	add.w	d0,revs
.ex:	rts
.f2:	bsr	get_up_revs
	lsr.w	#2,d0
	add.w	d0,revs
	rts
.f1:	tst.b	cruise_pressed.w
	bne.b	.ex
	bsr	decrease_manual_revs
	rts

reduce_revs:				; used
	bsr	get_manual_brake_revs
	lsr.w	#3,d0
	sub.w	d0,revs.w
	cmp.w	#13500,revs.w
	bhi.b	.ex
	move.w	#13500,revs.w
.ex:	rts

decrease_manual_revs:			; used
	bsr	get_down_revs		; based on time to decelerate in a given gear
	sub.w	d0,revs.w		; massively unrealistic, but no change for now
	bpl.b	.ex
	clr.w	revs.w
.ex:	rts

apply_manual_brake:			; used
	bsr	get_manual_brake_revs
	lsl.w	#1,d0
	sub.w	d0,revs.w
	bmi.b	.f1
	rts
.f1:	clr.w	revs.w
	rts

get_manual_brake_revs:			; used
	movea.l	#manual_gear_brake_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
	mulu	braking_effectiveness.w,d0
	lsr.l	#4,d0
	rts
	
do_automatic_gears:			; used
	tst.b	pre_race.w
	bne	prea			; uses the manual code for this as well, as don't want to change gears in it

	tst.b	brake_pressed.w
	bne	apply_brake
	tst.b	accelerator_pressed.w
	beq.b	.f23			; accelerator not pressed
	tst.w	true_speed.w		; see if standing
	bne.b	.mvg

	tst.w	spark_count.w		; only trigger sparks if not already running
	bne.b	.mvg
	addq.w	#1,spark_count.w
	addq.w	#1,smoke_count.w

	tst.l	skidfx.w
	bne.b	.mvg

	sfx	skid,$2fff		; trigger a brief skid noise as well
	move.l	d0,skidfx.w
	st	short_skid.w

.mvg:	bsr.b	increase_revs
	rts
.f23:	tst.b	cruise_pressed.w	; if cruise held, nothing happens, so may need possible gear changes here
	bne.b	.ex
	bsr	decrease_revs
.ex:	rts

increase_revs:				; only used for automatics
	cmp.w	#down_gear_limit,revs.w
	bhi.b	.nk
	cmp.b	#1,gear.w
	beq.b	.nk
	bsr	change_down_gear
.nk:	bsr	get_up_revs
	add.w	d0,revs.w
.f1:	cmp.w	#up_gear_limit,revs.w
	blo.b	.ex
	cmp.b	#5,gear.w
	beq.b	.f24			; limit to maximum revs if in 5th
	bsr	change_up_gear
.ex:	rts
.f24:	cmp.w	#13500,revs.w
	blo.b	.ex
	move.w	#13500,revs.w
	rts

get_up_revs:				; used
	move.l	#gear_acceleration_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
;	tst.b	off_track.w
;	beq.b	.ex
;	lsr.w	#1,d0			; half the acceleration whilst off track
.ex:	rts

decrease_revs:				; used
	bsr	get_down_revs
	sub.w	d0,revs.w
	bmi.b	.f33
	cmp.w	#down_gear_limit,revs.w
	bhi.b	.ex
	cmp.b	#1,gear.w
	beq.b	.f32
	bsr	change_down_gear
.ex:	rts
.f32:	tst.w	revs.w
	bpl.b	.ex
.f33:	clr.w	revs.w
	rts

apply_brake:				; used
	bsr	get_automatic_brake_revs
	lsl.w	#1,d0
	sub.w	d0,revs.w
	bmi.b	.f34
	cmp.w	#brake_gear_limit,revs.w
	bhi.b	.ex
	cmp.b	#1,gear.w
	beq.b	.f35
	bsr	change_brake_gear
.ex:	rts
.f35:	tst.w	revs.w
	bpl.b	.ex
.f34:	clr.w	revs.w
	rts

get_automatic_brake_revs:		; used
	move.l	#automatic_gear_brake_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
	mulu	braking_effectiveness.w,d0
	lsr.l	#4,d0
	rts

get_new_revs:				; used
	move.l	#gear_ratios_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d2		;new gear
	move.w	-2(a3,d1.w),d3		;old gear
	beq.b	.fail		; ZERO PROTECTION
	clr.l	d0
	move.w	revs.w,d0
	divu	d3,d0
	mulu	d2,d0
	move.w	d0,revs.w
.fail:	rts

get_new_down_revs:			; used
	move.l	#gear_ratios_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d2		;new gear
	move.w	2(a3,d1.w),d3		;old gear
	beq.b	.ok		; fail - ZERO PROTECTION
	clr.l	d0
	move.w	revs.w,d0
	divu	d3,d0
	mulu	d2,d0
	move.w	d0,revs.w

	cmp.w	#13500,d0		; see if big revs !
	blt.b	.ok

	tst.w	spark_count.w
	bne.b	.ok
	addq.w	#1,spark_count.w

.ok:	rts

calculate_engine_sound:			; range :
	move.w	revs.w,d0		; 1500-13500
	cmp.w	#15000,d0
	blt.b	.ng
	move.w	#15000,d0
.ng:	move.w	#24,d1			; 24
	tst.b	pre_race.w
	bne.b	.sk
	sub.b	gear.w,d1		; 23-18
.sk:	mulu	d1,d0			; 27000-310500
	asr.l	#2,d0			; 6750-77625
	add.l	#60000,d0		; 66750-137625
	move.l	d0,engine_s2.w		; synth sound
	sub.l	#42000,d0		; 24750-95625
	asl.l	#7,d0			; ** new mod !
	swap	d0			; 48-186
	ext.l	d0
.f3:	move.l	d0,engine_sound.w	; sample sound
	rts


make_engine_sound:			; used

	mod_sfx	engine.w,engine_sound.w,#$4fff		;@ new sound code uses macro to change volume
;	mod_sfx	engine2.w,engine_s2.w,#$16ff		; volumes used to ensure changes to volume control work soon

	rts

get_gear_offset:			; used
	clr.w	d1
	move.b	gear.w,d1
	subq.b	#1,d1
	lsl.b	#1,d1
	move.w	d1,gear_offset.w
	rts

calculate_speed_of_car:			; used
	cmp.b	#automatic,gear_type.w
	bne.b	.f1
	move.l	#auto_gear_ratios_table,a3
	bra.b	.f2
.f1:	move.l	#gear_ratios_table,a3
.f2:	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0		; d0 now contains gear ratio multiplied by 16
	beq.b	.fail
	clr.l	d1
	move.w	revs.w,d1
	divu	d0,d1			;calculate speed
	lsl.w	#3,d1			;multiply by 64, but will divide by 8 after multiply, so reduce to 8
	mulu	speed_adjustment.w,d1
	move.l	d1,speed.w
.fail:	rts

get_down_revs:				; used
	move.l	#gear_decceleration_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
	rts

change_up_gear:				; used
	addq.b	#1,gear.w
	addq.w	#2,gear_offset.w
	move.l	#auto_gear_change_up_ratio_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0		; this is 256 * ratio between gears
	mulu	revs.w,d0		; gives the new revs required for same speed
	asr.l	#8,d0			; rescales to proper size
	move.w	d0,revs.w
	rts

change_down_gear:			; used
	subq.b	#1,gear.w
	subq.w	#2,gear_offset.w
	move.l	#auto_gear_change_down_ratio_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
	muls	revs.w,d0
	asr.l	#8,d0
	move.w	d0,revs.w
	rts

change_brake_gear:			; only used for automatic - left unchanged, because only bad circumstance
	subq.b	#1,gear.w		; is during crashes, in which case the brake button is forced off.
	subq.w	#2,gear_offset.w
	move.l	#auto_gear_change_brake_revs_table,a3
	move.w	gear_offset.w,d1
	move.w	(a3,d1.w),d0
	move.w	d0,revs.w
	rts
	
do_engine_sound:			; used
	bsr	calculate_engine_sound
	bsr	make_engine_sound
	rts

do_steering::				; used
;	move.b	#1,camera_lock_switch	; camera locked
	move.w	6(a1),d1		; robert is going to make the car angle 0-65k, so lets
	lsl.w	#6,d1			; make it robert friendly. now scaled to 65k
	move.w	d1,car_angle.w
	move.l	speed.w,d1		; REMEMBER that divide works on LONGS !!!!!!
	divu	#$252*2,d1		; converts to some sensible units (?) like mph
	asl.w	#1,d1			; for lookup into word length table
	move.l	#steer_limit_table,a5
	move.w	0(a5,d1.w),d2	
;	trace.w	#"Li"
;	trace.w	d2
	move.l	joy_cur.w,d0		;read joystick
	btst	#JOY_RIGHT,d0
	bne.b	turn_right		;right pressed
	btst	#JOY_LEFT,d0
	bne	turn_left		;left pressed
	move.l	#steer_amounts,steer_address.w
	tst.w	steer.w
	beq.b	.f15
.f16:	bmi	correct_right_turn
	bra	correct_left_turn
.f15:	move.l	#steer_amounts,steer_address.w
	bsr 	get_steering_wheel	; to ensure that letting go still allows wheel to move
;	bsr	do_steering_wheel
	rts

scale_back_angle:			; used
	move.w	car_angle.w,d1  	;scale back for now
	lsr	#6,d1
;	move.w	d1,6(a1)
	and.l	viewmove.w,d1		;clears to zero if viewpoint set not to move
	beq.b	ft			;RCD modification to prevent changing direction to ZERO when no change required !!!
	neg.w	d1
	move.w	d1,Genstr+2		;direction of view
ft:	bsr 	get_steering_wheel
;	bsr	do_steering_wheel
	rts

turn_right::				; used
	tst.w	steer.w
	ble.b	.f1			; if already right OR ZERO then no adjustments
	cmp.b	#3,steering_tightness.w
	beq.b	.f1			; also, only snap back if not in 'NO' mode
	clr.w	steer.w
	move.l	#steer_amounts,steer_address.w
	cmp.b	#1,steering_tightness.w
	beq.b	.f2			; if in manual mode don't over-shoot
.f1:	movea.l	steer_address.w,a0
	move.w	(a0)+,d0
	beq.b	.sk
	move.l	a0,steer_address.w
.sk:	muls.w	framect.w,d0
	cmp.b	#6,d1			; d1 is the offset from speed, so less than 6 is <30mph appx.
	blt.b	.nm
	muls	steering_user.w,d0
	asr.w	#8,d0
.nm: 	sub.w	d0,steer.w
	neg.w	d2
	cmp.w	steer.w,d2
	ble	scale_back_angle
	move.w	d2,steer.w
.f2:	bra	scale_back_angle

turn_left::				; used
	tst.w	steer.w
	bpl.b	.f1
	cmp.b	#3,steering_tightness.w
	beq.b	.f1
	clr.w	steer.w
	move.l	#steer_amounts,steer_address.w
	cmp.b	#1,steering_tightness.w
	beq.b	.f2			; if in manual mode don't over-shoot
.f1:	movea.l	steer_address.w,a0
	move.w	(a0)+,d0
	beq.b	.sk
	move.l	a0,steer_address.w
.sk:	muls.w	framect.w,d0
	cmp.b	#6,d1
	blt.b	.nm
	muls	steering_user.w,d0
	asr.w	#8,d0
.nm: 	add.w	d0,steer.w
	cmp.w	steer.w,d2
	bge	scale_back_angle
	move.w	d2,steer.w
.f2:	bra	scale_back_angle


correct_right_turn:			; this is where we go when the steer key is released
	cmp.b	#0,steering_tightness.w	; used
	beq.b	standard_correct_right_steer
	cmp.b	#2,steering_tightness.w
	beq.b	tight_correct_right_steer
	cmp.b	#4,steering_tightness.w
	beq.b	slow_correct_right_steer

	bra	scale_back_angle
;	rts		; no other option will make any change through letting go of button

tight_correct_right_steer:		; used
;	tas	strct.w
;	bne.b	.z
;	asr.w	steer.w
;	bra	scale_back_angle
.z:	clr.w	steer.w			; instant snap back for 'YES' mode
	move.l	#steer_amounts+4,steer_address.w
	bra	scale_back_angle

slow_correct_right_steer:		; used
	move.w	#standard,d0
	bra.b	strj

standard_correct_right_steer:		; used
	move.w	#standard*3,d0
strj:	cmp.w	#-24,steer.w
	bhs.b	.f1
	move.w	#-24,steer.w
.f1:	add.w	d0,steer.w
	bmi	scale_back_angle
	clr.w	steer.w
	move.l	#steer_amounts+4,steer_address.w
	bra	scale_back_angle

correct_left_turn:			; used
	cmp.b	#0,steering_tightness.w
	beq.b	standard_correct_left_steer
	cmp.b	#2,steering_tightness.w
	beq.b	tight_correct_left_steer
	cmp.b	#4,steering_tightness.w
	beq.b	slow_correct_left_steer

	bra	scale_back_angle
;	rts	

tight_correct_left_steer:		; used
;	tas	strct.w
;	bne.b	.z
;	asr.w	steer.w
;	bra	scale_back_angle
.z:	clr.w	steer.w
	move.l	#steer_amounts+4,steer_address.w
	bra	scale_back_angle

slow_correct_left_steer:		; used
	move.w	#standard,d0
	bra.b	stlj

standard_correct_left_steer:		; used
	move.w	#standard*3,d0
stlj:	cmp.w	#24,steer.w
	bls.b	.f1
	move.w	#24,steer.w
.f1:	sub.w	d0,steer.w
	bpl	scale_back_angle
	clr.w	steer.w
	move.l	#steer_amounts+4,steer_address.w
	bra	scale_back_angle

get_steering_wheel:			; this routine only makes the steering wheel anim frame display correctly
	move.w	steer.w,d1		; used
	asl.w	d1
	neg.w	d1
	bmi.b	.f2
	cmp.w	#24,d1
	ble.b	.f1
	move.w	#24,d1
	bra.b	.f1
.f2:	cmp.w	#-24,d1
	bhs.b	.f1
	move.w	#-24,d1
.f1:	move.w	d1,rota.w
	rts
	
roll_wheels:				; used
	move.w	true_speed.w,d0
	move.l	#3555>>2,d1	; limit for wheel rotation to prevent backward spins
	cmp.l	d1,d0
	bmi.b	nomaxx
	move.l	d1,d0
nomaxx:
	tst.b	reverse.w
	bne.b	.nmn		; when reversing, wheels go round backwards
	neg.l	d0
.nmn:	asr.l	#4,d0
	move.w	d0,8(a2)	; 8 after spins = 8 after left wheel start because left wheel is first spinning thang
	neg.l	d0
	move.w	d0,8+Struclen(a2)	; similarly, 8+Struclen after spins is 8 after right wheel start

noshift: rts

get_controls:				; tests keys, and record details, so that all routines have equal access
	move.l	joy_edge.w,d0		; used
	btst	#JOY_UP,d0
	sne.b	gear_up_pressed.w
	btst	#JOY_DOWN,d0
	sne.b	gear_down_pressed.w
	move.l	joy_cur.w,d0
	move.b	key_accel.w,d1
	btst	d1,d0
	sne.b	accelerator_pressed.w
	move.b	key_brake.w,d1
	btst	d1,d0
	sne.b	brake_pressed.w
	move.b	key_cruis.w,d1
	btst	d1,d0
	sne.b	cruise_pressed.w
	rts

dennis_initialise::		; this is pre-race initialisation
	move.b	#1,gear.w
	moveq	#0,d0
	move.w	d0,revs.w
	move.b	d0,crash_flag.w
	move.b	d0,start_crash.w
	move.b	d0,camera_lock_switch.w
	move.w	d0,crash_type.w
	move.b	d0,engine_on.w
	move.l	#steer_amounts,steer_address.w
	bsr	get_adjustments
	rts

get_tyre_factor:			; used
	move.b	tyre_type.w,d1		; 0=dry 1=wet
	lsl.b	#1,d1			; 0     2
	tst.b	weather.w
	beq.b	.f1			; skip if sunny
	add.b	#1,d1			; 1     3
.f1:	move.b	d1,tyre_factor.w
	rts

get_understeer_coefficient_and_braking_effectiveness:
	move.w	#65000,d1		; used
	move.w	#16,d2
	tst.b	weather.w
	beq.b	.f1
	sub.w	#20000,d1
	sub.w	#1,d2
.f1:	tst.b	foil_type.w		; low foil lose traction and braking
	bne.b	.f2
	sub.w	#20000,d1
	sub.w	#1,d2
.f2:	cmp.b	#1,tyre_factor.w	; 1 is dry tyres in wet weather
	bne.b	.f3
	sub.w	#20000,d1		; massive loss of steering control
	sub.w	#3,d2			; massive loss of braking
.f3:	move.w	d1,understeer.w
	move.w	d2,braking_effectiveness.w
	rts	

get_speed_adjustment:			; used
	move.w	#16,d1
	tst.b	weather.w
	beq.b	.f1
	sub.w	#1,d1
.f1:	tst.b	foil_type.w
	beq.b	.f2
	sub.w	#2,d1
.f2:	cmp.b	#1,tyre_factor.w	; speed loss for dry in rain
	beq.b	.f5
	cmp.b	#2,tyre_factor.w	; lose speed for wet in sun, but not for other combos
	bne.b	.f3
.f5:	sub.w	#1,d1
.f3:	move.w	d1,speed_adjustment.w
	rts

update_steer_table::
	movea.l	#rom_steer_amounts,a0
	movea.l	#steer_amounts,a1
	moveq	#0,d2
	tst.b	weather.w
	beq.b	.nil
	tst.b	tyre_type.w
	bne.b	.nil			; only dry tyres get shitty steering
	moveq	#2,d2
.nil:	moveq	#16,d0
.lp:	move.w	(a0)+,d1
	add.w	d2,d1
	move.w	d1,(a1)+
	dbra	d0,.lp

.exit:	rts

get_adjustments:			; used
	bsr	get_tyre_factor
	bsr	get_understeer_coefficient_and_braking_effectiveness
	bsr 	get_speed_adjustment
	bsr	update_steer_table
	rts


rom_steer_amounts::			; how much to turn the wheel when holding down the button
	dc.w	3	; 0
	dc.w	3	; 1
	dc.w	5	; 2
	dc.w	6	; 3
	dc.w	5	; 4
	dc.w	3	; 5
	dc.w	3	; 6
	dc.w	2	; 7
	dc.w	1	; 8
	dc.w	1	; 9
	dc.w	1	; 10
	dc.w	1	; 11
	dc.w	1	; 12
	dc.w	1	; 13
	dc.w	1	; 14
	dc.w	1	; 15
	dc.w	1	; 16
	dc.w	1	; 17
	dc.w	0	; 


