mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-06 15:02:29 +00:00
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.
361 lines
10 KiB
Plaintext
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
|