#constant VEHICLE_STATE_CONTROL	0
#constant VEHICLE_STATE_FREE		1
#constant VEHICLE_STATE_SPINOUT	2

#constant FRONT_RIGHT		0
#constant FRONT_LEFT			1
#constant REAR_RIGHT			2
#constant REAR_LEFT			3

#constant CAMERA_1ST			0
#constant CAMERA_3RD			1

#constant STEERING_LOCAL		0
#constant STEERING_GLOBAL	1

#constant VEHICLE_PLAYER		0
#constant VEHICLE_NPC		1

type tCamera
	style			as integer
	id				as integer
	dolly			as integer
	look			as integer
	ease			as float
	pos				as tPoint
	adjust			as tPoint
endtype

type tDelay
	amount			as float
	count			as float
endtype

type tHit
	id				as integer
	contact			as integer
	pos				as tPoint
endtype

type	tSensor
	f				as integer
	t				as integer				
endtype

type tWheel
	pivot			as integer
	id				as integer
	sensor			as tSensor
	pos				as tPoint
	radius			as float
	width			as float
	height			as float
	circumfrence		as float
	ray				as integer
	fromVect			as integer
	toVect			as integer
	shape			as integer
	hit				as tHit
endtype

type tVelocity
	current			as float
	max				as float
	last			as tPoint
	linearUnit		as float
	angularUnit		as float
	save			as float
	boost			as float
	time			as float
endtype

type tDrift
	on				as integer
	amount			as float
endtype

type tVehicle
	no				as integer
	slot			as integer	
	turnMode			as integer
	name			as string
	tag				as integer
	colour			as color
	path			as tPath
	
	distCurrentNode	as float
	distNextNode 	as float	
	
	chassis			as integer
	center			as integer
	detail			as integer
	drift			as tDrift
	hit				as integer
	size			as tPoint
	wheels			as tWheel[]
	dotID			as integer
	point			as integer	
	forward			as integer
	reverse			as integer
	rightSensor		as integer
	leftSensor		as integer
	wheelAngle		as float
	image			as integer
	lastPos			as tPoint
	camera1st		as tCamera
	camera3rd		as tCamera	
	camera			as tCamera
	ground			as integer
	vectV			as integer
	vectU			as integer
	suspension		as float
	flying			as integer
	delay			as tDelay
	velocity			as tVelocity
	steering			as integer
	tilt			as tTilt
	active			as integer
	npc				as integer
	collision		as integer
	action			as tAction
	vector1			as integer
	vector2			as integer
	dotHit			as float
	dotMove			as float
	dotNext			as float	
	dotTunnel		as float		
	stopped			as integer
	spot			as integer
	rumble 			as integer
	lap				as integer
	follow			as integer
	position			as integer
	ray				as integer
	reset			as float
	pickup			as integer
	coins			as integer
	finished			as integer
	monitor			as integer
	poop			as integer
	line			as integer[]
	engine			as integer
	bump			as integer
	bumpLast			as integer
	state			as integer
	landed			as integer
	crashed			as integer
	land			as integer
	boost			as integer
	boostOffset		as float
	marker			as integer
endtype

type tTilt
	force			as float
	range			as float
	damp			as float
	spring			as float
endtype

//
// Stick together all the parts for the vehicle
//
//	hit.obj								The hitbox
//	chassis.obj							The body of the car
//	fr.obj, fl.obj, rr.obj, rl.obj		Wheels 
//	direction (created)					Used to get the direction vector for the vehicle
//	pivot (created for each wheel)		For turning left/right so we can also rotate the wheel to roll
//	sensor (created for each wheel)		To detect if it is in contact with the ground and to simulate suspension
//  cam1								The first person camera position
//  dolly1								The first person dolly (Used by the camera to "LookAT")
//  cam3                                	The 3rd person camera position
//  dolly3								The 3rd person dolly
//	center								All the non physics bits are stuck to this so we can roll the chassis
//	detail								Detail that is not atached to the chassis (Hubcaps)
//
//	Modeling notes
//	The vehicle must alwasy point down the Z axis
//
//	If you model the car so you have groups named "hit", "chassis", "fr", "fl", "rr", "rl", "cam1", "dolly1", "cam3", "dolly3"
//	there is a function in MakeCar.agc called MakeCarFromModel(). It will split up your model into it's variuos pieces
//	There is also a vehicle.obj model in the suv folder which demonstrates how to format your model
//	The model is just a guideline. You could model a solid car, load it as tHit.obj, forget about the wheels and
//	chassis and it would work as long as it fits in the envelope of the hit.obj model (for physics purposes)
//


function	LoadVehicle(folder as string, texture as string, name as string, number as integer)
	vehicle	as tVehicle
	id		as integer
	i		as integer
	
	vehicle.name = name
	vehicle.tag = CreateText(name)
	SetTextSize(vehicle.tag, 18)
	vehicle.no = number - 1
	vehicle.slot = number - 1	
	vehicle.lap = 0
	
	if vehicle.slot < 0
		vehicle.slot = 0
	endif
	
	if DEBUG = FALSE
		SetTextVisible(vehicle.tag, 0)		
	endif
	
	vehicle.ray	   = Create3DPhysicsRay()
	vehicle.vector1 = CreateVector3()
	vehicle.vector2 = CreateVector3()	
	
	vehicle.image = LoadImage(folder+"/"+texture)
	
	vehicle.hit = 5000 + number
	LoadObject(vehicle.hit, folder+"/hit.obj")							// Load the hit box (This does all the work)
	SetObjectColor(vehicle.hit, 0, 0xff, 0, 0xff)
	SetObjectVisible(vehicle.hit, 0)
	
	vehicle.chassis = LoadObject(folder+"/chassis.obj")						// Load the chassis
	SetObjectImage(vehicle.chassis, vehicle.image, 1)
	SetObjectVisible(vehicle.chassis, 1)	

	vehicle.center = LoadObject(folder+"/center.obj")						// Load the chassis
	SetObjectVisible(vehicle.center, 0)	
	
	vehicle.boost = LoadObject(folder+"/boost.obj")						// Load the chassis
	SetObjectTransparency(vehicle.boost, 1)
	SetObjectLightMode(vehicle.boost, 0)
	SetObjectImage(vehicle.boost, LoadImage(folder+"/boostEffect.png"), 0)
	FixObjectToObject(vehicle.boost, vehicle.hit)
	SetObjectUVScale(vehicle.boost, 0, 0.5, 1.0)
	SetObjectVisible(vehicle.boost, 0)	

	
	id = CreateObjectPlane(0.5, 0.5)
	SetObjectPosition(id, 0, 0, (GetObjectDepth(vehicle.hit) * 0.5))
	vehicle.line.insert(id)
	id = CreateObjectPlane(0.5, 0.5)
	SetObjectPosition(id, 0, 0, -(GetObjectDepth(vehicle.hit) * 0.5))
	vehicle.line.insert(id)
	
	for i=0 to vehicle.line.length
		SetObjectVisible(vehicle.line[i], 0)
		FixObjectToObject(vehicle.line[i], vehicle.hit)
	next

	vehicle.poop = CreateObjectPlane(5, 5)
	SetObjectPosition(vehicle.poop, 0, 0, -(GetObjectDepth(vehicle.hit) * 0.8))	
	FixObjectToObject(vehicle.poop, vehicle.hit)
	SetObjectVisible(vehicle.poop, 0)	
	
	vehicle.detail = LoadObject(folder+"/detail.obj")					// Load the chassis
	SetObjectVisible(vehicle.detail, 1)	
	SetObjectImage(vehicle.detail, vehicle.image, 1)	
	FixObjectToObject(vehicle.detail, vehicle.chassis)	
					
	vehicle.forward = CreateObjectPlane(0.5, 0.5)						// Direction object so we can get a vector
	SetObjectPosition(vehicle.forward, GetObjectX(vehicle.center), GetObjectY(vehicle.center), GetObjectZ(vehicle.center) + 0.5)
	SetObjectVisible(vehicle.forward, 0)
	FixObjectToObject(vehicle.forward, vehicle.center)
	
	vehicle.dotID = CreateObjectPlane(0.5, 0.5)							// Direction object so we can get a vector
	SetObjectPosition(vehicle.dotID, GetObjectX(vehicle.center), GetObjectY(vehicle.center), GetObjectZ(vehicle.center) + 50)
	SetObjectVisible(vehicle.dotID, 0)
	FixObjectToObject(vehicle.dotID, vehicle.center)
	
	vehicle.reverse = CreateObjectPlane(0.5, 0.5)						// reverse object so we can get a vector
	SetObjectPosition(vehicle.reverse, GetObjectX(vehicle.center), GetObjectY(vehicle.center), GetObjectZ(vehicle.center) - 1)
	SetObjectVisible(vehicle.reverse, 0)
	FixObjectToObject(vehicle.reverse, vehicle.center)	
	
	vehicle.point = CreateObjectPlane(0.5, 0.5)						// reverse object so we can get a vector
	SetObjectPosition(vehicle.point, GetObjectX(vehicle.center), GetObjectY(vehicle.center), GetObjectZ(vehicle.center))
	SetObjectVisible(vehicle.point, 0)
	FixObjectToObject(vehicle.point, vehicle.center)	

	vehicle.suspension = 0.4
		
	LoadWheel(folder, "fr.obj", vehicle)									// Wheels
	LoadWheel(folder, "fl.obj", vehicle)
	LoadWheel(folder, "rr.obj", vehicle)
	LoadWheel(folder, "rl.obj", vehicle)

	vehicle.rightSensor = CreateObjectPlane(5, 5)						// right object so we can get a vector
	MoveObjectLocalX(vehicle.rightSensor, GetObjectWidth(vehicle.hit) * 1.3)
	SetObjectVisible(vehicle.rightSensor, 0)
	FixObjectToObject(vehicle.rightSensor, vehicle.center)	

	vehicle.leftSensor = CreateObjectPlane(5, 5)							// left object so we can get a vector
	MoveObjectLocalX(vehicle.leftSensor, -GetObjectWidth(vehicle.hit) * 1.3)	
	SetObjectVisible(vehicle.leftSensor, 0)
	FixObjectToObject(vehicle.leftSensor, vehicle.center)	

	if GetFileExists(folder+"/cam1.obj") = TRUE
		SetupCameras(folder, vehicle)									// Attach dolly and cameras
	else
		SetupCamera(folder, vehicle)		
	endif
	
	FixObjectToObject(vehicle.chassis, vehicle.hit)
	FixObjectToObject(vehicle.center, vehicle.hit)	
		
	vehicle.vectU = CreateVector3()
	vehicle.vectV = CreateVector3()
	
	GetDimensions(vehicle)	
		
endfunction vehicle

//
// Create thr hitbox for the vehicle
//
function CreatevehicleShape(vehicle ref as tVehicle)
	w 		as tWheel
	pos		as integer
	rot		as integer
	size 	as integer
	i		as integer
	p		as tPoint
	n		as string

	pos = CreateVector3(0, 0, 0)
	rot = CreateVector3(0, 0, 0)
	size = CreateVector3(0, 0, 0)		

	SetObjectShapeCompound(vehicle.hit) 
	
	p = GetObjectMeshPosition(vehicle.hit)
	SetVector3(pos, p.x, p.y, p.z)
	
	SetVector3(rot, 0, 0, 0)	
	
	p = GetObjectSize(vehicle.hit)	
	SetVector3(size, p.x * 0.5, p.y * 0.5, p.z * 0.5)

	AddObjectShapeBox(vehicle.hit, pos, rot, size)
																	// Wheels as spheres
	for i=0 to vehicle.wheels.length
		w = vehicle.wheels[i]
		p = GetObjectMeshPosition(w.id)		
	//	SetVector3(pos, w.pos.x * 0.9, w.pos.y , w.pos.z)
		SetVector3(pos, w.pos.x * 0.7, w.pos.y , w.pos.z)		
		AddObjectShapeSphere( vehicle.hit, pos, w.height) 
		vehicle.wheels[i] = w
	next
	
	DeleteVector3(pos)
	DeleteVector3(rot)
	DeleteVector3(size)		
						
endfunction


function	SetupCamera(folder as string, vehicle ref as tVehicle)
	p	as tPoint
		
	vehicle.camera.dolly = CreateObjectPlane(0.5, 0.5)
	SetObjectColor(vehicle.camera.dolly, 0xff, 0, 0, 0xff)
	SetObjectVisible(vehicle.camera.dolly, 0)
	
	vehicle.camera.id = LoadObject(folder+"/camera.obj")
	SetObjectVisible(vehicle.camera.id, 0)
	SetObjectColor(vehicle.camera.id, 0, 0xff, 0, 0xff)
		
	p = GetObjectMeshPosition(vehicle.camera.id)
	
	SetObjectPosition(vehicle.camera.id, -p.x, -p.y, -p.z)
	
	FixObjectPivot(vehicle.camera.id)
	
	SetObjectPosition(vehicle.camera.id, p.x, p.y, p.z)	
	
	FixObjectToObject(vehicle.camera.id, vehicle.camera.dolly)
	//FixObjectToObject(vehicle.camera.dolly, vehicle.center)

	vehicle.camera.ease = 1
	
	SetCameraPosition(1, p.x, p.y, p.z)
endfunction

function	SetupCameras(folder as string, vehicle ref as tVehicle)
	p	as tPoint
	
	vehicle.camera1st.style=CAMERA_1ST
	vehicle.camera1st.ease = 0.2
			
	vehicle.camera1st.dolly = LoadObject(folder+"/dolly1.obj")
	SetObjectVisible(vehicle.camera1st.dolly, 0)
	SetObjectColor(vehicle.camera1st.dolly, 0, 0xff, 0, 0xff)
	p = GetObjectMeshPosition(vehicle.camera1st.dolly)
	SetObjectPosition(vehicle.camera1st.dolly, -p.x, -p.y, -p.z)
	FixObjectPivot(vehicle.camera1st.dolly)
	SetObjectPosition(vehicle.camera1st.dolly, p.x, p.y, p.z)	
	
	vehicle.camera1st.id = LoadObject(folder+"/cam1.obj")		
	SetObjectColor(vehicle.camera1st.id, 0xff, 0, 0, 0xff)
	SetObjectVisible(vehicle.camera1st.id, 0)
	p = GetObjectMeshPosition(vehicle.camera1st.id)
	SetObjectPosition(vehicle.camera1st.id, -p.x, -p.y, -p.z)
	FixObjectPivot(vehicle.camera1st.id)
	SetObjectPosition(vehicle.camera1st.id, p.x, p.y, p.z)	
	
	FixObjectToObject(vehicle.camera1st.id, vehicle.center)
	FixObjectToObject(vehicle.camera1st.dolly, vehicle.center)	

	vehicle.camera3rd.style=CAMERA_3RD	
	vehicle.camera3rd.ease = 0.5
		
	vehicle.camera3rd.dolly = LoadObject(folder+"/dolly3.obj")		
	SetObjectColor(vehicle.camera3rd.dolly, 0xff, 0, 0, 0xff)
	SetObjectVisible(vehicle.camera3rd.dolly, 0)
//	p = GetObjectMeshPosition(vehicle.camera3rd.dolly)
//	SetObjectPosition(vehicle.camera3rd.dolly, -p.x, -p.y, -p.z)
//	FixObjectPivot(vehicle.camera3rd.dolly)
//	SetObjectPosition(vehicle.camera3rd.dolly, p.x, p.y, p.z)	
	
	vehicle.camera3rd.id = LoadObject(folder+"/cam3.obj")
	SetObjectVisible(vehicle.camera3rd.id, 0)
	SetObjectColor(vehicle.camera3rd.id, 0, 0xff, 0, 0xff)
	vehicle.camera3rd.pos = GetObjectMeshPosition(vehicle.camera3rd.id)
	SetObjectPosition(vehicle.camera3rd.id, -vehicle.camera3rd.pos.x, -vehicle.camera3rd.pos.y, -vehicle.camera3rd.pos.z)
	FixObjectPivot(vehicle.camera3rd.id)
	SetObjectPosition(vehicle.camera3rd.id, vehicle.camera3rd.pos.x, vehicle.camera3rd.pos.y, vehicle.camera3rd.pos.z)	
	
	FixObjectToObject(vehicle.camera3rd.id, vehicle.camera3rd.dolly)
	
	//FixObjectToObject(vehicle.camera3rd.dolly, vehicle.center)
	vehicle.camera3rd.look = LoadObject(folder+"/look.obj")
	SetObjectVisible(vehicle.camera3rd.look, 0)
	SetObjectColor(vehicle.camera3rd.look, 0, 0xff, 0, 0xff)
	vehicle.camera3rd.pos = GetObjectMeshPosition(vehicle.camera3rd.look)
	SetObjectPosition(vehicle.camera3rd.look, -vehicle.camera3rd.pos.x, -vehicle.camera3rd.pos.y, -vehicle.camera3rd.pos.z)
	FixObjectPivot(vehicle.camera3rd.look)
	SetObjectPosition(vehicle.camera3rd.look, vehicle.camera3rd.pos.x, vehicle.camera3rd.pos.y, vehicle.camera3rd.pos.z)	
	
	FixObjectToObject(vehicle.camera3rd.look, vehicle.camera3rd.dolly)


	vehicle.camera = vehicle.camera3rd
	//SetCameraPosition(1, p.x, p.y, p.z)
endfunction

function	LoadWheel(folder as string, name as string, vehicle ref as tVehicle)
	w	as tWheel
	h	as float
	
	w.id = LoadObject(folder+"/"+name)											// Load the wheel
	SetObjectImage(w.id, vehicle.image, 1)
			
	w.pos = GetObjectMeshPosition(w.id)
	
	w.width = (GetObjectMeshSizeMaxX( w.id, 1 ) - GetObjectMeshSizeMinX( w.id, 1 ))	
	w.height = (GetObjectMeshSizeMaxY( w.id, 1 ) - GetObjectMeshSizeMinY( w.id, 1 ))	// Diameter/Height
	w.radius = w.height * 0.5	
	w.circumfrence = 2 * w.radius * PI											// Radius
	SetObjectVisible(w.id, 1)
	SetObjectCollisionMode(w.id, 0)
																														
	SetObjectPosition(w.id, -w.pos.x, -w.pos.y, -w.pos.z)							// Move it so it's centered on (0,0,0)
	FixObjectPivot(w.id)															// Make it's center (0,0,0)

	w.pivot = CreateObjectPlane(16, 16)												// Create pivot so it can turn left/right
	RotateObjectLocalZ(w.pivot, 45)	
	FixObjectPivot(w.pivot)			
	SetObjectColor(w.pivot, 0, 0xff, 0, 0xff)	
	SetObjectVisible(w.pivot, 0)
	SetObjectCollisionMode(w.pivot, 0)
	
	w.sensor.f = CreateObjectPlane(4, 4)											// Create a sensor.f just below the wheel
	RotateObjectLocalZ(w.sensor.f, 45)
	FixObjectPivot(w.sensor.f)	
	SetObjectPosition(w.sensor.f, 0, -w.radius * 0.95, 0)											
	SetObjectColor(w.sensor.f, 0xff, 0xff, 0, 0xff)
	SetObjectVisible(w.sensor.f, 0)	
	SetObjectCollisionMode(w.sensor.f, 0)	
	
	w.sensor.t = CreateObjectPlane(4, 4)											// Create a sensor.t just below the wheel
	RotateObjectLocalZ(w.sensor.t, 45)
	FixObjectPivot(w.sensor.t)	
	SetObjectPosition(w.sensor.t, 0, -w.radius * 1.5, 0)											
	SetObjectColor(w.sensor.t, 0xff, 0, 0, 0xff)
	SetObjectVisible(w.sensor.t, 0)	
	SetObjectCollisionMode(w.sensor.t, 0)
	
	w.hit.id = CreateObjectBox(2, 2, 2)											// Create a sensor just below the wheel
//	RotateObjectLocalZ(w.hit.id, 45)
	FixObjectPivot(w.hit.id)
	SetObjectPosition(w.hit.id, 0, -w.radius, 0)											
	SetObjectColor(w.hit.id, 0xff, 0xff, 0xff, 0xff)
	SetObjectVisible(w.hit.id, 0)	
	SetObjectCollisionMode(w.hit.id, 0)	

	FixObjectToObject(w.sensor.f, w.pivot)										// Stick them together
	FixObjectToObject(w.sensor.t, w.pivot)	
	FixObjectToObject(w.id, w.pivot)																					
	FixObjectToObject(w.hit.id, w.pivot)		
	SetObjectPosition(w.pivot, w.pos.x, w.pos.y, w.pos.z)						// Move The pivot back where the wheel was
	
	FixObjectToObject(w.pivot, vehicle.center)
	
	w.shape = CreateObjectSphere(w.height, 8, 8)									// Visual feedback for physics wheel shape
	
	SetObjectPosition(w.shape, w.pos.x * 0.7, w.pos.y, w.pos.z)
	SetObjectColor(w.shape, 0, 0xff, 0, 0xff)
	FixObjectToObject(w.shape, vehicle.hit)
	SetObjectVisible(w.shape, 0)	
	
	w.ray = Create3DPhysicsRay()
	w.fromVect = CreateVector3()
	w.toVect = CreateVector3()
	
	vehicle.wheels.insert(w)
endfunction 


function	ToggleVisible(vehicle as tVehicle)
	v	as integer
	i	as integer
	w	as tWheel
	
	if GetObjectVisible(vehicle.hit) = FALSE or GetObjectVisible(vehicle.chassis) = FALSE
		v = TRUE
	else
		v = FALSE
	endif
	
	SetObjectVisible(vehicle.hit, v)
	SetObjectVisible(vehicle.chassis, v)	
	
	for i=0 to vehicle.wheels.length
		w = vehicle.wheels[i]
		SetObjectVisible(w.shape, v)
		SetObjectVisible(w.id, v)		
		SetObjectVisible(w.hit.id, abs(v - 1))
		SetObjectVisible(w.sensor.f, abs(v - 1))
		SetObjectVisible(w.sensor.t, abs(v - 1))				
		SetObjectVisible(w.pivot, abs(v - 1))						
	next
	
endfunction

function	ToggleHitShape(vehicle as tVehicle)
	v	as integer
	i	as integer
	
	if GetObjectVisible(vehicle.hit) = FALSE
		v = TRUE
	else
		v = FALSE
	endif
	
	SetObjectVisible(vehicle.hit, v)
	SetObjectVisible(vehicle.chassis, abs(v-1))	
	
	for i=0 to vehicle.wheels.length
		SetObjectVisible(vehicle.wheels[i].shape, v)
		SetObjectVisible(vehicle.wheels[i].id, abs(v - 1))		
	next
	
endfunction

function	GetDimensions(vehicle ref as tVehicle)
	box	as box
	GetObjectDimensions(vehicle.hit, box)
	GetObjectDimensions(vehicle.chassis, box)	
	GetObjectDimensions(vehicle.wheels[FRONT_RIGHT].id, box)		
	GetObjectDimensions(vehicle.wheels[REAR_RIGHT].id, box)		
	vehicle.size.x = box.x.max - box.x.min
	vehicle.size.y = box.y.max - box.y.min
	vehicle.size.z = box.z.max - box.z.min		
endfunction


function ObjectNotFound(fcn as string, id as integer)
	i as integer
	e as tEnvironment
	name as string = "Unknown"
	obj as tObject

	e = environment
		
	for i=0 to glevel.objs.length
		obj = glevel.objs[i]
		if obj.id = id
			name = obj.name
			exit
		endif
	next
	
	Message("Object not found in "+fcn+" ("+name+")")
	
	name=name
endfunction