mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 10:12:45 +00:00
880 lines
26 KiB
Plaintext
880 lines
26 KiB
Plaintext
var/list/DoorDirections = list(NORTH,WEST) //Which directions doors turfs can connect to zones
|
|
var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs can connect to zones
|
|
|
|
/zone
|
|
var/dbg_output = 0 //Enables debug output.
|
|
|
|
var/datum/gas_mixture/air //The air contents of the zone.
|
|
var/datum/gas_mixture/archived_air
|
|
|
|
var/list/contents //All the tiles that are contained in this zone.
|
|
var/list/unsimulated_tiles // Any space tiles in this list will cause air to flow out.
|
|
|
|
var/datum/gas_mixture/air_unsim //Overall average of the air in connected unsimualted tiles.
|
|
var/unsim_air_needs_update = 0 //Set to 1 on geometry changes, marks air_unsim as needing update.
|
|
|
|
var/list/connections //connection objects which refer to connections with other zones, e.g. through a door.
|
|
var/list/direct_connections //connections which directly connect two zones.
|
|
|
|
var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number
|
|
//of points they're connected at.
|
|
var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed.
|
|
|
|
var/last_update = 0
|
|
var/last_rebuilt = 0
|
|
var/status = ZONE_ACTIVE
|
|
var/interactions_with_neighbors = 0
|
|
var/interactions_with_unsim = 0
|
|
var/progress = "nothing"
|
|
|
|
|
|
/datum/gas_mixture/zone
|
|
Del()
|
|
CRASH("Something tried to delete a zone's air!")
|
|
. = ..()
|
|
|
|
//CREATION AND DELETION
|
|
/zone/New(turf/start)
|
|
. = ..()
|
|
//Get the turfs that are part of the zone using a floodfill method
|
|
if(istype(start,/list))
|
|
contents = start
|
|
else
|
|
contents = FloodFill(start)
|
|
|
|
//Change all the zone vars of the turfs, check for space to be added to unsimulated_tiles.
|
|
for(var/turf/T in contents)
|
|
if(T.zone && T.zone != src)
|
|
T.zone.RemoveTurf(T)
|
|
T.zone = src
|
|
if(!istype(T,/turf/simulated))
|
|
AddTurf(T)
|
|
|
|
//Generate the gas_mixture for use in txhis zone by using the average of the gases
|
|
//defined at startup.
|
|
//Changed to try and find the source of the error.
|
|
air = new /datum/gas_mixture/zone()
|
|
air.group_multiplier = contents.len
|
|
for(var/turf/simulated/T in contents)
|
|
if(!T.air)
|
|
continue
|
|
air.oxygen += T.air.oxygen / air.group_multiplier
|
|
air.nitrogen += T.air.nitrogen / air.group_multiplier
|
|
air.carbon_dioxide += T.air.carbon_dioxide / air.group_multiplier
|
|
air.toxins += T.air.toxins / air.group_multiplier
|
|
air.temperature += T.air.temperature / air.group_multiplier
|
|
for(var/datum/gas/trace in T.air.trace_gases)
|
|
var/datum/gas/corresponding_gas = locate(trace.type) in air.trace_gases
|
|
if(!corresponding_gas)
|
|
corresponding_gas = new trace.type()
|
|
air.trace_gases.Add(corresponding_gas)
|
|
corresponding_gas.moles += trace.moles
|
|
air.update_values()
|
|
|
|
//Add this zone to the global list.
|
|
if(air_master)
|
|
air_master.zones.Add(src)
|
|
air_master.active_zones.Add(src)
|
|
|
|
|
|
//DO NOT USE. Use the SoftDelete proc.
|
|
/zone/Del()
|
|
//Ensuring the zone list doesn't get clogged with null values.
|
|
for(var/turf/simulated/T in contents)
|
|
RemoveTurf(T)
|
|
air_master.ReconsiderTileZone(T)
|
|
|
|
if(air_master)
|
|
air_master.AddConnectionToCheck(connections)
|
|
|
|
air = null
|
|
|
|
. = ..()
|
|
|
|
|
|
//Handles deletion via garbage collection.
|
|
/zone/proc/SoftDelete()
|
|
air = null
|
|
|
|
if(air_master)
|
|
air_master.zones.Remove(src)
|
|
air_master.active_zones.Remove(src)
|
|
air_master.zones_needing_rebuilt.Remove(src)
|
|
air_master.AddConnectionToCheck(connections)
|
|
|
|
connections = null
|
|
for(var/connection/C in direct_connections)
|
|
if(C.A.zone == src)
|
|
C.A.zone = null
|
|
if(C.B.zone == src)
|
|
C.B.zone = null
|
|
if(C.zone_A == src)
|
|
C.zone_A = null
|
|
if(C.zone_B == src)
|
|
C.zone_B = null
|
|
direct_connections = null
|
|
|
|
//Ensuring the zone list doesn't get clogged with null values.
|
|
for(var/turf/simulated/T in contents)
|
|
RemoveTurf(T)
|
|
air_master.ReconsiderTileZone(T)
|
|
|
|
contents.Cut()
|
|
|
|
//Removing zone connections and scheduling connection cleanup
|
|
for(var/zone/Z in connected_zones)
|
|
Z.connected_zones.Remove(src)
|
|
if(!Z.connected_zones.len)
|
|
Z.connected_zones = null
|
|
|
|
if(Z.closed_connection_zones)
|
|
Z.closed_connection_zones.Remove(src)
|
|
if(!Z.closed_connection_zones.len)
|
|
Z.closed_connection_zones = null
|
|
|
|
connected_zones = null
|
|
closed_connection_zones = null
|
|
|
|
return 1
|
|
|
|
|
|
//ZONE MANAGEMENT FUNCTIONS
|
|
/zone/proc/AddTurf(turf/T)
|
|
//Adds the turf to contents, increases the size of the zone, and sets the zone var.
|
|
if(istype(T, /turf/simulated))
|
|
if(T in contents)
|
|
return
|
|
if(T.zone)
|
|
T.zone.RemoveTurf(T)
|
|
contents += T
|
|
if(air)
|
|
air.group_multiplier++
|
|
|
|
T.zone = src
|
|
|
|
else
|
|
if(!unsimulated_tiles)
|
|
unsimulated_tiles = list()
|
|
else if(T in unsimulated_tiles)
|
|
return
|
|
unsimulated_tiles += T
|
|
contents -= T
|
|
|
|
unsim_air_needs_update = 1
|
|
|
|
/zone/proc/RemoveTurf(turf/T)
|
|
//Same, but in reverse.
|
|
if(istype(T, /turf/simulated))
|
|
if(!(T in contents))
|
|
return
|
|
contents -= T
|
|
if(air)
|
|
air.group_multiplier--
|
|
|
|
if(T.zone == src)
|
|
T.zone = null
|
|
|
|
if(!contents.len)
|
|
SoftDelete()
|
|
|
|
else if(unsimulated_tiles)
|
|
unsimulated_tiles -= T
|
|
if(!unsimulated_tiles.len)
|
|
unsimulated_tiles = null
|
|
|
|
unsim_air_needs_update = 1
|
|
|
|
//Updates the air_unsim var
|
|
/zone/proc/UpdateUnsimAvg()
|
|
if(!unsimulated_tiles || !unsimulated_tiles.len) //if we don't have any unsimulated tiles, we can't do much.
|
|
return
|
|
|
|
if(!unsim_air_needs_update && air_unsim) //if air_unsim doesn't exist, we need to create it even if we don't need an update.
|
|
return
|
|
|
|
//Tempfix.
|
|
if(!air)
|
|
return
|
|
|
|
unsim_air_needs_update = 0
|
|
|
|
if(!air_unsim)
|
|
air_unsim = new /datum/gas_mixture
|
|
|
|
air_unsim.oxygen = 0
|
|
air_unsim.nitrogen = 0
|
|
air_unsim.carbon_dioxide = 0
|
|
air_unsim.toxins = 0
|
|
air_unsim.temperature = 0
|
|
|
|
var/correction_ratio = max(1, max(max(1, air.group_multiplier) + 3, 1) + unsimulated_tiles.len) / unsimulated_tiles.len
|
|
|
|
for(var/turf/T in unsimulated_tiles)
|
|
if(!istype(T, /turf/simulated))
|
|
air_unsim.oxygen += T.oxygen
|
|
air_unsim.carbon_dioxide += T.carbon_dioxide
|
|
air_unsim.nitrogen += T.nitrogen
|
|
air_unsim.toxins += T.toxins
|
|
air_unsim.temperature += T.temperature/unsimulated_tiles.len
|
|
|
|
//These values require adjustment in order to properly represent a room of the specified size.
|
|
air_unsim.oxygen *= correction_ratio
|
|
air_unsim.carbon_dioxide *= correction_ratio
|
|
air_unsim.nitrogen *= correction_ratio
|
|
air_unsim.toxins *= correction_ratio
|
|
|
|
air_unsim.group_multiplier = unsimulated_tiles.len
|
|
|
|
air_unsim.update_values()
|
|
return
|
|
|
|
//////////////
|
|
//PROCESSING//
|
|
//////////////
|
|
|
|
#define QUANTIZE(variable) (round(variable,0.0001))
|
|
|
|
/zone/proc/process()
|
|
. = 1
|
|
|
|
progress = "problem with: SoftDelete()"
|
|
|
|
//Deletes zone if empty.
|
|
if(!contents.len)
|
|
return SoftDelete()
|
|
|
|
progress = "problem with: Rebuild()"
|
|
|
|
if(!contents.len) //If we got soft deleted.
|
|
return
|
|
|
|
progress = "problem with: air regeneration"
|
|
|
|
//Sometimes explosions will cause the air to be deleted for some reason.
|
|
if(!air)
|
|
air = new()
|
|
air.oxygen = MOLES_O2STANDARD
|
|
air.nitrogen = MOLES_N2STANDARD
|
|
air.temperature = T0C
|
|
air.total_moles()
|
|
world.log << "Air object lost in zone. Regenerating."
|
|
|
|
|
|
progress = "problem with: ShareSpace()"
|
|
|
|
if(unsim_air_needs_update)
|
|
unsim_air_needs_update = 0
|
|
UpdateUnsimAvg()
|
|
|
|
if(unsimulated_tiles)
|
|
if(locate(/turf/simulated) in unsimulated_tiles)
|
|
for(var/turf/simulated/T in unsimulated_tiles)
|
|
unsimulated_tiles -= T
|
|
|
|
if(unsimulated_tiles.len)
|
|
var/moved_air = ShareSpace(air, air_unsim)
|
|
|
|
if(!air.compare(air_unsim))
|
|
interactions_with_unsim++
|
|
|
|
if(moved_air > vsc.airflow_lightest_pressure)
|
|
AirflowSpace(src)
|
|
else
|
|
unsimulated_tiles = null
|
|
|
|
//Check the graphic.
|
|
progress = "problem with: modifying turf graphics"
|
|
|
|
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
|
|
|
|
progress = "problem with an inbuilt byond function: some conditional checks"
|
|
|
|
//Only run through the individual turfs if there's reason to.
|
|
if(air.graphic != air.graphic_archived || air.temperature > PLASMA_FLASHPOINT)
|
|
|
|
progress = "problem with: turf/simulated/update_visuals()"
|
|
|
|
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)
|
|
|
|
progress = "problem with: item or turf temperature_expose()"
|
|
|
|
//Expose stuff to extreme heat.
|
|
if(air.temperature > PLASMA_FLASHPOINT)
|
|
for(var/atom/movable/item in S)
|
|
item.temperature_expose(air, air.temperature, CELL_VOLUME)
|
|
S.hotspot_expose(air.temperature, CELL_VOLUME)
|
|
|
|
progress = "problem with: calculating air graphic"
|
|
|
|
//Archive graphic so we can know if it's different.
|
|
air.graphic_archived = air.graphic
|
|
|
|
progress = "problem with: calculating air temp"
|
|
|
|
//Ensure temperature does not reach absolute zero.
|
|
air.temperature = max(TCMB,air.temperature)
|
|
|
|
progress = "problem with an inbuilt byond function: length(connections)"
|
|
|
|
//Handle connections to other zones.
|
|
if(length(connections))
|
|
|
|
progress = "problem with: ZMerge(), a couple of misc procs"
|
|
|
|
if(length(direct_connections))
|
|
for(var/connection/C in direct_connections)
|
|
|
|
//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.A.zone && C.B.zone)
|
|
if(C.A.zone.air.compare(C.B.zone.air) || unsimulated_tiles)
|
|
ZMerge(C.A.zone,C.B.zone)
|
|
|
|
progress = "problem with: ShareRatio(), Airflow(), a couple of misc procs"
|
|
|
|
//Share some
|
|
for(var/zone/Z in connected_zones)
|
|
//If that zone has already processed, skip it.
|
|
if(Z.last_update > last_update)
|
|
continue
|
|
|
|
//Handle adjacent zones that are sleeping
|
|
if(Z.status == ZONE_SLEEPING)
|
|
if(air.compare(Z.air))
|
|
continue
|
|
|
|
else
|
|
Z.SetStatus(ZONE_ACTIVE)
|
|
|
|
if(air && Z.air)
|
|
//Ensure we're not doing pointless calculations on equilibrium zones.
|
|
if(!air.compare(Z.air))
|
|
if(abs(Z.air.return_pressure() - air.return_pressure()) > vsc.airflow_lightest_pressure)
|
|
Airflow(src,Z)
|
|
var/unsimulated_boost = 0
|
|
if(unsimulated_tiles)
|
|
unsimulated_boost += unsimulated_tiles.len
|
|
if(Z.unsimulated_tiles)
|
|
unsimulated_boost += Z.unsimulated_tiles.len
|
|
unsimulated_boost = max(0, min(3, unsimulated_boost))
|
|
ShareRatio( air , Z.air , connected_zones[Z] + unsimulated_boost)
|
|
|
|
Z.interactions_with_neighbors++
|
|
interactions_with_neighbors++
|
|
|
|
if(!vsc.connection_insulation)
|
|
for(var/zone/Z in closed_connection_zones)
|
|
//If that zone has already processed, skip it.
|
|
if(Z.last_update > last_update || !Z.air)
|
|
continue
|
|
|
|
var/handle_temperature = abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta
|
|
|
|
if(Z.status == ZONE_SLEEPING)
|
|
if (handle_temperature)
|
|
Z.SetStatus(ZONE_ACTIVE)
|
|
else
|
|
continue
|
|
|
|
if(air && Z.air)
|
|
if( handle_temperature )
|
|
ShareHeat(air, Z.air, closed_connection_zones[Z])
|
|
|
|
Z.interactions_with_neighbors++
|
|
interactions_with_neighbors++
|
|
|
|
if(!interactions_with_neighbors && !interactions_with_unsim)
|
|
SetStatus(ZONE_SLEEPING)
|
|
|
|
interactions_with_neighbors = 0
|
|
interactions_with_unsim = 0
|
|
|
|
progress = "all components completed successfully, the problem is not here"
|
|
|
|
|
|
/zone/proc/SetStatus(var/new_status)
|
|
if(status == ZONE_SLEEPING && new_status == ZONE_ACTIVE)
|
|
air_master.active_zones.Add(src)
|
|
status = ZONE_ACTIVE
|
|
|
|
else if(status == ZONE_ACTIVE && new_status == ZONE_SLEEPING)
|
|
air_master.active_zones.Remove(src)
|
|
status = ZONE_SLEEPING
|
|
|
|
if(unsimulated_tiles && unsimulated_tiles.len)
|
|
UpdateUnsimAvg()
|
|
air.copy_from(air_unsim)
|
|
|
|
if(!archived_air)
|
|
archived_air = new
|
|
archived_air.copy_from(air)
|
|
|
|
|
|
/zone/proc/CheckStatus()
|
|
return status
|
|
|
|
|
|
/zone/proc/ActivateIfNeeded()
|
|
if(status == ZONE_ACTIVE) return
|
|
|
|
var/difference = 0
|
|
|
|
if(unsimulated_tiles && unsimulated_tiles.len)
|
|
UpdateUnsimAvg()
|
|
if(!air.compare(air_unsim))
|
|
difference = 1
|
|
|
|
if(!difference)
|
|
for(var/zone/Z in connected_zones) //Check adjacent zones for air difference.
|
|
if(!air.compare(Z.air))
|
|
difference = 1
|
|
break
|
|
|
|
if(difference) //We have a difference, activate the zone.
|
|
SetStatus(ZONE_ACTIVE)
|
|
|
|
return
|
|
|
|
|
|
/zone/proc/assume_air(var/datum/gas_mixture/giver)
|
|
if(status == ZONE_ACTIVE)
|
|
return air.merge(giver)
|
|
|
|
else
|
|
if(unsimulated_tiles && unsimulated_tiles.len)
|
|
UpdateUnsimAvg()
|
|
var/datum/gas_mixture/compare_air = new
|
|
compare_air.copy_from(giver)
|
|
compare_air.add(air_unsim)
|
|
compare_air.divide(air.group_multiplier)
|
|
|
|
if(air_unsim.compare(compare_air))
|
|
return 0
|
|
|
|
var/result = air.merge(giver)
|
|
|
|
if(!archived_air.compare(air))
|
|
SetStatus(ZONE_ACTIVE)
|
|
return result
|
|
|
|
|
|
/zone/proc/remove_air(var/amount)
|
|
if(status == ZONE_ACTIVE)
|
|
return air.remove(amount)
|
|
|
|
else
|
|
var/result = air.remove(amount)
|
|
|
|
if(!archived_air.compare(air))
|
|
SetStatus(ZONE_ACTIVE)
|
|
|
|
return result
|
|
|
|
////////////////
|
|
//Air Movement//
|
|
////////////////
|
|
|
|
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(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
|
|
|
|
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) / (size + share_size)
|
|
nit_avg = (full_nitro + unsim_nitrogen) / (size + share_size)
|
|
co2_avg = (full_co2 + unsim_co2) / (size + share_size)
|
|
plasma_avg = (full_plasma + unsim_plasma) / (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]
|
|
|
|
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()
|
|
|
|
return abs(old_pressure - A.return_pressure())
|
|
|
|
|
|
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))
|
|
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)
|
|
|
|
/* This was bad an I feel bad.
|
|
//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
|
|
|
|
full_heat_capacity = A.heat_capacity()
|
|
|
|
s_full_heat_capacity = B.heat_capacity()
|
|
|
|
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(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
|
|
|
|
//We need to adjust it to account for the insulation settings.
|
|
ratio *= 1 - vsc.connection_insulation
|
|
|
|
A.temperature = max(0, (A.temperature - temp_avg) * (1- (ratio / max(1,A.group_multiplier)) ) + temp_avg )
|
|
B.temperature = max(0, (B.temperature - temp_avg) * (1- (ratio / max(1,B.group_multiplier)) ) + temp_avg )
|
|
*/
|
|
|
|
///////////////////
|
|
//Zone Rebuilding//
|
|
///////////////////
|
|
//Used for updating zone geometry when a zone is cut into two parts.
|
|
|
|
zone/proc/Rebuild()
|
|
if(last_rebuilt == air_master.current_cycle)
|
|
return
|
|
|
|
last_rebuilt = air_master.current_cycle
|
|
|
|
var/list/new_zone_contents = IsolateContents()
|
|
if(new_zone_contents.len == 1)
|
|
return
|
|
|
|
var/list/current_contents
|
|
var/list/new_zones = list()
|
|
|
|
contents = new_zone_contents[1]
|
|
air.group_multiplier = contents.len
|
|
|
|
for(var/identifier in 2 to new_zone_contents.len)
|
|
current_contents = new_zone_contents[identifier]
|
|
var/zone/new_zone = new (current_contents)
|
|
new_zone.air.copy_from(air)
|
|
new_zones += new_zone
|
|
|
|
for(var/connection/connection in connections)
|
|
connection.Cleanup()
|
|
|
|
var/turf/simulated/adjacent
|
|
|
|
for(var/turf/unsimulated in unsimulated_tiles)
|
|
for(var/direction in cardinal)
|
|
adjacent = get_step(unsimulated, direction)
|
|
|
|
if(istype(adjacent) && adjacent.CanPass(null, unsimulated, 0, 0))
|
|
for(var/zone/zone in new_zones)
|
|
if(adjacent in zone)
|
|
zone.AddTurf(unsimulated)
|
|
|
|
|
|
//Implements a two-pass connected component labeling algorithm to determine if the zone is, in fact, split.
|
|
|
|
/zone/proc/IsolateContents()
|
|
var/list/current_adjacents = list()
|
|
var/adjacent_id
|
|
var/lowest_id
|
|
|
|
var/list/identical_ids = list()
|
|
var/list/turfs = contents.Copy()
|
|
var/current_identifier = 1
|
|
|
|
for(var/turf/simulated/current in turfs)
|
|
lowest_id = null
|
|
current_adjacents = list()
|
|
|
|
for(var/direction in cardinal)
|
|
var/turf/simulated/adjacent = get_step(current, direction)
|
|
if(!current.ZCanPass(adjacent))
|
|
continue
|
|
if(adjacent in turfs)
|
|
current_adjacents += adjacent
|
|
adjacent_id = turfs[adjacent]
|
|
|
|
if(adjacent_id && (!lowest_id || adjacent_id < lowest_id))
|
|
lowest_id = adjacent_id
|
|
|
|
if(!lowest_id)
|
|
lowest_id = current_identifier++
|
|
identical_ids += lowest_id
|
|
|
|
for(var/turf/simulated/adjacent in current_adjacents)
|
|
adjacent_id = turfs[adjacent]
|
|
if(adjacent_id != lowest_id)
|
|
if(adjacent_id)
|
|
identical_ids[adjacent_id] = lowest_id
|
|
turfs[adjacent] = lowest_id
|
|
turfs[current] = lowest_id
|
|
|
|
var/list/final_arrangement = list()
|
|
|
|
for(var/turf/simulated/current in turfs)
|
|
current_identifier = identical_ids[turfs[current]]
|
|
|
|
if( current_identifier > final_arrangement.len )
|
|
final_arrangement.len = current_identifier
|
|
final_arrangement[current_identifier] = list(current)
|
|
|
|
else
|
|
//Sanity check.
|
|
if(!islist(final_arrangement[current_identifier]))
|
|
final_arrangement[current_identifier] = list()
|
|
final_arrangement[current_identifier] += current
|
|
|
|
//lazy but fast
|
|
final_arrangement.Remove(null)
|
|
|
|
return final_arrangement
|
|
|
|
|
|
/*
|
|
if(!RequiresRebuild())
|
|
return
|
|
|
|
//Choose a random turf and regenerate the zone from it.
|
|
var/list/new_contents
|
|
var/list/new_unsimulated
|
|
|
|
var/list/turfs_needing_zones = list()
|
|
|
|
var/list/zones_to_check_connections = list(src)
|
|
|
|
if(!locate(/turf/simulated/floor) in contents)
|
|
for(var/turf/simulated/turf in contents)
|
|
air_master.ReconsiderTileZone(turf)
|
|
return SoftDelete()
|
|
|
|
var/turfs_to_ignore = list()
|
|
if(direct_connections)
|
|
for(var/connection/connection in direct_connections)
|
|
if(connection.A.zone != src)
|
|
turfs_to_ignore += A
|
|
else if(connection.B.zone != src)
|
|
turfs_to_ignore += B
|
|
|
|
new_unsimulated = ( unsimulated_tiles ? unsimulated_tiles : list() )
|
|
|
|
//Now, we have allocated the new turfs into proper lists, and we can start actually rebuilding.
|
|
|
|
//If something isn't carried over, it will need a new zone.
|
|
for(var/turf/T in contents)
|
|
if(!(T in new_contents))
|
|
RemoveTurf(T)
|
|
turfs_needing_zones += T
|
|
|
|
//Handle addition of new turfs
|
|
for(var/turf/S in new_contents)
|
|
if(!istype(S, /turf/simulated))
|
|
new_unsimulated |= S
|
|
new_contents.Remove(S)
|
|
|
|
//If something new is added, we need to deal with it seperately.
|
|
else if(!(S in contents) && istype(S, /turf/simulated))
|
|
if(!(S.zone in zones_to_check_connections))
|
|
zones_to_check_connections += S.zone
|
|
|
|
S.zone.RemoveTurf(S)
|
|
AddTurf(S)
|
|
|
|
//Handle the addition of new unsimulated tiles.
|
|
unsimulated_tiles = null
|
|
|
|
if(new_unsimulated.len)
|
|
for(var/turf/S in new_unsimulated)
|
|
if(istype(S, /turf/simulated))
|
|
continue
|
|
for(var/direction in cardinal)
|
|
var/turf/simulated/T = get_step(S,direction)
|
|
if(istype(T) && T.zone && S.CanPass(null, T, 0, 0))
|
|
T.zone.AddTurf(S)
|
|
|
|
//Finally, handle the orphaned turfs
|
|
|
|
for(var/turf/simulated/T in turfs_needing_zones)
|
|
if(!T.zone)
|
|
zones_to_check_connections += new /zone(T)
|
|
|
|
for(var/zone/zone in zones_to_check_connections)
|
|
for(var/connection/C in zone.connections)
|
|
C.Cleanup()*/
|
|
|