Merge branch 'master' into air-injector-link-fix

This commit is contained in:
SteelSlayer
2020-03-18 12:54:09 -05:00
1735 changed files with 185676 additions and 185063 deletions
@@ -1,155 +1,155 @@
/obj/machinery/atmospherics/binary
dir = SOUTH
initialize_directions = SOUTH|NORTH
use_power = IDLE_POWER_USE
layer = GAS_PUMP_LAYER
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/datum/pipeline/parent1
var/datum/pipeline/parent2
/obj/machinery/atmospherics/binary/New()
..()
switch(dir)
if(NORTH)
initialize_directions = NORTH|SOUTH
if(SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST)
initialize_directions = EAST|WEST
if(WEST)
initialize_directions = EAST|WEST
air1 = new
air2 = new
air1.volume = 200
air2.volume = 200
/obj/machinery/atmospherics/binary/Destroy()
if(node1)
node1.disconnect(src)
node1 = null
nullifyPipenet(parent1)
if(node2)
node2.disconnect(src)
node2 = null
nullifyPipenet(parent2)
return ..()
/obj/machinery/atmospherics/binary/atmos_init()
..()
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
var/c = check_connect_types(target,src)
if(c)
target.connected_to = c
connected_to = c
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
if(target.initialize_directions & get_dir(target,src))
var/c = check_connect_types(target,src)
if(c)
target.connected_to = c
connected_to = c
node2 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/binary/build_network(remove_deferral = FALSE)
if(!parent1)
parent1 = new /datum/pipeline()
parent1.build_pipeline(src)
if(!parent2)
parent2 = new /datum/pipeline()
parent2.build_pipeline(src)
..()
/obj/machinery/atmospherics/binary/disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
qdel(parent1)
node1 = null
else if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
qdel(parent2)
node2 = null
update_icon()
/obj/machinery/atmospherics/binary/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
if(P == parent1)
parent1.other_airs -= air1
parent1 = null
else if(P == parent2)
parent2.other_airs -= air2
parent2 = null
/obj/machinery/atmospherics/binary/returnPipenetAir(datum/pipeline/P)
if(P == parent1)
return air1
else if(P == parent2)
return air2
/obj/machinery/atmospherics/binary/pipeline_expansion(datum/pipeline/P)
if(P)
if(parent1 == P)
return list(node1)
else if(parent2 == P)
return list(node2)
else
return list(node1, node2)
/obj/machinery/atmospherics/binary/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
if(A == node1)
parent1 = P
else if(A == node2)
parent2 = P
/obj/machinery/atmospherics/binary/returnPipenet(obj/machinery/atmospherics/A)
if(A == node1)
return parent1
else if(A == node2)
return parent2
/obj/machinery/atmospherics/binary/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
if(Old == parent1)
parent1 = New
else if(Old == parent2)
parent2 = New
/obj/machinery/atmospherics/binary/unsafe_pressure_release(var/mob/user,var/pressures)
..()
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2 and assume it
var/datum/gas_mixture/environment = T.return_air()
var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
var/shared_loss = lost/2
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
T.assume_air(to_release)
air_update_turf(1)
/obj/machinery/atmospherics/binary/process_atmos()
..()
return parent1 && parent2
/obj/machinery/atmospherics/binary
dir = SOUTH
initialize_directions = SOUTH|NORTH
use_power = IDLE_POWER_USE
layer = GAS_PUMP_LAYER
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/datum/pipeline/parent1
var/datum/pipeline/parent2
/obj/machinery/atmospherics/binary/New()
..()
switch(dir)
if(NORTH)
initialize_directions = NORTH|SOUTH
if(SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST)
initialize_directions = EAST|WEST
if(WEST)
initialize_directions = EAST|WEST
air1 = new
air2 = new
air1.volume = 200
air2.volume = 200
/obj/machinery/atmospherics/binary/Destroy()
if(node1)
node1.disconnect(src)
node1 = null
nullifyPipenet(parent1)
if(node2)
node2.disconnect(src)
node2 = null
nullifyPipenet(parent2)
return ..()
/obj/machinery/atmospherics/binary/atmos_init()
..()
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
var/c = check_connect_types(target,src)
if(c)
target.connected_to = c
connected_to = c
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
if(target.initialize_directions & get_dir(target,src))
var/c = check_connect_types(target,src)
if(c)
target.connected_to = c
connected_to = c
node2 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/binary/build_network(remove_deferral = FALSE)
if(!parent1)
parent1 = new /datum/pipeline()
parent1.build_pipeline(src)
if(!parent2)
parent2 = new /datum/pipeline()
parent2.build_pipeline(src)
..()
/obj/machinery/atmospherics/binary/disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
qdel(parent1)
node1 = null
else if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
qdel(parent2)
node2 = null
update_icon()
/obj/machinery/atmospherics/binary/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
if(P == parent1)
parent1.other_airs -= air1
parent1 = null
else if(P == parent2)
parent2.other_airs -= air2
parent2 = null
/obj/machinery/atmospherics/binary/returnPipenetAir(datum/pipeline/P)
if(P == parent1)
return air1
else if(P == parent2)
return air2
/obj/machinery/atmospherics/binary/pipeline_expansion(datum/pipeline/P)
if(P)
if(parent1 == P)
return list(node1)
else if(parent2 == P)
return list(node2)
else
return list(node1, node2)
/obj/machinery/atmospherics/binary/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
if(A == node1)
parent1 = P
else if(A == node2)
parent2 = P
/obj/machinery/atmospherics/binary/returnPipenet(obj/machinery/atmospherics/A)
if(A == node1)
return parent1
else if(A == node2)
return parent2
/obj/machinery/atmospherics/binary/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
if(Old == parent1)
parent1 = New
else if(Old == parent2)
parent2 = New
/obj/machinery/atmospherics/binary/unsafe_pressure_release(var/mob/user,var/pressures)
..()
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2 and assume it
var/datum/gas_mixture/environment = T.return_air()
var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
var/shared_loss = lost/2
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
T.assume_air(to_release)
air_update_turf(1)
/obj/machinery/atmospherics/binary/process_atmos()
..()
return parent1 && parent2
@@ -1,125 +1,125 @@
//node1, air1, network1 correspond to input
//node2, air2, network2 correspond to output
/obj/machinery/atmospherics/binary/circulator
name = "circulator/heat exchanger"
desc = "A gas circulator pump and heat exchanger. Its input port is on the south side, and its output port is on the north side."
icon = 'icons/obj/atmospherics/circulator.dmi'
icon_state = "circ1-off"
var/side = CIRC_LEFT
var/global/const/CIRC_LEFT = WEST
var/global/const/CIRC_RIGHT = EAST
var/last_pressure_delta = 0
var/obj/machinery/power/generator/generator
anchored = 1
density = 1
can_unwrench = 1
var/side_inverted = 0
// Creating a custom circulator pipe subtype to be delivered through cargo
/obj/item/pipe/circulator
name = "circulator/heat exchanger fitting"
/obj/item/pipe/circulator/New(loc)
var/obj/machinery/atmospherics/binary/circulator/C = new /obj/machinery/atmospherics/binary/circulator(null)
..(loc, make_from = C)
/obj/machinery/atmospherics/binary/circulator/Destroy()
if(generator && generator.cold_circ == src)
generator.cold_circ = null
else if(generator && generator.hot_circ == src)
generator.hot_circ = null
return ..()
/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air()
var/datum/gas_mixture/inlet = get_inlet_air()
var/datum/gas_mixture/outlet = get_outlet_air()
var/output_starting_pressure = outlet.return_pressure()
var/input_starting_pressure = inlet.return_pressure()
if(output_starting_pressure >= input_starting_pressure - 10)
//Need at least 10 KPa difference to overcome friction in the mechanism
last_pressure_delta = 0
return null
//Calculate necessary moles to transfer using PV = nRT
if(inlet.temperature > 0)
var/pressure_delta = (input_starting_pressure - output_starting_pressure) / 2
var/transfer_moles = pressure_delta * outlet.volume/(inlet.temperature * R_IDEAL_GAS_EQUATION)
last_pressure_delta = pressure_delta
//log_debug("pressure_delta = [pressure_delta]; transfer_moles = [transfer_moles];")
//Actually transfer the gas
var/datum/gas_mixture/removed = inlet.remove(transfer_moles)
parent1.update = 1
parent2.update = 1
return removed
else
last_pressure_delta = 0
/obj/machinery/atmospherics/binary/circulator/process_atmos()
..()
update_icon()
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_air()
if(side_inverted==0)
return air2
else
return air1
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_air()
if(side_inverted==0)
return air1
else
return air2
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_side()
if(dir==SOUTH||dir==NORTH)
if(side_inverted==0)
return "South"
else
return "North"
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_side()
if(dir==SOUTH||dir==NORTH)
if(side_inverted==0)
return "North"
else
return "South"
/obj/machinery/atmospherics/binary/circulator/attackby(obj/item/W as obj, mob/user as mob, params)
if(ismultitool(W))
if(side_inverted == 0)
side_inverted = 1
else
side_inverted = 0
to_chat(user, "<span class='notice'>You reverse the circulator's valve settings. The inlet of the circulator is now on the [get_inlet_side(dir)] side.</span>")
desc = "A gas circulator pump and heat exchanger. Its input port is on the [get_inlet_side(dir)] side, and its output port is on the [get_outlet_side(dir)] side."
else
return ..()
/obj/machinery/atmospherics/binary/circulator/update_icon()
..()
if(stat & (BROKEN|NOPOWER))
icon_state = "circ[side]-p"
else if(last_pressure_delta > 0)
if(last_pressure_delta > ONE_ATMOSPHERE)
icon_state = "circ[side]-run"
else
icon_state = "circ[side]-slow"
else
icon_state = "circ[side]-off"
return 1
//node1, air1, network1 correspond to input
//node2, air2, network2 correspond to output
#define CIRC_LEFT WEST
#define CIRC_RIGHT EAST
/obj/machinery/atmospherics/binary/circulator
name = "circulator/heat exchanger"
desc = "A gas circulator pump and heat exchanger. Its input port is on the south side, and its output port is on the north side."
icon = 'icons/obj/atmospherics/circulator.dmi'
icon_state = "circ1-off"
var/side = CIRC_LEFT
var/last_pressure_delta = 0
var/obj/machinery/power/generator/generator
anchored = 1
density = 1
can_unwrench = 1
var/side_inverted = 0
// Creating a custom circulator pipe subtype to be delivered through cargo
/obj/item/pipe/circulator
name = "circulator/heat exchanger fitting"
/obj/item/pipe/circulator/New(loc)
var/obj/machinery/atmospherics/binary/circulator/C = new /obj/machinery/atmospherics/binary/circulator(null)
..(loc, make_from = C)
/obj/machinery/atmospherics/binary/circulator/Destroy()
if(generator && generator.cold_circ == src)
generator.cold_circ = null
else if(generator && generator.hot_circ == src)
generator.hot_circ = null
return ..()
/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air()
var/datum/gas_mixture/inlet = get_inlet_air()
var/datum/gas_mixture/outlet = get_outlet_air()
var/output_starting_pressure = outlet.return_pressure()
var/input_starting_pressure = inlet.return_pressure()
if(output_starting_pressure >= input_starting_pressure - 10)
//Need at least 10 KPa difference to overcome friction in the mechanism
last_pressure_delta = 0
return null
//Calculate necessary moles to transfer using PV = nRT
if(inlet.temperature > 0)
var/pressure_delta = (input_starting_pressure - output_starting_pressure) / 2
var/transfer_moles = pressure_delta * outlet.volume/(inlet.temperature * R_IDEAL_GAS_EQUATION)
last_pressure_delta = pressure_delta
//log_debug("pressure_delta = [pressure_delta]; transfer_moles = [transfer_moles];")
//Actually transfer the gas
var/datum/gas_mixture/removed = inlet.remove(transfer_moles)
parent1.update = 1
parent2.update = 1
return removed
else
last_pressure_delta = 0
/obj/machinery/atmospherics/binary/circulator/process_atmos()
..()
update_icon()
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_air()
if(side_inverted==0)
return air2
else
return air1
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_air()
if(side_inverted==0)
return air1
else
return air2
/obj/machinery/atmospherics/binary/circulator/proc/get_inlet_side()
if(dir==SOUTH||dir==NORTH)
if(side_inverted==0)
return "South"
else
return "North"
/obj/machinery/atmospherics/binary/circulator/proc/get_outlet_side()
if(dir==SOUTH||dir==NORTH)
if(side_inverted==0)
return "North"
else
return "South"
/obj/machinery/atmospherics/binary/circulator/multitool_act(mob/user, obj/item/I)
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
if(!side_inverted)
side_inverted = TRUE
else
side_inverted = FALSE
to_chat(user, "<span class='notice'>You reverse the circulator's valve settings. The inlet of the circulator is now on the [get_inlet_side(dir)] side.</span>")
desc = "A gas circulator pump and heat exchanger. Its input port is on the [get_inlet_side(dir)] side, and its output port is on the [get_outlet_side(dir)] side."
/obj/machinery/atmospherics/binary/circulator/update_icon()
..()
if(stat & (BROKEN|NOPOWER))
icon_state = "circ[side]-p"
else if(last_pressure_delta > 0)
if(last_pressure_delta > ONE_ATMOSPHERE)
icon_state = "circ[side]-run"
else
icon_state = "circ[side]-slow"
else
icon_state = "circ[side]-off"
return 1
@@ -91,4 +91,4 @@
return WEST
else
return 0
@@ -1,233 +1,233 @@
/obj/machinery/atmospherics/trinary/mixer
icon = 'icons/atmos/mixer.dmi'
icon_state = "map"
can_unwrench = 1
name = "gas mixer"
var/target_pressure = ONE_ATMOSPHERE
var/node1_concentration = 0.5
var/node2_concentration = 0.5
//node 3 is the outlet, nodes 1 & 2 are intakes
/obj/machinery/atmospherics/trinary/mixer/CtrlClick(mob/living/user)
if(!istype(user) || user.incapacitated())
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user) && !issilicon(usr))
return
if(!ishuman(usr) && !issilicon(usr))
return
toggle()
return ..()
/obj/machinery/atmospherics/trinary/mixer/AICtrlClick()
toggle()
return ..()
/obj/machinery/atmospherics/trinary/mixer/AltClick(mob/living/user)
if(!istype(user) || user.incapacitated())
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user) && !issilicon(usr))
return
if(!ishuman(usr) && !issilicon(usr))
return
set_max()
return
/obj/machinery/atmospherics/trinary/mixer/AIAltClick()
set_max()
return ..()
/obj/machinery/atmospherics/trinary/mixer/flipped
icon_state = "mmap"
flipped = 1
/obj/machinery/atmospherics/trinary/mixer/proc/toggle()
if(powered())
on = !on
update_icon()
/obj/machinery/atmospherics/trinary/mixer/proc/set_max()
if(powered())
target_pressure = MAX_OUTPUT_PRESSURE
update_icon()
/obj/machinery/atmospherics/trinary/mixer/update_icon(safety = 0)
..()
if(flipped)
icon_state = "m"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += on ? "on" : "off"
else
icon_state += "off"
on = 0
/obj/machinery/atmospherics/trinary/mixer/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(flipped)
add_underlay(T, node2, turn(dir, 90))
else
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/trinary/mixer/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/mixer/New()
..()
air3.volume = 300
/obj/machinery/atmospherics/trinary/mixer/process_atmos()
..()
if(!on)
return 0
var/output_starting_pressure = air3.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles1 = 0
var/transfer_moles2 = 0
if(air1.temperature > 0)
transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
if(air2.temperature > 0)
transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
var/air1_moles = air1.total_moles()
var/air2_moles = air2.total_moles()
if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2))
if(!transfer_moles1 || !transfer_moles2) return
var/ratio = min(air1_moles/transfer_moles1, air2_moles/transfer_moles2)
transfer_moles1 *= ratio
transfer_moles2 *= ratio
//Actually transfer the gas
if(transfer_moles1 > 0)
var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1)
air3.merge(removed1)
if(transfer_moles2 > 0)
var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2)
air3.merge(removed2)
if(transfer_moles1)
parent1.update = 1
if(transfer_moles2)
parent2.update = 1
parent3.update = 1
return 1
/obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user)
if(..())
return
if(!allowed(user))
to_chat(user, "<span class='alert'>Access denied.</span>")
return
add_fingerprint(user)
ui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_mixer.tmpl", name, 370, 165, state = state)
ui.open()
/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
data["node1_concentration"] = round(node1_concentration*100)
data["node2_concentration"] = round(node2_concentration*100)
return data
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
if(..())
return 1
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if(href_list["node1"])
var/value = text2num(href_list["node1"])
node1_concentration = max(0, min(1, node1_concentration + value))
node2_concentration = max(0, min(1, node2_concentration - value))
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["node2"])
var/value = text2num(href_list["node2"])
node2_concentration = max(0, min(1, node2_concentration + value))
node1_concentration = max(0, min(1, node1_concentration - value))
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
. = TRUE
update_icon()
SSnanoui.update_uis(src)
/obj/machinery/atmospherics/trinary/mixer/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
var/t = copytext(stripped_input(user, "Enter the name for the mixer.", "Rename", name), 1, MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
return
name = t
return
else
return ..()
/obj/machinery/atmospherics/trinary/mixer
icon = 'icons/atmos/mixer.dmi'
icon_state = "map"
can_unwrench = 1
name = "gas mixer"
var/target_pressure = ONE_ATMOSPHERE
var/node1_concentration = 0.5
var/node2_concentration = 0.5
//node 3 is the outlet, nodes 1 & 2 are intakes
/obj/machinery/atmospherics/trinary/mixer/CtrlClick(mob/living/user)
if(!istype(user) || user.incapacitated())
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user) && !issilicon(usr))
return
if(!ishuman(usr) && !issilicon(usr))
return
toggle()
return ..()
/obj/machinery/atmospherics/trinary/mixer/AICtrlClick()
toggle()
return ..()
/obj/machinery/atmospherics/trinary/mixer/AltClick(mob/living/user)
if(!istype(user) || user.incapacitated())
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
return
if(!in_range(src, user) && !issilicon(usr))
return
if(!ishuman(usr) && !issilicon(usr))
return
set_max()
return
/obj/machinery/atmospherics/trinary/mixer/AIAltClick()
set_max()
return ..()
/obj/machinery/atmospherics/trinary/mixer/flipped
icon_state = "mmap"
flipped = 1
/obj/machinery/atmospherics/trinary/mixer/proc/toggle()
if(powered())
on = !on
update_icon()
/obj/machinery/atmospherics/trinary/mixer/proc/set_max()
if(powered())
target_pressure = MAX_OUTPUT_PRESSURE
update_icon()
/obj/machinery/atmospherics/trinary/mixer/update_icon(safety = 0)
..()
if(flipped)
icon_state = "m"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += on ? "on" : "off"
else
icon_state += "off"
on = 0
/obj/machinery/atmospherics/trinary/mixer/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(flipped)
add_underlay(T, node2, turn(dir, 90))
else
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/trinary/mixer/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/mixer/New()
..()
air3.volume = 300
/obj/machinery/atmospherics/trinary/mixer/process_atmos()
..()
if(!on)
return 0
var/output_starting_pressure = air3.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles1 = 0
var/transfer_moles2 = 0
if(air1.temperature > 0)
transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
if(air2.temperature > 0)
transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
var/air1_moles = air1.total_moles()
var/air2_moles = air2.total_moles()
if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2))
if(!transfer_moles1 || !transfer_moles2) return
var/ratio = min(air1_moles/transfer_moles1, air2_moles/transfer_moles2)
transfer_moles1 *= ratio
transfer_moles2 *= ratio
//Actually transfer the gas
if(transfer_moles1 > 0)
var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1)
air3.merge(removed1)
if(transfer_moles2 > 0)
var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2)
air3.merge(removed2)
if(transfer_moles1)
parent1.update = 1
if(transfer_moles2)
parent2.update = 1
parent3.update = 1
return 1
/obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user)
if(..())
return
if(!allowed(user))
to_chat(user, "<span class='alert'>Access denied.</span>")
return
add_fingerprint(user)
ui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_mixer.tmpl", name, 370, 165, state = state)
ui.open()
/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
data["node1_concentration"] = round(node1_concentration*100)
data["node2_concentration"] = round(node2_concentration*100)
return data
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
if(..())
return 1
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = Clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if(href_list["node1"])
var/value = text2num(href_list["node1"])
node1_concentration = max(0, min(1, node1_concentration + value))
node2_concentration = max(0, min(1, node2_concentration - value))
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["node2"])
var/value = text2num(href_list["node2"])
node2_concentration = max(0, min(1, node2_concentration + value))
node1_concentration = max(0, min(1, node1_concentration - value))
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
. = TRUE
update_icon()
SSnanoui.update_uis(src)
/obj/machinery/atmospherics/trinary/mixer/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
var/t = copytext(stripped_input(user, "Enter the name for the mixer.", "Rename", name), 1, MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
return
name = t
return
else
return ..()
@@ -1,213 +1,213 @@
/obj/machinery/atmospherics/trinary
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
use_power = IDLE_POWER_USE
var/on = 0
layer = GAS_FILTER_LAYER
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/datum/gas_mixture/air3
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/obj/machinery/atmospherics/node3
var/datum/pipeline/parent1
var/datum/pipeline/parent2
var/datum/pipeline/parent3
var/flipped = 0
/obj/machinery/atmospherics/trinary/New()
..()
if(!flipped)
switch(dir)
if(NORTH)
initialize_directions = EAST|NORTH|SOUTH
if(SOUTH)
initialize_directions = SOUTH|WEST|NORTH
if(EAST)
initialize_directions = EAST|WEST|SOUTH
if(WEST)
initialize_directions = WEST|NORTH|EAST
else
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|WEST
if(SOUTH)
initialize_directions = NORTH|SOUTH|EAST
if(EAST)
initialize_directions = WEST|EAST|NORTH
if(WEST)
initialize_directions = EAST|WEST|SOUTH
air1 = new
air2 = new
air3 = new
air1.volume = 200
air2.volume = 200
air3.volume = 200
/obj/machinery/atmospherics/trinary/Destroy()
if(node1)
node1.disconnect(src)
node1 = null
nullifyPipenet(parent1)
if(node2)
node2.disconnect(src)
node2 = null
nullifyPipenet(parent2)
if(node3)
node3.disconnect(src)
node3 = null
nullifyPipenet(parent3)
return ..()
/obj/machinery/atmospherics/trinary/atmos_init()
..()
//Mixer:
//1 and 2 is input
//Node 3 is output
//If we flip the mixer, 1 and 3 shall exchange positions
//Filter:
//Node 1 is input
//Node 2 is filtered output
//Node 3 is rest output
//If we flip the filter, 1 and 3 shall exchange positions
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, -90)
var/node3_connect = dir
if(flipped)
node2_connect = turn(node2_connect, -180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/trinary/build_network(remove_deferral = FALSE)
if(!parent1)
parent1 = new /datum/pipeline()
parent1.build_pipeline(src)
if(!parent2)
parent2 = new /datum/pipeline()
parent2.build_pipeline(src)
if(!parent3)
parent3 = new /datum/pipeline()
parent3.build_pipeline(src)
..()
/obj/machinery/atmospherics/trinary/disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
qdel(parent1)
node1 = null
else if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
qdel(parent2)
node2 = null
else if(reference == node3)
if(istype(node3, /obj/machinery/atmospherics/pipe))
qdel(parent3)
node3 = null
update_icon()
/obj/machinery/atmospherics/trinary/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
if(P == parent1)
parent1.other_airs -= air1
parent1 = null
else if(P == parent2)
parent2.other_airs -= air2
parent2 = null
else if(P == parent3)
parent3.other_airs -= air3
parent3 = null
/obj/machinery/atmospherics/trinary/returnPipenetAir(datum/pipeline/P)
if(P == parent1)
return air1
else if(P == parent2)
return air2
else if(P == parent3)
return air3
/obj/machinery/atmospherics/trinary/pipeline_expansion(datum/pipeline/P)
if(P)
if(parent1 == P)
return list(node1)
else if(parent2 == P)
return list(node2)
else if(parent3 == P)
return list(node3)
return list(node1, node2, node3)
/obj/machinery/atmospherics/trinary/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
if(A == node1)
parent1 = P
else if(A == node2)
parent2 = P
else if(A == node3)
parent3 = P
/obj/machinery/atmospherics/trinary/returnPipenet(obj/machinery/atmospherics/A)
if(A == node1)
return parent1
else if(A == node2)
return parent2
else if(A == node3)
return parent3
/obj/machinery/atmospherics/trinary/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
if(Old == parent1)
parent1 = New
else if(Old == parent2)
parent2 = New
else if(Old == parent3)
parent3 = New
/obj/machinery/atmospherics/trinary/unsafe_pressure_release(var/mob/user,var/pressures)
..()
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2+air3 and assume it
var/datum/gas_mixture/environment = T.return_air()
var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air3.temperature * R_IDEAL_GAS_EQUATION)
var/shared_loss = lost/3
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
to_release.merge(air3.remove(shared_loss))
T.assume_air(to_release)
air_update_turf(1)
/obj/machinery/atmospherics/trinary/process_atmos()
..()
return parent1 && parent2 && parent3
/obj/machinery/atmospherics/trinary
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
use_power = IDLE_POWER_USE
var/on = 0
layer = GAS_FILTER_LAYER
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/datum/gas_mixture/air3
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/obj/machinery/atmospherics/node3
var/datum/pipeline/parent1
var/datum/pipeline/parent2
var/datum/pipeline/parent3
var/flipped = 0
/obj/machinery/atmospherics/trinary/New()
..()
if(!flipped)
switch(dir)
if(NORTH)
initialize_directions = EAST|NORTH|SOUTH
if(SOUTH)
initialize_directions = SOUTH|WEST|NORTH
if(EAST)
initialize_directions = EAST|WEST|SOUTH
if(WEST)
initialize_directions = WEST|NORTH|EAST
else
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|WEST
if(SOUTH)
initialize_directions = NORTH|SOUTH|EAST
if(EAST)
initialize_directions = WEST|EAST|NORTH
if(WEST)
initialize_directions = EAST|WEST|SOUTH
air1 = new
air2 = new
air3 = new
air1.volume = 200
air2.volume = 200
air3.volume = 200
/obj/machinery/atmospherics/trinary/Destroy()
if(node1)
node1.disconnect(src)
node1 = null
nullifyPipenet(parent1)
if(node2)
node2.disconnect(src)
node2 = null
nullifyPipenet(parent2)
if(node3)
node3.disconnect(src)
node3 = null
nullifyPipenet(parent3)
return ..()
/obj/machinery/atmospherics/trinary/atmos_init()
..()
//Mixer:
//1 and 2 is input
//Node 3 is output
//If we flip the mixer, 1 and 3 shall exchange positions
//Filter:
//Node 1 is input
//Node 2 is filtered output
//Node 3 is rest output
//If we flip the filter, 1 and 3 shall exchange positions
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, -90)
var/node3_connect = dir
if(flipped)
node2_connect = turn(node2_connect, -180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/trinary/build_network(remove_deferral = FALSE)
if(!parent1)
parent1 = new /datum/pipeline()
parent1.build_pipeline(src)
if(!parent2)
parent2 = new /datum/pipeline()
parent2.build_pipeline(src)
if(!parent3)
parent3 = new /datum/pipeline()
parent3.build_pipeline(src)
..()
/obj/machinery/atmospherics/trinary/disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
qdel(parent1)
node1 = null
else if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
qdel(parent2)
node2 = null
else if(reference == node3)
if(istype(node3, /obj/machinery/atmospherics/pipe))
qdel(parent3)
node3 = null
update_icon()
/obj/machinery/atmospherics/trinary/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
if(P == parent1)
parent1.other_airs -= air1
parent1 = null
else if(P == parent2)
parent2.other_airs -= air2
parent2 = null
else if(P == parent3)
parent3.other_airs -= air3
parent3 = null
/obj/machinery/atmospherics/trinary/returnPipenetAir(datum/pipeline/P)
if(P == parent1)
return air1
else if(P == parent2)
return air2
else if(P == parent3)
return air3
/obj/machinery/atmospherics/trinary/pipeline_expansion(datum/pipeline/P)
if(P)
if(parent1 == P)
return list(node1)
else if(parent2 == P)
return list(node2)
else if(parent3 == P)
return list(node3)
return list(node1, node2, node3)
/obj/machinery/atmospherics/trinary/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
if(A == node1)
parent1 = P
else if(A == node2)
parent2 = P
else if(A == node3)
parent3 = P
/obj/machinery/atmospherics/trinary/returnPipenet(obj/machinery/atmospherics/A)
if(A == node1)
return parent1
else if(A == node2)
return parent2
else if(A == node3)
return parent3
/obj/machinery/atmospherics/trinary/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
if(Old == parent1)
parent1 = New
else if(Old == parent2)
parent2 = New
else if(Old == parent3)
parent3 = New
/obj/machinery/atmospherics/trinary/unsafe_pressure_release(var/mob/user,var/pressures)
..()
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2+air3 and assume it
var/datum/gas_mixture/environment = T.return_air()
var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
lost += pressures*environment.volume/(air3.temperature * R_IDEAL_GAS_EQUATION)
var/shared_loss = lost/3
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
to_release.merge(air3.remove(shared_loss))
T.assume_air(to_release)
air_update_turf(1)
/obj/machinery/atmospherics/trinary/process_atmos()
..()
return parent1 && parent2 && parent3
@@ -45,4 +45,4 @@
parent.update = 1
return 1
return 1
@@ -110,4 +110,4 @@
var/datum/gas/oxygen_agent_b/trace_gas = new
trace_gas.moles = (50 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
air_contents.trace_gases += trace_gas
air_contents.trace_gases += trace_gas
@@ -77,4 +77,4 @@
parent.update = 1
return 1
return 1
@@ -102,4 +102,4 @@
/obj/machinery/atmospherics/unary/process_atmos()
..()
return parent
return parent
@@ -344,27 +344,6 @@
playsound(loc, 'sound/weapons/bladeslice.ogg', 100, TRUE)
/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool))
var/obj/item/weldingtool/WT = W
if(WT.remove_fuel(0,user))
to_chat(user, "<span class='notice'>Now welding the vent.</span>")
if(do_after(user, 20 * WT.toolspeed, target = src))
if(!src || !WT.isOn()) return
playsound(src.loc, WT.usesound, 50, 1)
if(!welded)
user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.")
welded = 1
update_icon()
else
user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.")
welded = 0
update_icon()
else
to_chat(user, "<span class='notice'>The welding tool needs to be on to start this task.</span>")
return 1
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return 1
if(istype(W, /obj/item/screwdriver))
if(!welded)
if(open)
@@ -400,6 +379,23 @@
return ..()
/obj/machinery/atmospherics/unary/vent_pump/welder_act(mob/user, obj/item/I)
. = TRUE
if(!I.tool_use_check(user, 0))
return
WELDER_ATTEMPT_WELD_MESSAGE
if(I.use_tool(src, user, 20, volume = I.tool_volume))
if(!welded)
welded = TRUE
visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
"<span class='notice'>You weld [src] shut!</span>")
else
welded = FALSE
visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
"<span class='notice'>You unweld [src]!</span>")
update_icon()
/obj/machinery/atmospherics/unary/vent_pump/attack_hand()
if(!welded)
if(open)
@@ -393,27 +393,6 @@
playsound(loc, 'sound/weapons/bladeslice.ogg', 100, TRUE)
/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/W as obj, var/mob/user as mob, params)
if(istype(W, /obj/item/weldingtool))
var/obj/item/weldingtool/WT = W
if(WT.remove_fuel(0,user))
to_chat(user, "<span class='notice'>Now welding the scrubber.</span>")
if(do_after(user, 20 * WT.toolspeed, target = src))
if(!src || !WT.isOn()) return
playsound(get_turf(src), WT.usesound, 50, 1)
if(!welded)
user.visible_message("[user] welds the scrubber shut.", "You weld the vent scrubber.", "You hear welding.")
welded = 1
update_icon()
else
user.visible_message("[user] unwelds the scrubber.", "You unweld the scrubber.", "You hear welding.")
welded = 0
update_icon()
else
to_chat(user, "<span class='notice'>The welding tool needs to be on to start this task.</span>")
return 1
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return 1
if(istype(W, /obj/item/multitool))
update_multitool_menu(user)
return 1
@@ -423,3 +402,19 @@
return 1
return ..()
/obj/machinery/atmospherics/unary/vent_scrubber/welder_act(mob/user, obj/item/I)
. = TRUE
if(!I.tool_use_check(user, 0))
return
WELDER_ATTEMPT_WELD_MESSAGE
if(I.use_tool(src, user, 20, volume = I.tool_volume))
if(!welded)
welded = TRUE
visible_message("<span class='notice'>[user] welds [src] shut!</span>",\
"<span class='notice'>You weld [src] shut!</span>")
else
welded = FALSE
visible_message("<span class='notice'>[user] unwelds [src]!</span>",\
"<span class='notice'>You unweld [src]!</span>")
update_icon()