Files
Bubberstation/code/game/objects/effects/effect_system/effects_smoke.dm
Ryll Ryll 83ec7a698f Adds pulling rabbits from top-hats (#56773)
This PR makes it so using a wand on a top-hat makes a rabbit appear in
your hand! Fun! There's a 10% chance that instead of a cute bun you get
angry bees though, but a true performer will soldier on anyway. You can
now also scoop up rabbits in your hands, and scooping animals only
requires one free hand to do so instead of all your hands being free.
2021-02-22 10:16:12 +00:00

361 lines
10 KiB
Plaintext

/////////////////////////////////////////////
//// SMOKE SYSTEMS
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke
name = "smoke"
icon = 'icons/effects/96x96.dmi'
icon_state = "smoke"
pixel_x = -32
pixel_y = -32
opacity = FALSE
layer = FLY_LAYER
anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
animate_movement = FALSE
var/amount = 4
var/lifetime = 5
var/opaque = 1 //whether the smoke can block the view when in enough amount
/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16)
if(alpha == 0) //Handle already transparent case
return
if(frames == 0)
frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame".
var/step = alpha / frames
for(var/i = 0, i < frames, i++)
alpha -= step
if(alpha < 160)
set_opacity(0) //if we were blocking view, we aren't now because we're fading out
stoplag()
/obj/effect/particle_effect/smoke/Initialize()
. = ..()
create_reagents(500)
START_PROCESSING(SSobj, src)
/obj/effect/particle_effect/smoke/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/particle_effect/smoke/proc/kill_smoke()
STOP_PROCESSING(SSobj, src)
INVOKE_ASYNC(src, .proc/fade_out)
QDEL_IN(src, 10)
/obj/effect/particle_effect/smoke/process()
lifetime--
if(lifetime < 1)
kill_smoke()
return FALSE
for(var/mob/living/L in range(0,src))
smoke_mob(L)
return TRUE
/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C)
if(!istype(C))
return FALSE
if(lifetime<1)
return FALSE
if(C.internal != null || C.has_smoke_protection())
return FALSE
if(C.smoke_delay)
return FALSE
C.smoke_delay++
addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10)
return TRUE
/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C)
if(C)
C.smoke_delay = 0
/obj/effect/particle_effect/smoke/proc/spread_smoke()
var/turf/t_loc = get_turf(src)
if(!t_loc)
return
var/list/newsmokes = list()
for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke!
if(foundsmoke)
continue
for(var/mob/living/L in T)
smoke_mob(L)
var/obj/effect/particle_effect/smoke/S = new type(T)
reagents.copy_to(S, reagents.total_volume)
S.setDir(pick(GLOB.cardinals))
S.amount = amount-1
S.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
S.lifetime = lifetime
if(S.amount>0)
if(opaque)
S.set_opacity(TRUE)
newsmokes.Add(S)
//the smoke spreads rapidly but not instantly
for(var/obj/effect/particle_effect/smoke/SM in newsmokes)
addtimer(CALLBACK(SM, /obj/effect/particle_effect/smoke.proc/spread_smoke), 1)
/datum/effect_system/smoke_spread
var/amount = 10
effect_type = /obj/effect/particle_effect/smoke
/datum/effect_system/smoke_spread/set_up(radius = 5, loca)
if(isturf(loca))
location = loca
else
location = get_turf(loca)
amount = radius
/datum/effect_system/smoke_spread/start()
if(holder)
location = get_turf(holder)
var/obj/effect/particle_effect/smoke/S = new effect_type(location)
S.amount = amount
if(S.amount)
S.spread_smoke()
/////////////////////////////////////////////
// Bad smoke
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/bad
lifetime = 8
/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M)
. = ..()
if(.)
M.drop_all_held_items()
M.adjustOxyLoss(1)
M.emote("cough")
return TRUE
/obj/effect/particle_effect/smoke/bad/Crossed(atom/movable/AM, oldloc)
. = ..()
if(istype(AM, /obj/projectile/beam))
var/obj/projectile/beam/B = AM
B.damage = (B.damage/2)
/datum/effect_system/smoke_spread/bad
effect_type = /obj/effect/particle_effect/smoke/bad
/////////////////////////////////////////////
// Nanofrost smoke
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/freezing
name = "nanofrost smoke"
color = "#B2FFFF"
opaque = FALSE
/datum/effect_system/smoke_spread/freezing
effect_type = /obj/effect/particle_effect/smoke/freezing
var/blast = 0
var/temperature = 2
var/weldvents = TRUE
var/distcheck = TRUE
/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A)
if(isopenturf(A))
var/turf/open/T = A
if(T.air)
var/datum/gas_mixture/G = T.air
if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
G.temperature = temperature
T.air_update_turf(FALSE, FALSE)
for(var/obj/effect/hotspot/H in T)
qdel(H)
var/list/G_gases = G.gases
if(G_gases[/datum/gas/plasma])
G.assert_gas(/datum/gas/nitrogen)
G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES])
G_gases[/datum/gas/plasma][MOLES] = 0
G.garbage_collect()
if (weldvents)
for(var/obj/machinery/atmospherics/components/unary/U in T)
if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber.
U.welded = TRUE
U.update_appearance()
U.visible_message("<span class='danger'>[U] is frozen shut!</span>")
for(var/mob/living/L in T)
L.extinguish_mob()
for(var/obj/item/Item in T)
Item.extinguish()
/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0)
..()
blast = blast_radius
/datum/effect_system/smoke_spread/freezing/start()
if(blast)
for(var/turf/T in RANGE_TURFS(blast, location))
Chilled(T)
..()
/datum/effect_system/smoke_spread/freezing/decon
temperature = 293.15
distcheck = FALSE
weldvents = FALSE
/////////////////////////////////////////////
// Sleep smoke
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/sleeping
color = "#9C3636"
lifetime = 10
/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M)
if(..())
M.Sleeping(200)
M.emote("cough")
return 1
/datum/effect_system/smoke_spread/sleeping
effect_type = /obj/effect/particle_effect/smoke/sleeping
/////////////////////////////////////////////
// Chem smoke
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/chem
lifetime = 10
/obj/effect/particle_effect/smoke/chem/process()
. = ..()
if(.)
var/turf/T = get_turf(src)
var/fraction = 1/initial(lifetime)
for(var/atom/movable/AM in T)
if(AM.type == src.type)
continue
if(T.intact && HAS_TRAIT(AM, TRAIT_T_RAY_VISIBLE))
continue
reagents.expose(AM, TOUCH, fraction)
reagents.expose(T, TOUCH, fraction)
return TRUE
/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M)
if(lifetime<1)
return FALSE
if(!istype(M))
return FALSE
var/mob/living/carbon/C = M
if(C.internal != null || C.has_smoke_protection())
return FALSE
var/fraction = 1/initial(lifetime)
reagents.copy_to(C, fraction*reagents.total_volume)
reagents.expose(M, INGEST, fraction)
return TRUE
/datum/effect_system/smoke_spread/chem
var/obj/chemholder
effect_type = /obj/effect/particle_effect/smoke/chem
/datum/effect_system/smoke_spread/chem/New()
..()
chemholder = new /obj()
var/datum/reagents/R = new (500, REAGENT_HOLDER_INSTANT_REACT) //This is a safety for now to prevent smoke generating more smoke as the smoke reagents react in the smoke. This is prevented naturally from happening even if this is off, but I want to be sure that any edge cases are prevented before I get a chance to rework smoke reactions (specifically adding water or reacting away stabilizing agent in the middle of it).
chemholder.reagents = R
R.my_atom = chemholder
/datum/effect_system/smoke_spread/chem/Destroy()
qdel(chemholder)
chemholder = null
return ..()
/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE)
if(isturf(loca))
location = loca
else
location = get_turf(loca)
amount = radius
carry.copy_to(chemholder, carry.total_volume)
if(!silent)
var/contained = ""
for(var/reagent in carry.reagent_list)
contained += " [reagent] "
if(contained)
contained = "\[[contained]\]"
var/where = "[AREACOORD(location)]"
if(carry.my_atom?.fingerprintslast) //Some reagents don't have a my_atom in some cases
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
var/more = ""
if(M)
more = "[ADMIN_LOOKUPFLW(M)] "
if(!istype(carry.my_atom, /obj/machinery/plumbing))
message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].")
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].")
else
if(!istype(carry.my_atom, /obj/machinery/plumbing))
message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.")
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
/datum/effect_system/smoke_spread/chem/start()
var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
if(holder)
location = get_turf(holder)
var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location)
if(chemholder.reagents.total_volume > 1) // can't split 1 very well
chemholder.reagents.copy_to(S, chemholder.reagents.total_volume)
if(mixcolor)
S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with
S.amount = amount
if(S.amount)
S.spread_smoke() //calling process right now so the smoke immediately attacks mobs.
/////////////////////////////////////////////
// Transparent smoke
/////////////////////////////////////////////
//Same as the base type, but the smoke produced is not opaque
/datum/effect_system/smoke_spread/transparent
effect_type = /obj/effect/particle_effect/smoke/transparent
/obj/effect/particle_effect/smoke/transparent
opaque = FALSE
/proc/do_smoke(range=0, location=null, smoke_type=/obj/effect/particle_effect/smoke)
var/datum/effect_system/smoke_spread/smoke = new
smoke.effect_type = smoke_type
smoke.set_up(range, location)
smoke.start()
/////////////////////////////////////////////
// Bad Smoke (But Green)
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/bad/green
name = "green smoke"
color = "#00FF00"
opaque = FALSE
/datum/effect_system/smoke_spread/bad/green
effect_type = /obj/effect/particle_effect/smoke/bad/green
/////////////////////////////////////////////
// Quick smoke
/////////////////////////////////////////////
/obj/effect/particle_effect/smoke/quick
lifetime = 1
opaque = FALSE
/datum/effect_system/smoke_spread/quick
effect_type = /obj/effect/particle_effect/smoke/quick