diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm
index e2cd25cfba..d6bb3e8aaa 100644
--- a/code/ATMOSPHERICS/components/unary/vent_pump.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm
@@ -1,6 +1,10 @@
#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
#define INTERNAL_PRESSURE_BOUND 0
#define PRESSURE_CHECKS 1
+
+#define PRESSURE_CHECK_EXTERNAL 1
+#define PRESSURE_CHECK_INTERNAL 2
+
#undefine
/obj/machinery/atmospherics/unary/vent_pump
@@ -10,6 +14,8 @@
name = "Air Vent"
desc = "Has a valve and pump attached to it"
use_power = 1
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ active_power_usage = 7500 //This also doubles as a measure of how powerful the pump is, in Watts. 7500 W ~ 10 HP
var/area/initial_loc
level = 1
@@ -19,6 +25,9 @@
var/on = 0
var/pump_direction = 1 //0 = siphoning, 1 = releasing
+ var/last_power_draw = 0
+ var/last_flow_rate = 0
+
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
@@ -114,61 +123,158 @@
/obj/machinery/atmospherics/unary/vent_pump/process()
..()
+
+ //reset these each iteration
+ last_power_draw = 0
+ last_flow_rate = 0
+
if(stat & (NOPOWER|BROKEN))
return
if (!node)
on = 0
//broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0
if(!on)
+ update_use_power(0)
return 0
if(welded)
return 0
- var/datum/gas_mixture/environment = loc.return_air()
- var/environment_pressure = environment.return_pressure()
-
if(pump_direction) //internal -> external
- var/pressure_delta = 10000
-
- if(pressure_checks&1)
- pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
- if(pressure_checks&2)
- pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
-
- if(pressure_delta > 0.5)
- if(air_contents.temperature > 0)
- var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
-
- var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
-
- loc.assume_air(removed)
-
- if(network)
- network.update = 1
-
+ pump_to_external()
else //external -> internal
- var/pressure_delta = 10000
- if(pressure_checks&1)
- pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
- if(pressure_checks&2)
- pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
-
- if(pressure_delta > 0.5)
- if(environment.temperature > 0)
- var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
-
- var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
- if (isnull(removed)) //in space
- return
-
- air_contents.merge(removed)
-
- if(network)
- network.update = 1
+ pump_to_internal()
return 1
+
+/obj/machinery/atmospherics/unary/vent_pump/proc/pump_to_external()
+ var/datum/gas_mixture/environment = loc.return_air()
+ var/environment_pressure = environment.return_pressure()
+
+ var/pressure_delta = 10000
+
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
+ if(pressure_checks & PRESSURE_CHECK_INTERNAL)
+ pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
+
+ if(pressure_delta > 0.5 && (air_contents.temperature > 0 || environment.temperature > 0))
+ //Figure out how much gas to transfer
+
+ //unfortunately there's no good way to get the volume of the room, so assume 10 tiles
+ //we might overshoot in small rooms when dealing with huge pressures but it won't be so bad
+ var/output_volume = environment.volume * 10
+ var/air_temperature = environment.temperature? environment.temperature : air_contents.temperature
+
+ var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
+
+ //Calculate the amount of energy required
+ var/specific_entropy = environment.specific_entropy() - air_contents.specific_entropy() //environment is gaining moles, air_contents is loosing
+ var/specific_power = 0 // W/mol
+
+ //If specific_entropy is < 0 then transfer_moles is limited by how powerful the pump is
+ if (specific_entropy < 0)
+ specific_power = -specific_entropy*air_temperature //how much power we need per mole
+ transfer_moles = min(transfer_moles, active_power_usage / specific_power)
+
+ //Get the gas to be transferred
+ var/input_pressure = air_contents.return_pressure()
+ var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
+
+ if (isnull(removed)) //not sure why this would happen, but it does at the very beginning of the game
+ update_use_power(0)
+ return
+
+ if (input_pressure > 0)
+ last_flow_rate = removed.total_moles()*R_IDEAL_GAS_EQUATION*removed.temperature/input_pressure
+
+ //If specific_entropy is < 0 then extra power needs to be supplied to move gas
+ if (specific_entropy < 0)
+ //pump draws power and heats gas according to 2nd law of thermodynamics
+ var/power_draw = round(transfer_moles*specific_power)
+ removed.add_thermal_energy(power_draw)
+ handle_power_draw(power_draw)
+ else
+ handle_power_draw(idle_power_usage)
+
+ loc.assume_air(removed)
+
+ if(network)
+ network.update = 1
+ else
+ update_use_power(0)
+
+//This is largely identical to pump_to_external(), except since the source and sink are two different types we can't just reuse the same proc :(
+/obj/machinery/atmospherics/unary/vent_pump/proc/pump_to_internal()
+ var/datum/gas_mixture/environment = loc.return_air()
+ var/environment_pressure = environment.return_pressure()
+
+ var/pressure_delta = 10000
+
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
+ if(pressure_checks & PRESSURE_CHECK_INTERNAL)
+ pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
+
+ if(pressure_delta > 0.5 && (air_contents.temperature > 0 || environment.temperature > 0))
+ //Figure out how much gas to transfer
+ var/output_volume = air_contents.volume
+ if (network && network.air_transient)
+ output_volume = network.air_transient.volume //use the network volume if we can get it
+
+ var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature
+
+ var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
+
+ //Calculate the amount of energy required
+ var/specific_entropy = air_contents.specific_entropy() - environment.specific_entropy() //air_contents is gaining moles, environment is loosing
+ var/specific_power = 0 // W/mol
+
+ //If specific_entropy is < 0 then transfer_moles is limited by how powerful the pump is
+ if (specific_entropy < 0)
+ specific_power = -specific_entropy*air_temperature //how much power we need per mole
+ transfer_moles = min(transfer_moles, active_power_usage / specific_power)
+
+ //Get the gas to be transferred
+ var/input_pressure = environment.return_pressure()
+ var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
+
+ if (isnull(removed)) //in space
+ update_use_power(0)
+ return
+
+ if (input_pressure > 0)
+ last_flow_rate = removed.total_moles()*R_IDEAL_GAS_EQUATION*removed.temperature/input_pressure
+
+ //If specific_entropy is < 0 then extra power needs to be supplied to move gas
+ if (specific_entropy < 0)
+ //pump draws power and heats gas according to 2nd law of thermodynamics
+ var/power_draw = round(transfer_moles*specific_power)
+ removed.add_thermal_energy(power_draw)
+ handle_power_draw(power_draw)
+ else
+ handle_power_draw(idle_power_usage)
+
+ air_contents.merge(removed)
+
+ if(network)
+ network.update = 1
+ else
+ update_use_power(0)
+
+//This proc handles power usages so that we only have to call use_power() when the pump is loaded but not at full load.
+/obj/machinery/atmospherics/unary/vent_pump/proc/handle_power_draw(var/usage_amount)
+ if (usage_amount > active_power_usage - 5)
+ update_use_power(2)
+ else
+ update_use_power(1)
+
+ if (usage_amount > idle_power_usage)
+ use_power(round(usage_amount))
+
+ last_power_draw = usage_amount
+
//Radio remote control
/obj/machinery/atmospherics/unary/vent_pump/proc/set_frequency(new_frequency)
@@ -195,7 +301,9 @@
"internal" = internal_pressure_bound,
"external" = external_pressure_bound,
"timestamp" = world.time,
- "sigtype" = "status"
+ "sigtype" = "status",
+ "power_draw" = last_power_draw,
+ "flow_rate" = last_flow_rate,
)
if(!initial_loc.air_vent_names[id_tag])
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index 826d2e0b3b..8f0751dc63 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -797,7 +797,7 @@ Toxins: [phoron_percent]%
sensor_data += {"
[long_name][state]
Operating:
-[data["power"]?"on":"off"]
+[data["power"]?"on":"off"] Flow Rate: [data["flow_rate"]] L/s
Pressure checks:
external