Files
vgstation13/code/ZAS/Processing.dm

286 lines
8.8 KiB
Plaintext

#define QUANTIZE(variable) (round(variable,0.0001))
zone/proc/process()
//Deletes zone if empty.
if(!contents.len)
del src
return 0
//Does rebuilding stuff. Not sure if used.
if(rebuild)
rebuild = 0
Rebuild() //Shoving this into a proc.
//Sometimes explosions will cause the air to be deleted for some reason.
if(!air)
air = new()
air.adjust(MOLES_O2STANDARD, 0, MOLES_N2STANDARD, 0, list())
world.log << "Air object lost in zone. Regenerating."
//Counting up space.
var/total_space = 0
if(space_tiles)
for(var/T in space_tiles)
if(!istype(T,/turf/space))
RemoveSpace(T)
total_space = space_tiles.len
//Add checks to ensure that we're not sucking air out of an empty room.
if(total_space && air.total_moles > 0.1 && air.temperature > TCMB+0.5)
//If there is space, air should flow out of the zone.
if(abs(air.return_pressure()) > vsc.airflow_lightest_pressure)
AirflowSpace(src)
ShareSpace(air,total_space*vsc.zone_share_percent/200)
//React the air here.
air.react(null,0)
//Check the graphic.
air.graphic = 0
if(air.toxins > MOLES_PLASMA_VISIBLE)
air.graphic = 1
else if(air.trace_gases.len)
var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air.trace_gases
if(sleeping_agent && (sleeping_agent.moles > 1))
air.graphic = 2
//Only run through the individual turfs if there's reason to.
if(air.graphic != air.graphic_archived || air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
for(var/turf/simulated/S in contents)
//Update overlays.
if(air.graphic != air.graphic_archived)
if(S.HasDoor(1))
S.update_visuals()
else
S.update_visuals(air)
//Expose stuff to extreme heat.
if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
for(var/atom/movable/item in S)
item.temperature_expose(air, air.temperature, CELL_VOLUME)
S.temperature_expose(air, air.temperature, CELL_VOLUME)
//Archive graphic so we can know if it's different.
air.graphic_archived = air.graphic
//Ensure temperature does not reach absolute zero.
air.temperature = max(TCMB,air.temperature)
//Handle connections to other zones.
if(length(connections))
for(var/connection/C in connections)
//Check if the connection is valid first.
if(!C.Cleanup())
continue
//Do merging if conditions are met. Specifically, if there's a non-door connection
//to somewhere with space, the zones are merged regardless of equilibrium, to speed
//up spacing in areas with double-plated windows.
if(C && !C.indirect && C.A.zone && C.B.zone)
if(C.A.zone.air.compare(C.B.zone.air) || total_space)
ZMerge(C.A.zone,C.B.zone)
//Share some
for(var/zone/Z in connected_zones)
//Ensure we're not doing pointless calculations on equilibrium zones.
if(abs(air.total_moles - Z.air.total_moles) > 0.1 || abs(air.temperature - Z.air.temperature) > 0.1)
if(abs(Z.air.return_pressure() - air.return_pressure()) > vsc.airflow_lightest_pressure)
Airflow(src,Z)
ShareRatio( air , Z.air , connected_zones[Z]*vsc.zone_share_percent/200 )
//Divided by 200 since each zone is processed. Each connection is considered twice
//Space tiles force it to try and move twice as much air.
proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, ratio)
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var
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)
A.oxygen = (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg
A.nitrogen = (A.nitrogen - nit_avg) * (1-ratio) + nit_avg
A.carbon_dioxide = (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
A.toxins = (A.toxins - plasma_avg) * (1-ratio) + plasma_avg
A.temperature = (A.temperature - temp_avg) * (1-ratio) + temp_avg
B.oxygen = (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg
B.nitrogen = (B.nitrogen - nit_avg) * (1-ratio) + nit_avg
B.carbon_dioxide = (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
B.toxins = (B.toxins - plasma_avg) * (1-ratio) + plasma_avg
B.temperature = (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
A.update_values()
B.update_values()
if(A.compare(B)) return 1
else return 0
proc/ShareSpace(datum/gas_mixture/A, ratio)
//A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room.
var
size = max(1,A.group_multiplier)
share_size = max(1,A.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
space_heat_capacity = MINIMUM_HEAT_CAPACITY * share_size
oxy_avg = (full_oxy) / (size + share_size)
nit_avg = (full_nitro) / (size + share_size)
co2_avg = (full_co2) / (size + share_size)
plasma_avg = (full_plasma) / (size + share_size)
temp_avg = (A.temperature * full_heat_capacity + TCMB * space_heat_capacity) / (full_heat_capacity + space_heat_capacity)
A.oxygen = (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg
A.nitrogen = (A.nitrogen - nit_avg) * (1-ratio) + nit_avg
A.carbon_dioxide = (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg
A.toxins = (A.toxins - plasma_avg) * (1-ratio) + plasma_avg
A.temperature = (A.temperature - temp_avg) * (1-ratio) + temp_avg
//833 * 0.9 + 833 =
//(5000/3) = 1666
//(5000/6) = 833
for(var/datum/gas/G in A.trace_gases)
var/G_avg = (G.moles*size + 0) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
A.update_values()
return 1
zone/proc/connected_zones()
//A legacy proc for getting connected zones.
. = list()
for(var/connection/C in connections)
var/zone/Z
if(C.A.zone == src)
Z = C.B.zone
else
Z = C.A.zone
if(Z in .)
.[Z]++
else
. += Z
.[Z] = 1
zone/proc/Rebuild()
//Choose a random turf and regenerate the zone from it.
var
turf/simulated/sample = pick(contents)
list/new_contents
problem = 0
contents.Remove(null) //I can't believe this is needed.
if(!contents.len)
del src
var/list/turfs_to_consider = contents.Copy()
do
if(sample)
turfs_to_consider.Remove(sample)
if(!turfs_to_consider.len)
break
sample = pick(turfs_to_consider) //Nor this.
while(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1))
if(!istype(sample) || !sample.CanPass(null, sample, 1.5, 1)) //Not a single valid turf.
for(var/turf/simulated/T in contents)
air_master.tiles_to_update |= T
del src
new_contents = FloodFill(sample)
for(var/turf/space/S in new_contents)
if(!space_tiles)
space_tiles = list()
space_tiles |= S
if(contents.len != new_contents.len)
problem = 1
//If something isn't carried over, there was a complication.
for(var/turf/T in contents)
if(!(T in new_contents))
T.zone = null
problem = 1
if(problem)
//Build some new zones for stuff that wasn't included.
var/list/turf/simulated/rebuild_turfs = contents - new_contents
var/list/turf/simulated/reconsider_turfs = list()
contents = new_contents
for(var/turf/T in rebuild_turfs)
if(istype(T,/turf/space))
air_master.tiles_to_update |= T
else if(!T.zone && T.CanPass(null, T, 1.5, 1))
var/zone/Z = new /zone(T)
Z.air.copy_from(air)
else
reconsider_turfs |= T
for(var/turf/T in reconsider_turfs)
if(!T.zone)
var/zone/Z = new /zone(T)
Z.air.copy_from(air)
for(var/turf/T in contents)
if(T.zone && T.zone != src)
T.zone.RemoveTurf(T)
T.zone = src
else if(!T.zone)
T.zone = src
air.group_multiplier = contents.len
if(space_tiles)
var/list/new_space_tiles = space_tiles.Copy()
space_tiles = null
for(var/turf/space/S in new_space_tiles)
for(var/direction in cardinal)
var/turf/simulated/T = get_step(S,direction)
if(istype(T) && T.zone)
T.zone.AddSpace(S)