-- LUA Script - precede every function and global member with lowercase name of script + '_main' local Q = require "scriptbank\\quatlib" local U = require "scriptbank\\utillib" local P = require "scriptbank\\physlib" local rad = math.rad local deg = math.deg local abs = math.abs local cos = math.cos local min = math.min local max = math.max local atan = math.atan2 local posList = { [ 'Pressure Gauge' ] = { typ = 'Base' }, [ 'Gauge Needle' ] = { base = 'Pressure Gauge', typ = 'Needle', xo = -2.135, yo = 12.171, zo = 0 }, [ 'Joint (Pipe Work)' ] = { typ = 'Base' }, [ 'Stop Valve Tap (Pipe Work)' ] = { base = 'Joint (Pipe Work)', typ = 'Valve', xo = 7, yo = 16, zo = 0 }, } local dynEnts = {} function gauges_init_name( e, name ) Include( "quatlib.lua" ) Include( "utillib.lua" ) Include( "physlib.lua" ) dynEnts[ e ] = { name = name, state = 'init' } -- set health to a stupidly high value SetEntityHealthSilent( e, 1000000) end local function findBase( de ) for k, v in pairs( dynEnts ) do if posList[ v.name ].typ == 'Base' and v.state == 'ready' and v.atts[ de.name ] == 0 then return k end end end local function gimbalAdj( ya ) if abs( ya - 90 ) < 0.001 then return 89.999 elseif abs( ya + 90 ) < 0.001 then return -89.999 end return ya end local function positionEnt( e, x, y, z, xa, ya, za ) CollisionOff( e ) ResetPosition( e, x, y, z ) ya = gimbalAdj( ya ) ResetRotation( e, xa, ya, za ) CollisionOn( e ) end local function GaugesGetPressure( name ) for k, v in pairs( dynEnts ) do if v.name == name then return v.pressure end end end local function GaugesSetPressure( name, pressure ) for k, v in pairs( dynEnts ) do if v.name == name then v.pressure = pressure v.state = 'rotating' break end end end local function processPressure( change, moveAmount ) if change then local pressure = GaugesGetPressure( 'Gauge Needle' ) if moveAmount < 0 then if pressure > 0 then GaugesSetPressure( 'Gauge Needle', pressure - 1 ) end else if pressure < 100 then GaugesSetPressure( 'Gauge Needle', pressure + 1 ) end end end end local lastTime = 0 local moveAmount = 0 function gauges_main( e ) local de = dynEnts[ e ] if de == nil then return end local typ = posList[ de.name ].typ local timeNow = g_Time if timeNow > lastTime + 20 then moveAmount = ( timeNow - lastTime ) / 20 lastTime = timeNow end if de.state == 'done' then -- no more processing needed for this entity return elseif de.state == 'init' then if typ == 'Base' then -- first work out what our attachments are de.atts = {} for k, v in pairs( posList ) do if v.typ ~= 'Base' and v.base == de.name then de.atts[ k ] = 0 end end de.x, de.y, de.z, de.xa, de.ya, de.za = GetEntityPosAng( e ) -- now mark ourselves as ready de.state = 'ready' else -- must be attachment so look for a base that is ready -- to accept us local base = findBase( de ) if base == nil then return end local b = dynEnts[ base ] b.atts[ de.name ] = e local p = posList[ de.name ] local xo, yo, zo = U.Rotate3D( p.xo, p.yo, p.zo, rad( b.xa ), rad( b.ya ), rad( b.za ) ) de.x, de.y, de.z = b.x + xo, b.y + yo, b.z + zo positionEnt( e, de.x, de.y, de.z, b.xa, b.ya, b.za ) de.obj = g_Entity[ e ].obj de.baseObj = g_Entity[ base ].obj de.baseEnt = base de.state = 'idle' end elseif de.state == 'ready' then -- check if we have all attachments for k, v in pairs( de.atts ) do if v == 0 then PromptLocal( e, "Don't have a " .. k .. '!' ) return end end de.state = 'done' elseif de.state == 'idle' then if typ == 'Needle' then de.pressure = 0 de.angle = -145 de.state = 'rotating' local _, _, _, xa, ya, za = GetEntityPosAng( e ) de.quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) elseif typ == 'Valve' then de.state = 'off' de.angle = 0 local _, _, _, xa, ya, za = GetEntityPosAng( e ) de.quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) end elseif de.state == 'rotating' then local tgtAng = -145 + de.pressure * 2.9 if de.angle > tgtAng then de.angle = de.angle - moveAmount elseif de.angle < tgtAng then de.angle = de.angle + moveAmount else de.state = 'stationary' end turnQ = Q.FromEuler( -rad( de.angle ), 0, 0 ) xa, ya, za = Q.ToEuler( Q.Mul( de.quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) elseif de.state == 'off' then -- detect player if U.PlayerLookingNear( e, 80, 30 ) then Prompt( "LMB to open valve" ) if g_MouseClick == 1 then de.state = 'turning' de.tgtAng = 420 end end elseif de.state == 'on' then -- detect player if U.PlayerLookingNear( e, 80, 30 ) then Prompt( "LMB to close valve" ) if g_MouseClick == 1 then de.state = 'turning' de.tgtAng = 0 end end elseif de.state == 'turning' then if de.tgtAng == 0 then if de.angle > de.tgtAng then de.angle = de.angle - moveAmount processPressure( de.angle < 300, -moveAmount ) else de.state = 'off' end else if de.angle < de.tgtAng then de.angle = de.angle + moveAmount processPressure( de.angle > 100, moveAmount ) else de.state = 'on' end end turnQ = Q.FromEuler( 0, -rad( de.angle ), 0 ) xa, ya, za = Q.ToEuler( Q.Mul( de.quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) end end