-- 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 atan = math.atan2 local posList = { [ 'Standing Globe 1a' ] = { base = 'Standing Globe 1b', typ = 'Rotate', xo = -0.1, yo = 36.825, zo = 17.715 }, [ 'Standing Globe 1b' ] = { typ = 'Base' }, [ 'Cat Cage 1c' ] = { base = 'Cat Cage 1b', typ = 'DoorL', xo = -4.254, yo = 4.96, zo = -11.77 }, [ 'Cat Cage 1b' ] = { typ = 'Base' }, [ 'Cabinet 2b' ] = { typ = 'Base' }, [ 'Cabinet Drawer 2a' ] = { base = 'Cabinet 2b', typ = 'Drawer', xo = 22.1, yo = 34.7, zo = -9.1 }, [ 'Cabinet Drawer 2b' ] = { base = 'Cabinet 2b', typ = 'Drawer', xo = 22.1, yo = 34.7, zo = 9.1 }, [ 'Cabinet Door 2a' ] = { base = 'Cabinet 2b', typ = 'DoorL', xo = 21, yo = 21.5, zo = -17.2 }, [ 'Cabinet Door 2b' ] = { base = 'Cabinet 2b', typ = 'DoorR', xo = 21, yo = 21.5, zo = 17.2 }, [ 'Cabinet 1b' ] = { typ = 'Base' }, [ 'Cabinet Drawer 1a' ] = { base = 'Cabinet 1b', typ = 'Drawer', xo = 23, yo = 37, zo = -11.45 }, [ 'Cabinet Drawer 1b' ] = { base = 'Cabinet 1b', typ = 'Drawer', xo = 23, yo = 37, zo = 11.45 }, [ 'Cabinet Bot Door 1a' ] = { base = 'Cabinet 1b', typ = 'DoorR', xo = 21.7, yo = 19, zo = 21.8 }, [ 'Cabinet Bot Door 1b' ] = { base = 'Cabinet 1b', typ = 'DoorL', xo = 21.7, yo = 19, zo = -21.8 } } local dynEnts = {} function antiques_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 g_disableWeapon = g_disableWeapon or nil function PU_GetEntityCarried() return g_disableWeapon end g_handIcon = g_handIcon or nil g_handOn = g_handOn or {} local handSize = 15 local handOn = g_handOn local keyOrMousePressed = {} local function processSelect( de, timeNow ) if de.state == 'closed' then de.state = 'opening' de.timer = timeNow + 800 elseif de.state == 'open' then de.state = 'closing' de.timer = timeNow + 800 elseif de.state == 'stationary' then -- get contact point local objX = GetIntersectCollisionX() local objZ = GetIntersectCollisionZ() -- get object position and angle local ex, _, ez, xa, ya, za = GetObjectPosAng( de.obj ) local dims = P.GetObjectDimensions( de.obj ) -- work out centre of object local ox, _, oz = U.Rotate3D( dims.cx, dims.cy, dims.cz, xa, ya, za ); local cx, cz = ex + ox, ez + oz -- now work out angle from player to object local px, pz = g_PlayerPosX, g_PlayerPosZ local angle1 = atan( px - cx, pz - cz ) local angle2 = atan( px - objX, pz - objZ ) -- PromptDuration( deg( angle1 ) .. "," .. deg( angle2 ), 3000 ) de.state = 'rotating' if angle2 > angle1 then de.spin = -1 else de.spin = 1 end elseif de.state == 'rotating' then de.state = 'stationary' de.spin = 0 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 function antiques_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 de.state = 'done' elseif de.state == 'idle' then if posList[ de.name ].typ ~= 'Rotate' then de.state = 'closed' else de.state = 'stationary' end elseif de.state == 'rotating' then local _, _, _, xa, ya, za = GetEntityPosAng( e ) if abs( ya - 90 ) < 0.001 then ya = 89.999 elseif abs( ya + 90 ) < 0.001 then ya = -89.999 end local quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local turnQ = Q.FromEuler( 0, rad( de.spin * moveAmount ), 0 ) if de.spin > 0.004 then de.spin = de.spin - 0.004 elseif de.spin < -0.004 then de.spin = de.spin + 0.004 else de.spin = 0 de.state = 'stationary' end xa, ya, za = Q.ToEuler( Q.Mul( quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) elseif de.state == 'opening' then if timeNow < de.timer then if posList[ de.name ].typ == 'DoorL' then local _, _, _, xa, ya, za = GetEntityPosAng( e ) local quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local turnQ = Q.FromEuler( 0, rad( moveAmount ), 0 ) xa, ya, za = Q.ToEuler( Q.Mul( quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) elseif posList[ de.name ].typ == 'DoorR' then local _, _, _, xa, ya, za = GetEntityPosAng( e ) local quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local turnQ = Q.FromEuler( 0, -rad( moveAmount ), 0 ) xa, ya, za = Q.ToEuler( Q.Mul( quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) else local _, _, _, xa, ya, za = GetEntityPosAng( e ) local xv, yv, zv = U.Rotate3D( 0.22 * moveAmount, 0, 0, rad( xa ), rad ( ya ), rad ( za ) ) de.x, de.y, de.z = de.x + xv, de.y + yv, de.z + zv positionEnt( e, de.x, de.y, de.z, xa, ya, za ) end else de.state = 'open' end elseif de.state == 'closing' then if timeNow < de.timer then if posList[ de.name ].typ == 'DoorL' then local _, _, _, xa, ya, za = GetEntityPosAng( e ) local quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local turnQ = Q.FromEuler( 0, -rad( moveAmount ), 0 ) xa, ya, za = Q.ToEuler( Q.Mul( quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) elseif posList[ de.name ].typ == 'DoorR' then local _, _, _, xa, ya, za = GetEntityPosAng( e ) local quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local turnQ = Q.FromEuler( 0, rad( moveAmount ), 0 ) xa, ya, za = Q.ToEuler( Q.Mul( quat, turnQ ) ) positionEnt( e, de.x, de.y, de.z, deg( xa ), deg( ya ), deg( za ) ) else local _, _, _, xa, ya, za = GetEntityPosAng( e ) local xv, yv, zv = U.Rotate3D( 0.22 * moveAmount, 0, 0, rad( xa ), rad ( ya ), rad ( za ) ) de.x, de.y, de.z = de.x - xv, de.y - yv, de.z - zv positionEnt( e, de.x, de.y, de.z, xa, ya, za ) end else de.state = 'closed' end end -- set up hand sprite if required if g_handIcon == nil then g_handIcon = CreateSprite( LoadImage( "scriptbank\\pickuppable\\hand1.png" ) ) SetSpriteOffset ( g_handIcon, -1 , handSize / 2 ) SetSpriteSize ( g_handIcon, -1 , handSize ) SetSpriteDepth ( g_handIcon, 0 ) SetSpritePosition( g_handIcon, 250, 250 ) handOn[ e ] = false end if U.PlayerLookingAt( e, 60 ) then if not handOn[ e ] then SetSpritePosition( g_handIcon, 50, 50 ) handOn[ e ] = true g_disableWeapon = true return end if ( g_MouseClick == 1 or g_KeyPressE == 1 ) then if not keyOrMousePressed[ e ] then keyOrMousePressed[ e ] = true processSelect( de, timeNow ) end else keyOrMousePressed[ e ] = false end elseif handOn[ e ] then handOn[ e ] = false keyOrMousePressed[ e ] = false SetSpritePosition( g_handIcon, 250, 250 ) for _, v in pairs( handOn ) do if v then return end end g_disableWeapon = nil end -- PromptLocal( e, de.state ) end