-- LUA Script - precede every function and global member with lowercase name of script + '_main' local U = require "scriptbank\\utillib" local sub = string.sub local find = string.find local min = math.min local max = math.max local random = math.random local lights = {} local controls = {} local reactionDelay = 200 local defaultSensitivity = 1.4 local defaultFadeSpeed = 4 local defaultTriggerDist = 200 local motionDelay = 3000 -- 3 second local function GetArgs( str, sep ) local sep = sep or ',' local pos = 1 local list = {} local length = #str while pos < length + 1 do local nextPos = find( str, sep, pos + 1 ) or length if nextPos < length then list[ #list + 1 ] = sub( str, pos, nextPos - 1 ) else list[ #list + 1 ] = sub( str, pos, nextPos ) break end pos = nextPos + 1 end return list end function light_control_init_name( e, name ) Include( "utillib.lua" ) local myArgs = GetArgs( name, '_' ) if myArgs == {} then PromptDuration( "No Args", 10000 ) return end if myArgs[ 1 ] == 'Light' then local sens = defaultSensitivity if myArgs[ 2 ] ~= nil and myArgs[ 2 ] ~= "0" then sens = tonumber( myArgs[ 2 ] ) end local fads = defaultFadeSpeed if myArgs[ 3 ] ~= nil and myArgs[ 2 ] ~= "0" then fads = tonumber( myArgs[ 3 ] ) end if sens < 0 or fads < 0 then PromptDuration( "Negative Args not allowed", 10000 ) return end lights[ e ] = { state = 'init', sensitivity = sens, fadeSpeed = fads, ident = myArgs[ 4 ] } else local dist = defaultTriggerDist if myArgs[ 1 ] == nil then myArgs[ 1 ] = 'Normal' end if myArgs[ 2 ] ~= nil then if string.lower( myArgs[ 2 ] ) == 'zone' then dist = 0 else dist = tonumber( myArgs[ 2 ] ) end end if dist < 0 then PromptDuration( "Negative Args not allowed", 10000 ) return end controls[ e ] = { state = 'init', name = myArgs[ 1 ], dist = dist, ident = myArgs[ 3 ] } end end local function getRGB( id ) local r, g, b = GetLightRGB( id ) return { r = r, g = g, b = b } end local function getPos( id ) local x, y, z = GetLightPosition( id ) return { x = x, y = 0, z = z } end local function inRange( pa, pb, dist ) return U.CloserThan( pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, dist ) end local function lightFadeOn( bulb ) local col = getRGB( bulb.id ) local c = bulb.colour if col.r < c.r or col.g < c.g or col.b < c.b then col.r = min( c.r, col.r + bulb.fadeSpeed * bulb.rFact ) col.g = min( c.g, col.g + bulb.fadeSpeed * bulb.gFact ) col.b = min( c.b, col.b + bulb.fadeSpeed * bulb.bFact ) SetLightRGB( bulb.id, col.r, col.g, col.b ) else SetLightRGB( bulb.id, c.r, c.g, c.b ) bulb.state = 'on' end end local function lightFlickerOn( bulb, timeNow ) local col = getRGB( bulb.id ) local c = bulb.colour if timeNow > bulb.flickerTime then SetLightRGB( bulb.id, c.r, c.g, c.b ) bulb.state = 'on' elseif random() > 0.85 then if bulb.flicker == 'off' then SetLightRGB( bulb.id, c.r, c.g, c.b ) bulb.flicker = 'on' else SetLightRGB( bulb.id, 0, 0, 0 ) bulb.flicker = 'off' end end end local function lightFadeOff( bulb ) local col = getRGB( bulb.id ) local c = bulb.colour if col.r > 0 or col.g > 0 or col.b > 0 then col.r = max( 0, col.r - bulb.fadeSpeed * bulb.rFact ) col.g = max( 0, col.g - bulb.fadeSpeed * bulb.gFact ) col.b = max( 0, col.b - bulb.fadeSpeed * bulb.bFact ) SetLightRGB( bulb.id, col.r, col.g, col.b ) else SetLightRGB( bulb.id, 0, 0, 0 ) bulb.state = 'off' end end local function lightOff( bulb, typ ) if bulb.state ~= 'off' then if typ ~= 'Fade' then local c = bulb.colour SetLightRGB( bulb.id, 0, 0, 0 ) bulb.state = 'off' bulb.ctrEnt = 0 else bulb.state = 'FadeOff' bulb.ctrEnt = 0 end end end local function lightOn( e, bulb, typ, act, timeNow, moving ) local motionDetect = false if act == 'Motion' then motionDetect = true end if bulb.state == 'off' and ( not motionDetect or moving ) then if typ == 'Fade' then bulb.state = 'FadeOn' elseif typ == 'FlickerStart' then bulb.state = 'FlickerOn' bulb.flicker = 'off' bulb.flickerTime = timeNow + ( 1000 + random() * 2000 ) elseif typ == 'FlickerAlways' then bulb.state = 'FlickerAlways' bulb.flicker = 'off' bulb.flickerTime = math.huge else local c = bulb.colour SetLightRGB( bulb.id, c.r, c.g, c.b ) bulb.state = 'on' end bulb.ctrEnt = e elseif motionDetect and not moving then lightOff( bulb, typ ) end end local function processName( name ) local actType = sub( name, 1, 6 ) if actType == 'Motion' or actType == 'OnOnly' or actType == 'Switch' then return sub( name, 7, #name ), actType end actType = sub( name, 1, 7 ) if actType == 'OffOnly' then return sub( name, 8, #name ), actType end actType = sub( name, 1, 8 ) if actType == 'Sequence' then return sub( name, 9, #name ), actType end return name end local function canTrigger( e, control, actType, ePress ) if control.dist == 0 then local Ent = g_Entity[ e ] return Ent.plrinzone == 1 elseif actType == 'Switch' then if U.PlayerLookingNear( e, control.dist, 40 ) then PromptDuration( "Press E to operate switch", reactionDelay ) if ePress and not control.epress then if control.state == 'off' then control.state = 'on' else control.state = 'off' end PlaySound( e, 0 ) control.epress = true return true end end else return U.PlayerCloserThan( e, control.dist ) end end local moving = false local ppx, ppz = 0, 0 local controlEnt = nil local EKeyPressed = false function light_control_main(e) local bulb = lights[ e ] local control = controls[ e ] local timeNow = g_Time if bulb ~= nil then -- PromptLocal( e, bulb.state ) if bulb.state == 'init' then bulb.id = GetEntityLightNumber( e ) bulb.colour = getRGB( bulb.id ) bulb.rFact = bulb.colour.r / 255 bulb.gFact = bulb.colour.g / 255 bulb.bFact = bulb.colour.b / 255 bulb.range = GetLightRange( bulb.id ) * bulb.sensitivity bulb.pos = getPos( bulb.id ) bulb.ctrEnt = 0 SetLightRGB( bulb.id, 0, 0, 0 ) bulb.state = 'off' elseif bulb.state == 'FadeOn' then lightFadeOn( bulb ) elseif bulb.state == 'FadeOff' then lightFadeOff( bulb ) elseif bulb.state == 'FlickerOn' or bulb.state == 'FlickerAlways' then lightFlickerOn( bulb, timeNow ) else return end end if control ~= nil then --PromptLocal( e, control.state .. ", " .. control.name ) if control.state == 'init' then local Ent = g_Entity[ e ] control.pos = { x = Ent.x, y = 0, z = Ent.z } control.timer = g_Time + reactionDelay control.epress = false control.mtime = 0 control.state = 'off' else if controlEnt == nil then controlEnt = e end if controlEnt == e then --Prompt( GetScancode() ) moving = false local tppx, tppz = g_PlayerPosX, g_PlayerPosZ if tppx ~= ppx or tppz ~= ppz then moving = true ppx, ppz = tppx, tppz control.mtime = timeNow + motionDelay elseif timeNow < control.mtime then moving = true end if g_KeyPressE == 1 then EKeyPressed = true end end if timeNow > control.timer then control.timer = timeNow + reactionDelay local mainType, actType = processName( control.name ) if canTrigger( e, control, actType, EKeyPressed ) then -- Prompt( mainType .. ", " .. ( actType or 'nil' ) .. ", " .. control.dist ) for k, v in pairs( lights ) do if v.state ~= 'init' then if control.ident == v.ident then if ( ( actType == 'Switch' and control.state == 'on' ) or ( actType ~= 'OffOnly' and actType ~= 'Switch' ) ) and inRange( control.pos, v.pos, v.range ) then lightOn( e, v, mainType, actType, timeNow, moving ) elseif ( ( actType == 'Switch' and control.state == 'off' ) or ( actType ~= 'OnOnly' and actType ~= 'Switch' ) ) and ( v.ctrEnt == e or ( actType == 'OffOnly' and inRange( control.pos, v.pos, v.range ) ) ) then lightOff( v, mainType ) end end end end elseif actType ~= 'OnOnly' and actType ~= 'OffOnly' and actType ~= 'Switch' then for k, v in pairs( lights ) do if ( v.ctrEnt == e or control.ident == v.ident ) and v.state ~= 'off' and inRange( control.pos, v.pos, v.range ) then lightOff( v, mainType ) end end end if controlEnt == e and g_KeyPressE == 0 then EKeyPressed = false end if not EKeyPressed then control.epress = false end end end end end