Lots of work on acids, smoke, foam, reagents reaction() proc.

- fixed the fraction argument in reaction(...., INGESTED, fraction) so the proper amounts of each reagent react, not all of it.
- slight optimization of datum/reagents/reaction()
- small optimization /datum/reagent/proc/reaction_mob
- the smoke's reagents no longer do direct transfer upon crossed()/move() but uses "reagents.reaction( mob, TOUCH)" only.
- fixes no ingesting smoke if it's in the dark.
- removed block gas smoke effect flag from clown mask and other non "actual" gas mask.
- refactor how protection against touched chems being absorbed is done. get_permeability_protection() to get that protection. No more

simple RNG get touched or not, now the amount that touches you depends on your protection and the volume in question.
- changes acid_act to take volume into account.
- chem_smoke now uses process() just like foam, we remove the reaction from crossed() and Move(), it's only done in process() now.
- optimization of effect/smoke, OOP! And now all smoke effects use objprocessing instead of shitty sleep/spawn
- removed mob var/coughedtime.
- add a volume check to item/acid_act(), there's a threshold to be able to melt and then a probability to melt (acidpwr&volume).
- greatly lowered the amount of reagent in the smoke from dead blobspore (so the volume isn't enough for melting)
- human/acid_act(): damage to limbs depends on acidpwr&volume.
- fixes metalfoam not working.
- smoke powder: only one start() call.
- Amound of smoke objects depends on amount of smoke recipe created.
- Adds an argument to add_reagent() to block automatic call of handle_reaction()
- When using reagents/proc/trans_to(), reactions are now only handled after every reagent is transfered and not before.
- Amount of smoke objects depends on amount of smoke reagent created.
- radius of foam reaction depends on amount of foam reagent created.
- The amount of other reagents inside the smoke/foam decides the life expectancy of the effect.
- The amount of reagents in each small smoke cloud/foam cell depends on the amount of other reagents in the initial reaction but also

how much smoke/foam was created (more smoke means dilution of the reagents).
- smoke/foam's reagent reaction on mob decreases the life expectancy of the effect (to avoid reagent duplication)
- The amount of reagent reacting with atoms is less if the life expectancy is high.(to avoid reagent duplication)
- The amount of movement from the smoke now depends on the number of smoke clouds created.
- removing some useless code in chem_grenade/prime().
- When calling human/acid_act(), item acid melting chance lowers after each each successful melt in the list, some of the acid is

"used" to melt that item so the next items have a lower chance to melt (to make melting every clothing harder).
- remove the banned reagent list from sprays, not needed anymore now that acid is nerfed.
- chem_grenade reaction, if there's no reagent left after reaction (smoke/foam/etc, reagents cleared) you don't get the steam effect

and immediate reaction with all atoms around the grenade explosion. (Fixes foam cleaner grenade deleting bloodstains around it as soon

as the grenade explodes, even if the foam hasn't reached the tile yet).
- melted storage items now drop their content instead of deleting everything.
This commit is contained in:
phil235
2015-06-22 00:35:24 +02:00
parent f4cf6ffc95
commit b0cd6d34b1
57 changed files with 485 additions and 598 deletions
@@ -16,7 +16,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
/obj/effect/effect/Destroy()
..()
return QDEL_HINT_PUTINPOOL
/*
/datum/effect/effect/proc/fadeOut(var/atom/A, var/frames = 16)
if(A.alpha == 0) //Handle already transparent case
return
@@ -27,7 +27,7 @@ would spawn and follow the beaker, even if it is carried or thrown.
A.alpha -= step
sleep(world.tick_lag)
return
*/
/datum/effect/effect/system
var/number = 3
var/cardinals = 0
@@ -10,10 +10,10 @@
layer = TURF_LAYER + 0.1
mouse_opacity = 0
var/amount = 3
var/expand = 1
animate_movement = 0
var/metal = 0
var/lifetime = 6
var/max_lifetime = 6
/obj/effect/effect/foam/metal/aluminium
@@ -36,16 +36,20 @@
/obj/effect/effect/foam/Destroy()
SSobj.processing.Remove(src)
return ..()
/*
/obj/effect/effect/foam/metal/New(loc)
..()
var/obj/structure/foamedmetal/M = new(src.loc)
M.metal = metal
M.updateicon()
M.updateicon()*/
/obj/effect/effect/foam/proc/kill_foam()
SSobj.processing.Remove(src)
if(metal)
var/obj/structure/foamedmetal/M = new(src.loc)
M.metal = metal
M.updateicon()
flick("[icon_state]-disolve", src)
spawn(5)
qdel(src)
@@ -55,21 +59,36 @@
lifetime--
if(lifetime < 1)
kill_foam()
return
var/fraction = 1/max_lifetime
for(var/obj/O in range(0,src))
if(O.type == src.type)
continue
reagents.reaction(O, TOUCH, fraction)
for(var/mob/living/L in range(0,src))
foam_mob(L)
var/T = get_turf(src)
reagents.reaction(T, TOUCH, fraction)
if(--amount < 0)
return
for(var/atom/M in view(1,src))
if(M == src)
continue
reagents.reaction(M, TOUCH)
spread_foam()
/obj/effect/effect/foam/proc/foam_mob(var/mob/living/L as mob)
if(lifetime<1)
return
if(!istype(L))
return
var/fraction = 1/max_lifetime
reagents.reaction(L, TOUCH, fraction)
lifetime--
/obj/effect/effect/foam/Crossed(var/atom/movable/AM)
if(istype(AM, /mob/living/carbon))
var/mob/living/carbon/M = AM
M.slip(5, 2, src)
/obj/effect/effect/foam/metal/Crossed(var/atom/movable/AM)
return
@@ -87,10 +106,14 @@
if(foundfoam)
continue
var/obj/effect/effect/foam/F = PoolOrNew(/obj/effect/effect/foam, T)
for(var/mob/living/L in T)
foam_mob(L)
var/obj/effect/effect/foam/F = PoolOrNew(src.type, T)
F.amount = amount
reagents.copy_to(F, (reagents.total_volume))
F.color = color
F.metal = metal
F.max_lifetime = max_lifetime
/obj/effect/effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -136,7 +159,6 @@
amount = round(sqrt(amt / 2), 1)
carry.copy_to(chemholder, carry.total_volume)
/datum/effect/effect/system/foam_spread/metal/set_up(amt=5, loca, var/datum/reagents/carry = null, var/metaltype)
..()
metal = metaltype
@@ -148,11 +170,12 @@
else
var/obj/effect/effect/foam/F = PoolOrNew(foamtype, location)
var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
chemholder.reagents.copy_to(F, chemholder.reagents.total_volume)
chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount) //how much reagents each foam cell holds
F.color = foamcolor
F.amount = amount
F.metal = metal
F.max_lifetime = Clamp(round(sqrt(chemholder.reagents.total_volume/2), 1), 3, 10) //how long each foam cell lasts.
F.lifetime = F.max_lifetime
//////////////////////////////////////////////////////////
// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
@@ -6,37 +6,92 @@
/obj/effect/effect/smoke
name = "smoke"
icon = 'icons/effects/water.dmi'
icon_state = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 8.0
/obj/effect/effect/harmless_smoke
name = "smoke"
icon_state = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 6.0
//Remove this bit to use the old smoke
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
/obj/effect/effect/harmless_smoke/New()
..()
spawn (100)
qdel(src)
/datum/effect/effect/system/harmless_smoke_spread
var/total_smoke = 0 // To stop it being spammed and lagging!
icon_state = "smoke"
opacity = 1
anchored = 0
mouse_opacity = 0
var/steps = 0
var/lifetime = 10
var/direction
var/fading = 0
/datum/effect/effect/system/harmless_smoke_spread/set_up(n = 5, c = 0, loca, direct)
if(n > 10)
n = 10
/obj/effect/effect/smoke/proc/fade_out(var/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
sleep(world.tick_lag)
/obj/effect/effect/smoke/New()
..()
create_reagents(500)
SSobj.processing.Add(src)
lifetime = lifetime + rand(1,3)
/obj/effect/effect/smoke/Destroy()
SSobj.processing.Remove(src)
..()
/obj/effect/effect/smoke/proc/kill_smoke()
SSobj.processing.Remove(src)
qdel(src)
/obj/effect/effect/smoke/process()
world << "Process"
lifetime--
if(lifetime < 3 && !fading)
fading = 1
spawn(0)
fade_out(100)
if(lifetime < 1)
kill_smoke()
return 0
if(steps >= 1)
step(src,direction)
steps--
return 1
/obj/effect/effect/smoke/Crossed(mob/living/M as mob)
if(!istype(M))
return
smoke_mob(M)
/obj/effect/effect/smoke/Cross(mob/living/M as mob)
if(!istype(M))
return
smoke_mob(M)
/obj/effect/effect/smoke/proc/smoke_mob(mob/living/carbon/M as mob)
if(!istype(M))
return 0
if(lifetime<1)
return 0
if(M.internal != null || (M.wear_mask && (M.wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT)))
return 0
if(M.smoke_delay)
return 0
M.smoke_delay++
spawn(10)
if(M)
M.smoke_delay = 0
return 1
/datum/effect/effect/system/smoke_spread
var/direction
var/smoke_type = /obj/effect/effect/smoke
/datum/effect/effect/system/smoke_spread/set_up(n = 5, c = 0, loca, direct)
if(n > 20)
n = 20
number = n
cardinals = c
if(istype(loca, /turf/))
@@ -46,70 +101,39 @@
if(direct)
direction = direct
/datum/effect/effect/system/smoke_spread/start()
for(var/i=0, i<src.number, i++)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/smoke/S = PoolOrNew(smoke_type, location)
SSobj.processing.Add(S)
if(!direction)
if(src.cardinals)
S.direction = pick(cardinal)
else
S.direction = pick(alldirs)
else
S.direction = direction
S.steps = pick(0,1,1,1,2,2,2,3)
/datum/effect/effect/system/harmless_smoke_spread/start()
var/i = 0
for(i=0, i<src.number, i++)
if(src.total_smoke > 20)
return
spawn(0)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/harmless_smoke/smoke = PoolOrNew(/obj/effect/effect/harmless_smoke, location)
src.total_smoke++
var/direction = src.direction
if(!direction)
if(src.cardinals)
direction = pick(cardinal)
else
direction = pick(alldirs)
for(i=0, i<pick(0,1,1,1,2,2,2,3), i++)
sleep(10)
step(smoke,direction)
spawn(75+rand(10,30))
if(smoke)
fadeOut(smoke)
qdel(smoke)
src.total_smoke--
/////////////////////////////////////////////
// Bad smoke
/////////////////////////////////////////////
/obj/effect/effect/bad_smoke
name = "smoke"
icon_state = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 6.0
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
/obj/effect/effect/smoke/bad/process()
if(..())
for(var/mob/living/carbon/M in range(1,src))
smoke_mob(M)
/obj/effect/effect/bad_smoke/New()
..()
spawn (200+rand(10,30))
qdel(src)
/obj/effect/effect/smoke/bad/smoke_mob(mob/living/carbon/M as mob)
if(..())
M.drop_item()
M.adjustOxyLoss(1)
M.emote("cough")
/obj/effect/effect/bad_smoke/Move()
..()
for(var/mob/living/carbon/M in get_turf(src))
if (M.internal != null && M.wear_mask && (M.wear_mask.flags & MASKINTERNALS))
else
M.drop_item()
M.adjustOxyLoss(1)
if (M.coughedtime != 1)
M.coughedtime = 1
M.emote("cough")
spawn(20)
if(M && M.loc)
M.coughedtime = 0
return
/obj/effect/effect/bad_smoke/CanPass(atom/movable/mover, turf/target, height=0)
/obj/effect/effect/smoke/bad/CanPass(atom/movable/mover, turf/target, height=0)
if(height==0) return 1
if(istype(mover, /obj/item/projectile/beam))
var/obj/item/projectile/beam/B = mover
@@ -117,135 +141,73 @@
return 1
/obj/effect/effect/bad_smoke/Crossed(mob/living/carbon/M as mob )
..()
if(istype(M, /mob/living/carbon))
if (M.internal != null && M.wear_mask && (M.wear_mask.flags & MASKINTERNALS))
return
else
M.drop_item()
M.adjustOxyLoss(1)
if (M.coughedtime != 1)
M.coughedtime = 1
M.emote("cough")
spawn(20)
if(M && M.loc)
M.coughedtime = 0
return
/datum/effect/effect/system/bad_smoke_spread
var/total_smoke = 0 // To stop it being spammed and lagging!
var/direction
/datum/effect/effect/system/bad_smoke_spread/set_up(n = 5, c = 0, loca, direct)
if(n > 20)
n = 20
number = n
cardinals = c
if(istype(loca, /turf/))
location = loca
else
location = get_turf(loca)
if(direct)
direction = direct
/datum/effect/effect/system/bad_smoke_spread/start()
var/i = 0
for(i=0, i<src.number, i++)
if(src.total_smoke > 20)
return
spawn(0)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/bad_smoke/smoke = PoolOrNew(/obj/effect/effect/bad_smoke, location)
src.total_smoke++
var/direction = src.direction
if(!direction)
if(src.cardinals)
direction = pick(cardinal)
else
direction = pick(alldirs)
for(i=0, i<pick(0,1,1,1,2,2,2,3), i++)
sleep(10)
step(smoke,direction)
spawn(150+rand(10,30))
if(smoke)
fadeOut(smoke)
qdel(smoke)
src.total_smoke--
/datum/effect/effect/system/smoke_spread/bad
smoke_type = /obj/effect/effect/smoke/bad
/////////////////////////////////////////////
// Chem smoke
/////////////////////////////////////////////
/obj/effect/effect/chem_smoke
name = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 6.0
/obj/effect/effect/smoke/chem
icon = 'icons/effects/chemsmoke.dmi'
pixel_x = -32
pixel_y = -32
icon_state = ""
var/max_lifetime = 10
/obj/effect/effect/smoke/chem/process()
if(..())
var/fraction = 1/max_lifetime
for(var/obj/O in range(1,src))
if(O.type == src.type)
continue
reagents.reaction(O, TOUCH, fraction)
for(var/turf/T in range(1,src))
reagents.reaction(T, TOUCH, fraction)
for(var/mob/living/L in range(1,src))
smoke_mob(L)
/obj/effect/effect/smoke/chem/smoke_mob((mob/living/carbon/M as mob))
if(lifetime<1)
return
if(!istype(M))
return
var/fraction = 1/max_lifetime
reagents.reaction(M, TOUCH, fraction)
lifetime--
/obj/effect/effect/chem_smoke/New()
..()
create_reagents(500)
spawn(200+rand(10,30))
qdel(src)
/obj/effect/effect/chem_smoke/Move()
..()
for(var/mob/living/A in view(1, src))
if(reagents.total_volume >= 1)
reagents.reaction(A, TOUCH)
reagents.trans_to(A.reagents, 10)
return
/obj/effect/effect/chem_smoke/Crossed(mob/living/carbon/M as mob )
..()
if(reagents.total_volume >= 1)
reagents.reaction(M, TOUCH)
reagents.trans_to(M.reagents, 10)
/datum/effect/effect/system/chem_smoke_spread
var/total_smoke = 0 // To stop it being spammed and lagging!
var/direction
/datum/effect/effect/system/smoke_spread/chem
var/obj/chemholder
smoke_type = /obj/effect/effect/smoke/chem
/datum/effect/effect/system/chem_smoke_spread/New()
/datum/effect/effect/system/smoke_spread/chem/New()
..()
chemholder = PoolOrNew(/obj)
var/datum/reagents/R = new/datum/reagents(500)
chemholder.reagents = R
R.my_atom = chemholder
/datum/effect/effect/system/chem_smoke_spread/Destroy()
/datum/effect/effect/system/smoke_spread/chem/Destroy()
chemholder = null
..()
return QDEL_HINT_PUTINPOOL
/datum/effect/effect/system/chem_smoke_spread/set_up(var/datum/reagents/carry = null, n = 5, c = 0, loca, direct, silent = 0)
/datum/effect/effect/system/smoke_spread/chem/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
carry.copy_to(chemholder, carry.total_volume)
if(!silent)
var/contained = ""
@@ -270,140 +232,63 @@
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
/datum/effect/effect/system/chem_smoke_spread/start()
var/i = 0
/datum/effect/effect/system/smoke_spread/chem/start()
var/color = mix_color_from_reagents(chemholder.reagents.reagent_list)
for(i=0, i<src.number, i++)
if(src.total_smoke > 20)
return
spawn(0)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/chem_smoke/smoke = PoolOrNew(/obj/effect/effect/chem_smoke, 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.color = color // give the smoke color, if it has any to begin with
for(var/i=0, i<src.number, i++)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/smoke/chem/S = PoolOrNew(smoke_type, location)
if(!direction)
if(src.cardinals)
S.direction = pick(cardinal)
else
// if no color, just use the old smoke icon
smoke.icon = 'icons/effects/96x96.dmi'
smoke.icon_state = "smoke"
S.direction = pick(alldirs)
else
S.direction = direction
if(number<=5)
S.steps = pick(0,1,1)
else if(number<=10)
S.steps = pick(0,1,1,1,2)
else
S.steps = pick(0,1,1,1,2,2,2,3)
S.max_lifetime = Clamp(round(sqrt(chemholder.reagents.total_volume/2), 1), 4, 10) //the more chemicals, the longer the smoke duration.
S.lifetime = S.max_lifetime
for(i=0, i<pick(0,1,1,1,2,2,2,3), i++)
sleep(10)
step(smoke,direction)
spawn(150+rand(10,30))
if(smoke)
fadeOut(smoke)
qdel(smoke)
src.total_smoke--
if(chemholder.reagents.total_volume > 1) // can't split 1 very well
chemholder.reagents.copy_to(S, chemholder.reagents.total_volume / number) // copy reagents to each smoke, divide evenly
if(color)
S.color = color // give the smoke color, if it has any to begin with
else
// if no color, just use the old smoke icon
S.icon = 'icons/effects/96x96.dmi'
S.icon_state = "smoke"
S.process() //calling process right now so the smoke immediately attacks mobs.
/////////////////////////////////////////////
// Sleep smoke
/////////////////////////////////////////////
/obj/effect/effect/sleep_smoke
name = "smoke"
icon_state = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 6.0
//Remove this bit to use the old smoke
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
/obj/effect/effect/smoke/sleeping
color = "#9C3636"
/obj/effect/effect/sleep_smoke/New()
..()
spawn (200+rand(10,30))
qdel(src)
/obj/effect/effect/smoke/sleeping/process()
for(var/mob/living/carbon/M in range(1,src))
smoke_mob(M)
/obj/effect/effect/sleep_smoke/Move()
..()
for(var/mob/living/carbon/M in get_turf(src))
if (M.internal != null && M.wear_mask && (M.wear_mask.flags & MASKINTERNALS))
// if (M.wear_suit, /obj/item/clothing/suit/wizrobe && (M.hat, /obj/item/clothing/head/wizard) && (M.shoes, /obj/item/clothing/shoes/sandal)) // I'll work on it later
else
M.drop_item()
M:sleeping += 5
if (M.coughedtime != 1)
M.coughedtime = 1
M.emote("cough")
spawn(20)
if(M && M.loc)
M.coughedtime = 0
return
/obj/effect/effect/sleep_smoke/Crossed(mob/living/carbon/M as mob )
..()
if(istype(M, /mob/living/carbon))
if (M.internal != null && M.wear_mask && (M.wear_mask.flags & MASKINTERNALS))
// if (M.wear_suit, /obj/item/clothing/suit/wizrobe && (M.hat, /obj/item/clothing/head/wizard) && (M.shoes, /obj/item/clothing/shoes/sandal)) // Work on it later
/obj/effect/effect/smoke/sleeping/smoke_mob(mob/living/carbon/M as mob)
if(..())
if(M.internal != null || (M.wear_mask && (M.wear_mask.flags & BLOCK_GAS_SMOKE_EFFECT)))
return
else
M.drop_item()
M:sleeping += 5
if (M.coughedtime != 1)
M.coughedtime = 1
M.emote("cough")
spawn(20)
if(M && M.loc)
M.coughedtime = 0
return
/datum/effect/effect/system/sleep_smoke_spread
var/total_smoke = 0 // To stop it being spammed and lagging!
var/direction
/datum/effect/effect/system/sleep_smoke_spread/set_up(n = 5, c = 0, loca, direct)
if(n > 20)
n = 20
number = n
cardinals = c
if(istype(loca, /turf/))
location = loca
else
location = get_turf(loca)
if(direct)
direction = direct
M.sleeping = max(M.sleeping,10)
M.emote("cough")
/datum/effect/effect/system/sleep_smoke_spread/start()
var/i = 0
for(i=0, i<src.number, i++)
if(src.total_smoke > 20)
return
spawn(0)
if(holder)
src.location = get_turf(holder)
var/obj/effect/effect/sleep_smoke/smoke = PoolOrNew(/obj/effect/effect/sleep_smoke, location)
src.total_smoke++
var/direction = src.direction
if(!direction)
if(src.cardinals)
direction = pick(cardinal)
else
direction = pick(alldirs)
for(i=0, i<pick(0,1,1,1,2,2,2,3), i++)
sleep(10)
step(smoke,direction)
spawn(150+rand(10,30))
if(smoke)
fadeOut(smoke)
qdel(smoke)
src.total_smoke--
/datum/effect/effect/system/smoke_spread/sleeping
smoke_type = /obj/effect/effect/smoke/sleeping
var/obj/chemholder