-- LUA Script - precede every function and global member with lowercase name of script + '_main' local U = require "scriptbank\\utillib" local Q = require "scriptbank\\quatlib" local rad = math.rad local deg = math.deg local min = math.min local max = math.max local torches = {} local lights = {} function torchgo_init_name( e, name ) Include( "utillib.lua" ) Include( "quatlib.lua" ) if name == 'Light' then lights[ e ] = { used = false } Hide( e ) else local Ent = g_Entity[ e ] torches[ e ] = { state = 'init', name = name, obj = Ent.obj, light = nil, lightOn = false, range = 500 } end end local function GetLight( e ) local E1 = g_Entity[ e ] for k, v in pairs( lights ) do if not v.used then local E2 = g_Entity[ k ] if U.CloserThan( E1.x, E1.y, E1.z, E2.x, E2.y, E2.z, 100 ) then lights[ k ].used = true return GetEntityLightNumber( k ) end end end end local flameOffs = { x = -0.9, y = 2.2, z = 20 } local lightOffs = { x = 0, y = 0, z = 20 } local carryOffs = { x = -12, y = -10, z = 23 } local collOffs = { ybot = -10, ytop = 5, dist = 7 } local RayCastEnt = IntersectAll local RayCastTer = RayTerrain local function AnythingThere( x, y, z, dist, aY , ignore ) local x1, _, z1 = U.Rotate3D( 0, 0, dist, 0, aY, 0 ) local objectHit = RayCastEnt( x, y, z, x + x1, y, z + z1, ignore ) if objectHit ~= nil and objectHit ~= 0 then return true end if RayCastTer( x, y, z, x + x1, y, z + z1 ) == 1 then return true end end local function wrapAng( ang ) if ang < 0 then return 360 + ang end if ang > 360 then return ang -360 end return ang end local lastx, lasty, lastz = 0, 0, 0 local function HandleCollision( t, nx, ny, nz, aForwd ) if lastx == 0 then lastx, lasty, lastz = nx, ny, nz return end if nx ~= lastx or ny ~= lasty or nz ~= lastz then lastx, lasty, lastz = nx, ny, nz -- stop player pushing carried entity through other objects -- treat light as a cylinder and detect other entities in front of it local co = collOffs local botY, topY = ny + co.ybot, ny + co.ytop local aLeft45, aRght45 = aForwd - rad( 45 ), aForwd + rad( 45 ) local aLeft90, aRght90 = aForwd - rad( 90 ), aForwd + rad( 90 ) if AnythingThere( nx, botY, nz, co.dist, aForwd, t.obj ) or AnythingThere( nx, topY, nz, co.dist, aForwd, t.obj ) or AnythingThere( nx, botY, nz, co.dist, aLeft45, t.obj ) or AnythingThere( nx, topY, nz, co.dist, aLeft45, t.obj ) or AnythingThere( nx, botY, nz, co.dist, aRght45, t.obj ) or AnythingThere( nx, topY, nz, co.dist, aRght45, t.obj ) or AnythingThere( nx, botY, nz, co.dist, aLeft90, t.obj ) or AnythingThere( nx, topY, nz, co.dist, aLeft90, t.obj ) or AnythingThere( nx, botY, nz, co.dist, aRght90, t.obj ) or AnythingThere( nx, topY, nz, co.dist, aRght90, t.obj ) then SetGamePlayerControlPushangle( wrapAng( g_PlayerAngY - 180 ) ) SetGamePlayerControlPushforce( 0.8 ) end end end local torchimage = torchimage or ParticlesLoadImage( "effectbank\\particles\\torchflame115.png", 10 ) local ems = { img1 = { id = torchimage, frames = 121 }, img2 = { id = torchimage, frames = 121 } } local function addEmitters( e, t ) if ems.img1 ~= nil then t.emitter1 = { id = ParticlesGetFreeEmitter(), frm = ems.img1.frames - 1, frc = 0, frt = 0, fri = 23.25 } ParticlesAddEmitterEx( t.emitter1.id, 0, 0, -- Offset: minX minY minZ maxX maxY maxZ 0, 0, 0, 0, 0, 0, -- Scale: startMin startMax endMin endMax 28, 28, 28, 28, -- Speed (vector): minX minY minZ maxX maxY maxZ 0, 0, 0, 0, 0, 0, -- Rotate Z: minZ maxZ, Lifemin Lifemax 0, 0, 0, 0, -- Alpha: startMin startMax endMin endMax 70, 70, 70, 70, -- Freq, entityid, limbindex, particleimage, imageframes -1, 0, 0, ems.img1.id, ems.img1.frames ) end if ems.img2 ~= nil then t.emitter2 = { id = ParticlesGetFreeEmitter(), frm = ems.img1.frames - 1, frc = 20, frt = 0, fri = 21.28 } ParticlesAddEmitterEx( t.emitter2.id, 0, 1, -- Offset: minX minY minZ maxX maxY maxZ 0, 0, 0, 0, 0, 0, -- Scale: startMin startMax endMin endMax 28, 28, 28, 28, -- Speed (vector): minX minY minZ maxX maxY maxZ 0, 0, 0, 0, 0, 0, -- Rotate Z: minZ maxZ, Lifemin Lifemax 0, 0, 0, 0, -- Alpha: startMin startMax endMin endMax 70, 70, 70, 70, -- Freq, entityid, limbindex, particleimage, imageframes -1, 0, 0, ems.img2.id, ems.img2.frames ) end t.emitter1.frm = 115 t.emitter2.frm = 115 ParticlesSetLife( t.emitter1.id, -1, 25, 25, 100, 0, 20) ParticlesSetLife( t.emitter2.id, -1, 25, 25, 100, 0, 20 ) ParticlesLoadEffect( "effectbank\\reloaded\\decal_basic_additive.fx", t.emitter1.id ) ParticlesLoadEffect( "effectbank\\reloaded\\decal_basic_additive.fx", t.emitter2.id ) end local function frameIncrement( em, curTime ) if curTime > em.frt then em.frt = curTime + em.fri if em.frc < em.frm then em.frc = em.frc + 1 else em.frc = 0 end end ParticlesSetFrames( em.id, 1, em.frc, em.frc ) end local rotq1 = Q.FromEuler( rad( -60 ), rad( -10 ), rad( -20 ) ) local rotq2 = Q.FromEuler( rad( -25 ), rad( -10 ), rad( 12 ) ) local revq = Q.FromEuler( 0, rad( 180 ), 0 ) local function setAngle( t, aX, aY ) local quat = Q.FromEuler( aX, aY, 0 ) quat = Q.Mul( quat, revq ) quat = Q.Mul( quat, rotq2 ) local ax, ay, az = Q.ToEuler( quat ) if t.emitter1 ~= nil then ParticlesSetAngle( t.emitter1.id, deg( ax ), deg( ay ), deg( az ) ) end if t.emitter2 ~= nil then ParticlesSetAngle( t.emitter2.id, deg( ax ), deg( ay ), deg( az ) ) end end local function update( t, x, y, z, aX, aY, aZ, curTime ) setAngle( t, aX * 1.1, aY ) if t.emitter1 ~= nil then frameIncrement( t.emitter1, curTime ) ParticlesSpawnParticle( t.emitter1.id, x, y, z ) end if t.emitter2 ~= nil then frameIncrement( t.emitter2, curTime ) ParticlesSpawnParticle( t.emitter2.id, x, y, z ) end end local controlEnt = nil local lastTime = nil local timeDiff = 1 local lookingAt = nil local carried = nil local Epressed = false local flickerAmount = 20 local flickerRate = 2 local rangeMin = 380 local rangeMax = 620 local fpressed = false local torchx, torchy, torchz = 0, 0, 0 local angx, angy, angz = 0, 0, 0 function torchgo_main( e ) local torch = torches[ e ] if torch == nil then return end if torch.light == nil then torch.light = GetLight( e ) if torch.light ~= nil then SetLightRGB( torch.light, 0, 0, 0 ) else PromptLocal( e, "No light!" ) return end end --PromptLocal( e, torch.name .. ", " .. torch.state .. ", " .. ( carried or 'nil' ) .. ", " .. ( lookingAt or 'nil' ) ) if controlEnt == nil then controlEnt = e end local timeThisFrame = g_Time if controlEnt == e then if lastTime == nil then lastTime = timeThisFrame timeDiff = 1 else timeDiff = ( timeThisFrame - lastTime ) / ( 1000 / 60 ) lastTime = timeThisFrame end end if torch.state == 'init' then if carried == nil and U.PlayerLookingNear( e, 80, 40 ) and GetEntityVisibility( e ) == 1 and ( lookingAt == nil or lookingAt == e ) then Prompt( "Press E to pick up " .. torch.name ) lookingAt = e if g_KeyPressE == 1 then if not Epressed then Epressed = true PromptLocal( e, "" ) torch.state = 'carried' lookingAt = nil carried = e SetFlashLight( 0 ) SetFlashLightKeyEnabled( 0 ) addEmitters( e, torch ) torch.lightOn = true end else Epressed = false end elseif U.PlayerLookingNear( e, 80, 40 ) and GetEntityVisibility( e ) == 1 and lookingAt == nil then local carriedTorch = torches[ carried ] lookingAt = e Prompt( "Press E to swap " .. carriedTorch.name .. " with " .. torch.name ) if g_KeyPressE == 1 then if not Epressed then Epressed = true carriedTorch.state = 'dropped' local Ent = g_Entity[ e ] carriedTorch.posx = Ent.x carriedTorch.posy = Ent.y carriedTorch.posz = Ent.z carriedTorch.angY = Ent.angley carriedTorch.lightOn = false if carriedTorch.emitter1 ~= nil then ParticlesDeleteEmitter( carriedTorch.emitter1.id ) carriedTorch.emitter1 = nil end if carriedTorch.emitter2 ~= nil then ParticlesDeleteEmitter( carriedTorch.emitter2.id ) carriedTorch.emitter2 = nil end SetLightRGB( carriedTorch.light, 0, 0, 0 ) torch.lightOn = true torch.state = 'carried' SetFlashLight( 0 ) SetFlashLightKeyEnabled( 0 ) addEmitters( e, torch ) PromptLocal( e, "" ) lookingAt = nil carried = e end else Epressed = false end else lookingAt = nil end elseif torch.state == 'dropped' then local terry = GetTerrainHeight( torch.posx, torch.posz ) if torch.posy < terry then torch.posy = terry end PositionObject( torch.obj, torch.posx, torch.posy + 2, torch.posz ) RotateObject( torch.obj, 0, torch.angY, 0 ) CollisionOn( e ) PushObject( torch.obj, 0, 0, 0 ) torch.state = 'init' Show( e ) elseif torch.state == 'carried' then --if torchx == 0 then torchx, torchy, torchz = GetCameraPositionX(0) , GetCameraPositionY(0) , GetCameraPositionZ(0) angx, angy, angz = rad( GetCameraAngleX( 0 ) / 1.1 ), rad( GetCameraAngleY( 0 ) ), rad( GetCameraAngleZ( 0 ) ) --end if lookingAt == nil then if g_KeyPressSHIFT == 1 and g_KeyPressE == 1 then if not Epressed then Epressed = true torch.posx, torch.posy, torch.posz = GetEntityPosAng( e ) torch.angY = 0 torch.state = 'dropped' torch.lightOn = false carried = nil lookingAt = nil SetLightRGB( torch.light, 0, 0, 0 ) if torch.emitter1 ~= nil then ParticlesDeleteEmitter( torch.emitter1.id ) torch.emitter1 = nil end if torch.emitter2 ~= nil then ParticlesDeleteEmitter( torch.emitter2.id ) torch.emitter2 = nil end SetFlashLightKeyEnabled( 1 ) return end else Epressed = false end end local pX, pY, pZ = torchx, torchy, torchz local aX, aY, aZ = angx, angy, angz local XO, YO, ZO = U.Rotate3D ( carryOffs.x, carryOffs.y, carryOffs.z, aX, aY, aZ ) local lx, ly, lz = pX + XO, pY + YO, pZ + ZO local quat = Q.FromEuler( rad( g_PlayerAngX ), aY, 0 ) local lX, lY, lZ = Q.ToEuler( Q.Mul( quat, rotq1 ) ) CollisionOff( e ) PositionObject( torch.obj, lx, ly, lz ) RotateObject( torch.obj, deg( lX ), deg( lY ), deg( lZ ) ) -- now position flame XO, YO, ZO = U.Rotate3D ( flameOffs.x, flameOffs.y, flameOffs.z, lX, lY, lZ ) local fx, fy, fz = lx + XO, ly + YO, lz + ZO if g_KeyPressF == 1 then if not fpressed then fpressed = true torch.lightOn = not torch.lightOn end else fpressed = false end HandleCollision( torch, fx, fy, fz, aY ) if not torch.lightOn then Hide( e ) SetLightRGB( torch.light, 0, 0, 0 ) return else Show( e ) HandleCollision( torch, fx, fy, fz, aY ) end update( torch, fx, fy, fz, aX, aY, aZ, timeThisFrame ) -- and finally light XO, YO, ZO = U.Rotate3D ( lightOffs.x, lightOffs.y, lightOffs.z, lX, lY, lZ ) lx, ly, lz = lx + XO, ly + YO, lz + ZO SetLightPosition( torch.light, lx, ly, lz ) if torch.flicker == nil then torch.flicker = flickerAmount torch.increment = -flickerRate end SetLightRGB( torch.light, 200 + torch.flicker, 155 + torch.flicker, 0 ) torch.flicker = torch.flicker + torch.increment if torch.flicker < -flickerAmount then torch.increment = flickerRate * timeDiff elseif torch.flicker > flickerAmount then torch.increment = -flickerRate * timeDiff end SetLightRange ( torch.light, torch.range ) end end