/* Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure. node1, air1, network1 correspond to input node2, air2, network2 correspond to output Thus, the two variables affect pump operation are set in New(): air1.volume This is the volume of gas available to the pump that may be transfered to the output air2.volume Higher quantities of this cause more air to be perfected later but overall network volume is also increased as this increases... */ obj/machinery/atmospherics/binary/pump icon = 'icons/obj/atmospherics/pump.dmi' icon_state = "intact_off" name = "Gas pump" desc = "A pump" var/on = 0 var/target_pressure = ONE_ATMOSPHERE //var/max_volume_transfer = 10000 use_power = 1 idle_power_usage = 10 //10 W for internal circuitry 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/last_power_draw = 0 //for UI var/max_pressure_setting = 9000 //kPa var/frequency = 0 var/id = null var/datum/radio_frequency/radio_connection highcap name = "High capacity gas pump" desc = "A high capacity pump" target_pressure = 15000000 //15 GPa? Really? active_power_usage = 112500 //150 Horsepower on on = 1 icon_state = "intact_on" update_icon() if(stat & NOPOWER) icon_state = "intact_off" else if(node1 && node2) icon_state = "intact_[on?("on"):("off")]" else if(node1) icon_state = "exposed_1_off" else if(node2) icon_state = "exposed_2_off" else icon_state = "exposed_3_off" return process() // ..() if(stat & (NOPOWER|BROKEN)) return if(!on) return 0 var/output_starting_pressure = air2.return_pressure() if( (target_pressure - output_starting_pressure) < 0.01) //No need to pump gas if target is already reached! update_power_usage(0) return 1 var/output_volume = air2.volume if (network2 && network2.air_transient) output_volume = network2.air_transient.volume //note that the amount of gas in the adjacent pipe will still limit what we can transfer //This is pointless since gas_mixure/remove() won't let as remove more than is in the adjacent pipe anyways and removing gas directly from the network is not going to work. //output_volume = min(output_volume, max_volume_transfer) //Calculate necessary moles to transfer using PV=nRT if((air1.total_moles() > 0) && (air1.temperature > 0 || air2.temperature > 0)) var/air_temperature = (air2.temperature > 0)? air2.temperature : air1.temperature var/pressure_delta = target_pressure - output_starting_pressure var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) //The number of moles that would have to be transfered to bring air2 to the target pressure //estimate the amount of energy required var/specific_entropy = air2.specific_entropy() - air1.specific_entropy() //air2 is gaining moles, air1 is loosing var/specific_power = 0 // W/mol //src.visible_message("DEBUG: [src] >>> terminal pressures: sink = [air2.return_pressure()] kPa, source = [air1.return_pressure()] kPa") //src.visible_message("DEBUG: [src] >>> specific entropy = [air2.specific_entropy()] - [air1.specific_entropy()] = [specific_entropy] J/K") //if specific_entropy >= 0 then gas just flows naturally and we are not limited by how powerful the pump is. if (specific_entropy < 0) specific_power = -specific_entropy*air_temperature //how much power we need per mole //src.visible_message("DEBUG: [src] >>> limiting transfer_moles to [active_power_usage / specific_power] mol") transfer_moles = min(transfer_moles, active_power_usage / specific_power) //Actually transfer the gas var/datum/gas_mixture/removed = air1.remove(transfer_moles) air2.merge(removed) //src.visible_message("DEBUG: [src] >>> entropy_change = [specific_entropy*transfer_moles] J/K") //if specific_entropy >= 0 then gas is flowing naturally and we don't need to use extra power if (specific_entropy < 0) //pump draws power and heats gas according to 2nd law of thermodynamics var/power_draw = round(transfer_moles*specific_power) air2.add_thermal_energy(power_draw) update_power_usage(power_draw) //src.visible_message("DEBUG: [src] >>> drawing [power_draw] W of power.") else update_power_usage(0) if(network1) network1.update = 1 if(network2) network2.update = 1 return 1 //Radio remote control proc set_frequency(new_frequency) radio_controller.remove_object(src, frequency) frequency = new_frequency if(frequency) radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA) broadcast_status() if(!radio_connection) return 0 var/datum/signal/signal = new signal.transmission_method = 1 //radio signal signal.source = src signal.data = list( "tag" = id, "device" = "AGP", "power" = on, "target_output" = target_pressure, "sigtype" = "status" ) radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) return 1 //this proc handles power usages so that we only have to call use_power() when the pump is loaded but not at full load. update_power_usage(var/usage_amount) if (usage_amount > active_power_usage - 5) if (use_power < 2) update_use_power(2) else if (use_power >= 2) update_use_power(1) if (usage_amount > idle_power_usage) use_power(usage_amount) last_power_draw = usage_amount if (use_power > 0) last_power_draw = max(last_power_draw, idle_power_usage) turn_on() on = 1 update_use_power(1) turn_off() on = 0 last_power_draw = 0 update_use_power(0) ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) if(stat & (BROKEN|NOPOWER)) return // this is the data which will be sent to the ui var/data[0] data = list( "on" = on, "pressure_set" = round(target_pressure, 0.01), "max_pressure" = max_pressure_setting, "last_power_draw" = round(last_power_draw), "max_power_draw" = active_power_usage, ) // update the ui if it exists, returns null if no ui is passed/found ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) if (!ui) // the ui does not exist, so we'll create a new() one // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290) ui.set_initial_data(data) // when the ui is first opened this is the data it will use ui.open() // open the new ui window ui.set_auto_update(1) // auto update every Master Controller tick initialize() ..() if(frequency) set_frequency(frequency) receive_signal(datum/signal/signal) if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) return 0 if("power" in signal.data) if(text2num(signal.data["power"])) turn_on() else turn_off() if("power_toggle" in signal.data) if (on) turn_off() else turn_on() if("set_output_pressure" in signal.data) target_pressure = between( 0, text2num(signal.data["set_output_pressure"]), ONE_ATMOSPHERE*50 ) if("status" in signal.data) spawn(2) broadcast_status() return //do not update_icon spawn(2) broadcast_status() update_icon() return attack_hand(user as mob) if(..()) return src.add_fingerprint(usr) if(!src.allowed(user)) user << "\red Access denied." return usr.set_machine(src) ui_interact(user) return Topic(href,href_list) if(..()) return if(href_list["power"]) if (on) turn_off() else turn_on() switch(href_list["set_press"]) if ("min") target_pressure = 0 if ("max") target_pressure = max_pressure_setting if ("set") var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num src.target_pressure = max(0, min(max_pressure_setting, new_pressure)) usr.set_machine(src) src.add_fingerprint(usr) src.update_icon() return power_change() ..() update_icon() attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if (!istype(W, /obj/item/weapon/wrench)) return ..() if (!(stat & NOPOWER) && on) user << "\red You cannot unwrench this [src], turn it off first." return 1 var/turf/T = src.loc if (level==1 && isturf(T) && T.intact) user << "\red You must remove the plating first." return 1 var/datum/gas_mixture/int_air = return_air() var/datum/gas_mixture/env_air = loc.return_air() if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." add_fingerprint(user) return 1 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) user << "\blue You begin to unfasten \the [src]..." if (do_after(user, 40)) user.visible_message( \ "[user] unfastens \the [src].", \ "\blue You have unfastened \the [src].", \ "You hear ratchet.") new /obj/item/pipe(loc, make_from=src) del(src)