Solution found by adding the lines
Hide( GetGamePlayerControlThirdpersonCharactere() )
Show( GetGamePlayerControlThirdpersonCharactere() )
Thanks to AmenMoses
-- LUA Script - precede every function and global member with lowercase name of script + '_main'
--
-- vsync = 1 in setup.ini strongly recommended!
--
------------------------
-- user editable bits --
------------------------
local maxSpeed = 20 -- reversing is limited to half maxSpeed
local acceleration = 0.05 -- this is per frame
-- sound stuff
local baseSoundSpeed = 40000 -- nice deep sound for a big truck, make it higher for a pick-up
-- gear changes G1 G2 G3
local gearChng = { maxSpeed * 0.25, maxSpeed * 0.44, maxSpeed * 0.66, math.huge }
-- All positioning offsets are relative to vehicle model origin which for best results should be
-- dead centre of the rear axle, this script currently designed for rear wheel drive front wheel
-- steering 4 wheeled vehicles. These offsets are for an unscaled model, the script will factor
-- in the scaling factor at runtime so if the default model is scaled already strange results
-- *will* be expected.
-- 'bumpers' effectively, i.e. offset from origin to front and rear of vehicle
local frontOff, rearOff = 250, -90
-- road wheels
local wheelOffsets =
{{ x = -50.0, y = 0, z = 192.0 }, -- left front
{ x = -50.0, y = 0, z = 0.0 }, -- left rear
{ x = 50.0, y = 0, z = 192.0 }, -- right front
{ x = 50.0, y = 0, z = 0.0 } -- right rear
}
-- these offsets are for
local doorOffs = { passenger = { x = -65, y = 0, z = 170 },
drivers = { x = 65, y = 0, z = 170 } }
-- steering wheel
local sw_offs = { x = 18.5, y = 65, z = 197.0 }
local swPitch = 30
-- player positioning
local tpZoff, tpYoff = 380, 130
local fpXoff, fpYoff, fpZoff = 5, 80, 120
-- vehicle terrain limits
local maxRoll, maxPitch = 45, 60
-------------------------------------------------------
-- Edit anything below here at your own peril. :-) --
-------------------------------------------------------
local truck_vars = {}
local Q = require "scriptbank\\quatlib"
local U = require "scriptbank\\utillib"
local P = require "scriptbank\\physlib"
local sin = math.sin
local cos = math.cos
local rad = math.rad
local deg = math.deg
local abs = math.abs
local asin = math.asin
local atan = math.atan2
local modf = math.modf
local sqrt = math.sqrt
local sub = string.sub
local max = math.max
local min = math.min
local names = {}
local samplesLoaded = false
function truck021_init_name( e, name )
Include( "quatlib.lua" )
Include( "utillib.lua" )
Include( "physlib.lua" )
names[ e ] = name
if not samplesLoaded then
LoadGlobalSound( "audiobank\\Truck021\\Start.wav", 0 )
LoadGlobalSound( "audiobank\\Truck021\\Run.wav", 1 )
LoadGlobalSound( "audiobank\\Truck021\\Stop.wav", 2 )
LoadGlobalSound( "audiobank\\Truck021\\Gear.wav", 3 )
samplesLoaded = true
end
end
local function getDims( obj )
local xmin, ymin, zmin, xmax, ymax, zmax = GetObjectColBox( obj )
-- get scale factors for object
local sx, sy, sz = GetObjectScales( obj )
-- now work out width, height, length and mass
local w, h, l = (xmax - xmin) * sx, (ymax - ymin) * sy, (zmax - zmin) * sz
return { w = w, h = h, l = l, sx = sx, sy = sy, sz = sz }
end
function Truck021AddWheel( e, name )
for k, v in pairs( truck_vars ) do
if #v.wheels < 4 then
if sub(v.name,1,6) == sub(name,1,6) then
local Obj = g_Entity[e].obj
local Dims = getDims( Obj )
v.wheels[#v.wheels + 1] = { Ent = e, Obj = Obj, hght = Dims.h, quat = nil }
return true
end
end
end
end
function Truck021AddSteeringWheel( e, name )
for k, v in pairs( truck_vars ) do
if v.steering == nil then
if sub(v.name,1,6) == sub(name,1,6) then
local Obj = g_Entity[e].obj
v.steering = { Ent = e, Obj = Obj, quat = nil }
return true
end
end
end
end
local wheelHeights = {}
local function calcAngle( h1, h2, l )
return asin( ( h1 - h2 ) / l )
end
local function GetHeightUnderWheel(v, num, xo, yo, zo)
local x, y, z = v.x + xo, GetTerrainHeight(x, z) + 26, v.z + zo
local obj = IntersectAll(x, y - 5, z, x, y - v.wheels[num].hght, z, v.wheels[num].Obj)
if obj and obj ~= 0 then
return( GetIntersectCollisionY())
else
return GetTerrainHeight(x, z)
end
end
local function GetWheelHeights( v, xA, yA, zA )
local xo, yo, zo
-- given proposed vehicle position and current angles
-- calculate the terrain heights under the wheels
local avgHeight, avgRoll, avgPitch = 0, 0, 0
for i = 1, 4 do
local wo = wheelOffsets[i]
xo, yo, zo = U.Rotate3D( wo.x * v.dims.sx, wo.y * v.dims.sy, wo.z * v.dims.sz, xA, yA, zA )
wheelHeights[i] = GetHeightUnderWheel( v, i, xo, yo, zo ) + v.wheels[i].hght / 2
avgHeight = avgHeight + wheelHeights[i]
wheelHeights[i] = ( v.y + yo ) - wheelHeights[i]
end
avgHeight = avgHeight / 4
-- now work out vehicle angles
local ax1 = calcAngle( wheelHeights[1], wheelHeights[3],
wheelOffsets[3].x * v.dims.sx - wheelOffsets[1].x * v.dims.sx );
local ax2 = calcAngle( wheelHeights[2], wheelHeights[4],
wheelOffsets[4].x * v.dims.sx - wheelOffsets[2].x * v.dims.sx );
avgRoll = (ax1 + ax2) / 2
if avgRoll > rad( maxRoll) then
avgRoll = rad( maxRoll)
v.speed = v.speed / 2
end
if avgRoll < rad(-maxRoll) then
avgRoll = rad(-maxRoll)
v.speed = v.speed / 2
end
local p1 = calcAngle( wheelHeights[1], wheelHeights[2],
wheelOffsets[1].z * v.dims.sz + wheelOffsets[2].z * v.dims.sz );
local p2 = calcAngle( wheelHeights[3], wheelHeights[4],
wheelOffsets[3].z * v.dims.sz + wheelOffsets[4].z * v.dims.sz );
avgPitch = (p1 + p2) / 2
if avgPitch > rad( maxPitch) then avgPitch = rad( maxPitch) end
if avgPitch < rad(-maxPitch) then avgPitch = rad(-maxPitch) end
-- correct for axle offset
local L = ( wheelOffsets[ 1 ].z * v.dims.sz - wheelOffsets[ 2 ].z * v.dims.sz ) / 2
local ycor = sin( avgPitch ) * L
return avgHeight + ycor, avgPitch, avgRoll
end
local turnDir = { 'F', 'R', 'F', 'R' }
local rotQuat = nil
local finQuat = nil
local function PositionWheel( num, v, xA, yA, zA )
local wo = wheelOffsets[num]
local xo, yo, zo = U.Rotate3D( wo.x * v.dims.sx, wo.y * v.dims.sy, wo.z * v.dims.sz, xA, yA, zA )
local suspensionOffset = wheelHeights[num]
if suspensionOffset > 4 then suspensionOffset = 4 end
if suspensionOffset < -4 then suspensionOffset = -4 end
ResetPosition( v.wheels[num].Ent, v.x + xo,
v.y + yo - suspensionOffset,
v.z + zo );
if turnDir[num] == 'F' then
if num == 1 then
finQuat = Q.FromEuler( 0, rad( v.turnAng ), 0 )
else
finQuat = Q.FromEuler( 0, rad( -v.turnAng ), rad( 180 ))
end
else
if num == 2 then
finQuat = Q.FromEuler( 0, 0, 0 )
else
finQuat = Q.FromEuler( 0, 0, rad( 180 ) )
end
end
if num > 2 then suspensionOffset = -suspensionOffset end
finQuat = Q.Mul( v.quat, finQuat )
if num > 2 then
rotQuat = Q.FromEuler( rad( v.rotAng ), 0, rad( suspensionOffset * 2 ) )
else
rotQuat = Q.FromEuler( rad( -v.rotAng ), 0, rad( suspensionOffset * 2 ) )
end
v.rotAng = v.rotAng - v.speed / 5
if v.rotAng < -180 then
v.rotAng = v.rotAng + 360
elseif v.rotAng > 180 then
v.rotAng = v.rotAng - 360
end
finQuat = Q.Mul( finQuat, rotQuat )
local xA, yA, zA = Q.ToEuler( finQuat )
ResetRotation( v.wheels[num].Ent, deg( xA ), deg( yA ), deg( zA ) )
end
local function PositionWheels( v, xA, yA, zA )
for i = 1, 4 do
PositionWheel( i, v, xA, yA, zA )
end
end
local pitchQ = Q.FromEuler( rad( swPitch ), 0, 0 )
local function PositionSteering( v, xA, yA, zA )
local xo, yo, zo = U.Rotate3D( sw_offs.x * v.dims.sx, sw_offs.y * v.dims.sy, sw_offs.z * v.dims.sz, xA, yA, zA )
PositionObject( v.steering.Obj , v.x + xo, v.y + yo, v.z + zo )
local quat = Q.Mul( Q.FromEuler( xA, yA, zA ), pitchQ )
quat = Q.Mul( quat, Q.FromEuler( 0, 0, -rad( v.turnAng * 4.5 ) ) )
local sxA, syA, szA = Q.ToEuler( quat )
RotateObject( v.steering.Obj, deg( sxA ), deg( syA ), deg( szA ) )
end
local function PositionVehicle( e, v, xA, yA, zA )
local ay = deg(yA)
-- this weird looking code is to make sure the Euler 'gimbal lock' position
-- is avoided. For GG this is at -90 and +90 degrees in Y axis rotation.
if abs( ay - 90 ) < 0.001 then
ay = 89.999
elseif abs( ay + 90 ) < 0.001 then
ay = -89.999
end
CollisionOff( e )
PositionObject( v.obj , v.x, v.y, v.z )
RotateObject( v.obj, deg( xA ), ay, deg( zA ) )
CollisionOn( e )
PositionSteering( v, xA, yA, zA )
end
local collListForward = {}
local collListBackward = {}
local RayCastEnt = IntersectAll
local RayCastTer = RayTerrain
local objectHit = 0
local terrainHit = false
local delayCheck = math.huge
local function AnythingThere( x, y, z, vx, vy, vz )
terrainHit = false
objectHit = RayCastEnt( x, y, z, x + vx, y + vy, z + vz, 0 )
if objectHit ~= nil and objectHit ~= 0 then return true end
if RayCastTer( x, y, z, x + vx, y + vy, z + vz ) == 1 then
terrainHit = true
end
return terrainHit
end
local function ProcessHit( v, col )
if terrainHit then
if col == 'left' or col == 'right' then
v.speed = 0
end
else
local e = P.ObjectToEntity( objectHit )
if e ~= nil and ai_bot_state[ e ] ~= nil then
SetEntityHealth( e, 0 )
-- slightly slow down
v.speed = v.speed * 0.9
-- TBD, sound effect of collision?
else -- assume farah has met his mountain
v.speed = 0
if PositionCollision ~= nil then
PositionCollision( GetIntersectCollisionX(),
GetIntersectCollisionY(),
GetIntersectCollisionZ() )
end
-- TBD, process effect of collision, e.g. sound effect or damage to vehicle?
end
end
end
local function CheckForCollision( v, xA, yA, zA )
if collListForward[ v.obj ] == nil then
local fOff = frontOff * v.dims.sz
collListForward[ v.obj ] =
{ left = { x = -v.dims.w / 2, y = 20, z = fOff},
centre = { x = 0, y = 20, z = fOff},
right = { x = v.dims.w / 2, y = 20, z = fOff },
}
end
if collListBackward[ v.obj ] == nil then
local rOff = rearOff * v.dims.sz
collListBackward[ v.obj ] =
{ left = { x = -v.dims.w / 2, y = 20, z = rOff },
centre = { x = 0, y = 20, z = rOff },
right = { x = v.dims.w / 2, y = 20, z = rOff }
}
end
local colls, dist, diag
if v.speed == 0 then
objectHit = 0
return
elseif v.speed > 0 then
-- going forwards so cast rays from front corners
colls = collListForward[ v.obj ]
dist = max( 10, v.speed * 2 )
diag = v.dims.w
else
colls = collListBackward[ v.obj ]
dist = min( -10, v.speed * 2 )
diag = v.dims.w
end
for yOff = 80, 0, -20 do
for k, w in pairs( colls ) do
local vx, vy, vz = U.Rotate3D( 0, 0, dist, xA, yA, zA )
local fx, fy, fz = U.Rotate3D( w.x, w.y + yOff, w.z, xA, yA, zA )
if yOff == 0 then
-- Check for cliff hanger
if not AnythingThere( v.x + fx, v.y + fy, v.z + fz, 0, -150, 0 ) then
v.speed = 0
return
end
end
-- next check straight ahead
if AnythingThere( v.x + fx, v.y + fy, v.z + fz, vx, vy, vz ) then
ProcessHit( v, k )
if v.speed == 0 then return end
end
-- then diagonals
if k == 'left' then
vx, vy, vz = U.Rotate3D( diag, 0, dist, xA, yA, zA )
if AnythingThere( v.x + fx, v.y + fy, v.z + fz, vx, vy, vz ) then
ProcessHit( v, k .. " diag" )
if v.speed == 0 then return end
end
end
if k == 'right' then
vx, vy, vz = U.Rotate3D( -diag, 0, dist, xA, yA, zA )
if AnythingThere( v.x + fx, v.y + fy, v.z + fz, vx, vy, vz ) then
ProcessHit( v, k .. " diag" )
if v.speed == 0 then return end
end
end
end
end
end
local function MoveVehicle( v )
if v.speed ~= 0 then
-- check for collisions, for now if potential collision detected
local xA, yA, zA = Q.ToEuler( Q.Mul( v.quat,
Q.FromEuler( v.curPitch, 0, v.curRoll ) ) )
CheckForCollision( v, xA, yA, zA )
local mX, mY, mZ
if v.speed ~= 0 then
mX, mY, mZ = U.Rotate3D( 0, 0, v.speed, xA, yA, zA )
v.x, v.y, v.z = v.x + mX, v.y + mY, v.z + mZ
else
mX, mY, mZ = U.Rotate3D( 0, 0, 1, xA, yA, zA )
end
v.vmAng = deg( atan( mX, mZ ) )
-- we need to turn the vehicle a small amount each
-- frame until we are pointing in the right direction
v.quat = Q.Mul( v.quat, Q.FromEuler( 0, rad( v.turnAng / (20 * v.dims.sz) ) * (v.speed / maxSpeed), 0 ) )
end
end
local function GotEnts( e, v )
if #v.wheels ~= 4 then
PromptLocal( e, "Not enough wheel entities!" )
return false
end
if v.steering == nil then
PromptLocal( e, "No steering wheel" )
return false
end
return true
end
local function RealWorldYAngle( xa, ya, za )
-- Tricky to explain but basically g_PlayerAngY is the real-world
-- angle, i.e. 0-359 degrees, whereas the Euler angle for an entity
-- returned by GetObjectPosAng is not.
-- In order to get the 'real-world' equivalent we need to do some math.
-- first rotate a unit 'facing forward' vector by the Euler angles
local xv, _, zv = U.Rotate3D( 0, 0, 1, xa, ya, za )
-- now work out the angle from the x and z components of the result
return atan( xv, zv )
end
local function RevRealWorldYAngle( xa, ya, za )
local xv, _, zv = U.Rotate3D( 0, 0, -1, xa, ya, za )
return atan( xv, zv )
end
local function AttachPlayer( v, xA, yA, zA, inCab )
local cx, cy, cz, ax, ay, az
local xo, yo, zo
xo, yo, zo = U.Rotate3D( fpXoff * v.dims.sx, fpYoff * v.dims.sy, fpZoff * v.dims.sz, xA, yA, zA )
local y = GetTerrainHeight( v.x + xo, v.z + zo )
if y < 0 then return end
cx, cy, cz = v.x + xo, v.y + yo, v.z + zo
SetFreezePosition( cx, cy, cz )
local pxA, pyA, pzA = Q.ToEuler( Q.Mul( Q.FromEuler( xA, yA, zA ),
Q.FromEuler( 0, rad(v.turnAng / 1.5), 0 ) ) )
ax, ay, az = deg(pxA), deg(pyA), deg(pzA)
SetFreezeAngle( ax, ay, az )
TransportToFreezePosition()
if not inCab then
local tweak = abs( v.speed * 5 ) * v.dims.sz
if v.speed >= 0 then
xo, yo, zo = U.Rotate3D( v.turnAng * 2.5 * v.dims.sx, 0, -(tpZoff * v.dims.sz + tweak), xA, yA, zA )
else
xo, yo, zo = U.Rotate3D( v.turnAng * 2.5 * v.dims.sx, 0, tpZoff * v.dims.sz + tweak, xA, yA, zA )
end
local y = GetTerrainHeight( v.x + xo, v.z + zo )
if y < 0 then return end
if v.y + yo > y then y = v.y + yo end
cx, cy, cz = v.x + xo, y + tpYoff * v.dims.sy + tweak, v.z + zo
if v.speed >=0 then
ax, ay, az = 25 - v.speed, deg( RealWorldYAngle( pxA, pyA, pzA )), 0
else
pxA, pyA, pzA = Q.ToEuler( Q.Mul( Q.FromEuler( xA, yA, zA ),
Q.FromEuler( 0, rad(-v.turnAng / 1.5), 0 ) ) )
ax, ay, az = 25 + v.speed, deg( RevRealWorldYAngle( pxA, pyA, pzA )), 0
end
end
SetCameraPosition ( 0, cx, cy, cz )
SetCameraAngle ( 0, ax, ay, az )
end
local inCab = true
local QkeyPressed = false
local EkeyPressed = false
local currGear = 0
local function HandleGears( v )
if v.speed > gearChng[ currGear + 1 ] then
currGear = currGear + 1
PlayGlobalSound( 3 )
elseif v.speed <= 0 then -- must be reverse or stopped
currGear = 0
elseif currGear >= 1 and v.speed < gearChng[ currGear ] then
currGear = currGear - 1
PlayGlobalSound( 3 )
end
if currGear > 0 then
return v.speed - gearChng[ currGear ]
else
return abs ( v.speed )
end
end
local function DriveControls( v, xA, yA, zA )
-- accelerate/forward
if v.speed < maxSpeed and g_KeyPressW == 1 then
if v.speed < 0 then
v.speed = v.speed + acceleration * 2
-- TBD add braking sound here?
else
v.speed = v.speed + acceleration
end
local snd = HandleGears( v )
SetGlobalSoundSpeed( 1, baseSoundSpeed + snd * 5000 )
end
-- decelerate/reverse
if v.speed > -maxSpeed / 2 and g_KeyPressS == 1 then
if v.speed > 0 then
v.speed = v.speed - acceleration * 2
-- TBD add braking sound here?
else
v.speed = v.speed - acceleration
end
local snd = HandleGears( v )
SetGlobalSoundSpeed( 1, baseSoundSpeed + snd * 4000 )
end
end
local function PlayerControl( v, xA, yA, zA )
g_suspendplayercontrols = 1
-- Turn right
if g_KeyPressD == 1 then
if v.turnAng < 35 then
v.turnAng = v.turnAng + 0.3
end
elseif v.turnAng > 0 and v.speed ~= 0 then
v.turnAng = v.turnAng - 0.17
end
-- turn left
if g_KeyPressA == 1 then
if v.turnAng > -35 then
v.turnAng = v.turnAng - 0.3
end
elseif v.turnAng < 0 and v.speed ~= 0 then
v.turnAng = v.turnAng + 0.17
end
-- change viewpoint
if g_KeyPressQ == 1 then
if not QkeyPressed then
inCab = not inCab
QkeyPressed = true
end
else
QkeyPressed = false
end
-- exit
if g_KeyPressE == 1 and abs(v.speed) < 1 then
if not EkeyPressed then
v.state = 'stop'
StopGlobalSound( 1 )
PlayGlobalSound( 2 )
SetGlobalSoundSpeed( 2, baseSoundSpeed )
v.timer = g_Time + 3000
vispeed = 0
EkeyPressed = true
end
else
EkeyPressed = false
end
end
local function SmoothMotion( v )
if v.curPitch ~= v.tgtPitch then
local pitchDiff = v.tgtPitch - v.curPitch
if abs( pitchDiff ) < 0.005 then
v.curPitch = v.tgtPitch
else
v.curPitch = v.curPitch + pitchDiff / 3
end
end
if v.curRoll ~= v.tgtRoll then
local rollDiff = v.tgtRoll - v.curRoll
if abs( rollDiff ) < 0.005 then
v.curRoll = v.tgtRoll
else
v.curRoll = v.curRoll + rollDiff / 3
end
end
end
function truck021_main(e)
local vehicle = truck_vars[e]
if vehicle == nil then
local Ent = g_Entity[e]
local x, y, z, xA, yA, zA = GetObjectPosAng( Ent.obj )
truck_vars[e] =
{ state = 'init', name = names[e], obj = Ent.obj,
wheels = {},
steering = nil,
x = x, y = y, z = z, -- actual position
quat = Q.FromEuler( rad(xA) , rad(yA), rad(zA)), -- actual rotation
dims = getDims( Ent.obj ),
vmAng = 0, rotAng = 0, turnAng = 0,
curPitch = 0, tgtPitch = 0,
curRoll = 0, tgtRoll = 0,
speed = 0, timer = g_Time + 2000
}
return
end
if vehicle.state == 'init' and GotEnts( e, vehicle ) then
local xA, yA, zA = Q.ToEuler( vehicle.quat )
vehicle.y, vehicle.tgtPitch, vehicle.tgtRoll = GetWheelHeights( vehicle, xA, yA, zA )
SmoothMotion( vehicle )
xA, yA, zA = Q.ToEuler( Q.Mul( vehicle.quat,
Q.FromEuler( vehicle.curPitch, 0, vehicle.curRoll ) ) )
PositionVehicle( e, vehicle, xA, yA, zA )
PositionWheels( vehicle, xA, yA, zA )
if g_Time > vehicle.timer then
vehicle.state = 'idle'
end
elseif vehicle.state == 'idle' then
-- first check if we are in the general area of the vehicle
if U.PlayerLookingNear( e, 300, 170 ) then
-- if so check if we are stood by either the drivers door or the
-- passenger door
local xA, yA, zA = Q.ToEuler( Q.Mul( vehicle.quat,
Q.FromEuler( vehicle.curPitch, 0, vehicle.curRoll ) ) )
local dofs = doorOffs.drivers
local xo, yo, zo = U.Rotate3D( dofs.x * vehicle.dims.sx,
dofs.y * vehicle.dims.sy,
dofs.z * vehicle.dims.sz, xA, yA, zA )
local nearDoor = U.PlayerCloserThanPos( vehicle.x + xo,
vehicle.y + yo,
vehicle.z + zo, max( 50, 50 * vehicle.dims.sy ) )
if not nearDoor then
dofs = doorOffs.passenger
xo, yo, zo = U.Rotate3D( dofs.x * vehicle.dims.sx,
dofs.y * vehicle.dims.sy,
dofs.z * vehicle.dims.sz, xA, yA, zA )
nearDoor = U.PlayerCloserThanPos( vehicle.x + xo,
vehicle.y + yo,
vehicle.z + zo, max( 50, 50 * vehicle.dims.sy ) )
end
if nearDoor then
Prompt( "Press E key to drive me!" )
if g_KeyPressE == 1 then
if not EkeyPressed then
SetPlayerWeapons(0)
Hide( GetGamePlayerControlThirdpersonCharactere() )
SetCameraOverride( 3 )
vehicle.state = 'start'
EkeyPressed = true
PlayGlobalSound( 0 )
SetGlobalSoundSpeed( 0, baseSoundSpeed )
vehicle.timer = g_Time + 4000
end
else
EkeyPressed = false
end
end
end
elseif vehicle.state == 'start' then
local xA, yA, zA = Q.ToEuler( Q.Mul( vehicle.quat,
Q.FromEuler( vehicle.curPitch, 0, vehicle.curRoll ) ) )
vehicle.speed = 0
AttachPlayer( vehicle, xA, yA, zA, inCab )
if g_Time > vehicle.timer then
LoopGlobalSound( 1 )
SetGlobalSoundSpeed( 1, baseSoundSpeed )
vehicle.state = 'drive'
end
PlayerControl( vehicle, xA, yA, zA )
PositionSteering( vehicle, xA, yA, zA )
elseif vehicle.state == 'drive' then
MoveVehicle( vehicle )
local xA, yA, zA = Q.ToEuler( vehicle.quat )
vehicle.y, vehicle.tgtPitch, vehicle.tgtRoll = GetWheelHeights( vehicle, xA, yA, zA )
SmoothMotion( vehicle )
xA, yA, zA = Q.ToEuler( Q.Mul( vehicle.quat,
Q.FromEuler( vehicle.curPitch, 0, vehicle.curRoll ) ) )
PositionVehicle( e, vehicle, xA, yA, zA )
PositionWheels( vehicle, xA, yA, zA )
AttachPlayer( vehicle, xA, yA, zA, inCab )
PlayerControl( vehicle, xA, yA, zA )
DriveControls( vehicle, xA, yA, zA )
elseif vehicle.state == 'stop' then
local xA, yA, zA = Q.ToEuler( Q.Mul( vehicle.quat,
Q.FromEuler( vehicle.curPitch, 0, vehicle.curRoll ) ) )
AttachPlayer( vehicle, xA, yA, zA, inCab )
PositionSteering( vehicle, xA, yA, zA )
if g_Time > vehicle.timer then
Show( GetGamePlayerControlThirdpersonCharactere() )
SetCameraOverride( 0 )
SetPlayerWeapons(1)
local dofs = doorOffs.drivers
local xo, yo, zo = U.Rotate3D( dofs.x, dofs.y, dofs.z, xA, yA, zA )
SetFreezePosition( vehicle.x + xo, vehicle.y + yo + 40, vehicle.z + zo )
SetFreezeAngle( 0, vehicle.vmAng, 0 )
TransportToFreezePosition()
vehicle.state = 'idle'
end
end
end