-- 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 atan = math.atan2 local sqrt = math.sqrt local lower = string.lower local random= math.random local torches = {} local lights = {} --local torchimages = torchimages or ParticlesLoadImage( "effectbank\\particles\\fire\\gtorch.dds", 10 ) local torchimages = torchimages or ParticlesLoadImage( "effectbank\\particles\\fire2\\torchflame115.dds", 10 ) local candleimages = candleimages or ParticlesLoadImage( "effectbank\\particles\\fire2\\candleturb64.dds", 11 ) local lanternimages = lanternimages or ParticlesLoadImage( "effectbank\\particles\\fire2\\lant.dds", 12 ) local Xref = { [ 'ignite\\torch' ] = { name = 'TorchPOV', limb = 25 }, [ 'ignite\\lantern' ] = { name = 'LanternPOV', limb = 57 }, [ 'ignite\\candle' ] = { name = 'CandlePOV', limb = 25 } } local posOffsets = { TorchPOV = { x = 1, y = 0, z = 5.5 }, LanternPOV = { x = 0.5, y = 0, z = 3.9 }, CandlePOV = { x = -1, y = 0, z = 3.0 } } function ignitetorch3_init_name( e, name ) Include( "utillib.lua" ) Include( "quatlib.lua" ) if name == 'Light' then lights[ e ] = { used = false } else torches[ e ] = { state = 'init', name = name, light = nil } end CollisionOff( e ) Hide( e ) SetAnimation( 0 ) end local timeDiff = 1 local lastTime = nil local lastPos = nil local function smoothMotion( e, rx, ry, rz, aY, t ) local x, _, z = U.Rotate3D( 0, 0, 1, 0, aY, 0 ) --if lastPos == nil then -- t.angle = 0 -- lastPos = { x = rx + x, z = rz + z } --else -- local nx, nz = rx + x, rz + z -- local dx, dz = nx - lastPos.x, nz - lastPos.z -- t.angle = sqrt( dx^2 + dz^2 ) / 10 -- lastPos = { x = nx, z = nz } --end local obj = g_Entity[ e ].obj PositionObject( obj, rx, ry, rz ) RotateObject( obj, g_PlayerAngX, deg( aY), 0 ) 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 function setAngle( t, aX, aY ) local quat = Q.FromEuler( aX, aY, 0 ) if t.name == "TorchPOV" then quat = Q.Mul( quat, Q.FromEuler( 0, 0, rad( 5 ) ) ) end 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 setScale( t ) local scale = 7 if t.name == 'TorchPOV' then scale = 26 end if t.emitter1 ~= nil then ParticlesSetScale( t.emitter1.id, scale, scale, scale, scale ) end if t.emitter2 ~= nil then ParticlesSetScale( t.emitter2.id, scale, scale, scale, scale ) end end local tweakVals = { TorchPOV = { x = -1.5, y = 0.1, z = -0.2, xr = 0.0, yr = 0.0, zr = 0.0 }, LanternPOV = { x = 0.0, y = 0.2, z = 0.0, xr = 0.0, yr = 0.0, zr = 0.0 }, CandlePOV = { x = 0.0, y = -0.2, z = 0.0, xr = 0.0, yr = 0.0, zr = 0.0 } } local function update( t, aX, aY, aZ, curTime ) local tv = tweakVals[ t.name ] local xo, yo, zo = U.Rotate3D( tv.x, tv.y, tv.z, aX, aY, aZ ) setAngle( t, aX * 2, aY ) setScale( t ) if t.emitter1 ~= nil then ParticlesSetOffset( t.emitter1.id, min( xo - tv.xr, xo + tv.xr ), min( yo - tv.yr, yo + tv.yr ), min( zo - tv.zr, zo + tv.zr ), max( xo - tv.xr, xo + tv.xr ), max( yo - tv.yr, yo + tv.yr ), max( zo - tv.zr, zo + tv.zr ) ) frameIncrement( t.emitter1, curTime ) ParticlesSpawnParticle( t.emitter1.id ) end if t.emitter2 ~= nil then ParticlesSetOffset( t.emitter2.id, min( xo - tv.xr, xo + tv.xr ), min( yo - tv.yr, yo + tv.yr ), min( zo - tv.zr, zo + tv.zr ), max( xo - tv.xr, xo + tv.xr ), max( yo - tv.yr, yo + tv.yr ), max( zo - tv.zr, zo + tv.zr ) ) frameIncrement( t.emitter2, curTime ) ParticlesSpawnParticle( t.emitter2.id ) end end local emDetails = { TorchPOV = { img1 = { id = torchimages, frames = 121 }, img2 = { id = torchimages, frames = 121 } }, LanternPOV = { img1 = { id = lanternimages, frames = 16 } }, CandlePOV = { img1 = { id = candleimages, frames = 64 } } } local function addEmitters( e, t, limb ) local em = emDetails[ t.name ] if em.img1 ~= nil then t.emitter1 = { id = ParticlesGetFreeEmitter(), frm = em.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 6, 6, 6, 6, -- 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, e, limb, em.img1.id, em.img1.frames ) end if em.img2 ~= nil then t.emitter2 = { id = ParticlesGetFreeEmitter(), frm = em.img1.frames - 1, frc = 20, frt = 0, fri = 21.28 } local ymin, ymax = em.img1.yspl, em.img1.ysph ParticlesAddEmitterEx( t.emitter2.id, 0, 1, -- Offset: minX minY minZ maxX maxY maxZ 0, 0, 0, 0, 0, 0, -- Scale: startMin startMax endMin endMax 0, 0, 0, 0, -- 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, e, limb, em.img2.id, em.img2.frames ) end if t.name == 'TorchPOV' then 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 ) else -- max mpf ParticlesSetLife( t.emitter1.id, -1, 25, 25, 100, 0, 20) 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 lightOffs = { TorchPOV = { x = 10, y = 25, z = 30.0 }, LanternPOV = { x = -5, y = -3, z = 25.0 }, CandlePOV = { x = 3, y = 5, z = 30.0 } } local collOffs = { TorchPOV = { ybot = -10, ytop = 5, dist = 7 }, LanternPOV = { ybot = -5, ytop = 5, dist = 9 }, CandlePOV = { ybot = -15, ytop = 15, dist = 10 } } 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( torch, nx, ny, nz, aForwd, Ent ) 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[ torch.name ] 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, Ent.obj ) or AnythingThere( nx, topY, nz, co.dist, aForwd, Ent.obj ) or AnythingThere( nx, botY, nz, co.dist, aLeft45, Ent.obj ) or AnythingThere( nx, topY, nz, co.dist, aLeft45, Ent.obj ) or AnythingThere( nx, botY, nz, co.dist, aRght45, Ent.obj ) or AnythingThere( nx, topY, nz, co.dist, aRght45, Ent.obj ) or AnythingThere( nx, botY, nz, co.dist, aLeft90, Ent.obj ) or AnythingThere( nx, topY, nz, co.dist, aLeft90, Ent.obj ) or AnythingThere( nx, botY, nz, co.dist, aRght90, Ent.obj ) or AnythingThere( nx, topY, nz, co.dist, aRght90, Ent.obj ) then SetGamePlayerControlPushangle( wrapAng( g_PlayerAngY - 180 ) ) SetGamePlayerControlPushforce( 0.8 ) end end end local lightVals = { TorchPOV = { nmin = 650, nmax = 800, nspeed = 100 }, LanternPOV = { nmin = 400, nmax = 475, nspeed = 300, nfuel = 700 }, CandlePOV = { nmin = 250, nmax = 300, nspeed = 300 } } local quell = 0 local whispvol = 0 local timer = 0 local nolight = 300 local nolightspeed = 500 local killplayer = 0 function SetQuell( val ) quell = val end local flickerMin, flickerMax = 20, 50 local function HandleLight( t, timeNow ) local lv = t.lv if t.flickerTime == nil or timeNow > t.flickerTime then t.range = random( lv.nmin, lv.nmax ) t.flickerTime = timeNow + random( flickerMin, flickerMax ) end SetLightRange ( t.light, t.range ) if t.name == 'TorchPOV' then SetLightRGB( t.light, 255 - 3200 / lv.nmax, 175 - 6400 / lv.nmax, 89 - 6400 / lv.nmax ) elseif t.name == 'CandlePOV' then SetLightRGB( t.light, 255 - 200 / lv.nmax, 175 - 6400 / lv.nmax, 89 - 6400 / lv.nmax ) elseif t.name == 'LanternPOV' then SetLightRGB( t.light, 255 - 3200 / lv.nmax, 175 - 6400 / lv.nmax, 89 - 6400 / lv.nmax ) end end local function HandleSoundAndSpeed( t, timeNow ) SetGamePlayerControlCanRun( 0 ) if t.name == 'TorchPOV' then whispvol = max( 99 - t.lv.nmin / 12 - quell ) SetGamePlayerControlTopspeed( 0.7 ) elseif t.name == 'CandlePOV' then whispvol = max( 1, 99 - t.lv.nmin / 6 - quell ) SetGamePlayerControlTopspeed( 1 ) elseif t.name == 'LanternPOV' then whispvol = max( 1, 99 - t.lv.nmin / 9 - quell ) SetGamePlayerControlTopspeed( 0.45 ) end if quell == 0 and nolight > 1 then if whispvol >= 1 and nolightstart == 0 then timer = timeNow + nolightspeed nolightstart = 1 elseif timeNow > timer then nolight = nolight - 1 whispvol = max( 1, 99.9 - nolight ) timer = timeNow + nolightspeed end end SetGlobalSoundVolume ( 1, whispvol ) if GetGlobalSoundPlaying( 1 ) ~= 1 then PlayGlobalSound( 1 ) end end local function HandleDeath( t ) if whispvol > 98 and killplayer == 0 then ForcePlayer( random( 0, 360 ), 5 ) SetPlayerHealth( 0 ) killplayer = 1 end end local soundLoaded = false local plx, plz = 0, 0 function ignitetorch3_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!" ) end if not soundLoaded then HideHuds() LoadGlobalSound( "audiobank\\Ignite\\ghostlywhispers.ogg", 1 ) --LoadGlobalSound( "audiobank\\Ignite\\torchignite.ogg", 2 ) soundLoaded = true end --return end local thisEnt = false local gunName = g_PlayerGunName for k, v in pairs( Xref ) do if lower( gunName ) == k then if torch.name == v.name then if torch.state == 'init' then local lv = lightVals[ torch.name ] torch.lv = { nmin = lv.nmin, nmax = lv.nmax, nspeed = lv.nspeed, nfuel = lv.nfuel } addEmitters( e, torch, v.limb ) torch.state = 'used' Show( e ) SetAnimation( 1 ) LoopAnimation( e ) end thisEnt = true elseif torch.name ~= v.name then if torch.state == 'used' then torch.state = 'init' 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 SetLightRGB( torch.light, 0, 0, 0 ) Hide( e ) end end end end if not thisEnt then return end local Ent = g_Entity[ e ] local timeThisFrame = g_Time if lastTime == nil then lastTime = timeThisFrame timeDiff = 1 else timeDiff = ( timeThisFrame - lastTime ) / ( 1000 / 60 ) lastTime = timeThisFrame end --local pX, pY, pZ = g_PlayerPosX, g_PlayerPosY + 28.5, g_PlayerPosZ local pX, pY, pZ = GetCameraPositionX(0) , GetCameraPositionY(0) , GetCameraPositionZ(0) --if GetGamePlayerStatePlayerDucking() == 1 then pY = pY - 18.5 end --local aX, aY, aZ = rad( g_PlayerAngX ), rad( g_PlayerAngY ), rad( g_PlayerAngZ ) local aX, aY, aZ = rad( GetCameraAngleX( 0 ) ) / 2, rad( GetCameraAngleY( 0 ) ), rad( GetCameraAngleZ( 0 ) ) local offs = posOffsets[ torch.name ] local XO, YO, ZO = U.Rotate3D ( offs.x, offs.y, offs.z, aX, aY, aZ ) local lx, ly, lz = pX + XO, pY + YO, pZ + ZO smoothMotion( e, lx, ly, lz, aY, torch ) update( torch, aX, aY, aZ, timeThisFrame ) -- light position etc local lo = lightOffs[ torch.name ] XO, YO, ZO = U.Rotate3D ( lo.x, lo.y, lo.z, aX, aY, aZ ) lx, ly, lz = pX + XO, pY + YO, pZ + ZO SetLightPosition( torch.light, lx, ly, lz ) HandleLight( torch, timeThisFrame ) HandleCollision( torch, lx, ly, lz, aY, Ent ) --HandleSoundAndSpeed( torch, timeThisFrame ) HandleDeath( torch ) --Prompt( whispvol .. ", " .. nolight .. ", " .. (torch.emitter1.frc or 'nil') ) end