-- 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 atan = math.atan2 local posList = { [ 'Grand Clock 1c' ] = { base = 'Grand Clock 1a', typ = 'Pendulum', xo = 0, yo = 0, zo = 0 }, [ 'Grand Clock 1a' ] = { typ = 'Base' }, [ 'Grand Clock 1b' ] = { base = 'Grand Clock 1a', typ = 'None', xo = 0, yo = 0, zo = 0 }, [ 'Minute Hand' ] = { base = 'Grand Clock 1a', typ = 'Mhand', xo = 0, yo = 76.25, zo = -6.5 }, [ 'Hour Hand' ] = { base = 'Grand Clock 1a', typ = 'Hhand', xo = 0, yo = 76.25, zo = -6.53 } } local dynEnts = {} function gfclock_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 positionEnt( e, x, y, z, xa, ya, za ) CollisionOff( e ) ResetPosition( e, x, y, z ) ResetRotation( e, xa, ya, za ) CollisionOn( e ) end local lastTime = 0 local moveAmount = 0 local swingMax = 3.2 local swingSpeed = 0.07 function gfclock_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.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 LoopSound( e, 0 ) de.state = 'done' elseif de.state == 'idle' then if typ == 'Pendulum' then de.state = 'swing' de.angle = 0 -- straight down de.direction = 'right' local _, _, _, xa, ya, za = GetEntityPosAng( e ) de.quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) elseif typ == 'Hhand' or typ == 'Mhand' then de.timer = 0 de.state = 'rotating' local _, _, _, xa, ya, za = GetEntityPosAng( e ) de.quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) else de.state = 'done' end elseif de.state == 'rotating' and timeNow > de.timer then de.timer = timeNow + 1000 local nowTime = os.time() local hours = tonumber( os.date( '%I' ) ) local mins = tonumber( os.date( '%M' ) ) local turnQ if typ == 'Mhand' then turnQ = Q.FromEuler( 0, 0, rad( -mins * 6 ) ) elseif typ == 'Hhand' then turnQ = Q.FromEuler( 0, 0, rad( -hours * 30 - mins / 2 ) ) end 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 == 'swing' then local tweak = cos( rad( abs( de.angle ) * 88 / swingMax ) ) if de.direction == 'right' then de.angle = de.angle + swingSpeed * moveAmount * tweak if de.angle >= swingMax then de.direction = 'left' de.angle = swingMax end else de.angle = de.angle - swingSpeed * moveAmount * tweak if de.angle <= -swingMax then de.direction = 'right' de.angle = -swingMax end end local turnQ = Q.FromEuler( 0, 0, rad( de.angle ) ) xa, ya, za = Q.ToEuler( Q.Mul( de.quat, turnQ ) ) local xo, yo, zo = U.Rotate3D( de.angle * 2, 0, 0, xa, ya, za ) positionEnt( e, de.x + xo, de.y + yo, de.z + zo, deg( xa ), deg( ya ), deg( za ) ) end end