More ZAS updating (#15922)

* Clean up the diff

* Some new defines

* Guess I missed that

* Remove the flipped

* Move direct

* More SSair stuff

* Tidier

* Unsimulated edge tick

* Removes useless shit

* Remove additional garbage

* Dusting

* More unticked files

* I missed another, apparently

* Yet another

* Wow, an actual change! Sort of

* god damn it

* Oh, that was commented out

* These are actually very slightly different

* bad

* More readable

* Does nothing

* Roughly mimics old behavior

* Unnecessary

* Equivalent

* This makes sense above, but not here

* *shrug

* Missed these

* Destroy AirflowCanMove()

* Some cleanup

* Unification

* Bools

* Actually it SHOULD be like this

* Alright that would have been too hardcore

* Update doc

* Oops

* I have OCD

* Cleanup

* Fuck group_multiplier

* This was all unused

* Also unused

* Add some stuff

* Move stuff

* Add nothing

* Remove old

* Unused

* Move

* Some new procs

* I touched it bitch

* Compiles, probably

* Air no longer flows nonsensically

* Probably makes compare() work

* [Another synonym for cleaner]

* Potentially done

* Last thing I know of

* Oh yeah this too
This commit is contained in:
Exxion
2017-11-01 03:16:32 -04:00
committed by Pieter-Jan Briers
parent bed4665115
commit fa5183d5da
16 changed files with 550 additions and 2097 deletions

View File

@@ -35,6 +35,9 @@
#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 //Minimum temperature difference before group processing is suspended
#define MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER 0.5 //Minimum temperature difference before the gas temperatures are just set to be equal
#define MINIMUM_PRESSURE_DELTA_TO_SUSPEND 0.1 //The minimum pressure difference required for groups to remain separate (unless they meet other conditions). Chosen arbitrarily.
#define MINIMUM_PRESSURE_RATIO_TO_SUSPEND 0.05 //Minimum RELATIVE difference in pressure for groups to stay separate (unless they meet other conditions). Also chosen arbitrarily.
#define MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION T20C+10
#define MINIMUM_TEMPERATURE_START_SUPERCONDUCTION T20C+200

View File

@@ -12,10 +12,19 @@
#define R_IDEAL_GAS_EQUATION 8.314 //kPa*L/(K*mol)
#define ONE_ATMOSPHERE 101.325 //kPa
// Radiation constants.
#define STEFAN_BOLTZMANN_CONSTANT 5.6704e-8 // W/(m^2*K^4).
#define COSMIC_RADIATION_TEMPERATURE 3.15 // K.
#define AVERAGE_SOLAR_RADIATION 200 // W/m^2. Kind of arbitrary. Really this should depend on the sun position much like solars.
#define RADIATOR_OPTIMUM_PRESSURE 3771 // kPa at 20 C. This should be higher as gases aren't great conductors until they are dense. Used the critical pressure for air.
#define GAS_CRITICAL_TEMPERATURE 132.65 // K. The critical point temperature for air.
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
#define TCMB 2.73 // -270.42degC
#define QUANTIZE(variable) (round(variable, 0.0001))
#define INFINITY 1e31 //closer than enough
#define SPEED_OF_LIGHT 3e8 //not exact but hey!

View File

@@ -137,36 +137,13 @@
return network
/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
air_sample.volume = mingle_volume
var/datum/gas_mixture/air_sample = air.remove_volume(mingle_volume)
if(istype(target) && target.zone)
//Have to consider preservation of group statuses
var/datum/gas_mixture/turf_copy = new
var/datum/gas_mixture/turf_air = target.return_air()
turf_copy.copy_from(target.zone.air)
turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
equalize_gases(list(air_sample, turf_air))
air.merge(air_sample)
equalize_gases(list(air_sample, turf_copy))
air.merge(air_sample)
turf_copy.subtract(target.zone.air)
target.zone.air.merge(turf_copy)
else
var/datum/gas_mixture/turf_air = target.return_air()
equalize_gases(list(air_sample, turf_air))
air.merge(air_sample)
//turf_air already modified by equalize_gases()
/*
if(istype(target) && !target.processing)
if(target.air)
if(target.air.check_tile_graphic())
target.update_visuals(target.air)
*/
if(network)
network.update = 1
@@ -214,7 +191,7 @@
air.temperature += self_temperature_delta
if(modeled_location.zone)
modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
modeled_location.zone.air.temperature += sharer_temperature_delta
else
modeled_location.air.temperature += sharer_temperature_delta

View File

@@ -32,282 +32,143 @@ atom/movable/airflow_hit(atom/A)
AUTOMATIC PROCS:
Airflow(zone/A, zone/B)
Causes objects to fly along a pressure gradient.
Called by zone updates. A and B are two connected zones.
AirflowSpace(zone/A)
Causes objects to fly into space.
Called by zone updates. A is a zone connected to space.
atom/movable/GotoAirflowDest(n)
atom/movable/RepelAirflowDest(n)
Called by main airflow procs to cause the object to fly to or away from destination at speed n.
Called by main airflow procs to cause the object to fly to (n > 0) or away from (n < 0) destination at speed scaled by abs(n).
Probably shouldn't call this directly unless you know what you're
doing and have set airflow_dest. airflow_hit() will be called if the object collides with an obstacle.
*/
mob/var/tmp/last_airflow_stun = 0
mob/proc/airflow_stun()
if(stat == 2 || (flags & INVULNERABLE))
return 0
if(last_airflow_stun > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown))
return 0
/mob/var/tmp/last_airflow_stun = 0
/mob/proc/airflow_stun()
if(isDead() || (flags & INVULNERABLE) || (status_flags & GODMODE))
return FALSE
if(world.time < last_airflow_stun + zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown))
return FALSE
// if(!zas_settings.Get(/datum/ZAS_Setting/airflow_push) || !(M_HARDCORE in mutations)) //This block was added in the original XGM PR, but, again, I don't want to bundle balance with system.
// return FALSE
// if(locked_to)
// to_chat(src, "<span class='notice'>Air suddenly rushes past you!</span>")
// return FALSE
if(!(status_flags & CANSTUN) && !(status_flags & CANKNOCKDOWN))
to_chat(src, "<span class='notice'>You stay upright as the air rushes past you.</span>")
return 0
return FALSE
if(knockdown <= 0)
to_chat(src, "<span class='warning'>The sudden rush of air knocks you over!</span>")
SetKnockdown(5)
last_airflow_stun = world.time
/mob/living/silicon/airflow_stun()
return
mob/living/silicon/airflow_stun()
/mob/living/carbon/slime/airflow_stun()
return
mob/living/carbon/metroid/airflow_stun()
return
mob/living/carbon/human/airflow_stun()
if(last_airflow_stun > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown))
return 0
/mob/living/carbon/human/airflow_stun()
if(world.time < last_airflow_stun + zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown))
return FALSE
if(locked_to || (flags & INVULNERABLE))
return 0
return FALSE
if(shoes)
if(CheckSlip() < 1)
return 0
return FALSE
if(!(status_flags & CANSTUN) && !(status_flags & CANKNOCKDOWN))
to_chat(src, "<span class='notice'>You stay upright as the air rushes past you.</span>")
return 0
return FALSE
if(knockdown <= 0)
to_chat(src, "<span class='warning'>The sudden rush of air knocks you over!</span>")
SetKnockdown(rand(1,5))
last_airflow_stun = world.time
return
atom/movable/proc/check_airflow_movable(n)
if(anchored && !ismob(src))
return 0
if(!istype(src,/obj/item) && n < zas_settings.Get(/datum/ZAS_Setting/airflow_dense_pressure))
return 0
/atom/movable/proc/check_airflow_movable(n)
return (!anchored && n >= zas_settings.Get(/datum/ZAS_Setting/airflow_dense_pressure))
return 1
/mob/check_airflow_movable(n)
// if(M_HARDCORE in mutations)
// return TRUE //It really is hardcore //TOO hardcore, probably
mob/check_airflow_movable(n)
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_heavy_pressure))
return 0
return 1
return FALSE
if(status_flags & GODMODE || (flags & INVULNERABLE))
return FALSE
if(locked_to)
return FALSE
if(CheckSlip() < 0)
return FALSE
mob/dead/observer/check_airflow_movable()
return 0
if (grabbed_by.len)
return FALSE
mob/living/silicon/check_airflow_movable()
return 0
return TRUE
mob/virtualhearer/check_airflow_movable()
return 0
/mob/living/carbon/human/check_airflow_movable(n)
if(reagents.has_reagent(MEDCORES))
return FALSE
return ..()
/mob/dead/observer/check_airflow_movable()
return FALSE
obj/item/check_airflow_movable(n)
. = ..()
switch(w_class)
if(2)
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
return 0
if(3)
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_light_pressure))
return 0
if(4,5)
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure))
return 0
/mob/living/silicon/check_airflow_movable()
return FALSE
/*
//The main airflow code. Called by zone updates.
//Zones A and B are air zones. n represents the amount of air moved.
/mob/virtualhearer/check_airflow_movable()
return FALSE
proc/Airflow(zone/A, zone/B)
set background = 1
var/n = B.air.return_pressure() - A.air.return_pressure()
//Don't go any further if n is lower than the lowest value needed for airflow.
if(abs(n) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
return
//These turfs are the midway point between A and B, and will be the destination point for thrown objects.
var/list/connection/connections_A = A.connections
var/list/turf/connected_turfs = list()
for(var/connection/C in connections_A) //Grab the turf that is in the zone we are flowing to (determined by n)
if( ( A == C.A.zone || A == C.zone_A ) && ( B == C.B.zone || B == C.zone_B ) )
if(n < 0)
connected_turfs |= C.B
else
connected_turfs |= C.A
else if( ( A == C.B.zone || A == C.zone_B ) && ( B == C.A.zone || B == C.zone_A ) )
if(n < 0)
connected_turfs |= C.A
else
connected_turfs |= C.B
//Get lists of things that can be thrown across the room for each zone (assumes air is moving from zone B to zone A)
spawn()
var/list/air_sucked = B.movables()
var/list/air_repelled = A.movables()
if(n < 0)
//air is moving from zone A to zone B
var/list/temporary_pplz = air_sucked
air_sucked = air_repelled
air_repelled = temporary_pplz
if(zas_settings.Get(/datum/ZAS_Setting/airflow_push) || 1) // If enabled
for(var/atom/movable/M in air_sucked)
if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
continue
//Check for knocking people over
if(ismob(M) && n > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure))
if(M:status_flags & GODMODE)
continue
M:airflow_stun()
if(M.check_airflow_movable(n))
//Check for things that are in range of the midpoint turfs.
var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
if(M in range(U))
close_turfs += U
if(!close_turfs.len)
continue
//If they're already being tossed, don't do it again.
if(!M.airflow_speed)
M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
M.GotoAirflowDest(abs(n)/5)
//Do it again for the stuff in the other zone, making it fly away.
for(var/atom/movable/M in air_repelled)
if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
continue
if(ismob(M) && abs(n) > zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure))
if(M:status_flags & GODMODE)
continue
M:airflow_stun()
if(M.check_airflow_movable(abs(n)))
var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
if(M in range(U))
close_turfs += U
if(!close_turfs.len)
continue
//If they're already being tossed, don't do it again.
if(!M.airflow_speed)
M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
spawn M.RepelAirflowDest(abs(n)/5)
proc/AirflowSpace(zone/A)
spawn()
//The space version of the Airflow(A,B,n) proc.
var/n = A.air.return_pressure()
//Here, n is determined by only the pressure in the room.
if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
return
var/list/connected_turfs = A.unsimulated_tiles //The midpoints are now all the space connections.
var/list/pplz = A.movables() //We only need to worry about things in the zone, not things in space.
if(zas_settings.Get(/datum/ZAS_Setting/airflow_push) || 1) // If enabled
for(var/atom/movable/M in pplz)
if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
continue
if(ismob(M) && n > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure))
var/mob/O = M
if(O.status_flags & GODMODE)
continue
O.airflow_stun()
if(M.check_airflow_movable(n))
var/list/close_turfs = list()
for(var/turf/U in connected_turfs)
if(M in range(U))
close_turfs += U
if(!close_turfs.len)
continue
//If they're already being tossed, don't do it again.
if(!M.airflow_speed)
M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
M.GotoAirflowDest(n/10)
//Sometimes shit breaks, and M isn't there after the spawn.
*/
/obj/item/check_airflow_movable(n)
if(anchored)
return FALSE
switch(w_class) //Note that switch() evaluates the FIRST matching case, so the case that executes for a given w_class is the one for which it is the UPPER bound.
if(0 to W_CLASS_TINY)
return TRUE
if(W_CLASS_TINY to W_CLASS_SMALL)
return (n >= zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
if(W_CLASS_SMALL to W_CLASS_MEDIUM)
return (n >= zas_settings.Get(/datum/ZAS_Setting/airflow_light_pressure))
if(W_CLASS_MEDIUM to INFINITY)
return (n >= zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure))
/atom/movable/var/tmp/turf/airflow_dest
/atom/movable/var/tmp/airflow_speed = 0
/atom/movable/var/tmp/airflow_time = 0
/atom/movable/var/tmp/last_airflow = 0
// Mainly for bustanuts.
/atom/movable/proc/AirflowCanPush()
return 1
/mob/AirflowCanPush()
return 1
/mob/living/carbon/human/AirflowCanPush()
if(reagents.has_reagent(MEDCORES))
return 0
return ..()
/atom/movable/proc/GotoAirflowDest(n)
last_airflow = world.time
if(pulledby)
if(!airflow_dest || pulledby)
return
if(world.time < last_airflow + zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
return
if(airflow_dest == loc)
return
if(ismob(src))
var/mob/M = src
if(M.status_flags & GODMODE || (flags & INVULNERABLE))
return
if(M.grabbed_by.len)
return
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(H.locked_to)
return
if(H.shoes)
if(H.CheckSlip() < 0)
return
to_chat(src, "<SPAN CLASS='warning'>You are sucked away by airflow!</SPAN>")
var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful.
to_chat(src, "<span class='warning'>You are sucked away by airflow!</span>")
var/xo = airflow_dest.x - x
var/yo = airflow_dest.y - y
var/airflow_falloff = 9 - sqrt(xo ** 2 + yo ** 2)
if(airflow_falloff < 1)
airflow_dest = null
return
if(n < 0)
n *= -2 //Back when GotoAirflowDest() and RepelAirflowDest() were separate procs, the latter was called with differential/5 rather than differential/10. This is to maintain consistency.
xo *= -1
yo *= -1
airflow_speed = Clamp(n * (9 / airflow_falloff), 1, 9)
var
xo = airflow_dest.x - src.x
yo = airflow_dest.y - src.y
od = 0
airflow_dest = null
var/od = FALSE
if(!density)
density = 1
od = 1
density = TRUE
od = TRUE
last_airflow = world.time
spawn(0)
while(airflow_speed > 0 && Process_Spacemove(1))
airflow_speed = min(airflow_speed,15)
@@ -315,14 +176,14 @@ proc/AirflowSpace(zone/A)
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
if(od)
density = 0
density = FALSE
sleep(tick_multiplier)
else
if(od)
density = 0
density = FALSE
sleep(max(1,10-(airflow_speed+3)) * tick_multiplier)
if(od)
density = 1
density = TRUE
if ((!( src.airflow_dest ) || src.loc == src.airflow_dest))
airflow_dest = locate(Clamp(x + xo, 1, world.maxx), Clamp(y + yo, 1, world.maxy), z)
if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy))
@@ -330,73 +191,14 @@ proc/AirflowSpace(zone/A)
if(!isturf(loc))
break
step_towards(src, src.airflow_dest)
if(ismob(src) && src:client)
var/mob/M = src
var/mob/M = src
if(istype(M) && M.client)
M.delayNextMove(zas_settings.Get(/datum/ZAS_Setting/airflow_mob_slowdown))
airflow_dest = null
airflow_speed = 0
airflow_time = 0
if(od)
density = 0
/atom/movable/proc/RepelAirflowDest(n)
if(pulledby)
return
if(airflow_dest == loc)
step_away(src,loc)
if(ismob(src))
var/mob/M = src
if(M.status_flags & GODMODE || (flags & INVULNERABLE))
return
if(M.grabbed_by.len)
return
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(H.locked_to)
return
if(H.shoes)
if(H.CheckSlip() < 0)
return
to_chat(src, "<SPAN CLASS='warning'>You are pushed away by airflow!</SPAN>")
last_airflow = world.time
var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful.
if(airflow_falloff < 1)
airflow_dest = null
return
airflow_speed = Clamp(n * (9 / airflow_falloff), 1, 9)
var
xo = -(airflow_dest.x - src.x)
yo = -(airflow_dest.y - src.y)
od = 0
airflow_dest = null
if(!density)
density = 1
od = 1
spawn(0)
while(airflow_speed > 0)
airflow_speed = min(airflow_speed,15)
airflow_speed -= zas_settings.Get(/datum/ZAS_Setting/airflow_speed_decay)
if(airflow_speed > 7)
if(airflow_time++ >= airflow_speed - 7)
sleep(tick_multiplier)
else
sleep(max(1,10-(airflow_speed+3)) * tick_multiplier)
if ((!( src.airflow_dest ) || src.loc == src.airflow_dest))
airflow_dest = locate(Clamp(x + xo, 1, world.maxx), Clamp(y + yo, 1, world.maxy), z)
if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy))
break
if (!isturf(loc))
break
step_towards(src, src.airflow_dest)
if(ismob(src) && src:client)
var/mob/M = src
M.delayNextMove(zas_settings.Get(/datum/ZAS_Setting/airflow_mob_slowdown))
airflow_dest = null
airflow_speed = 0
airflow_time = 0
if(od)
density = 0
density = FALSE
/atom/movable/to_bump(atom/Obstacle)
if(airflow_speed > 0 && airflow_dest)
@@ -407,17 +209,15 @@ proc/AirflowSpace(zone/A)
. = ..()
sound_override = 0
atom/movable/proc/airflow_hit(atom/A)
/atom/movable/proc/airflow_hit(atom/A)
airflow_speed = 0
airflow_dest = null
mob/airflow_hit(atom/A)
/mob/airflow_hit(atom/A)
if(size == SIZE_TINY)
return //Slamming into a mouse/roach doesn't make much sense
if(!sound_override)
for(var/mob/M in hearers(src))
M.show_message("<span class='danger'>\The [src] slams into \a [A]!</span>",1,"<span class='warning'>You hear a loud slam!</span>",2)
visible_message(message = "<span class='danger'>\The [src] slams into \a [A]!</span>", blind_message = "<span class='danger'>You hear a loud slam!</span>")
//playsound(get_turf(src), "smash.ogg", 25, 1, -1)
if(istype(A,/obj/item))
var/obj/item/item = A
@@ -426,40 +226,17 @@ mob/airflow_hit(atom/A)
SetKnockdown(rand(1,5))
. = ..()
obj/airflow_hit(atom/A)
/obj/airflow_hit(atom/A)
if(!sound_override)
for(var/mob/M in hearers(src))
M.show_message("<span class='danger'>\The [src] slams into \a [A]!</span>",1,"<span class='warning'>You hear a loud slam!</span>",2)
visible_message(message = "<span class='danger'>\The [src] slams into \a [A]!</span>", blind_message = "<span class='warning'>You hear a loud slam!</span>")
//playsound(get_turf(src), "smash.ogg", 25, 1, -1)
. = ..()
obj/item/airflow_hit(atom/A)
/obj/item/airflow_hit(atom/A)
airflow_speed = 0
airflow_dest = null
mob/living/carbon/human/airflow_hit(atom/A)
// for(var/mob/M in hearers(src))
// M.show_message("<span class='danger'>[src] slams into [A]!</span>",1,"<span class='warning'>You hear a loud slam!</span>",2)
//playsound(get_turf(src), "punch", 25, 1, -1)
/*See this? This is how you DON'T handle armor values for protection
if(prob(33))
loc:add_blood(src)
bloody_body(src)
var/b_loss = airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_damage)
var/blocked = run_armor_check(LIMB_HEAD,"melee")
apply_damage(b_loss/3, BRUTE, LIMB_HEAD, blocked, 0, used_weapon = "Airflow")
blocked = run_armor_check(LIMB_CHEST,"melee")
apply_damage(b_loss/3, BRUTE, LIMB_CHEST, blocked, 0, used_weapon = "Airflow")
blocked = run_armor_check(LIMB_GROIN,"melee")
apply_damage(b_loss/3, BRUTE, LIMB_GROIN, blocked, 0, used_weapon = "Airflow")
*/
/mob/living/carbon/human/airflow_hit(atom/A)
var/b_loss = airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_damage)
for(var/i in contents)
@@ -483,19 +260,11 @@ mob/living/carbon/human/airflow_hit(atom/A)
T.add_blood(src)
bloody_body(src)
if(zas_settings.Get(/datum/ZAS_Setting/airflow_push) || AirflowCanPush())
if(zas_settings.Get(/datum/ZAS_Setting/airflow_push) || (M_HARDCORE in mutations))
if(airflow_speed > 10)
paralysis += round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun))
stunned = max(stunned,paralysis + 3)
Paralyse(round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun)))
Stun(paralysis + 3)
else
stunned += round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun)/2)
Stun(round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun)/2))
. = ..()
zone/proc/movables()
. = list()
for(var/turf/T in contents)
for(var/atom/A in T)
if(istype(A, /obj/effect) || isobserver(A) || isAIEye(A))
continue
. += A

View File

@@ -1,141 +1,101 @@
/*
Overview:
These are what handle gas transfers between zones and into space.
They are found in a zone's edges list and in SSair.edges.
Each edge updates every air tick due to their role in gas transfer.
They come in two flavors, /connection_edge/zone and /connection_edge/unsimulated.
As the type names might suggest, they handle inter-zone and spacelike connections respectively.
Class Vars:
A - This always holds a zone. In unsimulated edges, it holds the only zone.
connecting_turfs - This holds a list of connected turfs, mainly for the sake of airflow.
coefficent - This is a marker for how many connections are on this edge. Used to determine the ratio of flow.
connection_edge/zone
B - This holds the second zone with which the first zone equalizes.
direct - This counts the number of direct (i.e. with no doors) connections on this edge.
Any value of this is sufficient to make the zones mergeable.
connection_edge/unsimulated
B - This holds an unsimulated turf which has the gas values this edge is mimicing.
air - Retrieved from B on creation and used as an argument for the legacy ShareSpace() proc.
Class Procs:
add_connection(connection/c)
Adds a connection to this edge. Usually increments the coefficient and adds a turf to connecting_turfs.
remove_connection(connection/c)
Removes a connection from this edge. This works even if c is not in the edge, so be careful.
If the coefficient reaches zero as a result, the edge is erased.
contains_zone(zone/Z)
Returns true if either A or B is equal to Z. Unsimulated connections return true only on A.
erase()
Removes this connection from processing and zone edge lists.
tick()
Called every air tick on edges in the processing list. Equalizes gas.
flow(list/movable, differential, repelled)
Airflow proc causing all objects in movable to be checked against a pressure differential.
If repelled is true, the objects move away from any turf in connecting_turfs, otherwise they approach.
A check against vsc.lightest_airflow_pressure should generally be performed before calling this.
get_connected_zone(zone/from)
Helper proc that allows getting the other zone of an edge given one of them.
Only on /connection_edge/zone, otherwise use A.
*/
/connection_edge/var/zone/A
/connection_edge
var/zone/A
/connection_edge/var/list/connecting_turfs = list()
var/list/connecting_turfs = list()
var/direct = 0
var/sleeping = 1
/connection_edge/var/coefficient = 0
var/coefficient = 0
/connection_edge/New()
CRASH("Cannot make connection edge without specifications.")
/connection_edge/proc/add_connection(connection/c)
coefficient++
// to_chat(world, "Connection added: [type] Coefficient: [coefficient]")
if(c.direct())
direct++
/connection_edge/proc/remove_connection(connection/c)
// to_chat(world, "Connection removed: [type] Coefficient: [coefficient-1]")
coefficient--
if(coefficient <= 0)
erase()
if(c.direct())
direct--
/connection_edge/proc/contains_zone(zone/Z)
/connection_edge/proc/erase()
SSair.remove_edge(src)
// to_chat(world, "[type] Erased.")
/connection_edge/proc/tick()
/connection_edge/proc/flow(list/movable, differential, repelled, flipped = 0)
//Flipped tells us if we are going from A to B or from B to A.
/connection_edge/proc/recheck()
/connection_edge/proc/flow(list/blown, differential)
if(!zas_settings.Get(/datum/ZAS_Setting/airflow_push))
return
for(var/atom/movable/M in movable)
if(!M.AirflowCanPush())
continue
//If they're already being tossed, don't do it again.
if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay))
continue
if(M.airflow_speed)
continue
for(var/atom/movable/AM in blown)
//Check for knocking people over
if(ismob(M) && differential > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure))
if(M:status_flags & GODMODE)
continue
M:airflow_stun()
if(ismob(AM) && differential > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure))
var/mob/M = AM
M.airflow_stun()
if(M.check_airflow_movable(differential))
if(AM.check_airflow_movable(differential))
//Check for things that are in range of the midpoint turfs.
var/list/close_turfs = list()
for(var/turf/U in connecting_turfs)
if(get_dist(M,U) < world.view)
if(get_dist(AM,U) < world.view)
close_turfs += U
if(!close_turfs.len)
continue
M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
AM.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards.
if(M)
if(repelled)
if(flipped)
if(!(M.loc in src:A.contents))
continue
else if(!(M.loc in src:B.contents))
continue
M.RepelAirflowDest(differential/5)
else
if(flipped)
if(!(M.loc in src:B.contents))
continue
else if(!(M.loc in src:A.contents))
continue
M.GotoAirflowDest(differential/10)
AM.GotoAirflowDest(differential/10)
/connection_edge/zone/var/zone/B
/connection_edge/zone/var/direct = 0
/connection_edge/zone
var/zone/B
/connection_edge/zone/New(zone/A, zone/B)
@@ -144,18 +104,13 @@ Class Procs:
A.edges.Add(src)
B.edges.Add(src)
//id = edge_id(A,B)
// to_chat(world, "New edge between [A] and [B]")
/connection_edge/zone/add_connection(connection/c)
. = ..()
connecting_turfs.Add(c.A)
if(c.direct())
direct++
/connection_edge/zone/remove_connection(connection/c)
connecting_turfs.Remove(c.A)
if(c.direct())
direct--
. = ..()
/connection_edge/zone/contains_zone(zone/Z)
@@ -170,38 +125,29 @@ Class Procs:
if(A.invalid || B.invalid)
erase()
return
// to_chat(world, "[id]: Tick [SSair.current_cycle]: \...")
if(direct)
if(SSair.equivalent_pressure(A, B))
// to_chat(world, "merged.")
erase()
SSair.merge(A, B)
// to_chat(world, "zones merged.")
return
//SSair.equalize(A, B)
ShareRatio(A.air,B.air,coefficient)
SSair.mark_zone_update(A)
SSair.mark_zone_update(B)
// to_chat(world, "equalized.")
var/equiv = A.air.share_tiles(B.air, coefficient)
var/differential = A.air.return_pressure() - B.air.return_pressure()
if(abs(differential) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
return
if(abs(differential) >= zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
flow(A.contents, differential)
flow(B.contents, -differential)
var/list/attracted
var/list/repelled
var/flipped = 0
if(differential > 0)
attracted = A.movables()
repelled = B.movables()
else
flipped = 1
attracted = B.movables()
repelled = A.movables()
if(equiv)
if(direct)
erase()
SSair.merge(A, B)
return
else
SSair.mark_edge_sleeping(src)
equalize_gases(A.get_equalized_zone_air())
flow(attracted, abs(differential), 0, flipped)
flow(repelled, abs(differential), 1, flipped)
SSair.mark_zone_update(A)
SSair.mark_zone_update(B)
/connection_edge/zone/recheck()
if(!A.air.compare(B.air))
SSair.mark_edge_active(src)
//Helper proc to get connections for a zone.
/connection_edge/zone/proc/get_connected_zone(zone/from)
@@ -210,8 +156,9 @@ Class Procs:
else
return A
/connection_edge/unsimulated/var/turf/B
/connection_edge/unsimulated/var/datum/gas_mixture/air
/connection_edge/unsimulated
var/turf/B
var/datum/gas_mixture/air
/connection_edge/unsimulated/New(zone/A, turf/B)
src.A = A
@@ -219,16 +166,13 @@ Class Procs:
A.edges.Add(src)
air = B.return_air()
//id = 52*A.id
// to_chat(world, "New edge from [A] to [B].")
/connection_edge/unsimulated/add_connection(connection/c)
. = ..()
connecting_turfs.Add(c.B)
air.group_multiplier = coefficient
/connection_edge/unsimulated/remove_connection(connection/c)
connecting_turfs.Remove(c.B)
air.group_multiplier = coefficient
. = ..()
/connection_edge/unsimulated/erase()
@@ -242,219 +186,31 @@ Class Procs:
if(A.invalid)
erase()
return
// to_chat(world, "[id]: Tick [SSair.current_cycle]: To [B]!")
//A.air.mimic(B, coefficient)
ShareSpace(A.air,air,dbg_out)
SSair.mark_zone_update(A)
var/equiv = A.air.share_space(air, coefficient)
var/differential = A.air.return_pressure() - air.return_pressure()
if(abs(differential) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
return
if(abs(differential) >= zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure))
flow(A.contents, abs(differential), differential < 0)
var/list/attracted = A.movables()
flow(attracted, abs(differential), differential < 0)
if(equiv)
A.air.copy_from(air)
SSair.mark_edge_sleeping(src)
var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
ratio = sharing_lookup_table[6]
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
size = max(1,A.group_multiplier)
share_size = max(1,B.group_multiplier)
full_oxy = A.oxygen * size
full_nitro = A.nitrogen * size
full_co2 = A.carbon_dioxide * size
full_plasma = A.toxins * size
full_heat_capacity = A.heat_capacity() * size
s_full_oxy = B.oxygen * share_size
s_full_nitro = B.nitrogen * share_size
s_full_co2 = B.carbon_dioxide * share_size
s_full_plasma = B.toxins * share_size
s_full_heat_capacity = B.heat_capacity() * share_size
oxy_avg = (full_oxy + s_full_oxy) / (size + share_size)
nit_avg = (full_nitro + s_full_nitro) / (size + share_size)
co2_avg = (full_co2 + s_full_co2) / (size + share_size)
plasma_avg = (full_plasma + s_full_plasma) / (size + share_size)
temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
if(connecting_tiles && sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg )
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
A.toxins = max(0, (A.toxins - plasma_avg) * (1-ratio) + plasma_avg )
A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg )
B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg )
B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
B.toxins = max(0, (B.toxins - plasma_avg) * (1-ratio) + plasma_avg )
B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg )
for(var/datum/gas/G in A.trace_gases)
var/datum/gas/H = locate(G.type) in B.trace_gases
if(H)
var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
else
H = new G.type
B.trace_gases += H
var/G_avg = (G.moles*size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
for(var/datum/gas/G in B.trace_gases)
var/datum/gas/H = locate(G.type) in A.trace_gases
if(!H)
H = new G.type
A.trace_gases += H
var/G_avg = (G.moles*size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
A.update_values()
B.update_values()
if(A.compare(B))
return 1
else
return 0
proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
//A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room.
if(!unsimulated_tiles)
return 0
var
unsim_oxygen = 0
unsim_nitrogen = 0
unsim_co2 = 0
unsim_plasma = 0
unsim_heat_capacity = 0
unsim_temperature = 0
size = max(1,A.group_multiplier)
var/tileslen
var/share_size
if(istype(unsimulated_tiles, /datum/gas_mixture))
var/datum/gas_mixture/avg_unsim = unsimulated_tiles
unsim_oxygen = avg_unsim.oxygen
unsim_co2 = avg_unsim.carbon_dioxide
unsim_nitrogen = avg_unsim.nitrogen
unsim_plasma = avg_unsim.toxins
unsim_temperature = avg_unsim.temperature
share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier)
tileslen = avg_unsim.group_multiplier
if(dbg_output)
to_chat(world, "O2: [unsim_oxygen] N2: [unsim_nitrogen] Size: [share_size] Tiles: [tileslen]")
else if(istype(unsimulated_tiles, /list))
if(!unsimulated_tiles.len)
return 0
// We use the same size for the potentially single space tile
// as we use for the entire room. Why is this?
// Short answer: We do not want larger rooms to depressurize more
// slowly than small rooms, preserving our good old "hollywood-style"
// oh-shit effect when large rooms get breached, but still having small
// rooms remain pressurized for long enough to make escape possible.
share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len)
var/correction_ratio = share_size / unsimulated_tiles.len
for(var/turf/T in unsimulated_tiles)
unsim_oxygen += T.oxygen
unsim_co2 += T.carbon_dioxide
unsim_nitrogen += T.nitrogen
unsim_plasma += T.toxins
unsim_temperature += T.temperature/unsimulated_tiles.len
//These values require adjustment in order to properly represent a room of the specified size.
unsim_oxygen *= correction_ratio
unsim_co2 *= correction_ratio
unsim_nitrogen *= correction_ratio
unsim_plasma *= correction_ratio
tileslen = unsimulated_tiles.len
else //invalid input type
return 0
unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma)
var
ratio = sharing_lookup_table[6]
old_pressure = A.return_pressure()
full_oxy = A.oxygen * size
full_nitro = A.nitrogen * size
full_co2 = A.carbon_dioxide * size
full_plasma = A.toxins * size
full_heat_capacity = A.heat_capacity() * size
oxy_avg = (full_oxy + unsim_oxygen*share_size) / (size + share_size)
nit_avg = (full_nitro + unsim_nitrogen*share_size) / (size + share_size)
co2_avg = (full_co2 + unsim_co2*share_size) / (size + share_size)
plasma_avg = (full_plasma + unsim_plasma*share_size) / (size + share_size)
temp_avg = 0
if((full_heat_capacity + unsim_heat_capacity) > 0)
temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity)
if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[tileslen]
if(dbg_output)
to_chat(world, "Ratio: [ratio]")
to_chat(world, "Avg O2: [oxy_avg] N2: [nit_avg]")
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg )
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg )
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg )
A.toxins = max(0, (A.toxins - plasma_avg) * (1 - ratio) + plasma_avg )
A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg )
for(var/datum/gas/G in A.trace_gases)
var/G_avg = (G.moles * size) / (size + share_size)
G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg
A.update_values()
if(dbg_output)
to_chat(world, "Result: [abs(old_pressure - A.return_pressure())] kPa")
return abs(old_pressure - A.return_pressure())
SSair.mark_zone_update(A)
/connection_edge/unsimulated/recheck()
if(!A.air.compare(air))
SSair.mark_edge_active(src)
proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
//This implements a simplistic version of the Stefan-Boltzmann law.
var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5
var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier))
var/energy_delta = ((A.temperature - B.temperature) ** 4) * STEFAN_BOLTZMANN_CONSTANT * connecting_tiles * 2.5
var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity(), B.temperature * B.heat_capacity()))
if(maximum_energy_delta > abs(energy_delta))
if(energy_delta < 0)
maximum_energy_delta *= -1
energy_delta = maximum_energy_delta
A.temperature -= energy_delta / (A.heat_capacity() * A.group_multiplier)
B.temperature += energy_delta / (B.heat_capacity() * B.group_multiplier)
A.temperature -= energy_delta / A.heat_capacity()
B.temperature += energy_delta / B.heat_capacity()

View File

@@ -101,7 +101,6 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf)
to_chat(client, "Pressure: [air.return_pressure()] KPa")
to_chat(client, "")
to_chat(client, "Unsimulated Zone(space/catwalk) Tiles: [length(unsimulated_tiles)]")
to_chat(client, "Movable Objects: [length(movables())]")
to_chat(client, "<u>Connections: [length(connections)]</u>")
for(var/connection/C in connections)

View File

@@ -1,176 +0,0 @@
//Global Functions
//Contents: FloodFill, ZMerge, ZConnect
//Floods outward from an initial turf to fill everywhere it's zone would reach.
proc/FloodFill(turf/simulated/start)
if(!istype(start))
return list()
//The list of tiles waiting to be evaulated.
var/list/open = list(start)
//The list of tiles which have been evaulated.
var/list/closed = list()
//Loop through the turfs in the open list in order to find which adjacent turfs should be added to the zone.
while(open.len)
var/turf/simulated/T = pick(open)
//sanity!
if(!istype(T) || iscatwalk(T))
open -= T
continue
//Check all cardinal directions
for(var/d in cardinal)
var/turf/simulated/O = get_step(T,d)
//Ensure the turf is of proper type, that it is not in either list, and that air can reach it.
if(istype(O) && !iscatwalk(O) && !(O in open) && !(O in closed) && O.ZCanPass(T))
//Handle connections from a tile with a door.
if(T.HasDoor())
//If they both have doors, then they are not able to connect period.
if(O.HasDoor())
continue
//Connect first to north and west
if(d == NORTH || d == WEST)
open += O
//If that fails, and north/west cannot be connected to, see if west or south can be connected instead.
else
var/turf/simulated/W = get_step(O, WEST)
var/turf/simulated/N = get_step(O, NORTH)
if(!O.ZCanPass(N) && !O.ZCanPass(W) )
//If it cannot connect either to the north or west, connect it!
open += O
//If no doors are involved, add it immediately.
else if(!O.HasDoor())
open += O
//Handle connecting to a tile with a door.
else
if(d == SOUTH || d == EAST)
//doors prefer connecting to zones to the north or west
closed += O
else
//see if we need to force an attempted connection
//(there are no potentially viable zones to the north/west of the door)
var/turf/simulated/W = get_step(O, WEST)
var/turf/simulated/N = get_step(O, NORTH)
if( !O.ZCanPass(N) && !O.ZCanPass(W) )
//If it cannot connect either to the north or west, connect it!
closed += O
//This tile is now evaluated, and can be moved to the list of evaluated tiles.
open -= T
closed += T
return closed
//Procedure to merge two zones together.
proc/ZMerge(zone/A,zone/B)
//Sanity~
if(!istype(A) || !istype(B))
return
var/new_contents = A.contents + B.contents
//Set all the zone vars.
for(var/turf/simulated/T in B.contents)
T.zone = A
if(istype(A.air) && istype(B.air))
//Merges two zones so that they are one.
var/a_size = A.air.group_multiplier
var/b_size = B.air.group_multiplier
var/c_size = a_size + b_size
//Set air multipliers to one so air represents gas per tile.
A.air.group_multiplier = 1
B.air.group_multiplier = 1
//Remove some air proportional to the size of this zone.
A.air.remove_ratio(a_size/c_size)
B.air.remove_ratio(b_size/c_size)
//Merge the gases and set the multiplier to the sum of the old ones.
A.air.merge(B.air)
A.air.group_multiplier = c_size
//I hate when the air datum somehow disappears.
// Try to make it sorta work anyways. Fakit
else if(istype(B.air))
A.air = B.air
A.air.group_multiplier = A.contents.len
else if(istype(A.air))
A.air.group_multiplier = A.contents.len
//Doublefakit.
else
A.air = new
//Check for connections to merge into the new zone.
for(var/connection/C in B.connections)
//The Cleanup proc will delete the connection if the zones are the same.
// It will also set the zone variables correctly.
C.Cleanup()
//Add space tiles.
if(A.unsimulated_tiles && B.unsimulated_tiles)
A.unsimulated_tiles |= B.unsimulated_tiles
else if (B.unsimulated_tiles)
A.unsimulated_tiles = B.unsimulated_tiles
//Add contents.
A.contents = new_contents
//Remove the "B" zone, finally.
B.SoftDelete()
//Connects two zones by forming a connection object representing turfs A and B.
proc/ZConnect(turf/simulated/A,turf/simulated/B)
//Make sure that if it's space, it gets added to unsimulated_tiles instead.
if(!istype(B) || iscatwalk(B))
if(A.zone)
A.zone.AddTurf(B)
return
if(!istype(A) || iscatwalk(A))
if(B.zone)
B.zone.AddTurf(A)
return
if(!istype(A) || !istype(B))
return
//Make some preliminary checks to see if the connection is valid.
if(!A.zone || !B.zone)
return
if(A.zone == B.zone)
return
if(A.CanPass(null,B,0,1))
return ZMerge(A.zone,B.zone)
//Ensure the connection isn't already made.
if("\ref[A]" in SSair.turfs_with_connections)
for(var/connection/C in SSair.turfs_with_connections["\ref[A]"])
C.Cleanup()
if(C && (C.B == B || C.A == B))
return
//Make the connection.
new /connection(A,B)

View File

@@ -248,8 +248,6 @@
SSair.mark_zone_update(zone)
return zone.air
else
if(!air)
make_air()
c_copy_air()
return air
else
@@ -261,15 +259,13 @@
air = new/datum/gas_mixture
air.temperature = temperature
air.adjust(oxygen, carbon_dioxide, nitrogen, toxins)
air.group_multiplier = 1
air.volume = CELL_VOLUME
/turf/simulated/proc/c_copy_air()
if(!air)
air = new/datum/gas_mixture
air.copy_from(zone.air)
air.group_multiplier = 1
/turf/attack_hand(mob/user as mob)
user.Move_Pulled(src)
user.Move_Pulled(src)

View File

@@ -1,345 +0,0 @@
var/global/vs_control/vsc = new
// Whoever made this fucking thing: I hate you so much.
vs_control/var
// N3X15 - Added back in so we can tweak performance.
airflow_push = 0
airflow_push_NAME="Airflow - Push shit around"
airflow_push_DESC="1=yes please rape my server, 0=no"
airflow_push_METHOD="Toggle" // See ChangeSettings(). I'd rather not let people break this.
fire_consuption_rate = 0.75
fire_consuption_rate_NAME = "Fire - Air Consumption Ratio"
fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick."
fire_firelevel_multiplier = 25
fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant"
fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires."
fire_fuel_energy_release = 550000
fire_fuel_energy_release_NAME = "Fire - Fuel energy release"
fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance"
airflow_lightest_pressure = 20
airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %"
airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move."
airflow_light_pressure = 35
airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %"
airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move."
airflow_medium_pressure = 50
airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %"
airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move."
airflow_heavy_pressure = 65
airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %"
airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move."
airflow_dense_pressure = 85
airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %"
airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move."
airflow_stun_pressure = 60
airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %"
airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow."
airflow_stun_cooldown = 60
airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown"
airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again."
airflow_stun = 1
airflow_stun_NAME = "Airflow Impact - Stunning"
airflow_stun_DESC = "How much a mob is stunned when hit by an object."
airflow_damage = 2
airflow_damage_NAME = "Airflow Impact - Damage"
airflow_damage_DESC = "Damage from airflow impacts."
airflow_speed_decay = 1.5
airflow_speed_decay_NAME = "Airflow Speed Decay"
airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays."
airflow_delay = 30
airflow_delay_NAME = "Airflow Retrigger Delay"
airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again."
airflow_mob_slowdown = 1
airflow_mob_slowdown_NAME = "Airflow Slowdown"
airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow."
var/connection_insulation = 0.4
var/connection_insulation_NAME = "Connections - Insulation"
var/connection_insulation_DESC = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive."
var/connection_temperature_delta = 10
var/connection_temperature_delta_NAME = "Connections - Temperature Difference"
var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors."
vs_control
var
list/settings = list()
list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") // Oh jesus why. Learn to shift bits, you idiots.
pl_control/plc = new()
New()
. = ..()
settings = vars.Copy()
var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars.
for(var/V in D.vars)
settings -= V
for(var/V in settings)
if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD"))
settings -= V
settings -= "settings"
settings -= "bitflags"
settings -= "plc"
proc/ChangeSettingsDialog(mob/user,list/L)
//var/which = input(user,"Choose a setting:") in L
var/dat = ""
for(var/ch in L)
if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME"))
continue
var/vw
var/vw_desc = "No Description."
var/vw_name = ch
if(ch in plc.settings)
vw = plc.vars[ch]
if("[ch]_DESC" in plc.vars)
vw_desc = plc.vars["[ch]_DESC"]
if("[ch]_NAME" in plc.vars)
vw_name = plc.vars["[ch]_NAME"]
else
vw = vars[ch]
if("[ch]_DESC" in vars)
vw_desc = vars["[ch]_DESC"]
if("[ch]_NAME" in vars)
vw_name = vars["[ch]_NAME"]
dat += "<b>[vw_name] = [vw]</b> <A href='?src=\ref[src];changevar=[ch]'>\[Change\]</A><br>"
dat += "<i>[vw_desc]</i><br><br>"
user << browse(dat,"window=settings")
Topic(href,href_list)
if("changevar" in href_list)
ChangeSetting(usr,href_list["changevar"])
proc/ChangeSetting(mob/user,ch)
var/vw
var/how = "Text"
var/display_description = ch
if(ch in plc.settings)
vw = plc.vars[ch]
if("[ch]_NAME" in plc.vars)
display_description = plc.vars["[ch]_NAME"]
if("[ch]_METHOD" in plc.vars)
how = plc.vars["[ch]_METHOD"]
else
if(isnum(vw))
how = "Numeric"
else
how = "Text"
else
vw = vars[ch]
if("[ch]_NAME" in vars)
display_description = vars["[ch]_NAME"]
if("[ch]_METHOD" in vars)
how = vars["[ch]_METHOD"]
else
if(isnum(vw))
how = "Numeric"
else
how = "Text"
var/newvar = vw
switch(how)
if("Numeric")
newvar = input(user,"Enter a number:","Settings",newvar) as num
if("Bit Flag")
var/flag = input(user,"Toggle which bit?","Settings") in bitflags
flag = text2num(flag)
if(newvar & flag)
newvar &= ~flag
else
newvar |= flag
if("Toggle")
newvar = !newvar
if("Text")
newvar = input(user,"Enter a string:","Settings",newvar) as text
if("Long Text")
newvar = input(user,"Enter text:","Settings",newvar) as message
vw = newvar
if(ch in plc.settings)
plc.vars[ch] = vw
else
vars[ch] = vw
if(how == "Toggle")
newvar = (newvar?"ON":"OFF")
to_chat(world, "<span class='notice'><b>[key_name(user)] changed the setting [display_description] to [newvar].</b></span>")
if(ch in plc.settings)
ChangeSettingsDialog(user,plc.settings)
else
ChangeSettingsDialog(user,settings)
proc/RandomizeWithProbability()
for(var/V in settings)
var/newvalue
if("[V]_RANDOM" in vars)
if(isnum(vars["[V]_RANDOM"]))
newvalue = prob(vars["[V]_RANDOM"])
else if(istext(vars["[V]_RANDOM"]))
newvalue = roll(vars["[V]_RANDOM"])
else
newvalue = vars[V]
V = newvalue
proc/ChangePlasma()
for(var/V in plc.settings)
plc.Randomize(V)
proc/SetDefault(var/mob/user)
var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\
"ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish")
var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices
if(!def)
return
switch(def)
if("Plasma - Standard")
plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
plc.PLASMAGUARD_ONLY = 0
plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000.
plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited.
plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
plc.PLASMA_HALLUCINATION = 0
plc.CONTAMINATION_LOSS = 0.02
if("Plasma - Low Hazard")
plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth.
plc.PLASMAGUARD_ONLY = 0
plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000
plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited.
plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
plc.PLASMA_HALLUCINATION = 0
plc.CONTAMINATION_LOSS = 0.01
if("Plasma - High Hazard")
plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
plc.PLASMAGUARD_ONLY = 0
plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000.
plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
plc.PLASMA_HALLUCINATION = 1
plc.CONTAMINATION_LOSS = 0.05
if("Plasma - Oh Shit!")
plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth.
plc.PLASMAGUARD_ONLY = 1
plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000.
plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited.
plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection.
plc.PLASMA_HALLUCINATION = 1
plc.CONTAMINATION_LOSS = 0.075
if("ZAS - Normal")
airflow_push=0
airflow_lightest_pressure = 20
airflow_light_pressure = 35
airflow_medium_pressure = 50
airflow_heavy_pressure = 65
airflow_dense_pressure = 85
airflow_stun_pressure = 60
airflow_stun_cooldown = 60
airflow_stun = 1
airflow_damage = 2
airflow_speed_decay = 1.5
airflow_delay = 30
airflow_mob_slowdown = 1
if("ZAS - Forgiving")
airflow_push=0
airflow_lightest_pressure = 45
airflow_light_pressure = 60
airflow_medium_pressure = 120
airflow_heavy_pressure = 110
airflow_dense_pressure = 200
airflow_stun_pressure = 150
airflow_stun_cooldown = 90
airflow_stun = 0.15
airflow_damage = 0.15
airflow_speed_decay = 1.5
airflow_delay = 50
airflow_mob_slowdown = 0
if("ZAS - Dangerous")
airflow_push=1
airflow_lightest_pressure = 15
airflow_light_pressure = 30
airflow_medium_pressure = 45
airflow_heavy_pressure = 55
airflow_dense_pressure = 70
airflow_stun_pressure = 50
airflow_stun_cooldown = 50
airflow_stun = 2
airflow_damage = 3
airflow_speed_decay = 1.2
airflow_delay = 25
airflow_mob_slowdown = 2
if("ZAS - Hellish")
airflow_push=1
airflow_lightest_pressure = 20
airflow_light_pressure = 30
airflow_medium_pressure = 40
airflow_heavy_pressure = 50
airflow_dense_pressure = 60
airflow_stun_pressure = 40
airflow_stun_cooldown = 40
airflow_stun = 3
airflow_damage = 4
airflow_speed_decay = 1
airflow_delay = 20
airflow_mob_slowdown = 3
to_chat(world, "<span class='notice'><b>[key_name(user)] changed the global plasma/ZAS settings to \"[def]\"</b></span>")
pl_control
var/list/settings = list()
New()
. = ..()
settings = vars.Copy()
var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars.
for(var/V in D.vars)
settings -= V
for(var/V in settings)
if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC"))
settings -= V
settings -= "settings"
proc/Randomize(V)
var/newvalue
if("[V]_RANDOM" in vars)
if(isnum(vars["[V]_RANDOM"]))
newvalue = prob(vars["[V]_RANDOM"])
else if(istext(vars["[V]_RANDOM"]))
var/txt = vars["[V]_RANDOM"]
if(findtextEx(txt,"PROB"))
txt = splittext(txt,"/")
txt[1] = replacetext(txt[1],"PROB","")
var/p = text2num(txt[1])
var/r = txt[2]
if(prob(p))
newvalue = roll(r)
else
newvalue = vars[V]
else if(findtextEx(txt,"PICK"))
txt = replacetext(txt,"PICK","")
txt = splittext(txt,",")
newvalue = pick(txt)
else
newvalue = roll(txt)
else
newvalue = vars[V]
vars[V] = newvalue

View File

@@ -28,11 +28,8 @@ Class Procs:
rebuild()
Invalidates the zone and marks all its former tiles for updates.
add_tile_air(turf/simulated/T)
Adds the air contained in T.air to the zone's air supply. Called when adding a turf.
tick()
Called only when the gas content is changed. Archives values and changes gas graphics.
Called only when the gas content is changed. Changes gas graphics.
dbg_data(mob/M)
Sends M a printout of important figures for the zone.
@@ -51,8 +48,7 @@ Class Procs:
/zone/New()
SSair.add_zone(src)
air.temperature = TCMB
air.group_multiplier = 1
air.volume = CELL_VOLUME
air.volume = 0
/zone/proc/add(turf/simulated/T)
#ifdef ZASDBG
@@ -62,7 +58,8 @@ Class Procs:
#endif
var/datum/gas_mixture/turf_air = T.return_air()
add_tile_air(turf_air)
air.volume += turf_air.volume
air.merge(turf_air)
T.zone = src
contents.Add(T)
T.set_graphic(air.graphics)
@@ -74,12 +71,14 @@ Class Procs:
ASSERT(T.zone == src)
soft_assert(T in contents, "Lists are weird broseph")
#endif
contents.Remove(T)
T.zone = null
var/datum/gas_mixture/turf_air = T.return_air()
air.volume -= turf_air.volume
air.divide(1 + turf_air.volume / air.volume)
contents.Remove(T)
T.set_graphic(0)
if(contents.len)
air.group_multiplier = contents.len
else
if(!contents.len)
c_invalidate()
/zone/proc/c_merge(zone/into)
@@ -113,26 +112,36 @@ Class Procs:
T.needs_air_update = 0 //Reset the marker so that it will be added to the list.
SSair.mark_for_update(T)
/zone/proc/add_tile_air(datum/gas_mixture/tile_air)
//air.volume += CELL_VOLUME
air.group_multiplier = 1
air.multiply(contents.len)
air.merge(tile_air)
air.divide(contents.len+1)
air.group_multiplier = contents.len+1
//Gets a list of the gas_mixtures of all zones connected to this one through arbitrarily many sleeping edges.
//This is to cut down somewhat on differentials across open doors.
//Yes, recursion is slow, but this will generally not be called very often, and will rarely have to recurse more than a few levels deep.
//That said, feel free to optimize it if you want.
//
//At the top level, just call it with no arg. The arg generally is for internal use.
/zone/proc/get_equalized_zone_air(list/found = list())
found += air
. = found //I want to minimize the call stack left over after the recursive call. Honestly the implicit return is probably the same as an explicit one, but I'd rather play it safe.
for(var/connection_edge/zone/E in edges)
if(E.sleeping)
var/zone/Z = E.get_connected_zone(src)
if(!(Z.air in found))
Z.get_equalized_zone_air(found)
/zone/proc/tick()
air.archive()
if(air.check_tile_graphic())
for(var/turf/simulated/T in contents)
T.set_graphic(air.graphics)
for(var/connection_edge/E in edges)
if(E.sleeping)
E.recheck()
/zone/proc/dbg_data(mob/M)
to_chat(M, name)
to_chat(M, "O2: [air.oxygen] N2: [air.nitrogen] CO2: [air.carbon_dioxide] P: [air.toxins]")
to_chat(M, "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]<5D>K ([air.temperature - T0C]<5D>C)")
to_chat(M, "O2 per N2: [(air.nitrogen ? air.oxygen/air.nitrogen : "N/A")] Moles: [air.total_moles]")
to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])")
to_chat(M, "Simulated: [contents.len] ([air.volume / CELL_VOLUME])")
// to_chat(M, "Unsimulated: [unsimulated_contents.len]")
// to_chat(M, "Edges: [edges.len]")
if(invalid)

File diff suppressed because it is too large Load Diff

View File

@@ -144,8 +144,6 @@ Class Procs:
simulated_turf_count++
S.update_air_properties()
processing_parts[SSAIR_EDGES] = edges //A temporary hack to make edges actually work before the later PR to add edge sleeping, etc.
to_chat(world, {"<span class='info'>Total Simulated Turfs: [simulated_turf_count]
Total Zones: [zones.len]
Total Edges: [edges.len]
@@ -353,33 +351,31 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
Z.needs_update = 1
//The following is for a system update coming in a later PR.
/datum/subsystem/air/proc/mark_edge_sleeping(connection_edge/E)
#ifdef ZASDBG
ASSERT(istype(E))
#endif
if(E.sleeping)
return
processing_parts[SSAIR_EDGES] -= E
E.sleeping = 1
///datum/subsystem/air/proc/mark_edge_sleeping(connection_edge/E)
// #ifdef ZASDBG
// ASSERT(istype(E))
// #endif
// if(E.sleeping)
// return
// processing_parts[SSAIR_EDGES] -= E
// E.sleeping = 1
//
//
///datum/subsystem/air/proc/mark_edge_active(connection_edge/E)
// #ifdef ZASDBG
// ASSERT(istype(E))
// #endif
// if(!E.sleeping)
// return
// processing_parts[SSAIR_EDGES] |= E
// E.sleeping = 0
// #ifdef ZASDBG
// if(istype(E, /connection_edge/zone/))
// var/connection_edge/zone/ZE = E
// world << "ZASDBG: Active edge! Areas: [get_area(pick(ZE.A.contents))] / [get_area(pick(ZE.B.contents))]"
// else
// world << "ZASDBG: Active edge! Area: [get_area(pick(E.A.contents))]"
// #endif
/datum/subsystem/air/proc/mark_edge_active(connection_edge/E)
#ifdef ZASDBG
ASSERT(istype(E))
#endif
if(!E.sleeping)
return
processing_parts[SSAIR_EDGES] |= E
E.sleeping = 0
#ifdef ZASDBG
if(istype(E, /connection_edge/zone/))
var/connection_edge/zone/ZE = E
world << "ZASDBG: Active edge! Areas: [get_area(pick(ZE.A.contents))] / [get_area(pick(ZE.B.contents))]"
else
world << "ZASDBG: Active edge! Area: [get_area(pick(E.A.contents))]"
#endif
/datum/subsystem/air/proc/equivalent_pressure(zone/A, zone/B)
@@ -394,7 +390,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
return edge
var/connection_edge/edge = new/connection_edge/zone(A,B)
edges.Add(edge)
// edge.recheck()
edge.recheck()
return edge
else
for(var/connection_edge/unsimulated/edge in A.edges)
@@ -402,7 +398,7 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
return edge
var/connection_edge/edge = new/connection_edge/unsimulated(A,B)
edges.Add(edge)
// edge.recheck()
edge.recheck()
return edge
@@ -422,8 +418,8 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
/datum/subsystem/air/proc/remove_edge(connection_edge/E)
edges.Remove(E)
// if(!E.sleeping)
// processing_parts[SSAIR_EDGES] -= E
if(!E.sleeping)
processing_parts[SSAIR_EDGES] -= E
/datum/subsystem/air/proc/add_hotspot(var/obj/effect/fire/H)

View File

@@ -23,7 +23,8 @@
/obj/machinery/atmospherics/miner/New()
..()
air_contents = new
air_contents.volume=1000
air_contents.volume = 1000
pumping.volume = 1000 //Same as above so copying works correctly
air_contents.temperature = T20C
AddAir()
air_contents.update_values()

View File

@@ -26,4 +26,4 @@
// if (!my_air.compare(conn_air))
// myturf.reset_delay()
// zturf_conn.reset_delay()
my_air.share(conn_air)
my_air.share_tiles(conn_air, 1)

View File

@@ -349,13 +349,13 @@ Subject's pulse: ??? BPM"})
var/unknown_concentration = 1 - (o2_concentration + n2_concentration + co2_concentration + plasma_concentration)
if(n2_concentration > 0.01)
message += "<br>[human_standard && abs(n2_concentration - N2STANDARD) > 20 ? "<span class='bad'>" : "<span class='notice'>"] Nitrogen: [round(scanned.nitrogen, 0.1)] mol, [round(n2_concentration*100)]%</span>"
message += "<br>[human_standard && abs(n2_concentration - N2STANDARD) > 20 ? "<span class='bad'>" : "<span class='notice'>"] Nitrogen: [round(scanned.nitrogen / scanned.volume * CELL_VOLUME, 0.1)] mol, [round(n2_concentration*100)]%</span>"
if(o2_concentration > 0.01)
message += "<br>[human_standard && abs(o2_concentration - O2STANDARD) > 2 ? "<span class='bad'>" : "<span class='notice'>"] Oxygen: [round(scanned.oxygen, 0.1)] mol, [round(o2_concentration*100)]%</span>"
message += "<br>[human_standard && abs(o2_concentration - O2STANDARD) > 2 ? "<span class='bad'>" : "<span class='notice'>"] Oxygen: [round(scanned.oxygen / scanned.volume * CELL_VOLUME, 0.1)] mol, [round(o2_concentration*100)]%</span>"
if(co2_concentration > 0.01)
message += "<br>[human_standard ? "<span class='bad'>" : "<span class='notice'>"] CO2: [round(scanned.carbon_dioxide, 0.1)] mol, [round(co2_concentration*100)]%</span>"
message += "<br>[human_standard ? "<span class='bad'>" : "<span class='notice'>"] CO2: [round(scanned.carbon_dioxide / scanned.volume * CELL_VOLUME, 0.1)] mol, [round(co2_concentration*100)]%</span>"
if(plasma_concentration > 0.01)
message += "<br>[human_standard ? "<span class='bad'>" : "<span class='notice'>"] Plasma: [round(scanned.toxins, 0.1)] mol, [round(plasma_concentration*100)]%</span>"
message += "<br>[human_standard ? "<span class='bad'>" : "<span class='notice'>"] Plasma: [round(scanned.toxins / scanned.volume * CELL_VOLUME, 0.1)] mol, [round(plasma_concentration*100)]%</span>"
if(unknown_concentration > 0.01)
message += "<br><span class='notice'>Unknown: [round(unknown_concentration*100)]%</span>"

View File

@@ -623,42 +623,43 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
var/tiles = environment.return_volume() / CELL_VOLUME
to_chat(src, "<span class='notice'><B>Results:</B></span>")
if(abs(pressure - ONE_ATMOSPHERE) < 10)
to_chat(src, "<span class='notice'>Pressure: [round(pressure,0.1)] kPa</span>")
to_chat(src, "<span class='notice'>Pressure: [round(pressure, 0.1)] kPa</span>")
else
to_chat(src, "<span class='warning'>Pressure: [round(pressure,0.1)] kPa</span>")
to_chat(src, "<span class='warning'>Pressure: [round(pressure, 0.1)] kPa</span>")
if(total_moles)
var/o2_concentration = environment.oxygen/total_moles
var/n2_concentration = environment.nitrogen/total_moles
var/co2_concentration = environment.carbon_dioxide/total_moles
var/plasma_concentration = environment.toxins/total_moles
var/o2_concentration = environment.oxygen / total_moles
var/n2_concentration = environment.nitrogen / total_moles
var/co2_concentration = environment.carbon_dioxide / total_moles
var/plasma_concentration = environment.toxins / total_moles
var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration)
var/unknown_concentration = 1 - (o2_concentration + n2_concentration + co2_concentration + plasma_concentration)
if(abs(n2_concentration - N2STANDARD) < 20)
to_chat(src, "<span class='notice'>Nitrogen: [round(n2_concentration*100)]% ([round(environment.nitrogen,0.01)] moles)</span>")
to_chat(src, "<span class='notice'>Nitrogen: [round(n2_concentration * 100)]% ([round(environment.nitrogen / tiles, 0.01)] moles)</span>")
else
to_chat(src, "<span class='warning'>Nitrogen: [round(n2_concentration*100)]% ([round(environment.nitrogen,0.01)] moles)</span>")
to_chat(src, "<span class='warning'>Nitrogen: [round(n2_concentration * 100)]% ([round(environment.nitrogen / tiles, 0.01)] moles)</span>")
if(abs(o2_concentration - O2STANDARD) < 2)
to_chat(src, "<span class='notice'>Oxygen: [round(o2_concentration*100)]% ([round(environment.oxygen,0.01)] moles)</span>")
to_chat(src, "<span class='notice'>Oxygen: [round(o2_concentration * 100)]% ([round(environment.oxygen / tiles, 0.01)] moles)</span>")
else
to_chat(src, "<span class='warning'>Oxygen: [round(o2_concentration*100)]% ([round(environment.oxygen,0.01)] moles)</span>")
to_chat(src, "<span class='warning'>Oxygen: [round(o2_concentration * 100)]% ([round(environment.oxygen / tiles, 0.01)] moles)</span>")
if(co2_concentration > 0.01)
to_chat(src, "<span class='warning'>CO2: [round(co2_concentration*100)]% ([round(environment.carbon_dioxide,0.01)] moles)</span>")
to_chat(src, "<span class='warning'>CO2: [round(co2_concentration * 100)]% ([round(environment.carbon_dioxide / tiles, 0.01)] moles)</span>")
else
to_chat(src, "<span class='notice'>CO2: [round(co2_concentration*100)]% ([round(environment.carbon_dioxide,0.01)] moles)</span>")
to_chat(src, "<span class='notice'>CO2: [round(co2_concentration * 100)]% ([round(environment.carbon_dioxide / tiles, 0.01)] moles)</span>")
if(plasma_concentration > 0.01)
to_chat(src, "<span class='warning'>Plasma: [round(plasma_concentration*100)]% ([round(environment.toxins,0.01)] moles)</span>")
to_chat(src, "<span class='warning'>Plasma: [round(plasma_concentration * 100)]% ([round(environment.toxins / tiles, 0.01)] moles)</span>")
if(unknown_concentration > 0.01)
to_chat(src, "<span class='warning'>Unknown: [round(unknown_concentration*100)]% ([round(unknown_concentration*total_moles,0.01)] moles)</span>")
to_chat(src, "<span class='warning'>Unknown: [round(unknown_concentration * 100)]% ([round(unknown_concentration * total_moles / tiles, 0.01)] moles)</span>")
to_chat(src, "<span class='notice'>Temperature: [round(environment.temperature-T0C,0.1)]&deg;C</span>")
to_chat(src, "<span class='notice'>Heat Capacity: [round(environment.heat_capacity(),0.1)]</span>")
to_chat(src, "<span class='notice'>Temperature: [round(environment.temperature - T0C, 0.1)]&deg;C</span>")
to_chat(src, "<span class='notice'>Heat Capacity: [round(environment.heat_capacity(), 0.1)]</span>")
/mob/dead/observer/verb/toggle_darkness()