diff --git a/baystation12.dme b/baystation12.dme index d11073692a8..64cd4dafe0b 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -481,6 +481,7 @@ #include "code\game\objects\effects\aliens.dm" #include "code\game\objects\effects\anomalies.dm" #include "code\game\objects\effects\bump_teleporter.dm" +#include "code\game\objects\effects\chemsmoke.dm" #include "code\game\objects\effects\effect_system.dm" #include "code\game\objects\effects\gibs.dm" #include "code\game\objects\effects\glowshroom.dm" diff --git a/code/WorkInProgress/computer3/computer.dm b/code/WorkInProgress/computer3/computer.dm index 2b70c3b6e59..f537341096c 100644 --- a/code/WorkInProgress/computer3/computer.dm +++ b/code/WorkInProgress/computer3/computer.dm @@ -191,7 +191,7 @@ for(var/x in verbs) verbs -= x set_broken() - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(5, 0, src) smoke.start() return diff --git a/code/game/gamemodes/blob/blobs/factory.dm b/code/game/gamemodes/blob/blobs/factory.dm index 35130546fcd..e197ff6dea8 100644 --- a/code/game/gamemodes/blob/blobs/factory.dm +++ b/code/game/gamemodes/blob/blobs/factory.dm @@ -103,7 +103,7 @@ /mob/living/simple_animal/hostile/blobspore/Die() // On death, create a small smoke of harmful gas (s-Acid) - var/datum/effect/effect/system/chem_smoke_spread/S = new + var/datum/effect/effect/system/smoke_spread/chem/S = new var/turf/location = get_turf(src) // Create the reagents to put into the air, s-acid is yellow and stings a little diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 37b2de5a3ee..cf2ea1f487b 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -54,7 +54,7 @@ if(candidates.len) src.used = 1 var/client/C = pick(candidates) - new /obj/effect/effect/harmless_smoke(H.loc) + new /obj/effect/effect/smoke(H.loc) var/mob/living/carbon/human/M = new/mob/living/carbon/human(H.loc) M.key = C.key M << "You are the [H.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals." diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 4c2d0ae8fe0..8dca4ef26e1 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -27,7 +27,7 @@ /obj/effect/anomaly/proc/anomalyNeutralize() - new /obj/effect/effect/bad_smoke(loc) + new /obj/effect/effect/smoke/bad(loc) for(var/atom/movable/O in src) O.loc = src.loc diff --git a/code/game/objects/effects/chemsmoke.dm b/code/game/objects/effects/chemsmoke.dm new file mode 100644 index 00000000000..ee78cb5d5bc --- /dev/null +++ b/code/game/objects/effects/chemsmoke.dm @@ -0,0 +1,246 @@ +///////////////////////////////////////////// +// Chem smoke +///////////////////////////////////////////// +/obj/effect/effect/smoke/chem + icon = 'icons/effects/chemsmoke.dmi' + opacity = 0 + time_to_live = 300 + pass_flags = PASSTABLE | PASSGRILLE | PASSGLASS //PASSGLASS is fine here, it's just so the visual effect can "flow" around glass + +/obj/effect/effect/smoke/chem/New() + ..() + var/datum/reagents/R = new/datum/reagents(500) + reagents = R + R.my_atom = src + return + +/datum/effect/effect/system/smoke_spread/chem + smoke_type = /obj/effect/effect/smoke/chem + var/obj/chemholder + var/range + var/list/targetTurfs + var/list/wallList + var/floorArea + + +/datum/effect/effect/system/smoke_spread/chem/New() + ..() + chemholder = new/obj() + var/datum/reagents/R = new/datum/reagents(500) + chemholder.reagents = R + R.my_atom = chemholder + +//------------------------------------------ +//Sets up the chem smoke effect +// +// Calculates the max range smoke can travel, then gets all turfs in that view range. +// Culls the selected turfs to a (roughly) circle shape, then calls smokeFlow() to make +// sure the smoke can actually path to the turfs. This culls any turfs it can't reach. +//------------------------------------------ +/datum/effect/effect/system/smoke_spread/chem/set_up(var/datum/reagents/carry = null, n = 10, c = 0, loca, direct) + range = n * 0.3 + cardinals = c + carry.copy_to(chemholder, carry.total_volume) + + if(istype(loca, /turf/)) + location = loca + else + location = get_turf(loca) + + targetTurfs = new() + + //build affected area list + for(var/turf/T in view(range, location)) + //cull turfs to circle + if(cheap_pythag(T.x - location.x, T.y - location.y) <= range) + targetTurfs += T + + //make secondary list for reagents that affect walls + if(chemholder.reagents.has_reagent("thermite") || chemholder.reagents.has_reagent("plantbgone")) + wallList = new() + + //pathing check + smokeFlow(location, targetTurfs, wallList) + + floorArea = targetTurfs.len + + //Admin messaging + var/contained = "" + for(var/reagent in carry.reagent_list) + contained += " [reagent] " + if(contained) + contained = "\[[contained]\]" + var/area/A = get_area(location) + + var/where = "[A.name] | [location.x], [location.y]" + var/whereLink = "[where]" + + if(carry.my_atom.fingerprintslast) + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = "(?)" + message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") + else + message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + + +//------------------------------------------ +//Runs the chem smoke effect +// +// Spawns damage over time loop for each reagent held in the cloud. +// Applies reagents to walls that affect walls (only thermite and plant-b-gone at the moment). +// Also calculates target locations to spawn the visual smoke effect on, so the whole area +// is covered fairly evenly. +//------------------------------------------ +/datum/effect/effect/system/smoke_spread/chem/start() + + //reagent application + if(chemholder.reagents.reagent_list.len) + for(var/datum/reagent/R in chemholder.reagents.reagent_list) + var/proba = 100 + var/runs = 5 + + //dilute the reagents according to affected area + R.volume /= floorArea / 4 + chemholder.reagents.update_total() + + //apply wall affecting reagents to walls + if(R.id in list("thermite", "plantbgone")) + for(var/turf/T in wallList) + R.reaction_turf(T, R.volume) + + //reagents that should be applied to turfs in a random pattern + if(R.id == "carbon") + proba = 75 + else if(R.id in list("blood", "radium", "uranium")) + proba = 25 + + spawn(0) + for(var/i = 0, i < runs, i++) + for(var/turf/T in targetTurfs) + if(prob(proba)) + R.reaction_turf(T, R.volume) + for(var/atom/A in T.contents) + if(istype(A, /obj/effect/effect/smoke/chem)) //skip the item if it is chem smoke + continue + else if(istype(A, /mob)) + var/dist = cheap_pythag(T.x - location.x, T.y - location.y) + if(!dist) + dist = 1 + R.reaction_mob(A, volume = R.volume / dist) + else if(istype(A, /obj)) + R.reaction_obj(A, R.volume) + sleep(30) + + + //build smoke icon + var/color = mix_color_from_reagents(chemholder.reagents.reagent_list) + var/icon/I + if(color) + I = icon('icons/effects/chemsmoke.dmi') + I += color + else + I = icon('icons/effects/96x96.dmi', "smoke") + + + //distance between each smoke cloud + var/const/arcLength = 2.3559 + + + //calculate positions for smoke coverage - then spawn smoke + for(var/i = 0, i < range, i++) + var/radius = i * 1.5 + if(!radius) + spawn(0) + spawnSmoke(location, I, 1) + continue + + var/offset = 0 + var/points = round((radius * 2 * PI) / arcLength) + var/angle = round(ToDegrees(arcLength / radius), 1) + + if(!IsInteger(radius)) + offset = 45 //degrees + + for(var/j = 0, j < points, j++) + var/a = (angle * j) + offset + var/x = round(radius * cos(a) + location.x, 1) + var/y = round(radius * sin(a) + location.y, 1) + var/turf/T = locate(x,y,location.z) + if(T in targetTurfs) + var/dist = cheap_pythag(T.x - location.x, T.y - location.y) + if(!dist) + dist = 1 + spawn(0) + spawnSmoke(T, I, dist) + +//------------------------------------------ +// Randomizes and spawns the smoke effect. +// Also handles deleting the smoke once the effect is finished. +//------------------------------------------ +/datum/effect/effect/system/smoke_spread/chem/proc/spawnSmoke(var/turf/T, var/icon/I, var/dist = 1) + var/obj/effect/effect/smoke/chem/smoke = new(location) + chemholder.reagents.copy_to(smoke, chemholder.reagents.total_volume / dist, safety = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents + smoke.icon = I + smoke.layer = 6 + smoke.dir = pick(cardinal) + smoke.pixel_x = -32 + rand(-8,8) + smoke.pixel_y = -32 + rand(-8,8) + walk_to(smoke, T) + smoke.opacity = 1 //switching opacity on after the smoke has spawned, and then + sleep(150+rand(0,20)) // turning it off before it is deleted results in cleaner + smoke.opacity = 0 // lighting and view range updates + fadeOut(smoke) + smoke.delete() + +//------------------------------------------ +// Fades out the smoke smoothly using it's alpha variable. +//------------------------------------------ +/datum/effect/effect/system/smoke_spread/chem/proc/fadeOut(var/atom/A, var/frames = 16) + var/step = A.alpha / frames + for(var/i = 0, i < frames, i++) + A.alpha -= step + sleep(world.tick_lag) + return + +//------------------------------------------ +// Smoke pathfinder. Uses a flood fill method based on zones to +// quickly check what turfs the smoke (airflow) can actually reach. +//------------------------------------------ +/datum/effect/effect/system/smoke_spread/chem/proc/smokeFlow() + + var/list/pending = new() + var/list/complete = new() + + pending += location + + while(pending.len) + for(var/turf/simulated/current in pending) + for(var/D in cardinal) + var/turf/simulated/target = get_step(current, D) + + if(wallList) + if(istype(target, /turf/simulated/wall)) + if(!(target in wallList)) + wallList += target + continue + if(!target.zone) + continue + if(target in pending) + continue + if(target in complete) + continue + if(!(target in targetTurfs)) + continue + + pending += target + + pending -= current + complete += current + + targetTurfs = complete + + return \ No newline at end of file diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 4273a5f8595..ab9885db166 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -236,7 +236,7 @@ steam.start() -- spawns the effect delete() return -/obj/effect/effect/smoke/HasEntered(mob/living/carbon/M as mob ) +/obj/effect/effect/smoke/Crossed(mob/living/carbon/M as mob ) ..() if(istype(M)) affect(M) @@ -382,116 +382,7 @@ steam.start() -- spawns the effect /datum/effect/effect/system/smoke_spread/mustard smoke_type = /obj/effect/effect/smoke/mustard -///////////////////////////////////////////// -// Chem smoke -///////////////////////////////////////////// -/obj/effect/effect/smoke/chem - icon = 'icons/effects/chemsmoke.dmi' -/obj/effect/effect/smoke/chem/New() - ..() - var/datum/reagents/R = new/datum/reagents(500) - reagents = R - R.my_atom = src - return - -/obj/effect/effect/smoke/chem/Move() - ..() - for(var/atom/A in view(2, src)) - if(reagents.has_reagent("radium")||reagents.has_reagent("uranium")||reagents.has_reagent("carbon")||reagents.has_reagent("thermite"))//Prevents unholy radium spam by reducing the number of 'greenglows' down to something reasonable -Sieve - if(prob(5)) - reagents.reaction(A) - else - reagents.reaction(A) - - return - -/obj/effect/effect/smoke/chem/affect(mob/living/carbon/M as mob ) - reagents.reaction(M) - -/datum/effect/effect/system/smoke_spread/chem - smoke_type = /obj/effect/effect/smoke/chem - var/obj/chemholder - - New() - ..() - chemholder = new/obj() - var/datum/reagents/R = new/datum/reagents(500) - chemholder.reagents = R - R.my_atom = chemholder - - set_up(var/datum/reagents/carry = null, n = 5, c = 0, loca, direct, silent = 0) - if(n > 20) - n = 20 - number = n - cardinals = c - carry.copy_to(chemholder, carry.total_volume) - - - if(istype(loca, /turf/)) - location = loca - else - location = get_turf(loca) - if(direct) - direction = direct - if(!silent) - var/contained = "" - for(var/reagent in carry.reagent_list) - contained += " [reagent] " - if(contained) - contained = "\[[contained]\]" - var/area/A = get_area(location) - - var/where = "[A.name] | [location.x], [location.y]" - var/whereLink = "[where]" - - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) - var/more = "" - if(M) - more = "(?)" - message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") - else - message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") - - start() - var/i = 0 - - var/color = mix_color_from_reagents(chemholder.reagents.reagent_list) - - for(i=0, i 20) - return - spawn(0) - if(holder) - src.location = get_turf(holder) - var/obj/effect/effect/smoke/chem/smoke = new /obj/effect/effect/smoke/chem(src.location) - src.total_smoke++ - var/direction = src.direction - if(!direction) - if(src.cardinals) - direction = pick(cardinal) - else - direction = pick(alldirs) - - if(chemholder.reagents.total_volume != 1) // can't split 1 very well - chemholder.reagents.copy_to(smoke, chemholder.reagents.total_volume / number) // copy reagents to each smoke, divide evenly - - if(color) - smoke.icon += color // give the smoke color, if it has any to begin with - else - // if no color, just use the old smoke icon - smoke.icon = 'icons/effects/96x96.dmi' - smoke.icon_state = "smoke" - - for(i=0, i\The [src] is full." return reagents.remove_reagent(25,"water") - var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread() + var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad() smoke.set_up(5, 0, user.loc) smoke.start() playsound(user.loc, 'sound/effects/bamf.ogg', 50, 2) diff --git a/code/modules/events/tgevents/vent_clog.dm b/code/modules/events/tgevents/vent_clog.dm index d12631be36a..492b4480352 100755 --- a/code/modules/events/tgevents/vent_clog.dm +++ b/code/modules/events/tgevents/vent_clog.dm @@ -30,7 +30,7 @@ R.my_atom = vent R.add_reagent(pick(gunk), 50) - var/datum/effect/effect/system/chem_smoke_spread/smoke = new + var/datum/effect/effect/system/smoke_spread/chem/smoke = new smoke.set_up(R, rand(1, 2), 0, vent, 0, silent = 1) playsound(vent.loc, 'sound/effects/smoke.ogg', 50, 1, -3) smoke.start() diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index cd04a546dfd..6bb646771b0 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -250,22 +250,6 @@ var/breath_moles = environment.total_moles()*BREATH_PERCENTAGE breath = loc.remove_air(breath_moles) - if(istype(wear_mask, /obj/item/clothing/mask/gas)) - var/obj/item/clothing/mask/gas/G = wear_mask - var/datum/gas_mixture/filtered = new - - filtered.copy_from(breath) - filtered.toxins *= G.gas_filter_strength - for(var/datum/gas/gas in filtered.trace_gases) - gas.moles *= G.gas_filter_strength - filtered.update_values() - loc.assume_air(filtered) - - breath.toxins *= 1 - G.gas_filter_strength - for(var/datum/gas/gas in breath.trace_gases) - gas.moles *= 1 - G.gas_filter_strength - breath.update_values() - // Handle chem smoke effect -- Doohl var/block = 0 if(wear_mask) diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index c14e9f73f75..76e08259018 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -106,7 +106,7 @@ /obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob) do_teleport(user, user, 10) - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(10, 0, user.loc) smoke.start() charges-- diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index e2ce8735182..695794eece4 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -87,7 +87,7 @@ if(!stuff.anchored && stuff.loc) teleammount++ do_teleport(stuff, stuff, 10) - var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread() + var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread() smoke.set_up(max(round(10 - teleammount),1), 0, stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity smoke.start() diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 6e51abec59c..8c227b1a589 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -454,8 +454,6 @@ datum playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3) spawn(0) S.start() - sleep(10) - S.start() holder.clear_reagents() return diff --git a/code/modules/research/xenoarchaeology/machinery/coolant.dm b/code/modules/research/xenoarchaeology/machinery/coolant.dm index bc03553bee0..6c0652f4084 100644 --- a/code/modules/research/xenoarchaeology/machinery/coolant.dm +++ b/code/modules/research/xenoarchaeology/machinery/coolant.dm @@ -37,7 +37,7 @@ datum/chemical_reaction/coolant explode() /obj/structure/reagent_dispensers/coolanttank/proc/explode() - var/datum/effect/effect/system/harmless_smoke_spread/S = new /datum/effect/effect/system/harmless_smoke_spread + var/datum/effect/effect/system/smoke_spread/S = new /datum/effect/effect/system/smoke_spread //S.attach(src) S.set_up(5, 0, src.loc) diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index bc5d4929381..9deb1803262 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/chemsmoke.dmi b/icons/effects/chemsmoke.dmi index 5be1b638edd..4308e3d40bb 100644 Binary files a/icons/effects/chemsmoke.dmi and b/icons/effects/chemsmoke.dmi differ