diff --git a/code/ATMOSPHERICS/atmospherics_helpers.dm b/code/ATMOSPHERICS/atmospherics_helpers.dm index e59fcc52b2..ee599585c9 100644 --- a/code/ATMOSPHERICS/atmospherics_helpers.dm +++ b/code/ATMOSPHERICS/atmospherics_helpers.dm @@ -2,22 +2,26 @@ Atmos processes These procs generalize various processes used by atmos machinery, such as pumping, filtering, or scrubbing gas, allowing them to be reused elsewhere. + If no gas was moved/pumped/filtered/whatever, they return a negative number. + Otherwise they return the amount of energy needed to do whatever it is they do (equivalently power if done over 1 second). + In the case of free-flowing gas you can do things with gas and still use 0 power, hence the distinction between negative and non-negative return values. */ +/obj/machinery/atmospherics/var/last_flow_rate = 0 //Can't return multiple values, unfortunately + //Generalized gas pumping proc. //Moves gas from one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was pumped. //transfer_moles - Limits the amount of moles to transfer. The actual amount of gas moved may also be limited by available_power, if given. //available_power - the maximum amount of power that may be used when moving gas. If null then the transfer is not limited by power. - -/obj/machinery/atmospherics/var/last_flow_rate = 0 //Can't return multiple values, unfortunately... - /obj/machinery/atmospherics/proc/pump_gas(var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null, var/available_power = null) - if (source.total_moles < MINUMUM_MOLES_TO_PUMP) + if (source.total_moles < MINUMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing return -1 if (!transfer_moles) transfer_moles = source.total_moles + else + transfer_moles = min(source.total_moles, transfer_moles) //Calculate the amount of energy required and limit transfer_moles based on available power var/specific_power = calculate_specific_power(source, sink)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures @@ -30,7 +34,7 @@ last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here var/datum/gas_mixture/removed = source.remove(transfer_moles) - if (isnull(removed)) //not sure why this would happen, but it does at the very beginning of the game + if (!removed) //Just in case return -1 var/power_draw = specific_power*transfer_moles @@ -47,7 +51,7 @@ //total_transfer_moles - Limits the amount of moles to scrub. The actual amount of gas scrubbed may also be limited by available_power, if given. //available_power - the maximum amount of power that may be used when scrubbing gas. If null then the scrubbing is not limited by power. /obj/machinery/atmospherics/proc/scrub_gas(var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null) - if (source.total_moles < MINUMUM_MOLES_TO_FILTER) + if (source.total_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 filtering &= source.gas //only filter gasses that are actually there. @@ -63,12 +67,12 @@ specific_power_gas[g] = specific_power total_filterable_moles += source.gas[g] - if (total_filterable_moles < MINUMUM_MOLES_TO_FILTER) + if (total_filterable_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 var/total_specific_power = 0 //the power required to remove one mole of filterable gas for (var/g in filtering) - var/ratio = source.gas[g]/total_filterable_moles //converts the specific power per mole of pure gas to specific power per mole of filterable gas mix + var/ratio = source.gas[g]/total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of filterable gas mix total_specific_power = specific_power_gas[g]*ratio //Figure out how much of each gas to filter @@ -81,7 +85,7 @@ if (available_power && total_specific_power > 0) total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) - if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //we check this repeatedly so that we do as little processing as possible + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 var/power_draw = 0 @@ -91,19 +95,101 @@ //filter gas in proportion to the mole ratio transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles)) - source.gas[g] -= transfer_moles - sink.gas[g] += transfer_moles //do we need to check if g is in sink.gas first? + //use update=0. All the filtered gasses get added simultaneously, so we update after the for loop. + source.adjust_gas(g, -transfer_moles, update=0) + sink.adjust_gas_temp(g, transfer_moles, source.temperature, update=0) + power_draw += specific_power_gas[g]*transfer_moles - if (power_draw > 0) - sink.add_thermal_energy(power_draw) //gotta conserve that energy - //Remix the resulting gases sink.update_values() source.update_values() + if (power_draw > 0) + sink.add_thermal_energy(power_draw) //gotta conserve that energy + return power_draw +//Generalized gas filtering proc. +//Filtering is a bit different from scrubbing. Instead of selectively moving the targeted gas types from one gas mix to another, filtering splits +//the input gas into two outputs: one that contains /only/ the targeted gas types, and another that completely clean of the targeted gas types. +//filtering - A list of gasids to be filtered. These gasses get moved to sink_filtered, while the other gasses get moved to sink_clean. +//total_transfer_moles - Limits the amount of moles to input. The actual amount of gas filtered may also be limited by available_power, if given. +//available_power - the maximum amount of power that may be used when filtering gas. If null then the filtering is not limited by power. +/obj/machinery/atmospherics/proc/filter_gas(var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_filtered, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null) + if (source.total_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + filtering &= source.gas //only filter gasses that are actually there. + var/list/not_filtering = source.gas - filtering + + var/total_filterable_moles = 0 + var/total_unfilterable_moles = 0 + var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type + for (var/g in source.gas) + if (source.gas[g] < MINUMUM_MOLES_TO_FILTER) + continue + + if (g in filtering) + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY + total_filterable_moles += source.gas[g] + else + specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY + total_unfilterable_moles += source.gas[g] + + var/total_specific_power = 0 //the power required to remove one mole of input gas + for (var/g in source.gas) + var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix + total_specific_power = specific_power_gas[g]*ratio + + //Figure out how much of each gas to filter + if (!total_transfer_moles) + total_transfer_moles = source.total_moles + else + total_transfer_moles = min(total_transfer_moles, source.total_moles) + + //limit transfer_moles based on available power + if (available_power && total_specific_power > 0) + total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) + + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing + return -1 + + last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + var/datum/gas_mixture/removed = source.remove(total_transfer_moles) + if (!removed) //Just in case + return -1 + + var/filtered_power_used = 0 + var/unfiltered_power_used = 0 + for (var/g in removed.gas) + var/power_used = specific_power_gas[g]*removed.gas[g] + + //use update=0. All the filtered gasses get added simultaneously, so we update after the for loop. + if (g in filtering) + sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0) + filtered_power_used += power_used + else + sink_clean.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0) + unfiltered_power_used += power_used + + sink_filtered.update_values() + sink_clean.update_values() + + del(removed) //removed should have nothing in it now, so we can just get rid of it. + + if (filtered_power_used > 0) + sink_filtered.add_thermal_energy(filtered_power_used) //1st law - energy is conserved + if (unfiltered_power_used > 0) + sink_clean.add_thermal_energy(unfiltered_power_used) //1st law - energy is conserved + + return filtered_power_used + unfiltered_power_used + +/* + Helper procs for various things. +*/ + //Calculates the amount of power needed to move one mole from source to sink. /obj/machinery/atmospherics/proc/calculate_specific_power(datum/gas_mixture/source, datum/gas_mixture/sink) //Calculate the amount of energy required