local U = require "scriptbank\\utillib" local sub = string.sub local rad = math.rad local emitterDetails = {} local autoSaveTime = 10000 -- 20 seconds -- first 2 images are loaded by default, i.e. 1 - 2, 3 onwards are free for user to specify local ImageFiles = { [1] = { name = "Smoke", frames = 64 }, [2] = { name = "Flare", frames = 64 }, -- user defineable images [3] = { name = "effectbank\\particles\\flowerpuff.png", frames = 64 }, [4] = { name = "effectbank\\particles\\sparkthing.png", frames = 64 }, [5] = { name = "effectbank\\particles\\imploder.dds", frames = 16 } } local shaderFiles = { [1] = "effectbank\\reloaded\\decal_basic.fx", [2] = "effectbank\\reloaded\\decal_basic_additive.fx" } local maxImages = 2 local function loadImageFiles() for k, v in pairs( ImageFiles ) do if k > 2 then ParticlesLoadImage( v.name, k ) maxImages = maxImages + 1 end end end function particles_tester_init_name( e, name ) emitterDetails[ e ] = { state = 'init', name = name, line = 21, mode = 'entity', limb = 0 } HideHuds() end local function addBackslash( str ) local outStr = "" for i = 1, #str do local ch = sub( str, i, i ) outStr = outStr .. ch if ch == '\\' then outStr = outStr .. '\\' end end return outStr end local function CreateEmitter( em, e ) local emitter = ParticlesGetFreeEmitter() if emitter == -1 then return end local v = em.values local entity = e local limb = 0 if em.mode == 'player' then entity = -1 else limb = em.limb end local frames = ImageFiles[ em.image ].frames ParticlesAddEmitterEx( emitter, v[28], 0, v[1], v[3], v[5], v[2], v[4], v[6], v[13], v[14], v[15], v[16], v[7], v[9], v[11], v[8], v[10], v[12] , v[21], v[22], v[24], v[25], v[17], v[18], v[19], v[20], v[23], entity, limb, em.image, frames ) return emitter end local scrXmod = 2560 / GetDeviceWidth() local scrYmod = 1440 / GetDeviceHeight() * 1.2 local perChar = { 25/65, 12/65, 33/60 } local function DisplayText( x, y, size, text, addPanel ) if size > 3 or size < 1 then size = 1 end local numChars = string.len( text ) local panelWidth = scrXmod * numChars * perChar[ size ] if addPanel then Panel( x - 1, y - 1 - scrYmod , x + panelWidth, y + scrYmod ) TextColor( x, y, size, text, 200, 0, 0) else Text( x, y, size, text ) end end local sz = 3 local ro = 85 - 5 * scrXmod local function displayDetails( em ) local v = em.values DisplayText( ro, 3, sz, "Position: Min X > " .. v[ 1 ] .. " <", em.line == 1 ) DisplayText( ro, 8, sz, "Position: Max X > " .. v[ 2 ] .. " <", em.line == 2 ) DisplayText( ro, 13, sz, "Position: Min Y > " .. v[ 3 ] .. " <", em.line == 3 ) DisplayText( ro, 18, sz, "Position: Max Y > " .. v[ 4 ] .. " <", em.line == 4 ) DisplayText( ro, 23, sz, "Position: Min Z > " .. v[ 5 ] .. " <", em.line == 5 ) DisplayText( ro, 28, sz, "Position: Max Z > " .. v[ 6 ] .. " <", em.line == 6 ) DisplayText( ro, 33, sz, "Speed : Min X > " .. v[ 7 ] .. " <", em.line == 7 ) DisplayText( ro, 38, sz, "Speed : Max X > " .. v[ 8 ] .. " <", em.line == 8 ) DisplayText( ro, 43, sz, "Speed : Min Y > " .. v[ 9 ] .. " <", em.line == 9 ) DisplayText( ro, 48, sz, "Speed : Max Y > " .. v[ 10 ] .. " <", em.line == 10 ) DisplayText( ro, 53, sz, "Speed : Min Z > " .. v[ 11 ] .. " <", em.line == 11 ) DisplayText( ro, 58, sz, "Speed : Max Z > " .. v[ 12 ] .. " <", em.line == 12 ) DisplayText( ro, 63, sz, "Scale : BegMin > " .. v[ 13 ] .. " <", em.line == 13 ) DisplayText( ro, 68, sz, "Scale : BegMax > " .. v[ 14 ] .. " <", em.line == 14 ) DisplayText( ro, 73, sz, "Scale : EndMin > " .. v[ 15 ] .. " <", em.line == 15 ) DisplayText( ro, 78, sz, "Scale : EndMax > " .. v[ 16 ] .. " <", em.line == 16 ) DisplayText( ro, 83, sz, "Alpha : BegMin > " .. v[ 17 ] .. " <", em.line == 17 ) DisplayText( ro, 88, sz, "Alpha : BegMax > " .. v[ 18 ] .. " <", em.line == 18 ) DisplayText( ro, 93, sz, "Alpha : EndMin > " .. v[ 19 ] .. " <", em.line == 19 ) DisplayText( ro, 98, sz, "Alpha : EndMax > " .. v[ 20 ] .. " <", em.line == 20 ) DisplayText( 2, 3, sz, "Rotate : Min > " .. v[ 21 ] .. " <", em.line == 21 ) DisplayText( 2, 8, sz, "Rotate : Max > " .. v[ 22 ] .. " <", em.line == 22 ) DisplayText( 2, 13, sz, "Spawn Rate : > " .. v[ 23 ] .. " <", em.line == 23 ) DisplayText( 2, 18, sz, "Life Min : > " .. v[ 24 ] .. " <", em.line == 24 ) DisplayText( 2, 23, sz, "Life Max : > " .. v[ 25 ] .. " <", em.line == 25 ) DisplayText( 2, 28, sz, "Max Particles : > " .. v[ 26 ] .. " <", em.line == 26 ) DisplayText( 2, 33, sz, "Max Per frame : > " .. v[ 27 ] .. " <", em.line == 27 ) DisplayText( 2, 38, sz, "AnimSpeed : > " .. v[ 28 ] .. " <", em.line == 28 ) DisplayText( 2, 43, sz, "Gravity Min : > " .. v[ 29 ] .. " <", em.line == 29 ) DisplayText( 2, 48, sz, "Gravity Max : > " .. v[ 30 ] .. " <", em.line == 30 ) DisplayText( 2, 53, sz, "Wind Angle : > " .. v[ 31 ] .. " <", em.line == 31 ) DisplayText( 2, 58, sz, "Wind Amount : > " .. v[ 32 ] .. " <", em.line == 32 ) end local function displayOthers( em ) DisplayText( 2, 63, sz, "Mode : > " .. em.mode .. " <", em.line == 33 ) if em.mode == 'entity' then DisplayText( 2, 68, sz, "Limb index : > " .. em.limb .. " <", em.line == 34 ) end local img = ImageFiles[ em.image ] local shd = shaderFiles[ em.shader ] DisplayText( 2, 83, sz, "ImageFile : > " .. img.name .. " <", em.line == 35 ) DisplayText( 2, 88, sz, "ShaderFile : > " .. shd .. " <", em.line == 36 ) DisplayText( 2, 93, sz, "SAVE : > " .. em.name .. "_" .. em.vers .. ".lua" .. " <", em.line == 37 ) end local incVals = { { inc = 0.01, llim = -1000, ulim = 1000, typ = 'min' }, -- minX Positional increments { inc = 0.01, llim = -1000, ulim = 1000, typ = 'max' }, -- maxX { inc = 0.01, llim = -1000, ulim = 1000, typ = 'min' }, -- minY { inc = 0.01, llim = -1000, ulim = 1000, typ = 'max' }, -- maxY { inc = 0.01, llim = -1000, ulim = 1000, typ = 'min' }, -- minZ { inc = 0.01, llim = -1000, ulim = 1000, typ = 'max' }, -- maxZ { inc = 0.01, llim = -50, ulim = 50, typ = 'min' }, -- minX Speed increments { inc = 0.01, llim = -50, ulim = 50, typ = 'max' }, -- maxX { inc = 0.01, llim = -50, ulim = 50, typ = 'min' }, -- minY { inc = 0.01, llim = -50, ulim = 50, typ = 'max' }, -- maxY { inc = 0.01, llim = -50, ulim = 50, typ = 'min' }, -- minZ { inc = 0.01, llim = -50, ulim = 50, typ = 'max' }, -- maxZ { inc = 0.5, llim = 0, ulim = 500, typ = 'min' }, -- Scale increments { inc = 0.5, llim = 0, ulim = 500, typ = 'max' }, { inc = 0.5, llim = 0, ulim = 500, typ = 'min' }, { inc = 0.5, llim = 0, ulim = 500, typ = 'max' }, { inc = 0.5, llim = 0, ulim = 100, typ = 'min' }, -- Alpha increments { inc = 0.5, llim = 0, ulim = 100, typ = 'max' }, { inc = 0.5, llim = 0, ulim = 100, typ = 'min' }, { inc = 0.5, llim = 0, ulim = 100, typ = 'max' }, { inc = 0.1, llim = -10, ulim = 10, typ = 'min' }, -- Rotate increments { inc = 0.1, llim = -10, ulim = 10, typ = 'max' }, { inc = 1, llim = 0, ulim = 2000, typ = 'nml' }, -- Spawn Rate { inc = 1, llim = 0, ulim = 10000, typ = 'min' }, -- Life Min { inc = 1, llim = 0, ulim = 10000, typ = 'max' }, -- Life Max { inc = 1, llim = 0, ulim = 1000, typ = 'nml' }, -- Max total { inc = 1, llim = 0, ulim = 100, typ = 'nml' }, -- Max per frame { inc = 0.05, llim = 0, ulim = 20, typ = 'nml' }, -- Animspeed { inc = 0.05, llim = -10, ulim = 10, typ = 'min' }, -- Gravity min { inc = 0.05, llim = -10, ulim = 10, typ = 'max' }, -- Gravity max { inc = 0.5, llim = 0, ulim = 359, typ = 'nml' }, -- Wind angle { inc = 0.05, llim = 0, ulim = 10, typ = 'nml' } -- Wind amount } local function saveRaw( em ) local file = io.open( "scriptbank\\" .. em.name .. ".raw", "w+" ) io.output( file ) if file ~= nil then for k, v in pairs( em.values ) do io.write( k, "\n" ) io.write( v, "\n" ) end io.close( file ) end end local function loadRaw( em ) local file = io.open( "scriptbank\\" .. em.name .. ".raw", "r") if file ~= nil then for i = 1, #em.values do local index = tonumber( file:read() ) em.values[ index ] = tonumber( file:read() ) end io.close( file ) end end local function SaveValues( em ) local file = io.open( "scriptbank\\" .. em.name .. "_" .. em.vers .. ".lua", "w+" ) if file ~= nil then local v = em.values local frames = ImageFiles[ em.image ].frames io.output( file ) if em.image > 2 then io.write( "local img = ParticlesLoadImage( '" .. addBackslash( ImageFiles[ em.image ].name ) .. "' )", "\n" ) else io.write( "local img = " .. em.image, "\n" ) end io.write( "", "\n" ) io.write( "local emitterId = ParticlesGetFreeEmitter()", "\n" ) io.write( "", "\n" ) io.write( "ParticlesAddEmitterEx( emitterId,", "\n" ) io.write( " " .. v[ 28 ] .. ", -- anim speed", "\n" ) io.write( " " .. 0 .. ", -- start random", "\n" ) io.write( " " .. v[ 1 ] .. ", -- xpos min", "\n" ) io.write( " " .. v[ 3 ] .. ", -- ypos min", "\n" ) io.write( " " .. v[ 5 ] .. ", -- zpos min", "\n" ) io.write( " " .. v[ 2 ] .. ", -- xpos max", "\n" ) io.write( " " .. v[ 4 ] .. ", -- ypos max", "\n" ) io.write( " " .. v[ 6 ] .. ", -- zpos max", "\n" ) io.write( " " .. v[ 13 ] .. ", -- scale beg min", "\n" ) io.write( " " .. v[ 14 ] .. ", -- scale beg max", "\n" ) io.write( " " .. v[ 15 ] .. ", -- scale end min", "\n" ) io.write( " " .. v[ 16 ] .. ", -- scale end max", "\n" ) io.write( " " .. v[ 7 ] .. ", -- xspd min", "\n" ) io.write( " " .. v[ 9 ] .. ", -- yspd min", "\n" ) io.write( " " .. v[ 11 ] .. ", -- zspd min", "\n" ) io.write( " " .. v[ 8 ] .. ", -- xspd max", "\n" ) io.write( " " .. v[ 10 ] .. ", -- yspd max", "\n" ) io.write( " " .. v[ 12 ] .. ", -- zspd max", "\n" ) io.write( " " .. v[ 21 ] .. ", -- rot speed min", "\n" ) io.write( " " .. v[ 22 ] .. ", -- rot spd max", "\n" ) io.write( " " .. v[ 24 ] .. ", -- life min", "\n" ) io.write( " " .. v[ 25 ] .. ", -- life max", "\n" ) io.write( " " .. v[ 17 ] .. ", -- alpha beg min", "\n" ) io.write( " " .. v[ 18 ] .. ", -- alpha beg max", "\n" ) io.write( " " .. v[ 19 ] .. ", -- alpha end min", "\n" ) io.write( " " .. v[ 20 ] .. ", -- alpha end max", "\n" ) io.write( " " .. v[ 23 ] .. ", -- spawn rate", "\n" ) if em.mode == 'entity' then io.write( " " .. "e" .. ", -- entity id", "\n" ) io.write( " " .. em.limb .. ", -- limb index", "\n" ) else io.write( " " .. "-1" .. ", -- player relative", "\n" ) io.write( " " .. "0" .. ", -- ", "\n" ) end io.write( " " .. "img" .. ", -- particle image", "\n" ) io.write( " " .. frames .. " -- num frames", "\n" ) io.write( " )" , "\n" ) if em.shader > 1 then io.write( "", "\n" ) io.write( "ParticlesLoadEffect( '" .. addBackslash( shaderFiles[ em.shader ] ) .. "', emitterId )", "\n" ) end io.write( "", "\n" ) io.write( "ParticlesSetLife( emitterId, " .. v[23] .. ", -- spawn rate", "\n" ) io.write( " " .. v[24] .. ", -- life min", "\n" ) io.write( " " .. v[25] .. ", -- life max", "\n" ) io.write( " " .. v[26] .. ", -- max particles", "\n" ) io.write( " " .. 0 .. ", -- placeholder", "\n" ) io.write( " " .. v[27] .. ") -- max per frame", "\n" ) io.write( "", "\n" ) io.write( "ParticlesSetGravity( emitterId, " .. v[29] .. "," .. v[30] .. ") -- G min, G max", "\n" ) if v[32] ~= 0 then io.write( "", "\n" ) local wX, _, wZ = U.Rotate3D( 0, 0, v[32], 0, rad( v[31] ), 0 ) io.write( "ParticlesSetWindVector( " .. wX .. ", " .. wZ .. " ) -- Wind X, Wind Z", "\n" ) end io.close( file ) end end local function setValues( em ) local v = em.values ParticlesSetOffset( em.Id, v[1], v[3], v[5], v[2], v[4], v[6] ) ParticlesSetSpeed( em.Id, v[7] * 0.06, v[9] * 0.06, v[11] * 0.06, v[8] * 0.06, v[10] * 0.06, v[12] * 0.06 ) ParticlesSetScale( em.Id, v[13], v[14], v[15], v[16] ) ParticlesSetAlpha( em.Id, v[17], v[18], v[19], v[20] ) ParticlesSetRotation( em.Id, 0, 0, v[21], 0, 0, v[22] ) ParticlesSetLife( em.Id, v[23], v[24], v[25], v[26], 0, v[27] ) ParticlesSetFrames( em.Id, v[28] * 0.06, 1, ImageFiles[ em.image ].frames ) ParticlesSetGravity( em.Id, v[29], v[30] ) local wX, _, wZ = U.Rotate3D( 0, 0, v[32], 0, rad( v[31] ), 0 ) ParticlesSetWindVector( wX, wZ ) end local saveTimer = 0 local timer = 0 local maxLines = 37 local Epressed = false local saved = false function particles_tester_main( e ) local em = emitterDetails[ e ] if em == nil then return end if em.state == 'init' then loadImageFiles() em.vers = 1 em.image = 1 em.shader = 1 em.values = { 0, 0, 20, 20, 0, 0, -- positions 0, 0, 0, 0, 0, 0, -- speeds 50, 50, 50, 50, -- scales 50, 50, 0, 0, -- alpha 0, 0, -- rotate 20, 500, 500, -- freq, lmin, lmax 100, 25, 1, -- MaxT, MaxF, AnimSpeed 0, 0, -- Grav min, Grav max 0, 0 -- Wind ang, Wind amount } loadRaw( em ) em.state = 'ready' em.Id = CreateEmitter( em, e ) setValues( em ) end local timeNow = g_Time displayDetails( em ) displayOthers( em ) local keyP = GetScancode() local switchEmitter = false if keyP == 37 and timeNow > timer then if em.line < maxLines then em.line = em.line + 1 if em.line == 34 and em.mode ~= 'entity' then em.line = 35 end else em.line = 1 end timer = timeNow + 200 elseif keyP == 23 and timeNow > timer then if em.line > 1 then em.line = em.line - 1 if em.line == 34 and em.mode ~= 'entity' then em.line = 33 end else em.line = maxLines end timer = timeNow + 200 end if em.line < 33 then local incs = incVals[ em.line ] local val = em.values[ em.line ] if keyP == 12 and timeNow > timer then -- '-' key if val > incs.llim then if g_KeyPressSHIFT == 1 then em.values[ em.line ] = val - incs.inc * 10 elseif g_KeyPressQ == 1 then em.values[ em.line ] = val - incs.inc * 100 else em.values[ em.line ] = val - incs.inc end timer = timeNow + 100 end elseif keyP == 13 and timeNow > timer then -- '+' key if val < incs.ulim then if g_KeyPressSHIFT == 1 then em.values[ em.line ] = val + incs.inc * 10 elseif g_KeyPressQ == 1 then em.values[ em.line ] = val + incs.inc * 100 else em.values[ em.line ] = val + incs.inc end timer = timeNow + 100 end end if em.values[ em.line ] < incs.llim then em.values[ em.line ] = incs.llim end if em.values[ em.line ] > incs.ulim then em.values[ em.line ] = incs.ulim end if em.values[ em.line ] < 0 and em.values[ em.line ] > -incs.inc then em.values[ em.line ] = 0 end if em.values[ em.line ] > 0 and em.values[ em.line ] < incs.inc then em.values[ em.line ] = 0 end if incs.typ == 'min' and em.values[ em.line ] > em.values[ em.line + 1 ] then em.values[ em.line + 1 ] = em.values[ em.line ] elseif incs.typ == 'max' and em.values[ em.line ] < em.values[ em.line - 1 ] then em.values[ em.line - 1 ] = em.values[ em.line ] end if val ~= em.values[ em.line ] then setValues( em ) if timeNow > saveTimer then saveRaw( em ) saveTimer = timeNow + autoSaveTime end saved = false end elseif em.line == 33 then -- mode if keyP == 12 or keyP == 13 and timeNow > timer then if em.mode == 'entity' then em.mode = 'player' else em.mode = 'entity' end switchEmitter = true timer = timeNow + 100 end elseif em.line == 34 then if keyP == 12 and timeNow > timer then -- '-' key if em.limb > 0 then em.limb = em.limb - 1 switchEmitter = true end timer = timeNow + 100 elseif keyP == 13 and timeNow > timer then -- '+' key em.limb = em.limb + 1 switchEmitter = true timer = timeNow + 100 end elseif em.line == 35 then if keyP == 12 and timeNow > timer then -- '-' key if em.image > 1 then em.image = em.image - 1 switchEmitter = true end timer = timeNow + 100 elseif keyP == 13 and timeNow > timer then -- '+' key if em.image < maxImages then em.image = em.image + 1 switchEmitter = true end timer = timeNow + 100 end elseif em.line == 36 then local oldShader = em.shader if keyP == 12 and timeNow > timer then -- '-' key if em.shader > 1 then em.shader = em.shader - 1 end timer = timeNow + 100 elseif keyP == 13 and timeNow > timer then -- '+' key if em.shader < #shaderFiles then em.shader = em.shader + 1 end timer = timeNow + 100 end if em.shader ~= oldShader then ParticlesLoadEffect( shaderFiles[ em.shader ], em.Id ) saved = false end elseif em.line == 37 then if not saved then Prompt( "Press E to Save" ) else Prompt( "File Saved as: " .. em.name .. "_" .. em.vers .. ".lua" ) end if g_KeyPressE == 1 then if not Epressed and not saved then Epressed = true SaveValues( em ) saved = true end else Epressed = false end local tmpVers = em.vers if keyP == 12 and timeNow > timer then -- '-' key if em.vers > 1 then em.vers = em.vers - 1 end timer = timeNow + 100 elseif keyP == 13 and timeNow > timer then -- '+' key if em.vers < 99 then em.vers = em.vers + 1 end timer = timeNow + 100 end if tmpVers ~= em.vers then saved = false end end if switchEmitter then ParticlesDeleteEmitter( em.Id ) em.Id = CreateEmitter( em, e ) setValues( em ) ParticlesLoadEffect( shaderFiles[ em.shader ], em.Id ) saved = false end end