-- Door Generic v1 - authored by AmenMoses local Q = require "scriptbank\\quatlib" local U = require "scriptbank\\utillib" local V = require "scriptbank\\vectlib" local rad = math.rad local deg = math.deg local modf = math.modf local door_generic = {} -- DESCRIPTION: Open and close an entity to act as a door. -- DESCRIPTION: [@DoorKind=2( 1=Slide, 2=Rotate )] -- DESCRIPTION: [@DoorType=2( 1=Auto, 2=Manual, 3=DelayedClose )] -- DESCRIPTION: [DoorRange=100(0,500)] -- DESCRIPTION: [@HingeType=1(1=Right,2=Left)] -- DESCRIPTION: [Angle=0(0,360)] [Distance=90] -- DESCRIPTION: [DoorDelay=90] milliseconds -- DESCRIPTION: [OpeningTime#=1.5] seconds. -- DESCRIPTION: Customize the [ClosedText$="Door is closed. Find a way to open it"] -- DESCRIPTION: and optionally [!OpenWithEKey=0] -- DESCRIPTION: [UnlockedText$="E to open door"] -- DESCRIPTION: [AutoCloseDelay#=5.0] seconds -- DESCRIPTION: When door opening, play . -- DESCRIPTION: When the door is closing, play . local doorKinds = { 'Slide', 'Rotate' } local doorTypes = { 'Auto', 'Manual', 'DelayedClose' } local hingeTypes = { 'left','right' } function door_generic_properties( e, kind, door_type, range, hinge, angle, distance, door_delay, period, closedtext, openwithekey, unlockedtext, closedelay ) local door = door_generic[ e ] if door == nil then return end door.kind = doorKinds[ kind ] door.door_type = doorTypes[ door_type ] door.hinge = hingeTypes[ hinge ] door.door_range = range door.angle = angle door.distance = distance door.door_delay = door_delay door.period = period * 1000 door.closedelay = closedelay * 1000 door.withEkey = openwithekey == 1 door.closedtext = closedtext door.withEtext = unlockedtext end function door_generic_init( e ) door_generic[ e ] = { mode = 'init', raiseoffset = 0, currangle = 0 } end local function LookingAt( e, door ) return g_PlayerHealth > 0 and GetPlrLookingAt( e ) == 1 and ( door == nil or U.PlayerCloserThan( e, door.door_range ) ) end local function PositionDoor( e, door ) local v = V.Add( door.pos, V.Mul( door.vec, door.raiseoffset ) ) CollisionOff( e ) PositionObject( door.obj, v.x, v.y, v.z ) RotateObject( door.obj, door.ang.x, door.ang.y, door.ang.z ) CollisionOn( e) end local function rotateDoor( e, door ) local rotAng = door.currangle if door.hinge == 'right' then rotAng = -rotAng end local rotq = Q.FromEuler( 0, rad( rotAng ), 0 ) local ax, ay, az = Q.ToEuler( Q.Mul( door.quat, rotq ) ) CollisionOff( e ) ResetRotation( e, deg( ax ), deg( ay ), deg( az ) ) CollisionOn( e ) end local lastTime = 0 local timeDiff = 1 local timeSlice = 1000 / 60 function door_generic_main(e) local door = door_generic[ e ] if door == nil then return end local timeNow = g_Time if timeNow > lastTime then timeDiff = ( timeNow - lastTime ) / timeSlice lastTime = timeNow end local Ent = g_Entity[ e ] if door.mode == 'init' then door.obj = Ent.obj local x, y, z, xa, ya, za = GetObjectPosAng( door.obj ) door.pos = V.Create( x, y, z ) door.ang = V.Create( xa, ya, za ) door.quat = Q.FromEuler( rad( xa ), rad( ya ), rad( za ) ) local quat = Q.Mul( door.quat, Q.FromEuler( 0, 0, rad( door.angle ) ) ) xa, ya, za = Q.ToEuler( quat ) if door.kind == 'Slide' then door.perf = door.distance / door.period door.vec = V.FromEuler( xa, ya, za, true ) else -- assume 'Rotate' door.perf = door.angle / door.period end if Ent.activated == 0 then door.mode = 'closed' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 1 ) else door.mode = 'open' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 0 ) door.closeTime = 0 end elseif door.mode == 'closed' then if Ent.activated == 0 then if U.PlayerCloserThanPos( door.pos.x, door.pos.y, door.pos.z, door.door_range ) then if door.door_type == 'Auto' then SetEntityActivated( e, 1 ) elseif door.door_type == 'Manual' and LookingAt( e, door ) then if door.withEkey then Prompt( door.withEtext ) if g_KeyPressE == 1 then SetEntityActivated( e, 1 ) end else Prompt( door.closedtext ) end end end else door.mode = 'delay' door.nextMode = 'opening' door.time = g_Time + door.door_delay PlaySound( e, 0 ) end elseif door.mode == 'delay' then if g_Time >= door.time then door.mode = door.nextMode end elseif door.mode == 'opening' then if door.kind == 'Slide' then door.raiseoffset = door.raiseoffset + door.perf * timeSlice * timeDiff if door.raiseoffset >= door.distance then door.raiseoffset = door.distance door.mode = 'open' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 0 ) if door.door_type == 'DelayedClose' then door.closeTime = g_Time + door.closedelay end end else -- must be 'Rotate' if door.currangle < door.angle then door.currangle = door.currangle + door.perf * timeSlice * timeDiff rotateDoor( e, door ) else door.mode = 'open' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 0 ) if door.door_type == 'DelayedClose' then door.closeTime = g_Time + door.closedelay end end end elseif door.mode == 'open' then if ( door.door_type == 'Auto' and not U.PlayerCloserThanPos( door.pos.x, door.pos.y, door.pos.z, door.door_range ) ) or ( door.door_type == 'Manual' and ( Ent.activated == 0 or ( door.withEkey and g_KeyPressE == 1 and LookingAt( e, door ) ) ) ) or ( door.door_type == 'DelayedClose' and g_Time >= door.closeTime ) then door.mode = 'delay' door.nextMode = 'closing' door.time = g_Time + door.door_delay PlaySound( e, 1 ) end door.raiseoffset = door.distance elseif door.mode == 'closing' then if door.kind == 'Slide' then door.raiseoffset = door.raiseoffset - door.perf * timeSlice * timeDiff if door.raiseoffset <= 0 then door.raiseoffset = 0 door.mode = 'closed' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 1 ) end else -- must be 'Rotate' door.currangle = door.currangle - door.perf * timeSlice * timeDiff rotateDoor( e, door ) if door.currangle <= 0 then door.currangle = 0 door.mode = 'closed' RDBlockNavMesh( door.pos.x, door.pos.y, door.pos.z, 30, 1 ) end end SetEntityActivated( e, 0 ) end if door.kind == 'Slide' then PositionDoor( e, door ) end end