diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm index cea0efc3ab7..3eccad7e913 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/FEA_gas_mixture.dm @@ -965,6 +965,7 @@ What are the archived variables for? //Outputs: 1 if can rebuild, 0 if not. if(!sample) return 0 + if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \ ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen))) return 0 @@ -972,52 +973,61 @@ What are the archived variables for? ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen))) return 0 if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ - ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) + ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (carbon_dioxide > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) return 0 if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \ ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins))) return 0 + if(total_moles() > MINIMUM_AIR_TO_SUSPEND) if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) //world << "temp fail [temperature] & [sample.temperature]" return 0 - + var/check_moles if(sample.trace_gases.len) for(var/datum/gas/trace_gas in sample.trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(corresponding) - if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ - ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles))) - return 0 - else - return 0 + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + check_moles = corresponding.moles + else + check_moles = 0 + + if((abs(trace_gas.moles - check_moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((check_moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (check_moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles))) + return 0 if(trace_gases.len) for(var/datum/gas/trace_gas in trace_gases) - if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) - var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases - if(corresponding) - if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ - ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles))) - return 0 - else - return 0 + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + check_moles = corresponding.moles + else + check_moles = 0 + + if((abs(trace_gas.moles - check_moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*check_moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*check_moles))) + return 0 + return 1 -/datum/gas_mixture/proc/compare_unsim(turf/list/samples) - //Purpose: Compares a list of unsimulated tiles to self to see if within acceptable ranges that group processing may be enabled - //Called by: ZAS sleeping detection. - //Inputs: List of unsimulated turfs to compare to - //Outputs: 1 if within an acceptable range to sleep, 0 otherwise. - var/datum/gas_mixture/after_share = new - after_share.copy_from(src) +/datum/gas_mixture/proc/add(datum/gas_mixture/right_side) + oxygen += right_side.oxygen + carbon_dioxide += right_side.carbon_dioxide + nitrogen += right_side.nitrogen + toxins += right_side.toxins - ShareSpace(after_share, samples) + if(trace_gases.len || right_side.trace_gases.len) + for(var/datum/gas/trace_gas in right_side.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + trace_gases += corresponding + corresponding.moles += trace_gas.moles - return src.compare(after_share) + update_values() + return 1 /datum/gas_mixture/proc/subtract(datum/gas_mixture/right_side) //Purpose: Subtracts right_side from air_mixture. Used to help turfs mingle @@ -1025,18 +1035,42 @@ What are the archived variables for? //Inputs: Gas mix to remove //Outputs: 1 - oxygen -= right_side.oxygen - carbon_dioxide -= right_side.carbon_dioxide - nitrogen -= right_side.nitrogen - toxins -= right_side.toxins + oxygen = max(oxygen - right_side.oxygen) + carbon_dioxide = max(carbon_dioxide - right_side.carbon_dioxide) + nitrogen = max(nitrogen - right_side.nitrogen) + toxins = max(toxins - right_side.toxins) - if((trace_gases.len > 0)||(right_side.trace_gases.len > 0)) + if(trace_gases.len || right_side.trace_gases.len) for(var/datum/gas/trace_gas in right_side.trace_gases) var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - trace_gases += corresponding + if(corresponding) + corresponding.moles = max(0, corresponding.moles - trace_gas.moles) - corresponding.moles -= trace_gas.moles update_values() - return 1 \ No newline at end of file + return 1 + +/datum/gas_mixture/proc/multiply(factor) + oxygen *= factor + carbon_dioxide *= factor + nitrogen *= factor + toxins *= factor + + if(trace_gases && trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + trace_gas.moles *= factor + + update_values() + return 1 + +/datum/gas_mixture/proc/divide(factor) + oxygen /= factor + carbon_dioxide /= factor + nitrogen /= factor + toxins /= factor + + if(trace_gases && trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + trace_gas.moles /= factor + + update_values() + return 1 diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index b58cdd1903a..2a5c5818a49 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -10,6 +10,9 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs 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. @@ -126,6 +129,8 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs unsimulated_tiles += T contents -= T + unsim_air_needs_update = 1 + /zone/proc/RemoveTurf(turf/T) //Same, but in reverse. if(istype(T, /turf/simulated)) @@ -146,6 +151,45 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs if(!unsimulated_tiles.len) unsimulated_tiles = null + unsim_air_needs_update = 1 + +//Updates the air_unsim var +/zone/proc/UpdateUnsimAvg() + if(!unsim_air_needs_update) + 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// ////////////// @@ -180,20 +224,23 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs 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/old_pressure = air.return_pressure() - var/moved_air = ShareSpace(air,unsimulated_tiles) + var/moved_air = ShareSpace(air, air_unsim) + + if(!air.compare(air_unsim)) + interactions_with_unsim++ if(moved_air > vsc.airflow_lightest_pressure) AirflowSpace(src) - - if(old_pressure && (moved_air / old_pressure) > MINIMUM_AIR_RATIO_TO_SUSPEND) //Check if we've moved enough air to be considered awake. - interactions_with_unsim++ else unsimulated_tiles = null @@ -310,11 +357,11 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs Z.interactions_with_neighbors++ interactions_with_neighbors++ - if(!interactions_with_neighbors && !interactions_with_unsim) - SetStatus(ZONE_SLEEPING) + if(!interactions_with_neighbors && !interactions_with_unsim) + SetStatus(ZONE_SLEEPING) - interactions_with_neighbors = 0 - interactions_with_unsim = 0 + interactions_with_neighbors = 0 + interactions_with_unsim = 0 progress = "all components completed successfully, the problem is not here" @@ -327,6 +374,11 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs 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) @@ -342,12 +394,13 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs var/difference = 0 if(unsimulated_tiles && unsimulated_tiles.len) - if(air.compare_unsim(unsimulated_tiles)) + 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)) + if(!air.compare(Z.air)) difference = 1 break @@ -362,11 +415,20 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs 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 @@ -443,6 +505,7 @@ proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) 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 @@ -451,6 +514,15 @@ proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) 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() @@ -459,7 +531,7 @@ proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) 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 || !unsimulated_tiles.len) + if(!unsimulated_tiles) return 0 var @@ -472,6 +544,22 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) 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 @@ -479,20 +567,25 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) // 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) - correction_ratio = share_size / 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 + 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 - //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 unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_plasma) var @@ -517,8 +610,8 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) 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 >= unsimulated_tiles.len) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[unsimulated_tiles.len] + 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 )