//Warning! Do not animate to low alpha values unless you animate to a high non 255 value first. This breaks things for some bizzare reason. // particle system states #define PS_READY 1 #define PS_RUNNING 2 #define PS_FINISHED 0 // -------------------------------------------------------------------------------------------------------------------------------------- // Base object used for particles /obj/particle name = "" desc = "" mouse_opacity = 0 anchored = 1 density = 0 opacity = 0 layer = EFFECTS_LAYER_BASE animate_movement = NO_STEPS //Stop shifting around recycled particles. var/atom/target = null // target location for directional particles var/override_state = null // -------------------------------------------------------------------------------------------------------------------------------------- // Master particle datum, handles creating and recycling particles and particle systems var/datum/particleMaster/particleMaster = new /datum/particleMaster var/list/particleTypes = null var/list/particleSystems = null New() particleTypes = list() particleSystems = list() for (var/ptype in typesof(/datum/particleType) - /datum/particleType) var/datum/particleType/typeDatum = new ptype() particleTypes[typeDatum.name] = typeDatum proc/SpawnSystem(var/datum/particleSystem/system) if (!istype(system)) return particleSystems += system return system // check if a particular location has a particle system running there proc/CheckSystemExists(var/systemType, var/atom/location) for (var/datum/particleSystem/system in particleSystems) if (system.type == systemType && system.location == location) return 1 return 0 // kill a particle system in progress proc/RemoveSystem(var/systemType, var/atom/location) for (var/datum/particleSystem/system in particleSystems) if (system.type == systemType && system.location == location) system.Die() particleSystems -= system // Called by the particle process loop in the game controller // Runs every effect that's ready to go and cleans up anything that's finished or in an invalid location proc/Tick() // Set background tells byond that it can sleep(0) this proc automatically within loops to get other stuff running. set background = 1 for (var/datum/particleSystem/system in particleSystems) if (!istype(system.location)) system.state = PS_FINISHED particleSystems -= system continue switch(system.state) if (PS_FINISHED) particleSystems -= system continue if (PS_READY) // This is the only place a spawn is remotely helpful // Adding a lot of extra spawn(0) calls can really shit up the scheduler spawn(0) system.Run() continue //Spawns specified particle. If type can be recycled, do that - else create new. After time is over, move particle to recycling to avoid del and new calls. proc/SpawnParticle(var/atom/location, var/particleTypeName = null, var/particleTime = null, var/particleColor = null, var/atom/target = null, var/particleSprite = null) //This should be the only thing you access from the outside. var/datum/particleType/pType = particleTypes[particleTypeName] if (istype(pType)) var/obj/particle/p = unpool(/obj/particle) p.loc = get_turf(location) p.color = particleColor if (particleSprite) p.override_state = particleSprite if (target) p.target = get_turf(target) pType.Apply(p) spawn(particleTime) if (p) pType.Reset(p) pool(p) return p else return 0 // -------------------------------------------------------------------------------------------------------------------------------------- // These datums are used by the particle master datum to apply the various effects to the base particle object before use. /datum/particleType var/name = null var/icon = null var/icon_state = null // ugly but fast var/matrix/first = null var/matrix/second = null var/matrix/third = null var/static/matrix/reset_matrix = matrix() New() MatrixInit() proc/MatrixInit() return proc/Apply(var/obj/particle/par) if (istype(par)) par.icon = icon par.icon_state = par.override_state ? par.override_state : icon_state return 1 return 0 proc/Reset(var/obj/particle/par) if (istype(par)) par.alpha = 255 par.blend_mode = 0 par.color = null par.pixel_x = 0 par.pixel_y = 0 par.transform = null par.override_state = null animate(par) return 1 return 0 /datum/particleType/fireTest name = "fireTest" icon = 'icons/effects/effects.dmi' icon_state = "fpart" MatrixInit() first = matrix() second = matrix() Apply(var/obj/particle/par) if (..()) par.blend_mode = BLEND_ADD par.alpha = 0 par.pixel_x = rand (-3, 3) par.pixel_y = -16 + rand(-3,3) first.Turn(rand(-90, 90)) second.Turn(rand(-90, 90)) var/x_float = rand(-5, 5) animate(par, time = 10, transform = first, pixel_y = 0, pixel_x = x_float, alpha = 255) animate(transform = second, time = 10, pixel_y = 16, pixel_x = round(x_float / 2), alpha = 0) first.Reset() /datum/particleType/exppart name = "exppart" icon = 'icons/effects/64x64.dmi' icon_state = "exppart" MatrixInit() first = matrix() Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD par.Turn(rand(90, 90)) first.Turn(rand(90, 90)) first.Scale(1.5, 1.5) animate(par, transform = first, time = 20, pixel_y = rand(-64, 64), pixel_x = rand(-64, 64), easing = CUBIC_EASING|EASE_IN, alpha = 0) MatrixInit() /datum/particleType/mechpart name = "mechpart" icon = 'icons/effects/particles.dmi' icon_state = "2x2outline" Apply(var/obj/particle/par) if(..()) if (!par || !par.target) return //Wire: Fix for Cannot read null.x var/move_x = (par.target.x - par.x) * 32 var/move_y = (par.target.y - par.y) * 32 animate(par, time = get_dist(par, par.target) * 5, pixel_y = move_y, pixel_x = move_x , color = "#0000FF", easing = LINEAR_EASING) /datum/particleType/elecpart name = "elecpart" icon = 'icons/effects/particles.dmi' icon_state = "electro" MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD par.pixel_x += rand(-3,3) par.pixel_y += rand(-3,3) first.Turn(rand(-90, 90)) first.Scale(0.1,0.1) par.transform = first second = matrix(first, 20, MATRIX_SCALE) third.Scale(0.1,0.1) third.Turn(rand(-90, 90)) var/move_x = rand(-96, 96) var/move_y = rand(-96, 96) animate(par,transform = second, time = 5, alpha = 100) animate(transform = third, time = 10, pixel_y = move_y, pixel_x = move_x, alpha = 1) MatrixInit() /datum/particleType/elecpart_green name = "elecpart_green" MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD par.pixel_x += rand(-10,10) par.pixel_y += rand(-10,10) var/rot = rand(-90, 90) first.Turn(rot) first.Scale(0.1,0.1) par.transform = first second = matrix(first, 10, MATRIX_SCALE) third = matrix(matrix(first, rot, MATRIX_ROTATE), 0.1, MATRIX_SCALE) animate(par,transform = second, time = 5, alpha = 245) animate(transform = third, time = 5, alpha = 50) MatrixInit() /datum/particleType/glitter name = "glitter" icon = 'icons/effects/glitter.dmi' MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += rand(-5,5) par.pixel_y += rand(-5,5) par.color = random_saturated_hex_color(1)//rgb(rand(25, 255),rand(25, 255),rand(25, 255)) par.icon_state = "glitter[rand(1,10)]" var/rot = rand(-45, 45) first.Turn(rot) first.Scale(0.1,0.1) par.transform = first second = matrix(first, 12, MATRIX_SCALE) third = matrix(matrix(second, rot, MATRIX_ROTATE), 0.1, MATRIX_SCALE) animate(par,transform = second, time = 10, alpha = 200) animate(transform = third, time = 10, alpha = 50) MatrixInit() /datum/particleType/sparkle name = "sparkle" icon = 'icons/effects/particles.dmi' icon_state = "sparkle" MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += rand(-10,10) par.pixel_y += rand(-10,10) var/rot = rand(-90, 90) first.Turn(rot) first.Scale(0.1,0.1) par.transform = first second = matrix(first, 10, MATRIX_SCALE) second.Scale(1.1,1.1) third = matrix(matrix(first, 0.1, MATRIX_SCALE), rot, MATRIX_ROTATE) animate(par,transform = second, time = 5, alpha = 245) animate(transform = third, time = 5, alpha = 50) MatrixInit() /datum/particleType/tpbeam name = "tpbeam" icon = 'icons/effects/particles.dmi' icon_state = "tpbeam" MatrixInit() first = matrix(1, 0.1, MATRIX_SCALE) second = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += rand (-16, 16) par.pixel_y = -16 par.alpha = 0 par.transform = first animate(par, time = 3, alpha = 255) animate(transform = second, time = 15 + rand(0,6), pixel_y = 32, alpha = 0) MatrixInit() /datum/particleType/swoosh name = "swoosh" icon = 'icons/effects/particles.dmi' icon_state = "swoosh" MatrixInit() first = matrix() second = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += rand(-14,14) par.pixel_y = -16 par.alpha = 200 var/xflip = rand(100) > 50 ? -1 : 1 first.Scale(xflip, 0.01) par.transform = first second.Scale(xflip, 1) animate(par,transform = second, time = 40, alpha = 0, pixel_y = 64) MatrixInit() /datum/particleType/fireworks name = "fireworks" icon = 'icons/effects/effects.dmi' icon_state = "wpart" MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD par.color = rgb(rand(0, 255),rand(0, 255),rand(0, 255)) first.Turn(rand(-180, 180)) second.Turn(rand(-90, 90)) second.Scale(0.5,0.5) third.Turn(rand(-90, 90)) if(!istype(par)) return animate(par, time = 10, transform = first, pixel_y = 96, alpha = 250) animate(transform = second, time = 10, pixel_y = 96 + rand(-32, 32), pixel_x = rand(-32, 32) + par.pixel_x, easing = SINE_EASING, alpha = 200) animate(transform = third, time = 7, pixel_y = 0, easing = LINEAR_EASING|EASE_OUT, alpha = 0) MatrixInit() /datum/particleType/confetti name = "confetti" icon = 'icons/effects/effects.dmi' icon_state = "wpart" MatrixInit() first = matrix() second = matrix() Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD var/r = 255 var/g = 255 var/b = 255 switch (rand(1, 3)) if (1) r = rand(0, 150) if (2) g = rand(0, 150) if (3) b = rand(0, 150) par.color = rgb(r, g, b) first.Turn(rand(-90, 90)) first.Scale(0.5,0.5) second.Turn(rand(-90, 90)) if(!istype(par)) return animate(par, transform = first, time = 4, pixel_y = rand(-32, 32) + par.pixel_y, pixel_x = rand(-32, 32) + par.pixel_x, easing = LINEAR_EASING) animate(transform = second, time = 5, alpha = 0, pixel_y = par.pixel_y - 5, easing = LINEAR_EASING|EASE_OUT) MatrixInit() /datum/particleType/gravaccel name = "gravaccel" icon = 'icons/effects/effects.dmi' icon_state = "wpart" MatrixInit() first = matrix(0.25, MATRIX_SCALE) second = matrix(0.125, MATRIX_SCALE) third = matrix(0.1, MATRIX_SCALE) Apply(var/obj/particle/par) if(..()) par.blend_mode = BLEND_ADD par.pixel_x = rand(-14, 14) par.pixel_y = rand(-14, 14) par.transform = first var/move_x = ((par.target.x-par.loc.x) * 2) * 32 + rand(-14, 14) var/move_y = ((par.target.y-par.loc.y) * 2) * 32 + rand(-14, 14) animate(par,transform = second, time = 25, pixel_y = move_y, pixel_x = move_x , easing = SINE_EASING) animate(transform = third, time = 5, easing = LINEAR_EASING|EASE_OUT) /datum/particleType/stink name = "stink" icon = 'icons/effects/effects.dmi' icon_state = "stink" MatrixInit() first = matrix(1, 0, MATRIX_SCALE) second = matrix() Apply(var/obj/particle/par) if(..()) par.alpha = 0 par.pixel_x += rand(-5,5) par.pixel_y = -16 par.transform = first animate(par, time = 10, transform = second, pixel_y = 0, alpha = 150) animate(time = 10, pixel_y = 16, alpha = 0) /datum/particleType/barrelSmoke name = "barrelSmoke" icon = 'icons/effects/64x64.dmi' icon_state = "smoke" MatrixInit() first = matrix() second = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += -16 par.pixel_y += -5 par.color = "#222222" first.Turn(rand(-90, 90)) first.Scale(0.1, 0.1) par.transform = first second = first second.Scale(5,5) second.Turn(rand(-90, 90)) animate(par,transform = second, time = 5, alpha = 90) animate(transform = third, time = 20, pixel_y = 75, alpha = 1) MatrixInit() /datum/particleType/cruiserSmoke name = "cruiserSmoke" icon = 'icons/effects/64x64.dmi' icon_state = "smoke" MatrixInit() first = matrix() second = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += rand(0, 96) par.pixel_y += rand(0, 96) par.color = "#777777" first.Turn(rand(-90, 90)) first.Scale(0.1, 0.1) par.transform = first second = first second.Scale(5,5) second.Turn(rand(-90, 90)) animate(par,transform = second, time = 5, color="#dddddd", alpha = 120) animate(transform = third, time = 20, pixel_y = par.pixel_y+32, alpha = 1) MatrixInit() /datum/particleType/areaSmoke name = "areaSmoke" icon = 'icons/effects/64x64.dmi' icon_state = "smoke" MatrixInit() first = matrix() second = matrix() third = matrix() Apply(var/obj/particle/par) if(..()) par.pixel_x += -16 + rand(-112,122) par.pixel_y += -16 + rand(-112,122) first.Turn(rand(-90, 90)) first.Scale(0.1, 0.1) par.transform = first second = first second.Scale(5,5) third.Scale(2,2) third.Turn(rand(-90, 90)) animate(par,transform = second, time = 5, alpha = 250) animate(transform = third, time = 20, alpha = 1) MatrixInit() /datum/particleType/chemSpray name = "chemSpray" icon = 'icons/effects/64x64.dmi' icon_state = "smoke" MatrixInit() first = matrix(0.1, MATRIX_SCALE) second = matrix(0.3, MATRIX_SCALE) third = matrix(0.6, MATRIX_SCALE) Apply(var/obj/particle/par) if(..()) par.alpha = 50 par.transform = first var/move_x var/move_y if (!par.loc) return if (par.target) move_x = (par.target.x-par.loc.x)*32 + rand(-32, 0) move_y = (par.target.y-par.loc.y)*32 + rand(-32, 0) else move_x = rand(-64, 64) move_y = rand(-64, 64) animate(par,transform = second, time = 10, pixel_y = move_y, pixel_x = move_x, alpha = 25) animate(transform = third, time = 5, alpha = 1) /datum/particleType/fireSpray name = "fireSpray" icon = 'icons/effects/64x64.dmi' icon_state = "smoke" MatrixInit() first = matrix(0.1, MATRIX_SCALE) second = matrix(0.3, MATRIX_SCALE) third = matrix(0.6, MATRIX_SCALE) Apply(var/obj/particle/par) if(..()) par.color = "#FF0000" par.alpha = 50 par.transform = first var/move_x var/move_y if (!par.loc) return if (par.target) move_x = (par.target.x-par.loc.x)*32 + rand(-32, 0) move_y = (par.target.y-par.loc.y)*32 + rand(-32, 0) else move_x = rand(-64, 64) move_y = rand(-64, 64) animate(par,transform = second, time = 20, color = "#FFFF00", pixel_y = move_y, pixel_x = move_x, alpha = 25) animate(transform = third, time = 10, color="#FFFFFF", alpha = 1) /datum/particleSystem/firespray var/runLength = 10 New(var/atom/location, var/atom/destination) ..(location, "fireSpray", 10, null, destination) Run() if (state != PS_RUNNING && ..()) for(var/x=0, x < runLength, x++) for(var/i=0, i