Implement Bay's SSmachinery and power usage updates, further unclogging the toilet (#13910)

This commit is contained in:
Wildkins
2022-05-16 18:50:16 +02:00
committed by GitHub
parent a18d6598e3
commit a4461a17af
296 changed files with 1662 additions and 1778 deletions
@@ -6,5 +6,5 @@
if(!.)
return
for(var/obj/machinery/light/L in SSmachinery.all_machines)
for(var/obj/machinery/light/L in SSmachinery.machinery)
L.fix()
+1 -1
View File
@@ -48,7 +48,7 @@
return
feedback_add_details("admin_verb","CPOW") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
for (var/datum/powernet/PN in SSpower.powernets)
for (var/datum/powernet/PN in SSmachinery.powernets)
if (!PN.nodes || !PN.nodes.len)
if(PN.cables && (PN.cables.len > 1))
var/obj/structure/cable/C = PN.cables[1]
+1 -1
View File
@@ -108,7 +108,7 @@
/client/proc/cmd_debug_make_powernets()
set category = "Debug"
set name = "Make Powernets"
makepowernets()
SSmachinery.makepowernets()
log_admin("[key_name(src)] has remade the powernet. makepowernets() called.",admin_key=key_name(usr))
message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.", 0)
feedback_add_details("admin_verb","MPWN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+279
View File
@@ -0,0 +1,279 @@
//--------------------------------------------
// Pipe colors
//
// Add them here and to the pipe_colors list
// to automatically add them to all relevant
// atmospherics devices.
//--------------------------------------------
/proc/pipe_color_lookup(var/color)
for(var/C in pipe_colors)
if(color == pipe_colors[C])
return "[C]"
/proc/pipe_color_check(var/color)
if(!color)
return 1
for(var/C in pipe_colors)
if(color == pipe_colors[C])
return 1
return 0
//--------------------------------------------
// Icon cache generation
//--------------------------------------------
/datum/pipe_icon_manager
var/list/pipe_icons[]
var/list/manifold_icons[]
var/list/device_icons[]
var/list/underlays[]
//var/list/underlays_down[]
//var/list/underlays_exposed[]
//var/list/underlays_intact[]
//var/list/pipe_underlays_exposed[]
//var/list/pipe_underlays_intact[]
var/list/omni_icons[]
/datum/pipe_icon_manager/New()
check_icons()
/datum/pipe_icon_manager/proc/get_atmos_icon(var/device, var/dir, var/color, var/state)
check_icons()
device = "[device]"
state = "[state]"
color = "[color]"
dir = "[dir]"
switch(device)
if("pipe")
return pipe_icons[state + color]
if("manifold")
return manifold_icons[state + color]
if("device")
return device_icons[state]
if("omni")
return omni_icons[state]
if("underlay")
return underlays[state + dir + color]
// if("underlay_intact")
// return underlays_intact[state + dir + color]
// if("underlay_exposed")
// return underlays_exposed[state + dir + color]
// if("underlay_down")
// return underlays_down[state + dir + color]
// if("pipe_underlay_exposed")
// return pipe_underlays_exposed[state + dir + color]
// if("pipe_underlay_intact")
// return pipe_underlays_intact[state + dir + color]
/datum/pipe_icon_manager/proc/check_icons()
if(!pipe_icons)
gen_pipe_icons()
if(!manifold_icons)
gen_manifold_icons()
if(!device_icons)
gen_device_icons()
if(!omni_icons)
gen_omni_icons()
//if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact)
if(!underlays)
gen_underlay_icons()
/datum/pipe_icon_manager/proc/gen_pipe_icons()
if(!pipe_icons)
pipe_icons = new()
var/icon/pipe = new('icons/atmos/pipes.dmi')
for(var/state in pipe.IconStates())
if(!state || findtext(state, "map"))
continue
var/cache_name = state
var/image/I = image('icons/atmos/pipes.dmi', icon_state = state)
pipe_icons[cache_name] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/pipes.dmi', icon_state = state)
I.color = pipe_colors[pipe_color]
pipe_icons[state + "[pipe_colors[pipe_color]]"] = I
pipe = new ('icons/atmos/heat.dmi')
for(var/state in pipe.IconStates())
if(!state || findtext(state, "map"))
continue
pipe_icons["hepipe" + state] = image('icons/atmos/heat.dmi', icon_state = state)
pipe = new ('icons/atmos/junction.dmi')
for(var/state in pipe.IconStates())
if(!state || findtext(state, "map"))
continue
pipe_icons["hejunction" + state] = image('icons/atmos/junction.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_manifold_icons()
if(!manifold_icons)
manifold_icons = new()
var/icon/pipe = new('icons/atmos/manifold.dmi')
for(var/state in pipe.IconStates())
if(findtext(state, "clamps"))
var/image/I = image('icons/atmos/manifold.dmi', icon_state = state)
manifold_icons[state] = I
continue
if(findtext(state, "core") || findtext(state, "4way"))
var/image/I = image('icons/atmos/manifold.dmi', icon_state = state)
manifold_icons[state] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/manifold.dmi', icon_state = state)
I.color = pipe_colors[pipe_color]
manifold_icons[state + pipe_colors[pipe_color]] = I
/datum/pipe_icon_manager/proc/gen_device_icons()
if(!device_icons)
device_icons = new()
var/icon/device
device = new('icons/atmos/vent_pump.dmi')
for(var/state in device.IconStates())
if(!state || findtext(state, "map"))
continue
device_icons["vent" + state] = image('icons/atmos/vent_pump.dmi', icon_state = state)
device = new('icons/atmos/vent_scrubber.dmi')
for(var/state in device.IconStates())
if(!state || findtext(state, "map"))
continue
device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_omni_icons()
if(!omni_icons)
omni_icons = new()
var/icon/omni = new('icons/atmos/omni_devices.dmi')
for(var/state in omni.IconStates())
if(!state || findtext(state, "map"))
continue
omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_underlay_icons()
if(!underlays)
underlays = new()
var/icon/pipe = new('icons/atmos/pipe_underlays.dmi')
for(var/state in pipe.IconStates())
if(state == "")
continue
var/cache_name = state
for(var/D in cardinal)
var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
underlays[cache_name + "[D]"] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
I.color = pipe_colors[pipe_color]
underlays[state + "[D]" + "[pipe_colors[pipe_color]]"] = I
/*
Leaving the old icon manager code commented out for now, as we may want to rewrite the new code to cleanly
separate the newpipe icon caching (speshul supply and scrubber lines) from the rest of the pipe code.
*/
/*
/datum/pipe_icon_manager/proc/gen_underlay_icons()
if(!underlays_intact)
underlays_intact = new()
if(!underlays_exposed)
underlays_exposed = new()
if(!underlays_down)
underlays_down = new()
if(!pipe_underlays_exposed)
pipe_underlays_exposed = new()
if(!pipe_underlays_intact)
pipe_underlays_intact = new()
var/icon/pipe = new('icons/atmos/pipe_underlays.dmi')
for(var/state in pipe.IconStates())
if(state == "")
continue
for(var/D in cardinal)
var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
switch(state)
if("intact")
underlays_intact["[D]"] = I
if("exposed")
underlays_exposed["[D]"] = I
if("down")
underlays_down["[D]"] = I
if("pipe_exposed")
pipe_underlays_exposed["[D]"] = I
if("pipe_intact")
pipe_underlays_intact["[D]"] = I
if("intact-supply")
underlays_intact["[D]"] = I
if("exposed-supply")
underlays_exposed["[D]"] = I
if("down-supply")
underlays_down["[D]"] = I
if("pipe_exposed-supply")
pipe_underlays_exposed["[D]"] = I
if("pipe_intact-supply")
pipe_underlays_intact["[D]"] = I
if("intact-scrubbers")
underlays_intact["[D]"] = I
if("exposed-scrubbers")
underlays_exposed["[D]"] = I
if("down-scrubbers")
underlays_down["[D]"] = I
if("pipe_exposed-scrubbers")
pipe_underlays_exposed["[D]"] = I
if("pipe_intact-scrubbers")
pipe_underlays_intact["[D]"] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
I.color = pipe_colors[pipe_color]
switch(state)
if("intact")
underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("exposed")
underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("down")
underlays_down["[D]" + pipe_colors[pipe_color]] = I
if("pipe_exposed")
pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("pipe_intact")
pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("intact-supply")
underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("exposed-supply")
underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("down-supply")
underlays_down["[D]" + pipe_colors[pipe_color]] = I
if("pipe_exposed-supply")
pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("pipe_intact-supply")
pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("intact-scrubbers")
underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("exposed-scrubbers")
underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("down-scrubbers")
underlays_down["[D]" + pipe_colors[pipe_color]] = I
if("pipe_exposed-scrubbers")
pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("pipe_intact-scrubbers")
pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I
*/
@@ -0,0 +1,457 @@
/*
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
/obj/machinery/atmospherics/var/last_power_draw = 0
/obj/machinery/portable_atmospherics/var/last_flow_rate = 0
/obj/machinery/atmospherics/var/debug = 0
/client/proc/atmos_toggle_debug(var/obj/machinery/atmospherics/M in range(world.view))
set name = "Toggle Debug Messages"
set category = "Debug"
M.debug = !M.debug
to_chat(usr, "[M]: Debug messages toggled [M.debug? "on" : "off"].")
//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.
/proc/pump_gas(var/obj/machinery/M, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null, var/available_power = null)
if (source.total_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing
return -1
if (isnull(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
if (!isnull(available_power) && specific_power > 0)
transfer_moles = min(transfer_moles, available_power / specific_power)
if (transfer_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update flow rate meter
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
if (A.debug)
A.visible_message("[A]: source entropy: [round(source.specific_entropy(), 0.01)] J/Kmol --> sink entropy: [round(sink.specific_entropy(), 0.01)] J/Kmol")
A.visible_message("[A]: specific entropy change = [round(sink.specific_entropy() - source.specific_entropy(), 0.01)] J/Kmol")
A.visible_message("[A]: specific power = [round(specific_power, 0.1)] W/mol")
A.visible_message("[A]: moles transferred = [transfer_moles] mol")
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.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 (!removed) //Just in case
return -1
var/power_draw = specific_power*transfer_moles
sink.merge(removed)
return power_draw
//Gas 'pumping' proc for the case where the gas flow is passive and driven entirely by pressure differences (but still one-way).
/proc/pump_gas_passive(var/obj/machinery/M, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null)
if (source.total_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing
return -1
if (isnull(transfer_moles))
transfer_moles = source.total_moles
else
transfer_moles = min(source.total_moles, transfer_moles)
var/equalize_moles = calculate_equalize_moles(source, sink)
transfer_moles = min(transfer_moles, equalize_moles)
if (transfer_moles < MINIMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update flow rate meter
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
if (A.debug)
A.visible_message("[A]: moles transferred = [transfer_moles] mol")
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.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(!removed) //Just in case
return -1
sink.merge(removed)
return 0
//Generalized gas scrubbing proc.
//Selectively moves specified gasses one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was filtered.
//filtering - A list of gasids to be scrubbed from source
//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.
/proc/scrub_gas(var/obj/machinery/M, 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 < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
//Determine the specific power of each filterable gas type, and the total amount of filterable gas (gasses selected to be scrubbed)
var/total_filterable_moles = 0 //the total amount of filterable gas
var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
for (var/g in filtering)
if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
continue
var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY
specific_power_gas[g] = specific_power
total_filterable_moles += source.gas[g]
if (total_filterable_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//now that we know the total amount of filterable gas, we can calculate the amount of power needed to scrub one mole of gas
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 //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas
total_specific_power += specific_power_gas[g]*ratio
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
total_transfer_moles = total_filterable_moles
else
total_transfer_moles = min(total_transfer_moles, total_filterable_moles)
//limit transfer_moles based on available power
if (!isnull(available_power) && total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update flow rate var
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
var/power_draw = 0
for (var/g in filtering)
var/transfer_moles = source.gas[g]
//filter gas in proportion to the mole ratio
transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles))
//use update=0. All the filtered gasses are supposed to be 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
//Remix the resulting gases
sink.update_values()
source.update_values()
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.
/proc/filter_gas(var/obj/machinery/M, 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 < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
var/total_specific_power = 0 //the power required to remove one mole of input gas
var/total_filterable_moles = 0 //the total amount of filterable gas
var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
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] < MINIMUM_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/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 (isnull(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 (!isnull(available_power) && total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update flow rate var
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.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 //power used to move filterable gas to sink_filtered
var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
for (var/g in removed.gas)
var/power_used = specific_power_gas[g]*removed.gas[g]
if (g in filtering)
//use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0)
removed.adjust_gas(g, -removed.gas[g], update=0)
filtered_power_used += power_used
else
unfiltered_power_used += power_used
sink_filtered.update_values()
removed.update_values()
sink_clean.merge(removed)
return filtered_power_used + unfiltered_power_used
//For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures.
//I don't like the copypasta, but I decided to keep both versions of gas filtering as filter_gas is slightly faster (doesn't create as many temporary lists, doesn't call update_values() as much)
//filter_gas can be removed and replaced with this proc if need be.
/proc/filter_gas_multi(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null)
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
var/total_specific_power = 0 //the power required to remove one mole of input gas
var/total_filterable_moles = 0 //the total amount of filterable gas
var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
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] < MINIMUM_MOLES_TO_FILTER)
continue
if (g in filtering)
var/datum/gas_mixture/sink_filtered = filtering[g]
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/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 (isnull(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 (!isnull(available_power) && total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update Flow Rate var
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.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/list/filtered_power_used = list() //power used to move filterable gas to the filtered gas mixes
var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
for (var/g in removed.gas)
var/power_used = specific_power_gas[g]*removed.gas[g]
if (g in filtering)
var/datum/gas_mixture/sink_filtered = filtering[g]
//use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=1)
removed.adjust_gas(g, -removed.gas[g], update=0)
if (power_used)
filtered_power_used[sink_filtered] = power_used
else
unfiltered_power_used += power_used
removed.update_values()
var/power_draw = unfiltered_power_used
for (var/datum/gas_mixture/sink_filtered in filtered_power_used)
power_draw += filtered_power_used[sink_filtered]
sink_clean.merge(removed)
return power_draw
//Similar deal as the other atmos process procs.
//mix_sources maps input gas mixtures to mix ratios. The mix ratios MUST add up to 1.
/proc/mix_gas(var/obj/machinery/M, var/list/mix_sources, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null)
if (!mix_sources.len)
return -1
var/total_specific_power = 0 //the power needed to mix one mole of gas
var/total_mixing_moles = null //the total amount of gas that can be mixed, given our mix ratios
var/total_input_volume = 0 //for flow rate calculation
var/total_input_moles = 0 //for flow rate calculation
var/list/source_specific_power = list()
for (var/datum/gas_mixture/source in mix_sources)
if (source.total_moles < MINIMUM_MOLES_TO_FILTER)
return -1 //either mix at the set ratios or mix no gas at all
var/mix_ratio = mix_sources[source]
if (!mix_ratio)
continue //this gas is not being mixed in
//mixing rate is limited by the source with the least amount of available gas
var/this_mixing_moles = source.total_moles/mix_ratio
if (isnull(total_mixing_moles) || total_mixing_moles > this_mixing_moles)
total_mixing_moles = this_mixing_moles
source_specific_power[source] = calculate_specific_power(source, sink)*mix_ratio/ATMOS_FILTER_EFFICIENCY
total_specific_power += source_specific_power[source]
total_input_volume += source.volume
total_input_moles += source.total_moles
if (total_mixing_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
if (isnull(total_transfer_moles))
total_transfer_moles = total_mixing_moles
else
total_transfer_moles = min(total_mixing_moles, total_transfer_moles)
//limit transfer_moles based on available power
if (!isnull(available_power) && total_specific_power > 0)
total_transfer_moles = min(total_transfer_moles, available_power / total_specific_power)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//Update flow rate var
if (istype(M, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/A = M
A.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here
if (istype(M, /obj/machinery/portable_atmospherics))
var/obj/machinery/portable_atmospherics/P = M
P.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here
var/total_power_draw = 0
for (var/datum/gas_mixture/source in mix_sources)
var/mix_ratio = mix_sources[source]
if (!mix_ratio)
continue
var/transfer_moles = total_transfer_moles * mix_ratio
var/datum/gas_mixture/removed = source.remove(transfer_moles)
var/power_draw = transfer_moles * source_specific_power[source]
total_power_draw += power_draw
sink.merge(removed)
return total_power_draw
/*
Helper procs for various things.
*/
//Calculates the amount of power needed to move one mole from source to sink.
/proc/calculate_specific_power(datum/gas_mixture/source, datum/gas_mixture/sink)
//Calculate the amount of energy required
var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature
var/specific_entropy = sink.specific_entropy() - source.specific_entropy() //sink is gaining moles, source is loosing
var/specific_power = 0 // W/mol
//If specific_entropy is < 0 then power is required to move gas
if (specific_entropy < 0)
specific_power = -specific_entropy*air_temperature //how much power we need per mole
return specific_power
//Calculates the amount of power needed to move one mole of a certain gas from source to sink.
/proc/calculate_specific_power_gas(var/gasid, datum/gas_mixture/source, datum/gas_mixture/sink)
//Calculate the amount of energy required
var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature
var/specific_entropy = sink.specific_entropy_gas(gasid) - source.specific_entropy_gas(gasid) //sink is gaining moles, source is loosing
var/specific_power = 0 // W/mol
//If specific_entropy is < 0 then power is required to move gas
if (specific_entropy < 0)
specific_power = -specific_entropy*air_temperature //how much power we need per mole
return specific_power
//Calculates the APPROXIMATE amount of moles that would need to be transferred to change the pressure of sink by pressure_delta
//If set, sink_volume_mod adjusts the effective output volume used in the calculation. This is useful when the output gas_mixture is
//part of a pipenetwork, and so it's volume isn't representative of the actual volume since the gas will be shared across the pipenetwork when it processes.
/proc/calculate_transfer_moles(datum/gas_mixture/source, datum/gas_mixture/sink, var/pressure_delta, var/sink_volume_mod=0)
if(source.temperature == 0 || source.total_moles == 0) return 0
var/output_volume = (sink.volume * sink.group_multiplier) + sink_volume_mod
var/source_total_moles = source.total_moles * source.group_multiplier
var/air_temperature = source.temperature
if(sink.total_moles > 0 && sink.temperature > 0)
//estimate the final temperature of the sink after transfer
var/estimate_moles = pressure_delta*output_volume/(sink.temperature * R_IDEAL_GAS_EQUATION)
var/sink_heat_capacity = sink.heat_capacity()
var/transfer_heat_capacity = source.heat_capacity()*estimate_moles/source_total_moles
air_temperature = (sink.temperature*sink_heat_capacity + source.temperature*transfer_heat_capacity) / (sink_heat_capacity + transfer_heat_capacity)
//get the number of moles that would have to be transfered to bring sink to the target pressure
return pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
//Calculates the APPROXIMATE amount of moles that would need to be transferred to bring source and sink to the same pressure
/proc/calculate_equalize_moles(datum/gas_mixture/source, datum/gas_mixture/sink)
if(source.temperature == 0) return 0
//Make the approximation that the sink temperature is unchanged after transferring gas
var/source_volume = source.volume * source.group_multiplier
var/sink_volume = sink.volume * sink.group_multiplier
var/source_pressure = source.return_pressure()
var/sink_pressure = sink.return_pressure()
return (source_pressure - sink_pressure)/(R_IDEAL_GAS_EQUATION * (source.temperature/source_volume + sink.temperature/sink_volume))
+138
View File
@@ -0,0 +1,138 @@
/*
Quick overview:
Pipes combine to form pipelines
Pipelines and other atmospheric objects combine to form pipe_networks
Note: A single pipe_network represents a completely open space
Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
*/
/obj/machinery/atmospherics
anchored = 1
idle_power_usage = 0
active_power_usage = 0
power_channel = ENVIRON
var/nodealert = 0
var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts
layer = 2.4 //under wires with their 2.44
var/connect_types = CONNECT_TYPE_REGULAR
var/icon_connect_type = "" //"-supply" or "-scrubbers"
var/initialize_directions = 0
var/pipe_color
var/global/datum/pipe_icon_manager/icon_manager
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
gfi_layer_rotation = GFI_ROTATION_OVERDIR
/obj/machinery/atmospherics/Initialize(mapload)
. = ..()
if(!icon_manager)
icon_manager = new()
if(!pipe_color)
pipe_color = color
color = null
if(!pipe_color_check(pipe_color))
pipe_color = null
if (mapload)
return INITIALIZE_HINT_LATELOAD
/obj/machinery/atmospherics/proc/atmos_init()
// atmos_init() and Initialize() must be separate, as atmos_init() can be called multiple times after the machine has been initialized.
/obj/machinery/atmospherics/LateInitialize()
atmos_init()
/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob)
if(istype(A, /obj/item/device/pipe_painter))
return FALSE
..()
/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type)
if(node)
if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
//underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
else
//underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
else
//underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
/obj/machinery/atmospherics/proc/update_underlays()
if(check_icon_cache())
return 1
else
return 0
obj/machinery/atmospherics/proc/check_connect_types(obj/machinery/atmospherics/atmos1, obj/machinery/atmospherics/atmos2)
return (atmos1.connect_types & atmos2.connect_types)
/obj/machinery/atmospherics/proc/check_connect_types_construction(obj/machinery/atmospherics/atmos1, obj/item/pipe/pipe2)
return (atmos1.connect_types & pipe2.connect_types)
/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
if(!istype(icon_manager))
if(!safety) //to prevent infinite loops
icon_manager = new()
check_icon_cache(1)
return 0
return 1
/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node)
//Don't use this for standard pipes
if(!istype(node))
return null
return node.pipe_color
/obj/machinery/atmospherics/process()
last_flow_rate = 0
last_power_draw = 0
build_network()
/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
// Check to see if should be added to network. Add self if so and adjust variables appropriately.
// Note don't forget to have neighbors look as well!
return null
/obj/machinery/atmospherics/proc/build_network()
// Called to build a network from this node
return null
/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference)
// Returns pipe_network associated with connection to reference
// Notes: should create network if necessary
// Should never return null
return null
/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
// Used when two pipe_networks are combining
/obj/machinery/atmospherics/proc/remove_network(datum/pipe_network/network)
reassign_network(network, null)
/obj/machinery/atmospherics/proc/return_network_air(datum/pipe_network/reference)
// Return a list of gas_mixture(s) in the object
// associated with reference pipe_network for use in rebuilding the networks gases list
// Is permitted to return null
/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/update_icon()
return null
@@ -0,0 +1,139 @@
/obj/machinery/atmospherics/binary
dir = SOUTH
initialize_directions = SOUTH|NORTH
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/datum/pipe_network/network1
var/datum/pipe_network/network2
/obj/machinery/atmospherics/binary/Initialize()
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
. = ..()
// Housekeeping and pipe network stuff below
/obj/machinery/atmospherics/binary/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
else if(reference == node2)
network2 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
/obj/machinery/atmospherics/binary/Destroy()
QDEL_NULL(air1)
QDEL_NULL(air2)
if(node1)
node1.disconnect(src)
QDEL_NULL(network1)
if(node2)
node2.disconnect(src)
QDEL_NULL(network2)
node1 = null
node2 = null
return ..()
/obj/machinery/atmospherics/binary/atmos_init()
if(node1 && node2) return
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))
if (check_connect_types(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))
if (check_connect_types(target,src))
node2 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/binary/build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
network1.build_network(node1, src)
if(!network2 && node2)
network2 = new /datum/pipe_network()
network2.normal_members += src
network2.build_network(node2, src)
/obj/machinery/atmospherics/binary/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network1
if(reference==node2)
return network2
return null
/obj/machinery/atmospherics/binary/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
network2 = new_network
return 1
/obj/machinery/atmospherics/binary/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
results += air1
if(network2 == reference)
results += air2
return results
/obj/machinery/atmospherics/binary/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null
else if(reference==node2)
qdel(network2)
node2 = null
update_icon()
update_underlays()
return null
/obj/machinery/atmospherics/binary/AltClick(var/mob/user)
if(!allowed(user))
to_chat(user, SPAN_WARNING("Access denied."))
return
Topic(src, list("power" = "1"))
@@ -0,0 +1,126 @@
//node1, air1, network1 correspond to input
//node2, air2, network2 correspond to output
/obj/machinery/atmospherics/binary/circulator
name = "circulator"
desc = "A gas circulator turbine and heat exchanger."
desc_info = "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
the center of the machine gives an indicator of how much elecrtricity is being generated."
icon = 'icons/obj/pipes.dmi'
icon_state = "circ-off"
anchored = FALSE
obj_flags = OBJ_FLAG_ROTATABLE
var/kinetic_efficiency = 0.04 //combined kinetic and kinetic-to-electric efficiency
var/volume_ratio = 0.2
var/recent_moles_transferred = 0
var/last_heat_capacity = 0
var/last_temperature = 0
var/last_pressure_delta = 0
var/last_worldtime_transfer = 0
var/last_stored_energy_transferred = 0
var/volume_capacity_used = 0
var/stored_energy = 0
density = TRUE
/obj/machinery/atmospherics/binary/circulator/Initialize()
. = ..()
desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
air1.volume = 400
/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air()
var/datum/gas_mixture/removed
if(anchored && !(stat&BROKEN) && network1)
var/input_starting_pressure = air1.return_pressure()
var/output_starting_pressure = air2.return_pressure()
last_pressure_delta = max(input_starting_pressure - output_starting_pressure - 5, 0)
//only circulate air if there is a pressure difference (plus 5kPa kinetic, 10kPa static friction)
if(air1.temperature > 0 && last_pressure_delta > 5)
//Calculate necessary moles to transfer using PV = nRT
recent_moles_transferred = (last_pressure_delta*network1.volume/(air1.temperature * R_IDEAL_GAS_EQUATION))/3 //uses the volume of the whole network, not just itself
volume_capacity_used = min( (last_pressure_delta*network1.volume/3)/(input_starting_pressure*air1.volume) , 1) //how much of the gas in the input air volume is consumed
//Calculate energy generated from kinetic turbine
stored_energy += 1/ADIABATIC_EXPONENT * min(last_pressure_delta * network1.volume , input_starting_pressure*air1.volume) * (1 - volume_ratio**ADIABATIC_EXPONENT) * kinetic_efficiency
//Actually transfer the gas
removed = air1.remove(recent_moles_transferred)
if(removed)
last_heat_capacity = removed.heat_capacity()
last_temperature = removed.temperature
//Update the gas networks.
network1.update = 1
last_worldtime_transfer = world.time
else
recent_moles_transferred = 0
update_icon()
return removed
/obj/machinery/atmospherics/binary/circulator/proc/return_stored_energy()
last_stored_energy_transferred = stored_energy
stored_energy = 0
return last_stored_energy_transferred
/obj/machinery/atmospherics/binary/circulator/process()
..()
if(last_worldtime_transfer < world.time - 50)
recent_moles_transferred = 0
update_icon()
/obj/machinery/atmospherics/binary/circulator/update_icon()
if(stat & (BROKEN|NOPOWER) || !anchored)
icon_state = "circ-p"
else if(last_pressure_delta > 0 && recent_moles_transferred > 0)
if(last_pressure_delta > 5*ONE_ATMOSPHERE)
icon_state = "circ-run"
else
icon_state = "circ-slow"
else
icon_state = "circ-off"
return 1
/obj/machinery/atmospherics/binary/circulator/attackby(obj/item/W as obj, mob/user as mob)
if (W.iswrench())
playsound(src.loc, W.usesound, 75, 1)
anchored = !anchored
user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \
"You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \
"You hear a ratchet")
if(anchored)
if(dir & (NORTH|SOUTH))
initialize_directions = NORTH|SOUTH
else if(dir & (EAST|WEST))
initialize_directions = EAST|WEST
atmos_init()
build_network()
if (node1)
node1.atmos_init()
node1.build_network()
if (node2)
node2.atmos_init()
node2.build_network()
else
if(node1)
node1.disconnect(src)
qdel(network1)
if(node2)
node2.disconnect(src)
qdel(network2)
node1 = null
node2 = null
return TRUE
else
..()
@@ -0,0 +1,271 @@
#define DEFAULT_PRESSURE_DELTA 10000
#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
#define INTERNAL_PRESSURE_BOUND 0
#define PRESSURE_CHECKS 1
#define PRESSURE_CHECK_EXTERNAL 1
#define PRESSURE_CHECK_INPUT 2
#define PRESSURE_CHECK_OUTPUT 4
/obj/machinery/atmospherics/binary/dp_vent_pump
icon = 'icons/atmos/vent_pump.dmi'
icon_state = "map_dp_vent"
//node2 is output port
//node1 is input port
name = "Dual Port Air Vent"
desc = "Has a valve and pump attached to it. There are two ports."
level = 1
use_power = POWER_USE_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER //connects to regular, supply and scrubbers pipes
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/input_pressure_min = INTERNAL_PRESSURE_BOUND
var/output_pressure_max = DEFAULT_PRESSURE_DELTA
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
var/pressure_checks = PRESSURE_CHECK_EXTERNAL
//1: Do not pass external_pressure_bound
//2: Do not pass input_pressure_min
//4: Do not pass output_pressure_max
var/broadcast_status_next_process = FALSE
/obj/machinery/atmospherics/binary/dp_vent_pump/Initialize()
. = ..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
icon = null
/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume
name = "Large Dual Port Air Vent"
/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/Initialize()
. = ..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0)
if(!check_icon_cache())
return
var/istate = ""
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
istate += "h"
if(!powered())
istate += "off"
else
istate += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
icon_state = istate
/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
return
else
if (node1)
add_underlay(T, node1, turn(dir, -180), node1.icon_connect_type)
else
add_underlay(T, node1, turn(dir, -180))
if (node2)
add_underlay(T, node2, dir, node2.icon_connect_type)
else
add_underlay(T, node2, dir)
/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i)
update_icon()
update_underlays()
/obj/machinery/atmospherics/binary/dp_vent_pump/process()
..()
last_power_draw = 0
last_flow_rate = 0
if(stat & (NOPOWER|BROKEN) || !use_power)
return 0
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
var/datum/gas_mixture/environment = loc.return_air()
var/power_draw = -1
//Figure out the target pressure difference
var/pressure_delta = get_pressure_delta(environment)
if(pressure_delta > 0.5)
if(pump_direction) //internal -> external
if (node1 && (environment.temperature || air1.temperature))
var/transfer_moles = calculate_transfer_moles(air1, environment, pressure_delta)
power_draw = pump_gas(src, air1, environment, transfer_moles, power_rating)
if(power_draw >= 0 && network1)
network1.update = 1
else //external -> internal
if (node2 && (environment.temperature || air2.temperature))
var/transfer_moles = calculate_transfer_moles(environment, air2, pressure_delta, (network2)? network2.volume : 0)
//limit flow rate from turfs
transfer_moles = min(transfer_moles, environment.total_moles*air2.volume/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air2, transfer_moles, power_rating)
if(power_draw >= 0 && network2)
network2.update = 1
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
return 1
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
var/pressure_delta = DEFAULT_PRESSURE_DELTA
var/environment_pressure = environment.return_pressure()
if(pump_direction) //internal -> external
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INPUT)
pressure_delta = min(pressure_delta, air1.return_pressure() - input_pressure_min) //decreasing the pressure here
else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
if(pressure_checks & PRESSURE_CHECK_OUTPUT)
pressure_delta = min(pressure_delta, output_pressure_max - air2.return_pressure()) //increasing the pressure here
return pressure_delta
//Radio remote control
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"tag" = id,
"device" = "ADVP",
"power" = use_power,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"input" = input_pressure_min,
"output" = output_pressure_max,
"external" = external_pressure_bound,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/binary/dp_vent_pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/binary/dp_vent_pump/examine(mob/user)
if(..(user, 1))
to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
/obj/machinery/atmospherics/unary/vent_pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"])
update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"])
update_use_power(!use_power)
if(signal.data["direction"])
pump_direction = text2num(signal.data["direction"])
if(signal.data["checks"])
pressure_checks = text2num(signal.data["checks"])
if(signal.data["purge"])
pressure_checks &= ~1
pump_direction = 0
if(signal.data["stabalize"])
pressure_checks |= 1
pump_direction = 1
if(signal.data["set_input_pressure"])
input_pressure_min = between(
0,
text2num(signal.data["set_input_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_output_pressure"])
output_pressure_max = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_external_pressure"])
external_pressure_bound = between(
0,
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["status"])
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
#undef DEFAULT_PRESSURE_DELTA
#undef EXTERNAL_PRESSURE_BOUND
#undef INTERNAL_PRESSURE_BOUND
#undef PRESSURE_CHECKS
#undef PRESSURE_CHECK_EXTERNAL
#undef PRESSURE_CHECK_INPUT
#undef PRESSURE_CHECK_OUTPUT
@@ -0,0 +1,300 @@
#define REGULATE_NONE 0
#define REGULATE_INPUT 1 //shuts off when input side is below the target pressure
#define REGULATE_OUTPUT 2 //shuts off when output side is above the target pressure
/obj/machinery/atmospherics/binary/passive_gate
name = "pressure regulator"
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
desc_info = "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing."
icon = 'icons/atmos/passive_gate.dmi'
icon_state = "map"
level = 1
use_power = POWER_USE_OFF
interact_offline = 1
var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards).
var/target_pressure = ONE_ATMOSPHERE
var/max_pressure_setting = ATMOS_PUMP_MAX_PRESSURE //kPa
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
var/regulate_mode = REGULATE_OUTPUT
var/flowing = 0 //for icons - becomes zero if the valve closes itself due to regulation mode
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
var/broadcast_status_next_process = FALSE
/obj/machinery/atmospherics/binary/passive_gate/on
unlocked = 1
/obj/machinery/atmospherics/binary/passive_gate/on/input
regulate_mode = REGULATE_INPUT
/obj/machinery/atmospherics/binary/passive_gate/on/output/max/Initialize()
. = ..()
target_pressure = max_pressure_setting
/obj/machinery/atmospherics/binary/passive_gate/on/input/max/Initialize()
. = ..()
target_pressure = max_pressure_setting
/obj/machinery/atmospherics/binary/passive_gate/scrubbers
name = "scrubbers pressure regulator"
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. This is one is for scrubber pipes."
icon_state = "map-scrubbers"
connect_types = CONNECT_TYPE_SCRUBBER
icon_connect_type = "-scrubbers"
unlocked = TRUE
target_pressure = 200
/obj/machinery/atmospherics/binary/passive_gate/supply
name = "supply pressure regulator"
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. This is one is for supply pipes."
icon_state = "map-supply"
connect_types = CONNECT_TYPE_SUPPLY
icon_connect_type = "-supply"
unlocked = TRUE
target_pressure = 200
/obj/machinery/atmospherics/binary/passive_gate/Initialize()
. = ..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
/obj/machinery/atmospherics/binary/passive_gate/update_icon()
icon_state = (unlocked && flowing)? "on" + icon_connect_type : "off" + icon_connect_type
/obj/machinery/atmospherics/binary/passive_gate/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, 180), icon_connect_type)
add_underlay(T, node2, dir, icon_connect_type)
/obj/machinery/atmospherics/binary/passive_gate/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/binary/passive_gate/process()
..()
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
last_flow_rate = 0
if(!unlocked)
return 0
var/output_starting_pressure = air2.return_pressure()
var/input_starting_pressure = air1.return_pressure()
var/pressure_delta
switch (regulate_mode)
if (REGULATE_INPUT)
pressure_delta = input_starting_pressure - target_pressure
if (REGULATE_OUTPUT)
pressure_delta = target_pressure - output_starting_pressure
//-1 if pump_gas() did not move any gas, >= 0 otherwise
var/returnval = -1
if((regulate_mode == REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures
flowing = 1
//flow rate limit
var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
//Figure out how much gas to transfer to meet the target pressure.
switch (regulate_mode)
if (REGULATE_INPUT)
transfer_moles = min(transfer_moles, air1.total_moles*(pressure_delta/input_starting_pressure))
if (REGULATE_OUTPUT)
transfer_moles = min(transfer_moles, calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0))
//pump_gas() will return a negative number if no flow occurred
returnval = pump_gas_passive(src, air1, air2, transfer_moles)
if (returnval >= 0)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
if (last_flow_rate)
flowing = 1
update_icon()
//Radio remote control
/obj/machinery/atmospherics/binary/passive_gate/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/passive_gate/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = unlocked,
"target_output" = target_pressure,
"regulate_mode" = regulate_mode,
"set_flow_rate" = set_flow_rate,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power" in signal.data)
unlocked = text2num(signal.data["power"])
if("power_toggle" in signal.data)
unlocked = !unlocked
if("set_target_pressure" in signal.data)
target_pressure = between(
0,
text2num(signal.data["set_target_pressure"]),
max_pressure_setting
)
if("set_regulate_mode" in signal.data)
regulate_mode = text2num(signal.data["set_regulate_mode"])
if("set_flow_rate" in signal.data)
regulate_mode = text2num(signal.data["set_flow_rate"])
if("status" in signal.data)
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
return
/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
usr.set_machine(src)
ui_interact(user)
return
/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
// this is the data which will be sent to the ui
var/data[0]
data = list(
"on" = unlocked,
"pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
"max_pressure" = max_pressure_setting,
"input_pressure" = round(air1.return_pressure()*100),
"output_pressure" = round(air2.return_pressure()*100),
"regulate_mode" = regulate_mode,
"set_flow_rate" = round(set_flow_rate*10),
"last_flow_rate" = round(last_flow_rate*10)
)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
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, "pressure_regulator.tmpl", name, 470, 370)
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
/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
if(..()) return 1
if(href_list["toggle_valve"])
unlocked = !unlocked
if(href_list["regulate_mode"])
switch(href_list["regulate_mode"])
if ("off") regulate_mode = REGULATE_NONE
if ("input") regulate_mode = REGULATE_INPUT
if ("output") regulate_mode = REGULATE_OUTPUT
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 = between(0, new_pressure, max_pressure_setting)
switch(href_list["set_flow_rate"])
if ("min")
set_flow_rate = 0
if ("max")
set_flow_rate = air1.volume
if ("set")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = between(0, new_flow_rate, air1.volume)
usr.set_machine(src) //Is this even needed with NanoUI?
src.update_icon()
src.add_fingerprint(usr)
return
/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
if (unlocked)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], turn it off first.</span>")
return TRUE
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
#undef REGULATE_NONE
#undef REGULATE_INPUT
#undef REGULATE_OUTPUT
@@ -0,0 +1,250 @@
/obj/machinery/atmospherics/pipeturbine
name = "turbine"
desc = "A gas turbine. Converting pressure into energy since 1884."
icon = 'icons/obj/pipeturbine.dmi'
icon_state = "turbine"
anchored = 0
density = 1
obj_flags = OBJ_FLAG_ROTATABLE
var/efficiency = 0.4
var/kin_energy = 0
var/datum/gas_mixture/air_in
var/datum/gas_mixture/air_out
var/volume_ratio = 0.2
var/kin_loss = 0.001
var/dP = 0
var/datum/pipe_network/network1
var/datum/pipe_network/network2
Initialize()
air_in = new
air_in.volume = 200
air_out = new
air_out.volume = 800
volume_ratio = air_in.volume / (air_in.volume + air_out.volume)
switch(dir)
if(NORTH)
initialize_directions = EAST|WEST
if(SOUTH)
initialize_directions = EAST|WEST
if(EAST)
initialize_directions = NORTH|SOUTH
if(WEST)
initialize_directions = NORTH|SOUTH
. = ..()
Destroy()
loc = null
if(node1)
node1.disconnect(src)
qdel(network1)
if(node2)
node2.disconnect(src)
qdel(network2)
node1 = null
node2 = null
return ..()
process()
..()
if(anchored && !(stat&BROKEN))
kin_energy *= 1 - kin_loss
dP = max(air_in.return_pressure() - air_out.return_pressure(), 0)
if(dP > 10)
kin_energy += 1/ADIABATIC_EXPONENT * dP * air_in.volume * (1 - volume_ratio**ADIABATIC_EXPONENT) * efficiency
air_in.temperature *= volume_ratio**ADIABATIC_EXPONENT
var/datum/gas_mixture/air_all = new
air_all.volume = air_in.volume + air_out.volume
air_all.merge(air_in.remove_ratio(1))
air_all.merge(air_out.remove_ratio(1))
air_in.merge(air_all.remove(volume_ratio))
air_out.merge(air_all)
update_icon()
if (network1)
network1.update = 1
if (network2)
network2.update = 1
update_icon()
cut_overlays()
if (dP > 10)
add_overlay("moto-turb")
if (kin_energy > 100000)
add_overlay("low-turb")
if (kin_energy > 500000)
add_overlay("med-turb")
if (kin_energy > 1000000)
add_overlay("hi-turb")
attackby(obj/item/W as obj, mob/user as mob)
if(W.iswrench())
anchored = !anchored
to_chat(user, "<span class='notice'>You [anchored ? "secure" : "unsecure"] the bolts holding \the [src] to the floor.</span>")
if(anchored)
if(dir & (NORTH|SOUTH))
initialize_directions = EAST|WEST
else if(dir & (EAST|WEST))
initialize_directions = NORTH|SOUTH
atmos_init()
build_network()
if (node1)
node1.atmos_init()
node1.build_network()
if (node2)
node2.atmos_init()
node2.build_network()
else
if(node1)
node1.disconnect(src)
qdel(network1)
if(node2)
node2.disconnect(src)
qdel(network2)
node1 = null
node2 = null
else
..()
//Goddamn copypaste from binary base class because atmospherics machinery API is not damn flexible
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
else if(reference == node2)
network2 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
atmos_init()
if(node1 && node2) return
var/node2_connect = turn(dir, -90)
var/node1_connect = turn(dir, 90)
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
build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
network1.build_network(node1, src)
if(!network2 && node2)
network2 = new /datum/pipe_network()
network2.normal_members += src
network2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network1
if(reference==node2)
return network2
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
network2 = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
results += air_in
if(network2 == reference)
results += air_out
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null
else if(reference==node2)
qdel(network2)
node2 = null
return null
/obj/machinery/power/turbinemotor
name = "motor"
desc = "Electrogenerator. Converts rotation into power."
icon = 'icons/obj/pipeturbine.dmi'
icon_state = "motor"
anchored = 0
density = 1
obj_flags = OBJ_FLAG_ROTATABLE
var/kin_to_el_ratio = 0.1 //How much kinetic energy will be taken from turbine and converted into electricity
var/obj/machinery/atmospherics/pipeturbine/turbine
Initialize()
..()
return INITIALIZE_HINT_LATELOAD
LateInitialize()
..()
updateConnection()
proc/updateConnection()
turbine = null
if(src.loc && anchored)
turbine = locate(/obj/machinery/atmospherics/pipeturbine) in get_step(src,dir)
if (turbine.stat & (BROKEN) || !turbine.anchored || turn(turbine.dir,180) != dir)
turbine = null
process()
updateConnection()
if(!turbine || !anchored || stat & (BROKEN))
return
var/power_generated = kin_to_el_ratio * turbine.kin_energy
turbine.kin_energy -= power_generated
add_avail(power_generated)
attackby(obj/item/W as obj, mob/user as mob)
if(W.iswrench())
anchored = !anchored
turbine = null
to_chat(user, "<span class='notice'>You [anchored ? "secure" : "unsecure"] the bolts holding \the [src] to the floor.</span>")
updateConnection()
else
..()
@@ -0,0 +1,244 @@
/*
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
name = "gas pump"
desc = "A pump."
desc_info = "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output."
icon = 'icons/atmos/pump.dmi'
icon_state = "map_off"
level = 1
var/target_pressure = ONE_ATMOSPHERE
//var/max_volume_transfer = 10000
use_power = POWER_USE_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP
var/max_pressure_setting = ATMOS_PUMP_MAX_PRESSURE //kPa
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
var/broadcast_status_next_process = FALSE
/obj/machinery/atmospherics/binary/pump/Initialize()
. = ..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
/obj/machinery/atmospherics/binary/pump/on
icon_state = "map_on"
use_power = POWER_USE_IDLE
/obj/machinery/atmospherics/binary/pump/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[use_power ? "on" : "off"]"
/obj/machinery/atmospherics/binary/pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
add_underlay(T, node2, dir)
/obj/machinery/atmospherics/binary/pump/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/binary/pump/process()
last_power_draw = 0
last_flow_rate = 0
if((stat & (NOPOWER|BROKEN)) || !use_power)
return
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
var/power_draw = -1
var/pressure_delta = target_pressure - air2.return_pressure()
if(pressure_delta > 0.01 && air1.temperature > 0)
//Figure out how much gas to transfer to meet the target pressure.
var/transfer_moles = calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0)
power_draw = pump_gas(src, air1, air2, transfer_moles, power_rating)
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
return 1
//Radio remote control
/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/pump/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = use_power,
"target_output" = target_pressure,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
// this is the data which will be sent to the ui
var/data[0]
data = list(
"on" = use_power,
"pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
"max_pressure" = max_pressure_setting,
"last_flow_rate" = round(last_flow_rate*10),
"last_power_draw" = round(last_power_draw),
"max_power_draw" = power_rating
)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
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
/obj/machinery/atmospherics/binary/pump/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"])
if(text2num(signal.data["power"]))
update_use_power(POWER_USE_IDLE)
else
update_use_power(POWER_USE_OFF)
if("power_toggle" in signal.data)
update_use_power(!use_power)
if(signal.data["set_output_pressure"])
target_pressure = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["status"])
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
usr.set_machine(src)
ui_interact(user)
return
/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
if(..()) return 1
if(href_list["power"])
update_use_power(!use_power)
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 = between(0, new_pressure, max_pressure_setting)
usr.set_machine(src)
src.add_fingerprint(usr)
src.update_icon()
/obj/machinery/atmospherics/binary/pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench() && !istype(W, /obj/item/pipewrench))
return ..()
if (!(stat & NOPOWER) && use_power)
to_chat(user, "<span class='warning'>You cannot unwrench this [src], turn it off first.</span>")
return TRUE
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 && !istype(W, /obj/item/pipewrench))
to_chat(user, "<span class='warning'>You cannot unwrench this [src], it's too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
else
to_chat(user, "<span class='warning'>You struggle to unwrench \the [src] with your pipe wrench.</span>")
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, istype(W, /obj/item/pipewrench) ? 80/W.toolspeed : 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
@@ -0,0 +1,19 @@
/obj/machinery/atmospherics/binary/pump/high_power
icon = 'icons/atmos/volume_pump.dmi'
icon_state = "map_off"
level = 1
name = "high power gas pump"
desc = "A pump. Has double the power rating of the standard gas pump."
power_rating = 15000 //15000 W ~ 20 HP
/obj/machinery/atmospherics/binary/pump/high_power/on
use_power = POWER_USE_IDLE
icon_state = "map_on"
/obj/machinery/atmospherics/binary/pump/high_power/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[use_power ? "on" : "off"]"
@@ -0,0 +1,111 @@
//--------------------------------------------
// Omni device port types
//--------------------------------------------
#define ATM_NONE 0
#define ATM_INPUT 1
#define ATM_OUTPUT 2
#define ATM_O2 3
#define ATM_N2 4
#define ATM_CO2 5
#define ATM_P 6 //Phoron
#define ATM_N2O 7
#define ATM_H2 8 //Hydrogen
//--------------------------------------------
// Omni port datum
//
// Used by omni devices to manage connections
// to other atmospheric objects.
//--------------------------------------------
/datum/omni_port
var/obj/machinery/atmospherics/omni/master
var/dir
var/update = 1
var/mode = 0
var/concentration = 0
var/con_lock = 0
var/transfer_moles = 0
var/datum/gas_mixture/air
var/obj/machinery/atmospherics/node
var/datum/pipe_network/network
/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH)
..()
dir = direction
if(istype(M))
master = M
air = new
air.volume = 200
/datum/omni_port/proc/connect()
if(node)
return
master.atmos_init()
master.build_network()
if(node)
node.atmos_init()
node.build_network()
/datum/omni_port/proc/disconnect()
if(node)
node.disconnect(master)
master.disconnect(node)
//--------------------------------------------
// Need to find somewhere else for these
//--------------------------------------------
//returns a text string based on the direction flag input
// if capitalize is true, it will return the string capitalized
// otherwise it will return the direction string in lower case
/proc/dir_name(var/dir, var/capitalize = 0)
var/string = null
switch(dir)
if(NORTH)
string = "North"
if(SOUTH)
string = "South"
if(EAST)
string = "East"
if(WEST)
string = "West"
if(!capitalize && string)
string = lowertext(string)
return string
//returns a direction flag based on the string passed to it
// case insensitive
/proc/dir_flag(var/dir)
dir = lowertext(dir)
switch(dir)
if("north")
return NORTH
if("south")
return SOUTH
if("east")
return EAST
if("west")
return WEST
else
return FALSE
/proc/mode_to_gasid(var/mode)
switch(mode)
if(ATM_O2)
return GAS_OXYGEN
if(ATM_N2)
return GAS_NITROGEN
if(ATM_CO2)
return GAS_CO2
if(ATM_P)
return GAS_PHORON
if(ATM_N2O)
return GAS_N2O
if(ATM_H2)
return GAS_HYDROGEN
else
return null
@@ -0,0 +1,270 @@
//--------------------------------------------
// Gas filter - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/filter
name = "omni gas filter"
icon_state = "map_filter"
base_icon = "filter"
desc_info = "Filters gas from a custom input direction, with up to two filtered outputs and a 'everything else' \
output. The filtered output's arrows glow orange."
var/list/active_filters = new()
var/datum/omni_port/input
var/datum/omni_port/output
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP
var/max_flow_rate = 200
var/set_flow_rate = 200
var/list/filtering_outputs = list() //maps gasids to gas_mixtures
/obj/machinery/atmospherics/omni/filter/Initialize()
. = ..()
rebuild_filtering_list()
for(var/datum/omni_port/P in ports)
P.air.volume = ATMOS_DEFAULT_VOLUME_FILTER
/obj/machinery/atmospherics/omni/filter/Destroy()
input = null
output = null
active_filters.Cut()
return ..()
/obj/machinery/atmospherics/omni/filter/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(input == P)
input = null
if(active_filters.Find(P))
active_filters -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
input = P
if(ATM_OUTPUT)
output = P
if(ATM_O2 to ATM_H2)
active_filters += P
/obj/machinery/atmospherics/omni/filter/error_check()
if(!input || !output || !active_filters)
return 1
if(active_filters.len < 1) //requires at least 1 filter ~otherwise why are you using a filter?
return 1
return 0
/obj/machinery/atmospherics/omni/filter/process()
if(!..())
return 0
var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference
var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug*
//Figure out the amount of moles to transfer
var/transfer_moles = (set_flow_rate/input_air.volume)*input_air.total_moles
var/power_draw = -1
if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
power_draw = filter_gas_multi(src, filtering_outputs, input_air, output_air, transfer_moles, power_rating)
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
if(input.network)
input.network.update = 1
if(output.network)
output.network.update = 1
for(var/datum/omni_port/P in active_filters)
if(P.network)
P.network.update = 1
return 1
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
user.set_machine(src)
var/list/data = new()
data = build_uidata()
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
ui.set_initial_data(data)
ui.open()
/obj/machinery/atmospherics/omni/filter/proc/build_uidata()
var/list/data = new()
data["power"] = use_power
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
var/filter = 1
var/f_type = null
switch(P.mode)
if(ATM_INPUT)
input = 1
filter = 0
if(ATM_OUTPUT)
output = 1
filter = 0
if(ATM_O2 to ATM_H2)
f_type = mode_send_switch(P.mode)
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"input" = input, \
"output" = output, \
"filter" = filter, \
"f_type" = f_type)
if(portData.len)
data["ports"] = portData
if(output)
data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals.
data["last_flow_rate"] = round(last_flow_rate*10)
return data
/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE)
switch(mode)
if(ATM_O2)
return "Oxygen"
if(ATM_N2)
return "Nitrogen"
if(ATM_CO2)
return "Carbon Dioxide"
if(ATM_P)
return "Phoron" //*cough* Plasma *cough*
if(ATM_N2O)
return "Nitrous Oxide"
if(ATM_H2)
return "Hydrogen"
else
return null
/obj/machinery/atmospherics/omni/filter/Topic(href, href_list)
if(..()) return 1
switch(href_list["command"])
if("power")
if(!configuring)
update_use_power(!use_power)
else
update_use_power(POWER_USE_OFF)
if("configure")
configuring = !configuring
if(configuring)
update_use_power(POWER_USE_OFF)
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !use_power)
switch(href_list["command"])
if("set_flow_rate")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"]))
if("switch_filter")
var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide", "Hydrogen")
switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode)
switch(mode)
if("Oxygen")
return ATM_O2
if("Nitrogen")
return ATM_N2
if("Carbon Dioxide")
return ATM_CO2
if("Phoron")
return ATM_P
if("Nitrous Oxide")
return ATM_N2O
if("Hydrogen")
return ATM_H2
if("in")
return ATM_INPUT
if("out")
return ATM_OUTPUT
if("None")
return ATM_NONE
else
return null
/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode)
//check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file
for(var/datum/omni_port/P in ports)
if(P.dir == dir)
if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT)
return
switch_mode(dir, mode)
/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode)
if(mode == null || !port)
return
var/datum/omni_port/target_port = null
var/list/other_ports = new()
for(var/datum/omni_port/P in ports)
if(P.dir == port)
target_port = P
else
other_ports += P
var/previous_mode = null
if(target_port)
previous_mode = target_port.mode
target_port.mode = mode
if(target_port.mode != previous_mode)
handle_port_change(target_port)
rebuild_filtering_list()
else
return
else
return
for(var/datum/omni_port/P in other_ports)
if(P.mode == mode)
var/old_mode = P.mode
P.mode = previous_mode
if(P.mode != old_mode)
handle_port_change(P)
update_ports()
/obj/machinery/atmospherics/omni/filter/proc/rebuild_filtering_list()
filtering_outputs.Cut()
for(var/datum/omni_port/P in ports)
var/gasid = mode_to_gasid(P.mode)
if(gasid)
filtering_outputs[gasid] = P.air
/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
@@ -0,0 +1,298 @@
//--------------------------------------------
// Gas mixer - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/mixer
name = "omni gas mixer"
icon_state = "map_mixer"
base_icon = "mixer"
desc_info = "Combines gas from custom input and output directions. The percentage of combined gas can be defined."
use_power = POWER_USE_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 3700 //3700 W ~ 5 HP
var/list/inputs = new()
var/datum/omni_port/output
//setup tags for initial concentration values (must be decimal)
var/tag_north_con
var/tag_south_con
var/tag_east_con
var/tag_west_con
var/max_flow_rate = 200
var/set_flow_rate = 200
var/list/mixing_inputs = list()
/obj/machinery/atmospherics/omni/mixer/Initialize()
. = ..()
if(mapper_set())
var/con = 0
for(var/datum/omni_port/P in ports)
switch(P.dir)
if(NORTH)
if(tag_north_con && tag_north == 1)
P.concentration = tag_north_con
con += max(0, tag_north_con)
if(SOUTH)
if(tag_south_con && tag_south == 1)
P.concentration = tag_south_con
con += max(0, tag_south_con)
if(EAST)
if(tag_east_con && tag_east == 1)
P.concentration = tag_east_con
con += max(0, tag_east_con)
if(WEST)
if(tag_west_con && tag_west == 1)
P.concentration = tag_west_con
con += max(0, tag_west_con)
for(var/datum/omni_port/P in ports)
P.air.volume = ATMOS_DEFAULT_VOLUME_MIXER
/obj/machinery/atmospherics/omni/mixer/Destroy()
inputs.Cut()
output = null
return ..()
/obj/machinery/atmospherics/omni/mixer/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(inputs.Find(P))
inputs -= P
switch(P.mode)
if(ATM_INPUT)
inputs += P
if(ATM_OUTPUT)
output = P
if(!mapper_set())
for(var/datum/omni_port/P in inputs)
P.concentration = 1 / max(1, inputs.len)
if(output)
output.air.volume = ATMOS_DEFAULT_VOLUME_MIXER * 0.75 * inputs.len
output.concentration = 1
rebuild_mixing_inputs()
/obj/machinery/atmospherics/omni/mixer/proc/mapper_set()
return (tag_north_con || tag_south_con || tag_east_con || tag_west_con)
/obj/machinery/atmospherics/omni/mixer/error_check()
if(!output || !inputs)
return 1
if(inputs.len < 2) //requires at least 2 inputs ~otherwise why are you using a mixer?
return 1
//concentration must add to 1
var/total = 0
for (var/datum/omni_port/P in inputs)
total += P.concentration
if (total != 1)
return 1
return 0
/obj/machinery/atmospherics/omni/mixer/process()
if(!..())
return 0
//Figure out the amount of moles to transfer
var/transfer_moles = 0
for (var/datum/omni_port/P in inputs)
transfer_moles += (set_flow_rate*P.concentration/P.air.volume)*P.air.total_moles
var/power_draw = -1
if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
power_draw = mix_gas(src, mixing_inputs, output.air, transfer_moles, power_rating)
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
for(var/datum/omni_port/P in inputs)
if(P.concentration && P.network)
P.network.update = 1
if(output.network)
output.network.update = 1
return 1
/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
usr.set_machine(src)
var/list/data = new()
data = build_uidata()
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
ui.set_initial_data(data)
ui.open()
/obj/machinery/atmospherics/omni/mixer/proc/build_uidata()
var/list/data = new()
data["power"] = use_power
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
switch(P.mode)
if(ATM_INPUT)
input = 1
if(ATM_OUTPUT)
output = 1
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"concentration" = P.concentration, \
"input" = input, \
"output" = output, \
"con_lock" = P.con_lock)
if(portData.len)
data["ports"] = portData
if(output)
data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals.
data["last_flow_rate"] = round(last_flow_rate*10)
return data
/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list)
if(..()) return 1
switch(href_list["command"])
if("power")
if(!configuring)
update_use_power(!use_power)
else
update_use_power(POWER_USE_OFF)
if("configure")
configuring = !configuring
if(configuring)
update_use_power(POWER_USE_OFF)
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !use_power)
switch(href_list["command"])
if("set_flow_rate")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), href_list["mode"])
if("switch_con")
change_concentration(dir_flag(href_list["dir"]))
if("switch_conlock")
con_lock(dir_flag(href_list["dir"]))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE)
if(mode != ATM_INPUT && mode != ATM_OUTPUT)
switch(mode)
if("in")
mode = ATM_INPUT
if("out")
mode = ATM_OUTPUT
else
mode = ATM_NONE
for(var/datum/omni_port/P in ports)
var/old_mode = P.mode
if(P.dir == port)
switch(mode)
if(ATM_INPUT)
if(P.mode == ATM_OUTPUT)
return
P.mode = mode
if(ATM_OUTPUT)
P.mode = mode
if(ATM_NONE)
if(P.mode == ATM_OUTPUT)
return
if(P.mode == ATM_INPUT && inputs.len > 2)
P.mode = mode
else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT)
P.mode = ATM_INPUT
if(P.mode != old_mode)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
update_ports()
rebuild_mixing_inputs()
/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
var/old_con = 0
var/non_locked = 0
var/remain_con = 1
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
old_con = P.concentration
else if(!P.con_lock)
non_locked++
else
remain_con -= P.concentration
//return if no adjustable ports
if(non_locked < 1)
return
var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100
//cap it between 0 and the max remaining concentration
new_con = between(0, new_con, remain_con)
//new_con = min(remain_con, new_con)
//clamp remaining concentration so we don't go into negatives
remain_con = max(0, remain_con - new_con)
//distribute remaining concentration between unlocked ports evenly
remain_con /= max(1, non_locked)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.concentration = new_con
else if(!P.con_lock)
P.concentration = remain_con
rebuild_mixing_inputs()
/obj/machinery/atmospherics/omni/mixer/proc/rebuild_mixing_inputs()
mixing_inputs.Cut()
for(var/datum/omni_port/P in inputs)
mixing_inputs[P.air] = P.concentration
/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.con_lock = !P.con_lock
@@ -0,0 +1,286 @@
//--------------------------------------------
// Base omni device
//--------------------------------------------
/obj/machinery/atmospherics/omni
name = "omni device"
icon = 'icons/atmos/omni_devices.dmi'
icon_state = "base"
initialize_directions = 0
level = 1
var/configuring = 0
//var/target_pressure = ONE_ATMOSPHERE //a base type as abstract as this should NOT be making these kinds of assumptions
var/base_icon
var/tag_north = ATM_NONE
var/tag_south = ATM_NONE
var/tag_east = ATM_NONE
var/tag_west = ATM_NONE
var/list/on_states = list()
var/list/off_states = list()
var/underlays_current[4]
var/list/ports = new()
/obj/machinery/atmospherics/omni/Initialize()
icon_state = "base"
ports = new()
for(var/d in cardinal)
var/datum/omni_port/new_port = new(src, d)
switch(d)
if(NORTH)
new_port.mode = tag_north
if(SOUTH)
new_port.mode = tag_south
if(EAST)
new_port.mode = tag_east
if(WEST)
new_port.mode = tag_west
if(new_port.mode > 0)
initialize_directions |= d
ports += new_port
. = ..()
/obj/machinery/atmospherics/omni/update_icon()
cut_overlays()
var/list/to_add = list(base_icon)
if(stat & NOPOWER)
to_add += off_states
else if(error_check())
to_add += "error"
else if (use_power)
to_add[1] = "[base_icon]_glow"
to_add += on_states
else
to_add += off_states
add_overlay(to_add)
underlays = underlays_current
/obj/machinery/atmospherics/omni/proc/error_check()
return
/obj/machinery/atmospherics/omni/process()
last_power_draw = 0
last_flow_rate = 0
if(error_check())
update_use_power(POWER_USE_OFF)
if((stat & (NOPOWER|BROKEN)) || !use_power)
return 0
return 1
/obj/machinery/atmospherics/omni/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/omni/attackby(var/obj/item/W as obj, var/mob/user as mob)
if(!W.iswrench())
return ..()
var/int_pressure = 0
for(var/datum/omni_port/P in ports)
int_pressure += P.air.return_pressure()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it is too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
playsound(src.loc, W.usesound, 50, 1)
if(do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/omni/attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
ui_interact(user)
return
/obj/machinery/atmospherics/omni/proc/update_port_icons()
if(!check_icon_cache())
return
on_states.Cut()
off_states.Cut()
for(var/datum/omni_port/P in ports)
var/ref_layer = 0
switch(P.dir)
if(NORTH)
ref_layer = 1
if(SOUTH)
ref_layer = 2
if(EAST)
ref_layer = 3
if(WEST)
ref_layer = 4
if(!ref_layer)
continue
var/list/underlay_icon = select_port_icons(P)
if(underlay_icon)
if(P.node)
underlays_current[ref_layer] = underlay_icon
else
underlays_current[ref_layer] = null
else
underlays_current[ref_layer] = null
update_icon()
// Assumes on_states and off_states have been cut if required.
/obj/machinery/atmospherics/omni/proc/select_port_icons(datum/omni_port/P)
if(!istype(P))
return
if(P.mode > 0)
var/ic_dir = dir_name(P.dir)
var/ic_on = ic_dir
var/ic_off = ic_dir
switch(P.mode)
if(ATM_INPUT)
ic_on += "_in_glow"
ic_off += "_in"
if(ATM_OUTPUT)
ic_on += "_out_glow"
ic_off += "_out"
if(ATM_O2 to ATM_H2)
ic_on += "_filter"
ic_off += "_out"
on_states += ic_on
off_states += ic_off
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
. = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
else
. = icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
/obj/machinery/atmospherics/omni/update_underlays()
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/omni/proc/update_ports()
sort_ports()
update_port_icons()
for(var/datum/omni_port/P in ports)
P.update = 0
/obj/machinery/atmospherics/omni/proc/sort_ports()
return
// Housekeeping and pipe network stuff below
/obj/machinery/atmospherics/omni/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
for(var/datum/omni_port/P in ports)
if(reference == P.node)
P.network = new_network
break
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
/obj/machinery/atmospherics/omni/Destroy()
loc = null
for(var/datum/omni_port/P in ports)
if(P.node)
P.node.disconnect(src)
qdel(P.network)
P.node = null
return ..()
/obj/machinery/atmospherics/omni/atmos_init()
for(var/datum/omni_port/P in ports)
if(P.node || P.mode == 0)
continue
for(var/obj/machinery/atmospherics/target in get_step(src, P.dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
P.node = target
break
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/build_network()
for(var/datum/omni_port/P in ports)
if(!P.network && P.node)
P.network = new /datum/pipe_network()
P.network.normal_members += src
P.network.build_network(P.node, src)
/obj/machinery/atmospherics/omni/return_network(obj/machinery/atmospherics/reference)
build_network()
for(var/datum/omni_port/P in ports)
if(reference == P.node)
return P.network
return null
/obj/machinery/atmospherics/omni/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
for(var/datum/omni_port/P in ports)
if(P.network == old_network)
P.network = new_network
return 1
/obj/machinery/atmospherics/omni/return_network_air(datum/pipe_network/reference)
var/list/results = list()
for(var/datum/omni_port/P in ports)
if(P.network == reference)
results += P.air
return results
/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference)
for(var/datum/omni_port/P in ports)
if(reference == P.node)
qdel(P.network)
P.node = null
P.update = 1
break
update_ports()
return null
/obj/machinery/atmospherics/omni/AltClick(var/mob/user)
if(!allowed(user))
to_chat(user, SPAN_WARNING("Access denied."))
return
Topic(src, list("power" = "1"))
@@ -0,0 +1,156 @@
/obj/machinery/atmospherics/portables_connector
icon = 'icons/atmos/connector.dmi'
icon_state = "map_connector"
name = "Connector Port"
desc = "For connecting portables devices related to atmospherics control."
dir = SOUTH
initialize_directions = SOUTH
var/obj/machinery/portable_atmospherics/connected_device
var/obj/machinery/atmospherics/node
var/datum/pipe_network/network
var/on = 0
use_power = POWER_USE_OFF
level = 1
/obj/machinery/atmospherics/portables_connector/Initialize()
initialize_directions = dir
. = ..()
/obj/machinery/atmospherics/portables_connector/update_icon()
icon_state = "connector"
/obj/machinery/atmospherics/portables_connector/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node, dir)
/obj/machinery/atmospherics/portables_connector/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/portables_connector/process()
..()
if(!on)
return
if(!connected_device)
on = 0
return
if(network)
network.update = 1
return 1
// Housekeeping and pipe network stuff below
/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
/obj/machinery/atmospherics/portables_connector/Destroy()
loc = null
if(connected_device)
connected_device.disconnect()
if(node)
node.disconnect(src)
qdel(network)
node = null
return ..()
/obj/machinery/atmospherics/portables_connector/atmos_init()
if(node) return
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/portables_connector/build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
return network
if(reference==connected_device)
return network
return null
/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(connected_device)
results += connected_device.air_contents
return results
/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
qdel(network)
node = null
update_underlays()
return null
/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
if (connected_device)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], dettach \the [connected_device] first.</span>")
return TRUE
if (locate(/obj/machinery/portable_atmospherics, src.loc))
return TRUE
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
@@ -0,0 +1,286 @@
/obj/machinery/atmospherics/trinary/filter
icon = 'icons/atmos/filter.dmi'
icon_state = "map"
density = 0
level = 1
name = "Gas filter"
use_power = POWER_USE_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP
var/temp = null // -- TLE
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER
/*
Filter types:
-1: Nothing
0: Phoron: Phoron, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen ONLY
3: Carbon Dioxide: Carbon Dioxide ONLY
4: Sleeping Agent (N2O)
5: Hydrogen (H2)
*/
var/filter_type = -1
var/list/filtered_out = list()
var/frequency = 0
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/trinary/filter/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/trinary/filter/Initialize()
. = ..()
switch(filter_type)
if(0) //removing hydrocarbons
filtered_out = list(GAS_PHORON)
if(1) //removing O2
filtered_out = list(GAS_OXYGEN)
if(2) //removing N2
filtered_out = list(GAS_NITROGEN)
if(3) //removing CO2
filtered_out = list(GAS_CO2)
if(4)//removing N2O
filtered_out = list(GAS_N2O)
if(5)//removing H2
filtered_out = list(GAS_HYDROGEN)
air1.volume = ATMOS_DEFAULT_VOLUME_FILTER
air2.volume = ATMOS_DEFAULT_VOLUME_FILTER
air3.volume = ATMOS_DEFAULT_VOLUME_FILTER
/obj/machinery/atmospherics/trinary/filter/update_icon()
if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
icon_state = "m"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += use_power ? "on" : "off"
else
icon_state += "off"
update_use_power(POWER_USE_OFF)
/obj/machinery/atmospherics/trinary/filter/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
add_underlay(T, node2, turn(dir, 90))
else
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/trinary/filter/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/trinary/filter/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/filter/process()
..()
last_power_draw = 0
last_flow_rate = 0
if((stat & (NOPOWER|BROKEN)) || !use_power)
return
//Figure out the amount of moles to transfer
var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
var/power_draw = -1
if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
power_draw = filter_gas(src, filtered_out, air1, air2, air3, transfer_moles, power_rating)
if(network2)
network2.update = 1
if(network3)
network3.update = 1
if(network1)
network1.update = 1
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
return 1
/obj/machinery/atmospherics/trinary/filter/atmos_init()
set_frequency(frequency)
..()
/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
if(..())
return
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
var/dat
var/current_filter_type
switch(filter_type)
if(0)
current_filter_type = "Phoron"
if(1)
current_filter_type = "Oxygen"
if(2)
current_filter_type = "Nitrogen"
if(3)
current_filter_type = "Carbon Dioxide"
if(4)
current_filter_type = "Nitrous Oxide"
if(5)
current_filter_type = "Hydrogen"
if(-1)
current_filter_type = "Nothing"
else
current_filter_type = "ERROR - Report this bug to the admin, please!"
dat += {"
<b>Power: </b><a href='?src=\ref[src];power=1'>[use_power?"On":"Off"]</a><br>
<b>Filtering: </b>[current_filter_type]<br><HR>
<h4>Set Filter Type:</h4>
<A href='?src=\ref[src];filterset=0'>Phoron</A><BR>
<A href='?src=\ref[src];filterset=1'>Oxygen</A><BR>
<A href='?src=\ref[src];filterset=2'>Nitrogen</A><BR>
<A href='?src=\ref[src];filterset=3'>Carbon Dioxide</A><BR>
<A href='?src=\ref[src];filterset=4'>Nitrous Oxide</A><BR>
<A href='?src=\ref[src];filterset=5'>Hydrogen</A><BR>
<A href='?src=\ref[src];filterset=-1'>Nothing</A><BR>
<HR>
<B>Set Flow Rate Limit:</B>
[src.set_flow_rate]L/s | <a href='?src=\ref[src];set_flow_rate=1'>Change</a><BR>
<B>Flow rate: </B>[round(last_flow_rate, 0.1)]L/s
"}
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_filter")
onclose(user, "atmo_filter")
return
/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
if(..())
return 1
usr.set_machine(src)
src.add_fingerprint(usr)
if(href_list["filterset"])
filter_type = text2num(href_list["filterset"])
filtered_out.Cut() //no need to create new lists unnecessarily
switch(filter_type)
if(0) //removing hydrocarbons
filtered_out += GAS_PHORON
if(1) //removing O2
filtered_out += GAS_OXYGEN
if(2) //removing N2
filtered_out += GAS_NITROGEN
if(3) //removing CO2
filtered_out += GAS_CO2
if(4)//removing N2O
filtered_out += GAS_N2O
if(5)//removing H2
filtered_out += GAS_HYDROGEN
if (href_list["temp"])
src.temp = null
if(href_list["set_flow_rate"])
var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = max(0, min(air1.volume, new_flow_rate))
if(href_list["power"])
update_use_power(!use_power)
src.update_icon()
src.updateUsrDialog()
/*
for(var/mob/M in viewers(1, src))
if ((M.client && M.machine == src))
src.attack_hand(M)
*/
return
/obj/machinery/atmospherics/trinary/filter/m_filter
icon_state = "mmap"
dir = SOUTH
initialize_directions = SOUTH|NORTH|EAST
obj/machinery/atmospherics/trinary/filter/m_filter/Initialize()
switch(dir)
if(NORTH)
initialize_directions = WEST|NORTH|SOUTH
if(SOUTH)
initialize_directions = SOUTH|EAST|NORTH
if(EAST)
initialize_directions = EAST|WEST|NORTH
if(WEST)
initialize_directions = WEST|SOUTH|EAST
. = ..()
/obj/machinery/atmospherics/trinary/filter/m_filter/atmos_init()
set_frequency(frequency)
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, 90)
var/node3_connect = dir
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()
@@ -0,0 +1,277 @@
/obj/machinery/atmospherics/trinary/mixer
icon = 'icons/atmos/mixer.dmi'
icon_state = "map"
density = 0
level = 1
name = "Gas mixer"
use_power = POWER_USE_IDLE
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER
var/list/mixing_inputs
//for mapping
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/update_icon(var/safety = 0)
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer))
icon_state = "m"
else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
icon_state = "t"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += use_power ? "on" : "off"
else
icon_state += "off"
update_use_power(POWER_USE_OFF)
/obj/machinery/atmospherics/trinary/mixer/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
add_underlay(T, node1, turn(dir, -90))
else
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
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/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/trinary/mixer/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/mixer/Initialize()
. = ..()
air1.volume = ATMOS_DEFAULT_VOLUME_MIXER
air2.volume = ATMOS_DEFAULT_VOLUME_MIXER
air3.volume = ATMOS_DEFAULT_VOLUME_MIXER * 1.5
if (!mixing_inputs)
mixing_inputs = list(src.air1 = node1_concentration, src.air2 = node2_concentration)
/obj/machinery/atmospherics/trinary/mixer/process()
..()
last_power_draw = 0
last_flow_rate = 0
if((stat & (NOPOWER|BROKEN)) || !use_power)
return
//Figure out the amount of moles to transfer
var/transfer_moles = (set_flow_rate*mixing_inputs[air1]/air1.volume)*air1.total_moles + (set_flow_rate*mixing_inputs[air1]/air2.volume)*air2.total_moles
var/power_draw = -1
if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
power_draw = mix_gas(src, mixing_inputs, air3, transfer_moles, power_rating)
if(network1 && mixing_inputs[air1])
network1.update = 1
if(network2 && mixing_inputs[air2])
network2.update = 1
if(network3)
network3.update = 1
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
return 1
/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
usr.set_machine(src)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[use_power?"On":"Off"]</a><br>
<b>Set Flow Rate Limit: </b>
[set_flow_rate]L/s | <a href='?src=\ref[src];set_press=1'>Change</a>
<br>
<b>Flow Rate: </b>[round(last_flow_rate, 0.1)]L/s
<br><hr>
<b>Node 1 Concentration:</b>
<a href='?src=\ref[src];node1_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node1_c=-0.01'>-</a>
[mixing_inputs[air1]]([mixing_inputs[air1]*100]%)
<a href='?src=\ref[src];node1_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node1_c=0.1'>+</a>
<br>
<b>Node 2 Concentration:</b>
<a href='?src=\ref[src];node2_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node2_c=-0.01'>-</a>
[mixing_inputs[air2]]([mixing_inputs[air2]*100]%)
<a href='?src=\ref[src];node2_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node2_c=0.1'>+</a>
"}
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_mixer")
onclose(user, "atmo_mixer")
return
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
if(..()) return 1
if(href_list["power"])
update_use_power(!use_power)
if(href_list["set_press"])
var/max_flow_rate = min(air1.volume, air2.volume)
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate))
if(href_list["node1_c"])
var/value = text2num(href_list["node1_c"])
src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value))
src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1]
if(href_list["node2_c"])
var/value = text2num(href_list["node2_c"])
src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value))
src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2]
src.update_icon()
src.updateUsrDialog()
return
obj/machinery/atmospherics/trinary/mixer/t_mixer
icon_state = "tmap"
dir = SOUTH
initialize_directions = SOUTH|EAST|WEST
//node 3 is the outlet, nodes 1 & 2 are intakes
obj/machinery/atmospherics/trinary/mixer/t_mixer/north
icon_state = "tmap"
dir = NORTH
initialize_directions = NORTH|EAST|WEST
//node 3 is the outlet, nodes 1 & 2 are intakes
obj/machinery/atmospherics/trinary/mixer/t_mixer/Initialize()
switch(dir)
if(NORTH)
initialize_directions = EAST|NORTH|WEST
if(SOUTH)
initialize_directions = SOUTH|WEST|EAST
if(EAST)
initialize_directions = EAST|NORTH|SOUTH
if(WEST)
initialize_directions = WEST|NORTH|SOUTH
. = ..()
obj/machinery/atmospherics/trinary/mixer/t_mixer/atmos_init()
..()
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -90)
var/node2_connect = turn(dir, 90)
var/node3_connect = dir
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/mixer/m_mixer
icon_state = "mmap"
dir = SOUTH
initialize_directions = SOUTH|NORTH|EAST
//node 3 is the outlet, nodes 1 & 2 are intakes
obj/machinery/atmospherics/trinary/mixer/m_mixer/Initialize()
switch(dir)
if(NORTH)
initialize_directions = WEST|NORTH|SOUTH
if(SOUTH)
initialize_directions = SOUTH|EAST|NORTH
if(EAST)
initialize_directions = EAST|WEST|NORTH
if(WEST)
initialize_directions = WEST|SOUTH|EAST
. = ..()
obj/machinery/atmospherics/trinary/mixer/m_mixer/atmos_init()
..()
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, 90)
var/node3_connect = dir
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()
@@ -0,0 +1,175 @@
/obj/machinery/atmospherics/trinary
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
use_power = POWER_USE_OFF
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/datum/gas_mixture/air3
var/obj/machinery/atmospherics/node3
var/datum/pipe_network/network1
var/datum/pipe_network/network2
var/datum/pipe_network/network3
/obj/machinery/atmospherics/trinary/Initialize()
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
air1 = new
air2 = new
air3 = new
air1.volume = 200
air2.volume = 200
air3.volume = 200
. = ..()
// Housekeeping and pipe network stuff below
/obj/machinery/atmospherics/trinary/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
else if(reference == node2)
network2 = new_network
else if (reference == node3)
network3 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
/obj/machinery/atmospherics/trinary/Destroy()
QDEL_NULL(air1)
QDEL_NULL(air2)
QDEL_NULL(air3)
if(node1)
node1.disconnect(src)
QDEL_NULL(network1)
if(node2)
node2.disconnect(src)
QDEL_NULL(network2)
if(node3)
node3.disconnect(src)
QDEL_NULL(network3)
node1 = null
node2 = null
node3 = null
return ..()
/obj/machinery/atmospherics/trinary/atmos_init()
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -180)
var/node2_connect = turn(dir, -90)
var/node3_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(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))
if (check_connect_types(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))
if (check_connect_types(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/trinary/build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
network1.build_network(node1, src)
if(!network2 && node2)
network2 = new /datum/pipe_network()
network2.normal_members += src
network2.build_network(node2, src)
if(!network3 && node3)
network3 = new /datum/pipe_network()
network3.normal_members += src
network3.build_network(node3, src)
/obj/machinery/atmospherics/trinary/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network1
if(reference==node2)
return network2
if(reference==node3)
return network3
return null
/obj/machinery/atmospherics/trinary/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
network2 = new_network
if(network3 == old_network)
network3 = new_network
return 1
/obj/machinery/atmospherics/trinary/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
results += air1
if(network2 == reference)
results += air2
if(network3 == reference)
results += air3
return results
/obj/machinery/atmospherics/trinary/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network1)
node1 = null
else if(reference==node2)
qdel(network2)
node2 = null
else if(reference==node3)
qdel(network3)
node3 = null
update_underlays()
return null
/obj/machinery/atmospherics/trinary/AltClick(var/mob/user)
if(!allowed(user))
to_chat(user, SPAN_WARNING("Access denied."))
return
Topic(src, list("power" = "1"))
@@ -0,0 +1,485 @@
/obj/machinery/atmospherics/tvalve
name = "manual switching valve"
desc = "A pipe valve."
desc_info = "Click this to toggle the mode. The direction with the green light is where the gas will flow."
icon = 'icons/atmos/tvalve.dmi'
icon_state = "map_tvalve0"
level = 1
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
var/state = 0 // 0 = go straight, 1 = go to side
// like a trinary component, node1 is input, node2 is side output, node3 is straight output
var/obj/machinery/atmospherics/node3
var/datum/pipe_network/network_node1
var/datum/pipe_network/network_node2
var/datum/pipe_network/network_node3
/obj/machinery/atmospherics/tvalve/bypass
icon_state = "map_tvalve1"
state = 1
/obj/machinery/atmospherics/tvalve/update_icon(animation)
if(animation)
flick("tvalve[src.state][!src.state]",src)
else
icon_state = "tvalve[state]"
/obj/machinery/atmospherics/tvalve/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/tvalve/mirrored))
add_underlay(T, node2, turn(dir, 90))
else
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/tvalve/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/tvalve/Initialize()
initialize_directions()
. = ..()
/obj/machinery/atmospherics/tvalve/proc/initialize_directions()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|EAST
if(SOUTH)
initialize_directions = NORTH|SOUTH|WEST
if(EAST)
initialize_directions = WEST|EAST|SOUTH
if(WEST)
initialize_directions = EAST|WEST|NORTH
/obj/machinery/atmospherics/tvalve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(state)
network_node2 = new_network
else
network_node3 = new_network
else if(reference == node2)
network_node2 = new_network
if(state)
network_node1 = new_network
else if(reference == node3)
network_node3 = new_network
if(!state)
network_node1 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
if(state)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
else
if(reference == node1)
if(node3)
return node3.network_expand(new_network, src)
else if(reference == node3)
if(node1)
return node1.network_expand(new_network, src)
return null
/obj/machinery/atmospherics/tvalve/Destroy()
loc = null
if(node1)
node1.disconnect(src)
qdel(network_node1)
if(node2)
node2.disconnect(src)
qdel(network_node2)
if(node3)
node3.disconnect(src)
qdel(network_node3)
node1 = null
node2 = null
node3 = null
return ..()
/obj/machinery/atmospherics/tvalve/proc/go_to_side()
if(state) return 0
state = 1
update_icon()
if(network_node1)
qdel(network_node1)
if(network_node3)
qdel(network_node3)
build_network()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
/obj/machinery/atmospherics/tvalve/proc/go_straight()
if(!state)
return 0
state = 0
update_icon()
if(network_node1)
qdel(network_node1)
if(network_node2)
qdel(network_node2)
build_network()
if(network_node1&&network_node3)
network_node1.merge(network_node3)
network_node3 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node3)
network_node3.update = 1
return 1
/obj/machinery/atmospherics/tvalve/attack_ai(mob/user as mob)
return
/obj/machinery/atmospherics/tvalve/attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.state)
src.go_straight()
else
src.go_to_side()
/obj/machinery/atmospherics/tvalve/process()
..()
. = PROCESS_KILL
/obj/machinery/atmospherics/tvalve/atmos_init()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 180)
node2_dir = turn(dir, -90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/tvalve/build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
if(!network_node3 && node3)
network_node3 = new /datum/pipe_network()
network_node3.normal_members += src
network_node3.build_network(node3, src)
/obj/machinery/atmospherics/tvalve/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
if(reference==node3)
return network_node3
return null
/obj/machinery/atmospherics/tvalve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
if(network_node3 == old_network)
network_node3 = new_network
return 1
/obj/machinery/atmospherics/tvalve/return_network_air(datum/pipe_network/reference)
return null
/obj/machinery/atmospherics/tvalve/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network_node1)
node1 = null
else if(reference==node2)
qdel(network_node2)
node2 = null
else if(reference==node3)
qdel(network_node3)
node2 = null
update_underlays()
return null
/obj/machinery/atmospherics/tvalve/digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_tvalve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/tvalve/digital/bypass
icon_state = "map_tvalve1"
state = 1
/obj/machinery/atmospherics/tvalve/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/tvalve/digital/update_icon()
..()
if(!powered())
icon_state = "tvalvenopower"
/obj/machinery/atmospherics/tvalve/digital/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
return src.attack_hand(user)
/obj/machinery/atmospherics/tvalve/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
..()
//Radio remote control
/obj/machinery/atmospherics/tvalve/digital/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/tvalve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/tvalve/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
if("valve_close")
if(state)
go_straight()
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
/obj/machinery/atmospherics/tvalve/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
if (istype(src, /obj/machinery/atmospherics/tvalve/digital))
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it's too complicated.</span>")
return TRUE
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)
to_chat(user, "<span class='warnng'>You cannot unwrench \the [src], it too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/tvalve/mirrored
icon_state = "map_tvalvem0"
/obj/machinery/atmospherics/tvalve/mirrored/bypass
icon_state = "map_tvalvem1"
state = 1
/obj/machinery/atmospherics/tvalve/mirrored/initialize_directions()
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
/obj/machinery/atmospherics/tvalve/mirrored/atmos_init()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 180)
node2_dir = turn(dir, 90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/tvalve/mirrored/update_icon(animation)
if(animation)
flick("tvalvem[src.state][!src.state]",src)
else
icon_state = "tvalvem[state]"
/obj/machinery/atmospherics/tvalve/mirrored/digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_tvalve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/tvalve/mirrored/digital/bypass
icon_state = "map_tvalvem1"
state = 1
/obj/machinery/atmospherics/tvalve/mirrored/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/tvalve/mirrored/digital/update_icon()
..()
if(!powered())
icon_state = "tvalvemnopower"
/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
return src.attack_hand(user)
/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
..()
//Radio remote control -eh?
/obj/machinery/atmospherics/tvalve/mirrored/digital/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/tvalve/mirrored/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/tvalve/mirrored/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
if("valve_close")
if(state)
go_straight()
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
@@ -0,0 +1,186 @@
//TODO: Put this under a common parent type with heaters to cut down on the copypasta
#define FREEZER_PERF_MULT 2.5
/obj/machinery/atmospherics/unary/freezer
name = "gas cooling system"
desc = "Cools gas when connected to pipe network."
desc_info = "Cools down the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
icon = 'icons/obj/sleeper.dmi'
icon_state = "freezer_0"
density = 1
anchored = 1
use_power = POWER_USE_OFF
idle_power_usage = 5 // 5 Watts for thermostat related circuitry
var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something.
var/internal_volume = 600 // L
var/max_power_rating = 20000 // Power rating when the usage is turned up to 100
var/power_setting = 100
var/set_temperature = T20C // Thermostat
var/cooling = 0
component_types = list(
/obj/item/circuitboard/unary_atmos/cooler,
/obj/item/stock_parts/matter_bin,
/obj/item/stock_parts/capacitor = 2,
/obj/item/stock_parts/manipulator,
/obj/item/stack/cable_coil{amount = 2}
)
/obj/machinery/atmospherics/unary/freezer/Initialize()
initialize_directions = dir
. = ..()
/obj/machinery/atmospherics/unary/freezer/atmos_init()
if(node)
return
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
if(target.initialize_directions & get_dir(target, src))
node = target
break
//copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
//check that there are no incompatible pipes/machinery in our own location
for(var/obj/machinery/atmospherics/M in src.loc)
if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
node = null
break
update_icon()
/obj/machinery/atmospherics/unary/freezer/update_icon()
if(node)
if(use_power && cooling)
icon_state = "freezer_1"
else
icon_state = "freezer"
else
icon_state = "freezer_0"
return
/obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
ui_interact(user)
/obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob)
ui_interact(user)
/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user)
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
if(!ui)
ui = new(user, src, "machinery-atmospherics-freezer", 440, 300, "Gas Cooling System")
ui.auto_update_content = TRUE
ui.open()
/obj/machinery/atmospherics/unary/freezer/vueui_data_change(list/data, mob/user, datum/vueui/ui)
data = list()
data["on"] = use_power ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
data["minGasTemperature"] = 0
data["maxGasTemperature"] = round(T20C+500)
data["targetGasTemperature"] = round(set_temperature)
data["powerSetting"] = power_setting
data["gasTemperatureBadTop"] = (T0C - 20)
data["gasTemperatureBadBottom"] = null
data["gasTemperatureAvgTop"] = (T0C - 20)
data["gasTemperatureAvgBottom"] = (T0C - 100)
return data
/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list)
if(..())
return 1
if(href_list["toggleStatus"])
update_use_power(!use_power)
update_icon()
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
set_temperature = min(set_temperature + amount, 1000)
else
set_temperature = max(set_temperature + amount, 0)
if(href_list["setPower"]) //setting power to 0 is redundant anyways
var/new_setting = between(0, text2num(href_list["setPower"]), 100)
set_power_level(new_setting)
add_fingerprint(usr)
/obj/machinery/atmospherics/unary/freezer/process()
..()
if(stat & (NOPOWER|BROKEN) || !use_power)
cooling = 0
update_icon()
return
if(network && air_contents.temperature > set_temperature)
cooling = 1
var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 )
//Assume the heat is being pumped into the hull which is fixed at heatsink_temperature
//not /really/ proper thermodynamics but whatever
var/cop = FREEZER_PERF_MULT * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop
heat_transfer = min(heat_transfer, cop * power_rating) //limit heat transfer by available power
var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat
if(debug)
visible_message("[src]: Removing [removed] W.")
use_power_oneoff(power_rating)
network.update = 1
else
cooling = 0
update_icon()
//upgrading parts
/obj/machinery/atmospherics/unary/freezer/RefreshParts()
..()
var/cap_rating = 0
var/manip_rating = 0
var/bin_rating = 0
for(var/obj/item/stock_parts/P in component_parts)
if(iscapacitor(P))
cap_rating += P.rating
else if(ismanipulator(P))
manip_rating += P.rating
else if(ismatterbin(P))
bin_rating += P.rating
power_rating = initial(power_rating) * cap_rating / 2 //more powerful
heatsink_temperature = initial(heatsink_temperature) / ((manip_rating + bin_rating) / 2) //more efficient
air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
set_power_level(power_setting)
/obj/machinery/atmospherics/unary/freezer/proc/set_power_level(var/new_power_setting)
power_setting = new_power_setting
power_rating = max_power_rating * (power_setting/100)
/obj/machinery/atmospherics/unary/freezer/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(default_deconstruction_screwdriver(user, O))
return TRUE
if(default_deconstruction_crowbar(user, O))
return TRUE
if(default_part_replacement(user, O))
return TRUE
return ..()
/obj/machinery/atmospherics/unary/freezer/examine(mob/user)
..(user)
if(panel_open)
to_chat(user, "The maintenance hatch is open.")
@@ -0,0 +1,21 @@
/obj/machinery/atmospherics/unary/generator_input
icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
icon_state = "intact"
density = 1
name = "Generator Input"
desc = "Placeholder"
var/update_cycle
update_icon()
if(node)
icon_state = "intact"
else
icon_state = "exposed"
return
proc
return_exchange_air()
return air_contents
@@ -0,0 +1,89 @@
/obj/machinery/atmospherics/unary/heat_exchanger
icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
icon_state = "intact"
density = 1
name = "Heat Exchanger"
desc = "Exchanges heat between two input gases. Setup for fast heat transfer"
var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null
var/update_cycle
update_icon()
if(node)
icon_state = "intact"
else
icon_state = "exposed"
return
atmos_init()
if(!partner)
var/partner_connect = turn(dir,180)
for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect))
if(target.dir & get_dir(src,target))
partner = target
partner.partner = src
break
..()
process()
..()
if(QDELETED(partner))
return 0
if(!SSair || SSair.times_fired <= update_cycle)
return 0
update_cycle = SSair.times_fired
partner.update_cycle = SSair.times_fired
var/air_heat_capacity = air_contents.heat_capacity()
var/other_air_heat_capacity = partner.air_contents.heat_capacity()
var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
var/other_old_temperature = partner.air_contents.temperature
if(combined_heat_capacity > 0)
var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature
var/new_temperature = combined_energy/combined_heat_capacity
air_contents.temperature = new_temperature
partner.air_contents.temperature = new_temperature
if(network)
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
if(partner.network)
if(abs(other_old_temperature-partner.air_contents.temperature) > 1)
partner.network.update = 1
return 1
attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
var/turf/T = src.loc
if (level==1 && isturf(T) && !T.is_plating())
to_chat(user, "<span class='warning'>You must remove the plating first.</span>")
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it is too exerted due to internal pressure.</span>")
add_fingerprint(user)
return 1
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
@@ -0,0 +1,174 @@
//TODO: Put this under a common parent type with freezers to cut down on the copypasta
#define HEATER_PERF_MULT 2.5
/obj/machinery/atmospherics/unary/heater
name = "gas heating system"
desc = "Heats gas when connected to a pipe network."
desc_info = "Heats up the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
icon = 'icons/obj/sleeper.dmi'
icon_state = "heater_0"
density = 1
anchored = 1
use_power = POWER_USE_OFF
idle_power_usage = 5 //5 Watts for thermostat related circuitry
var/max_temperature = T20C + 680
var/internal_volume = 600 //L
var/max_power_rating = 20000 //power rating when the usage is turned up to 100
var/power_setting = 100
var/set_temperature = T20C //thermostat
var/heating = 0 //mainly for icon updates
component_types = list(
/obj/item/circuitboard/unary_atmos/heater,
/obj/item/stock_parts/matter_bin,
/obj/item/stock_parts/capacitor = 2,
/obj/item/stack/cable_coil{amount = 5}
)
/obj/machinery/atmospherics/unary/heater/Initialize()
initialize_directions = dir
. = ..()
/obj/machinery/atmospherics/unary/heater/atmos_init()
if(node)
return
var/node_connect = dir
//check that there is something to connect to
for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
if(target.initialize_directions & get_dir(target, src))
node = target
break
//copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
//check that there are no incompatible pipes/machinery in our own location
for(var/obj/machinery/atmospherics/M in src.loc)
if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
node = null
break
update_icon()
/obj/machinery/atmospherics/unary/heater/update_icon()
if(node)
if(use_power && heating)
icon_state = "heater_1"
else
icon_state = "heater"
else
icon_state = "heater_0"
return
/obj/machinery/atmospherics/unary/heater/process()
..()
if(stat & (NOPOWER|BROKEN) || !use_power)
heating = 0
update_icon()
return
if(network && air_contents.total_moles && air_contents.temperature < set_temperature)
air_contents.add_thermal_energy(power_rating * HEATER_PERF_MULT)
use_power_oneoff(power_rating)
heating = 1
network.update = 1
else
heating = 0
update_icon()
/obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
ui_interact(user)
/obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob)
ui_interact(user)
/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user)
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
if(!ui)
ui = new(user, src, "machinery-atmospherics-freezer", 440, 300, "Gas Heating System")
ui.auto_update_content = TRUE
ui.open()
/obj/machinery/atmospherics/unary/heater/vueui_data_change(list/data, mob/user, datum/vueui/ui)
data = list()
data["on"] = use_power ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
data["minGasTemperature"] = 0
data["maxGasTemperature"] = round(max_temperature)
data["targetGasTemperature"] = round(set_temperature)
data["powerSetting"] = power_setting
data["gasTemperatureBadTop"] = (T20C+40)
data["gasTemperatureBadBottom"] = null
data["gasTemperatureAvgTop"] = null
data["gasTemperatureAvgBottom"] = null
return data
/obj/machinery/atmospherics/unary/heater/Topic(href, href_list)
if(..())
return 1
if(href_list["toggleStatus"])
update_use_power(!use_power)
update_icon()
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
set_temperature = min(set_temperature + amount, max_temperature)
else
set_temperature = max(set_temperature + amount, 0)
if(href_list["setPower"]) //setting power to 0 is redundant anyways
var/new_setting = between(0, text2num(href_list["setPower"]), 100)
set_power_level(new_setting)
add_fingerprint(usr)
//upgrading parts
/obj/machinery/atmospherics/unary/heater/RefreshParts()
..()
var/cap_rating = 0
var/bin_rating = 0
for(var/obj/item/stock_parts/P in component_parts)
if(iscapacitor(P))
cap_rating += P.rating
else if(ismatterbin(P))
bin_rating += P.rating
max_power_rating = initial(max_power_rating) * cap_rating / 2
max_temperature = max(initial(max_temperature) - T20C, 0) * ((bin_rating * 4 + cap_rating) / 5) + T20C
air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
set_power_level(power_setting)
/obj/machinery/atmospherics/unary/heater/proc/set_power_level(var/new_power_setting)
power_setting = new_power_setting
power_rating = max_power_rating * (power_setting/100)
/obj/machinery/atmospherics/unary/heater/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(default_deconstruction_screwdriver(user, O))
return TRUE
if(default_deconstruction_crowbar(user, O))
return TRUE
if(default_part_replacement(user, O))
return TRUE
return ..()
/obj/machinery/atmospherics/unary/heater/examine(mob/user)
..(user)
if(panel_open)
to_chat(user, "The maintenance hatch is open.")
@@ -0,0 +1,160 @@
//Basically a one way passive valve. If the pressure inside is greater than the environment then gas will flow passively,
//but it does not permit gas to flow back from the environment into the injector. Can be turned off to prevent any gas flow.
//When it receives the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power.
/obj/machinery/atmospherics/unary/outlet_injector
name = "air injector"
desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate."
desc_info = "Outputs the pipe's gas into the atmosphere, similar to an airvent. It can be controlled by a nearby atmospherics computer. \
A green light on it means it is on."
icon = 'icons/atmos/injector.dmi'
icon_state = "map_injector"
layer = 3
use_power = POWER_USE_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 15000 //15000 W ~ 20 HP
var/injecting = 0
var/volume_rate = 50 //flow rate limit
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
var/broadcast_status_next_process = FALSE
level = 1
/obj/machinery/atmospherics/unary/outlet_injector/Initialize()
. = ..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //Give it a small reservoir for injecting. Also allows it to have a higher flow rate limit than vent pumps, to differentiate injectors a bit more.
/obj/machinery/atmospherics/unary/outlet_injector/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[use_power ? "on" : "off"]"
/obj/machinery/atmospherics/unary/outlet_injector/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node, dir)
/obj/machinery/atmospherics/unary/outlet_injector/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/unary/outlet_injector/process()
..()
last_power_draw = 0
last_flow_rate = 0
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
if((stat & (NOPOWER|BROKEN)) || !use_power)
return
var/power_draw = -1
var/datum/gas_mixture/environment = loc.return_air()
if(environment && air_contents.temperature > 0)
var/transfer_moles = (volume_rate/air_contents.volume)*air_contents.total_moles //apply flow rate limit
power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
if(network)
network.update = 1
return 1
/obj/machinery/atmospherics/unary/outlet_injector/proc/inject()
if(injecting || (stat & NOPOWER))
return 0
var/datum/gas_mixture/environment = loc.return_air()
if (!environment)
return 0
injecting = 1
if(air_contents.temperature > 0)
var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, power_rating)
use_power_oneoff(power_used)
if(network)
network.update = 1
flick("inject", src)
/obj/machinery/atmospherics/unary/outlet_injector/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency)
/obj/machinery/atmospherics/unary/outlet_injector/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AO",
"power" = use_power,
"volume_rate" = volume_rate,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal)
return 1
/obj/machinery/atmospherics/unary/outlet_injector/atmos_init()
..()
set_frequency(frequency)
broadcast_status()
/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"])
update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"])
update_use_power(!use_power)
if(signal.data["inject"])
spawn inject()
return
if(signal.data["set_volume_rate"])
var/number = text2num(signal.data["set_volume_rate"])
volume_rate = between(0, number, air_contents.volume)
if(signal.data["status"])
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i)
update_underlays()
@@ -0,0 +1,48 @@
obj/machinery/atmospherics/unary/oxygen_generator
icon = 'icons/obj/atmospherics/oxygen_generator.dmi'
icon_state = "intact_off"
density = 1
name = "Oxygen Generator"
desc = ""
dir = SOUTH
initialize_directions = SOUTH
var/on = 0
var/oxygen_content = 10
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
else
icon_state = "exposed_off"
on = 0
return
Initialize()
. = ..()
air_contents.volume = 50
process()
..()
if(!on)
return 0
var/total_moles = air_contents.total_moles
if(total_moles < oxygen_content)
var/current_heat_capacity = air_contents.heat_capacity()
var/added_oxygen = oxygen_content - total_moles
air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
air_contents.adjust_gas(GAS_OXYGEN, added_oxygen)
if(network)
network.update = 1
return 1
@@ -0,0 +1,81 @@
#define RADIATION_CAPACITY 30000 //Radiation isn't particularly effective (TODO BALANCE)
/obj/machinery/atmospherics/unary/thermal_plate
//Based off Heat Reservoir and Space Heater
//Transfers heat between a pipe system and environment, based on which has a greater thermal energy concentration
icon = 'icons/obj/atmospherics/cold_sink.dmi'
icon_state = "intact_off"
name = "Thermal Transfer Plate"
desc = "Transfers heat to and from an area"
update_icon()
if(node)
icon_state = "intact_off"
else
icon_state = "exposed"
return
process()
..()
var/datum/gas_mixture/environment = loc.return_air()
//Get processable air sample and thermal info from environment
var/transfer_moles = 0.25 * environment.total_moles()
var/datum/gas_mixture/external_removed = environment.remove(transfer_moles)
if (!external_removed)
return radiate()
if (external_removed.total_moles() < 10)
return radiate()
//Get same info from connected gas
var/internal_transfer_moles = 0.25 * air_contents.total_moles()
var/datum/gas_mixture/internal_removed = air_contents.remove(internal_transfer_moles)
if (!internal_removed)
environment.merge(external_removed)
return 1
var/combined_heat_capacity = internal_removed.heat_capacity() + external_removed.heat_capacity()
var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + external_removed.heat_capacity() * external_removed.temperature
if(!combined_heat_capacity) combined_heat_capacity = 1
var/final_temperature = combined_energy / combined_heat_capacity
external_removed.temperature = final_temperature
environment.merge(external_removed)
internal_removed.temperature = final_temperature
air_contents.merge(internal_removed)
network.update = 1
return 1
proc/radiate()
var/internal_transfer_moles = 0.25 * air_contents.total_moles()
var/datum/gas_mixture/internal_removed = air_contents.remove(internal_transfer_moles)
if (!internal_removed)
return 1
var/combined_heat_capacity = internal_removed.heat_capacity() + RADIATION_CAPACITY
var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + (RADIATION_CAPACITY * 6.4)
var/final_temperature = combined_energy / combined_heat_capacity
internal_removed.temperature = final_temperature
air_contents.merge(internal_removed)
if (network)
network.update = 1
return 1
@@ -0,0 +1,102 @@
/obj/machinery/atmospherics/unary
dir = SOUTH
initialize_directions = SOUTH
//layer = TURF_LAYER+0.1
var/datum/gas_mixture/air_contents
var/obj/machinery/atmospherics/node
var/datum/pipe_network/network
Initialize()
initialize_directions = dir
air_contents = new
air_contents.volume = 200
. = ..()
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Destroy()
QDEL_NULL(air_contents)
if(node)
node.disconnect(src)
QDEL_NULL(network)
node = null
return ..()
atmos_init()
if(node) return
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node = target
break
update_icon()
update_underlays()
build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
return network
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network == reference)
results += air_contents
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
qdel(network)
node = null
update_icon()
update_underlays()
return null
/obj/machinery/atmospherics/unary/vent_pump/proc/is_welded() // TODO: refactor welding into unary
if (welded > 0)
return 1
return 0
/obj/machinery/atmospherics/unary/vent_scrubber/proc/is_welded()
if (welded > 0)
return 1
return 0
@@ -0,0 +1,467 @@
#define DEFAULT_PRESSURE_DELTA 10000
#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
/obj/machinery/atmospherics/unary/vent_pump
name = "air vent"
desc = "Has a valve and pump attached to it."
desc_info = "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm."
icon = 'icons/atmos/vent_pump.dmi'
icon_state = "map_vent"
use_power = POWER_USE_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY //connects to regular and supply pipes
var/area/initial_loc
level = 1
var/area_uid
var/id_tag = null
var/hibernate = 0 //Do we even process?
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
var/pressure_checks = PRESSURE_CHECKS
//1: Do not pass external_pressure_bound
//2: Do not pass internal_pressure_bound
//3: Do not pass either
// Used when handling incoming radio signals requesting default settings
var/external_pressure_bound_default = EXTERNAL_PRESSURE_BOUND
var/internal_pressure_bound_default = INTERNAL_PRESSURE_BOUND
var/pressure_checks_default = PRESSURE_CHECKS
var/welded = 0 // Added for aliens -- TLE
var/frequency = 1439
var/datum/radio_frequency/radio_connection
var/radio_filter_out
var/radio_filter_in
var/broadcast_status_next_process = FALSE
/obj/machinery/atmospherics/unary/vent_pump/on
use_power = POWER_USE_IDLE
icon_state = "map_vent_out"
/obj/machinery/atmospherics/unary/vent_pump/siphon
pump_direction = 0
/obj/machinery/atmospherics/unary/vent_pump/siphon/atmos
icon_state = "map_vent_in"
external_pressure_bound = 0
external_pressure_bound_default = 0
internal_pressure_bound = 2000
internal_pressure_bound_default = 2000
pressure_checks = 2
pressure_checks_default = 2
/obj/machinery/atmospherics/unary/vent_pump/siphon/on
use_power = POWER_USE_IDLE
icon_state = "map_vent_in"
/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos
use_power = POWER_USE_IDLE
icon_state = "map_vent_in"
external_pressure_bound = 0
external_pressure_bound_default = 0
internal_pressure_bound = 2000
internal_pressure_bound_default = 2000
pressure_checks = 2
pressure_checks_default = 2
/obj/machinery/atmospherics/unary/vent_pump/Initialize(mapload)
if(mapload)
var/turf/T = loc
var/image/I = image(icon, T, icon_state, EFFECTS_ABOVE_LIGHTING_LAYER, dir, pixel_x, pixel_y)
I.plane = 0
I.color = color
I.alpha = 125
LAZYADD(T.blueprints, I)
. = ..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP
initial_loc = loc.loc
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
setup_radio()
/obj/machinery/atmospherics/unary/vent_pump/proc/setup_radio()
//some vents work his own special way
radio_filter_in = frequency == 1439 ? (RADIO_FROM_AIRALARM) : null
radio_filter_out = frequency == 1439 ? (RADIO_TO_AIRALARM) : null
if(frequency)
radio_connection = register_radio(src, frequency, frequency, radio_filter_in)
// Different from the above.
/obj/machinery/atmospherics/unary/vent_pump/atmos_init()
..()
broadcast_status()
/obj/machinery/atmospherics/unary/vent_pump/Destroy()
unregister_radio(src, frequency)
return ..()
/obj/machinery/atmospherics/unary/vent_pump/high_volume
name = "Large Air Vent"
power_channel = EQUIP
power_rating = 15000 //15 kW ~ 20 HP
/obj/machinery/atmospherics/unary/vent_pump/high_volume/Initialize()
. = ..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
/obj/machinery/atmospherics/unary/vent_pump/engine
name = "Engine Core Vent"
power_channel = ENVIRON
power_rating = 30000 //15 kW ~ 20 HP
/obj/machinery/atmospherics/unary/vent_pump/engine/Initialize()
. = ..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //meant to match air injector
/obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0)
if (!node)
update_use_power(POWER_USE_OFF)
var/vent_icon = ""
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
vent_icon += "h"
if(welded)
vent_icon += "weld"
else if(!powered())
vent_icon += "off"
else
vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
icon_state = vent_icon
update_underlays()
/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
return
else
if(node)
add_underlay(T, node, dir, node.icon_connect_type)
else
add_underlay(T,, dir)
/obj/machinery/atmospherics/unary/vent_pump/hide()
queue_icon_update()
/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump()
if(stat & (NOPOWER|BROKEN))
return 0
if(!use_power)
return 0
if(welded)
return 0
return 1
/obj/machinery/atmospherics/unary/vent_pump/process()
..()
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
if (hibernate > world.time)
return 1
if (!node)
update_use_power(POWER_USE_OFF)
if(!can_pump())
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/power_draw = -1
//Figure out the target pressure difference
var/pressure_delta = get_pressure_delta(environment)
//src.visible_message("DEBUG >>> [src]: pressure_delta = [pressure_delta]")
if((environment.temperature || air_contents.temperature) && pressure_delta > 0.5)
if(pump_direction) //internal -> external
var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta)
power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
else //external -> internal
var/transfer_moles = calculate_transfer_moles(environment, air_contents, pressure_delta, (network)? network.volume : 0)
//limit flow rate from turfs
transfer_moles = min(transfer_moles, environment.total_moles*air_contents.volume/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
else
//If we're in an area that is fucking ideal, and we don't have to do anything, chances are we won't next tick either so why redo these calculations?
//JESUS FUCK. THERE ARE LITERALLY 250 OF YOU MOTHERFUCKERS ON ZLEVEL ONE AND YOU DO THIS SHIT EVERY TICK WHEN VERY OFTEN THERE IS NO REASON TO
if(pump_direction && pressure_checks == PRESSURE_CHECK_EXTERNAL) //99% of all vents
hibernate = world.time + (rand(100,200))
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
if(network)
network.update = 1
return 1
/obj/machinery/atmospherics/unary/vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
var/pressure_delta = DEFAULT_PRESSURE_DELTA
var/environment_pressure = environment.return_pressure()
if(pump_direction) //internal -> external
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INTERNAL)
pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here
else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INTERNAL)
pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here
return pressure_delta
/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"area" = src.area_uid,
"tag" = src.id_tag,
"device" = "AVP",
"power" = use_power,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"internal" = internal_pressure_bound,
"external" = external_pressure_bound,
"timestamp" = world.time,
"sigtype" = "status",
"power_draw" = last_power_draw,
"flow_rate" = last_flow_rate
)
var/area/A = get_area(src)
if(!A.air_vent_names[id_tag])
var/new_name = "[A.name] Vent Pump #[A.air_vent_names.len+1]"
A.air_vent_names[id_tag] = new_name
src.name = new_name
A.air_vent_info[id_tag] = signal.data
radio_connection.post_signal(src, signal, radio_filter_out)
return 1
/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
hibernate = 0
//log_debug("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])")
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["purge"] != null)
pressure_checks &= ~1
pump_direction = 0
if(signal.data["stabalize"] != null)
pressure_checks |= 1
pump_direction = 1
if(signal.data["power"] != null)
update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"] != null)
update_use_power(!use_power)
if(signal.data["checks"] != null)
if (signal.data["checks"] == "default")
pressure_checks = pressure_checks_default
else
pressure_checks = text2num(signal.data["checks"])
if(signal.data["checks_toggle"] != null)
pressure_checks = (pressure_checks?0:3)
if(signal.data["direction"] != null)
pump_direction = text2num(signal.data["direction"])
if(signal.data["set_internal_pressure"] != null)
if (signal.data["set_internal_pressure"] == "default")
internal_pressure_bound = internal_pressure_bound_default
else
internal_pressure_bound = between(
0,
text2num(signal.data["set_internal_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_external_pressure"] != null)
if (signal.data["set_external_pressure"] == "default")
external_pressure_bound = external_pressure_bound_default
else
external_pressure_bound = between(
0,
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["adjust_internal_pressure"] != null)
internal_pressure_bound = between(
0,
internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["adjust_external_pressure"] != null)
external_pressure_bound = between(
0,
external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["init"] != null)
name = signal.data["init"]
return
if(signal.data["status"] != null)
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user)
if(W.iswelder())
var/obj/item/weldingtool/WT = W
if (!WT.welding)
to_chat(user, SPAN_DANGER("\The [WT] must be turned on!"))
else if (WT.remove_fuel(0,user))
to_chat(user, SPAN_NOTICE("Now welding the vent."))
if(do_after(user, 30/W.toolspeed))
if(!src || !WT.isOn())
return TRUE
welded = !welded
update_icon()
playsound(src, 'sound/items/welder_pry.ogg', 50, 1)
user.visible_message(SPAN_NOTICE("\The [user] [welded ? "welds \the [src] shut" : "unwelds \the [src]"]."), \
SPAN_NOTICE("You [welded ? "weld \the [src] shut" : "unweld \the [src]"]."), \
"You hear welding.")
else
to_chat(user, SPAN_NOTICE("You fail to complete the welding."))
else
to_chat(user, SPAN_WARNING("You need more welding fuel to complete this task."))
return TRUE
else if(istype(W, /obj/item/melee/arm_blade))
if(!welded)
to_chat(user, SPAN_WARNING("\The [W] can only be used to tear open welded air vents!"))
return TRUE
user.visible_message(SPAN_WARNING("\The [user] starts using \the [W] to hack open \the [src]!"), SPAN_NOTICE("You start hacking open \the [src] with \the [W]..."))
user.do_attack_animation(src, W)
playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
var/cut_amount = 3
for(var/i = 0; i <= cut_amount; i++)
if(!W || !do_after(user, 30, src))
return TRUE
user.do_attack_animation(src, W)
user.visible_message(SPAN_WARNING("\The [user] smashes \the [W] into \the [src]!"), SPAN_NOTICE("You smash \the [W] into \the [src]."))
playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
if(i == cut_amount)
welded = FALSE
spark(get_turf(src), 3, alldirs)
playsound(loc, 'sound/items/welder_pry.ogg', 50, TRUE)
update_icon()
else
return ..()
/obj/machinery/atmospherics/unary/vent_pump/examine(mob/user)
if(..(user, 1))
to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
else
to_chat(user, "You are too far away to read the gauge.")
if(welded)
to_chat(user, "It seems welded shut.")
/obj/machinery/atmospherics/unary/vent_pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
if (!(stat & NOPOWER) && use_power)
to_chat(user, SPAN_WARNING("You cannot unwrench \the [src], turn it off first."))
return TRUE
var/turf/T = src.loc
if (node && node.level==1 && isturf(T) && !T.is_plating())
to_chat(user, SPAN_WARNING("You must remove the plating first."))
return TRUE
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)
to_chat(user, SPAN_WARNING("You cannot unwrench \the [src], it is too exerted due to internal pressure."))
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, SPAN_NOTICE("You begin to unfasten \the [src]..."))
if (do_after(user, 40/W.toolspeed))
user.visible_message( \
SPAN_NOTICE("\The [user] unfastens \the [src]."), \
SPAN_NOTICE("You have unfastened \the [src]."), \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/unary/vent_pump/Destroy()
if(initial_loc)
initial_loc.air_vent_info -= id_tag
initial_loc.air_vent_names -= id_tag
return ..()
#undef DEFAULT_PRESSURE_DELTA
#undef EXTERNAL_PRESSURE_BOUND
#undef INTERNAL_PRESSURE_BOUND
#undef PRESSURE_CHECKS
#undef PRESSURE_CHECK_EXTERNAL
#undef PRESSURE_CHECK_INTERNAL
@@ -0,0 +1,375 @@
/obj/machinery/atmospherics/unary/vent_scrubber
name = "air scrubber"
desc = "Has a valve and pump attached to it."
desc_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
icon = 'icons/atmos/vent_scrubber.dmi'
icon_state = "map_scrubber_off"
use_power = POWER_USE_OFF
idle_power_usage = 150 //internal circuitry, friction losses and stuff
power_rating = 7500 //7500 W ~ 10 HP
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SCRUBBER //connects to regular and scrubber pipes
level = 1
var/area/initial_loc
var/id_tag = null
var/frequency = 1439
var/datum/radio_frequency/radio_connection
var/hibernate = 0 //Do we even process?
var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
var/list/scrubbing_gas
var/panic = 0 //is this scrubber panicked?
var/area_uid
var/radio_filter_out
var/radio_filter_in
var/welded = 0
var/broadcast_status_next_process = FALSE
/obj/machinery/atmospherics/unary/vent_scrubber/on
use_power = POWER_USE_IDLE
icon_state = "map_scrubber_on"
/obj/machinery/atmospherics/unary/vent_scrubber/Initialize(mapload)
if(mapload)
var/turf/T = loc
var/image/I = image(icon, T, icon_state, EFFECTS_ABOVE_LIGHTING_LAYER, dir, pixel_x, pixel_y)
I.plane = 0
I.color = color
I.alpha = 125
LAZYADD(T.blueprints, I)
. = ..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_FILTER
initial_loc = get_area(loc)
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
if (frequency)
set_frequency(frequency)
if (!scrubbing_gas)
reset_scrubbing()
/obj/machinery/atmospherics/unary/vent_scrubber/proc/reset_scrubbing()
if (initial(scrubbing_gas))
scrubbing_gas = initial(scrubbing_gas)
else
scrubbing_gas = list()
for (var/g in gas_data.gases)
if (g != GAS_OXYGEN && g != GAS_NITROGEN)
add_to_scrubbing(g)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/add_to_scrubbing(new_gas)
scrubbing_gas |= new_gas
/obj/machinery/atmospherics/unary/vent_scrubber/proc/remove_from_scrubbing(old_gas)
scrubbing_gas -= old_gas
/obj/machinery/atmospherics/unary/vent_scrubber/atmos_init()
..()
broadcast_status()
/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
unregister_radio(src, frequency)
if(initial_loc)
initial_loc.air_scrub_info -= id_tag
initial_loc.air_scrub_names -= id_tag
return ..()
/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0)
var/turf/T = get_turf(src)
if(!istype(T))
return
if (welded)
icon_state = "weld"
return
if (!powered() || !use_power)
icon_state = "off"
else if (scrubbing)
icon_state = "on"
else
icon_state = "in"
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
return
else
if(node)
add_underlay(T, node, dir, node.icon_connect_type)
else
add_underlay(T,, dir)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = SSradio.add_object(src, frequency, radio_filter_in)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = TRANSMISSION_RADIO
signal.source = src
signal.data = list(
"area" = area_uid,
"tag" = id_tag,
"device" = "AScr",
"timestamp" = world.time,
"power" = use_power,
"scrubbing" = scrubbing,
"panic" = panic,
"filter_o2" = (GAS_OXYGEN in scrubbing_gas),
"filter_n2" = (GAS_NITROGEN in scrubbing_gas),
"filter_co2" = (GAS_CO2 in scrubbing_gas),
"filter_phoron" = (GAS_PHORON in scrubbing_gas),
"filter_n2o" = (GAS_N2O in scrubbing_gas),
"filter_h2" = (GAS_HYDROGEN in scrubbing_gas),
"sigtype" = "status"
)
var/area/A = get_area(src)
if(!A.air_scrub_names[id_tag])
var/new_name = "[A.name] Air Scrubber #[A.air_scrub_names.len+1]"
A.air_scrub_names[id_tag] = new_name
src.name = new_name
A.air_scrub_info[id_tag] = signal.data
radio_connection.post_signal(src, signal, radio_filter_out)
return 1
/obj/machinery/atmospherics/unary/vent_scrubber/process()
..()
if (hibernate > world.time)
return 1
if (!node)
update_use_power(POWER_USE_OFF)
if (broadcast_status_next_process)
broadcast_status()
broadcast_status_next_process = FALSE
if(!use_power || (stat & (NOPOWER|BROKEN)))
return 0
if(welded)
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/power_draw = -1
if(scrubbing)
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SCRUBBER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating)
else //Just siphon all air
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
if(scrubbing && power_draw <= 0) //99% of all scrubbers
//Fucking hibernate because you ain't doing shit.
hibernate = world.time + (rand(100,200))
if (power_draw >= 0)
last_power_draw = power_draw
use_power_oneoff(power_draw)
if(network)
network.update = 1
return 1
/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes.
update_icon()
update_underlays()
/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"] != null)
update_use_power(text2num(signal.data["power"]))
if(signal.data["power_toggle"] != null)
update_use_power(!use_power)
if(signal.data["panic_siphon"]) //must be before if("scrubbing") thing
panic = text2num(signal.data["panic_siphon"])
if(panic)
update_use_power(POWER_USE_IDLE)
scrubbing = 0
else
scrubbing = 1
if(signal.data["toggle_panic_siphon"] != null)
panic = !panic
if(panic)
update_use_power(POWER_USE_IDLE)
scrubbing = 0
else
scrubbing = 1
if(signal.data["scrubbing"] != null)
scrubbing = text2num(signal.data["scrubbing"])
if(scrubbing)
panic = 0
if(signal.data["toggle_scrubbing"])
scrubbing = !scrubbing
if(scrubbing)
panic = 0
var/list/toggle = list()
if(!isnull(signal.data["o2_scrub"]) && text2num(signal.data["o2_scrub"]) != (GAS_OXYGEN in scrubbing_gas))
toggle += GAS_OXYGEN
else if(signal.data["toggle_o2_scrub"])
toggle += GAS_OXYGEN
if(!isnull(signal.data["n2_scrub"]) && text2num(signal.data["n2_scrub"]) != (GAS_NITROGEN in scrubbing_gas))
toggle += GAS_NITROGEN
else if(signal.data["toggle_n2_scrub"])
toggle += GAS_NITROGEN
if(!isnull(signal.data["co2_scrub"]) && text2num(signal.data["co2_scrub"]) != (GAS_CO2 in scrubbing_gas))
toggle += GAS_CO2
else if(signal.data["toggle_co2_scrub"])
toggle += GAS_CO2
if(!isnull(signal.data["tox_scrub"]) && text2num(signal.data["tox_scrub"]) != (GAS_PHORON in scrubbing_gas))
toggle += GAS_PHORON
else if(signal.data["toggle_tox_scrub"])
toggle += GAS_PHORON
if(!isnull(signal.data["n2o_scrub"]) && text2num(signal.data["n2o_scrub"]) != (GAS_N2O in scrubbing_gas))
toggle += GAS_N2O
else if(signal.data["toggle_n2o_scrub"])
toggle += GAS_N2O
if(!isnull(signal.data["h2_scrub"]) && text2num(signal.data["h2_scrub"]) != (GAS_HYDROGEN in scrubbing_gas))
toggle += GAS_HYDROGEN
else if(signal.data["toggle_h2_scrub"])
toggle += GAS_HYDROGEN
scrubbing_gas ^= toggle
if(signal.data["init"] != null)
name = signal.data["init"]
return
if(signal.data["status"] != null)
broadcast_status_next_process = TRUE
return //do not update_icon
broadcast_status_next_process = TRUE
update_icon()
return
/obj/machinery/atmospherics/unary/vent_scrubber/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (W.iswrench())
if (!(stat & NOPOWER) && use_power)
to_chat(user, SPAN_WARNING("You cannot unwrench \the [src], turn it off first."))
return TRUE
var/turf/T = src.loc
if (node && node.level==1 && isturf(T) && !T.is_plating())
to_chat(user, SPAN_WARNING("You must remove the plating first."))
return TRUE
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)
to_chat(user, SPAN_WARNING("You cannot unwrench \the [src], it is too exerted due to internal pressure."))
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, SPAN_NOTICE("You begin to unfasten \the [src]..."))
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
SPAN_NOTICE("\The [user] unfastens \the [src]."), \
SPAN_NOTICE("You have unfastened \the [src]."), \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
if(W.iswelder())
var/obj/item/weldingtool/WT = W
if (!WT.welding)
to_chat(user, SPAN_DANGER("\The [WT] must be turned on!"))
else if (WT.remove_fuel(0,user))
to_chat(user, SPAN_NOTICE("Now welding \the [src]."))
playsound(src, 'sound/items/welder.ogg', 50, 1)
if(do_after(user, 20/W.toolspeed, act_target = src))
if(!src || !WT.isOn())
return TRUE
welded = !welded
update_icon()
playsound(src, 'sound/items/welder_pry.ogg', 50, 1)
user.visible_message(SPAN_NOTICE("\The [user] [welded ? "welds \the [src] shut" : "unwelds \the [src]"]."), \
SPAN_NOTICE("You [welded ? "weld \the [src] shut" : "unweld \the [src]"]."), \
"You hear welding.")
else
to_chat(user, SPAN_NOTICE("You fail to complete the welding."))
else
to_chat(user, SPAN_WARNING("You need more welding fuel to complete this task."))
return TRUE
if(istype(W, /obj/item/melee/arm_blade))
if(!welded)
to_chat(user, SPAN_WARNING("\The [W] can only be used to tear open welded scrubbers!"))
return TRUE
user.visible_message(SPAN_WARNING("\The [user] starts using \the [W] to hack open \the [src]!"), SPAN_NOTICE("You start hacking open \the [src] with \the [W]..."))
user.do_attack_animation(src, W)
playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
var/cut_amount = 3
for(var/i = 0; i <= cut_amount; i++)
if(!W || !do_after(user, 30, src))
return TRUE
user.do_attack_animation(src, W)
user.visible_message(SPAN_WARNING("\The [user] smashes \the [W] into \the [src]!"), SPAN_NOTICE("You smash \the [W] into \the [src]."))
playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
if(i == cut_amount)
welded = FALSE
spark(get_turf(src), 3, alldirs)
playsound(loc, 'sound/items/welder_pry.ogg', 50, TRUE)
update_icon()
return TRUE
return ..()
/obj/machinery/atmospherics/unary/vent_scrubber/examine(mob/user)
if(..(user, 1))
to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
else
to_chat(user, "You are too far away to read the gauge.")
if(welded)
to_chat(user, "It seems welded shut.")
@@ -0,0 +1,329 @@
/obj/machinery/atmospherics/valve
name = "manual valve"
desc = "A pipe valve."
desc_info = "Click this to turn the valve. If red, the pipes on each end are seperated. Otherwise, they are connected."
icon = 'icons/atmos/valve.dmi'
icon_state = "map_valve0"
level = 1
dir = SOUTH
initialize_directions = SOUTH|NORTH
var/open = 0
var/openDuringInit = 0
var/datum/pipe_network/network_node1
var/datum/pipe_network/network_node2
/obj/machinery/atmospherics/valve/open
open = 1
icon_state = "map_valve1"
/obj/machinery/atmospherics/valve/update_icon(animation)
if(animation)
flick("valve[src.open][!src.open]",src)
else
icon_state = "valve[open]"
/obj/machinery/atmospherics/valve/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, get_dir(src, node1))
add_underlay(T, node2, get_dir(src, node2))
/obj/machinery/atmospherics/valve/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/valve/Initialize()
switch(dir)
if(NORTH || SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST || WEST)
initialize_directions = EAST|WEST
. = ..()
/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(open)
network_node2 = new_network
else if(reference == node2)
network_node2 = new_network
if(open)
network_node1 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
if(open)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
return null
/obj/machinery/atmospherics/valve/Destroy()
loc = null
if(node1)
node1.disconnect(src)
qdel(network_node1)
if(node2)
node2.disconnect(src)
qdel(network_node2)
node1 = null
node2 = null
return ..()
/obj/machinery/atmospherics/valve/proc/open()
if(open) return 0
open = 1
update_icon()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
/obj/machinery/atmospherics/valve/proc/close()
if(!open)
return 0
open = 0
update_icon()
if(network_node1)
qdel(network_node1)
if(network_node2)
qdel(network_node2)
build_network()
return 1
/obj/machinery/atmospherics/valve/proc/normalize_dir()
if(dir==3)
set_dir(1)
else if(dir==12)
set_dir(4)
/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob)
return
/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.open)
src.close()
else
src.open()
/obj/machinery/atmospherics/valve/process()
..()
return PROCESS_KILL
/obj/machinery/atmospherics/valve/atmos_init()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_directions)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
if (check_connect_types(target,src))
node2 = target
break
build_network()
queue_icon_update()
update_underlays()
if(openDuringInit)
close()
open()
openDuringInit = 0
/obj/machinery/atmospherics/valve/build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
return null
/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
return 1
/obj/machinery/atmospherics/valve/return_network_air(datum/pipe_network/reference)
return null
/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
qdel(network_node1)
node1 = null
else if(reference==node2)
qdel(network_node2)
node2 = null
update_underlays()
return null
/obj/machinery/atmospherics/valve/digital // can be controlled by AI
name = "digital valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_valve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob)
if(!ai_can_interact(user))
return
return src.attack_hand(user)
/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
..()
log_and_message_admins("has [open ? "<span class='warning'>OPENED</span>" : "closed"] [name].", user)
/obj/machinery/atmospherics/valve/digital/AltClick(var/mob/abstract/observer/admin)
if (istype(admin))
if (admin.client && admin.client.holder && ((R_MOD|R_ADMIN) & admin.client.holder.rights))
if (open)
close()
else
if (alert(admin, "The valve is currently closed. Do you want to open it?", "Open the valve?", "Yes", "No") == "No")
return
open()
log_and_message_admins("has [open ? "opened" : "closed"] [name].", admin)
/obj/machinery/atmospherics/valve/digital/open
open = 1
icon_state = "map_valve1"
/obj/machinery/atmospherics/valve/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
queue_icon_update()
/obj/machinery/atmospherics/valve/digital/update_icon()
..()
if(!powered())
icon_state = "valve[open]nopower"
/obj/machinery/atmospherics/valve/digital/proc/set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/valve/digital/atmos_init()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!open)
open()
if("valve_close")
if(open)
close()
if("valve_toggle")
if(open)
close()
else
open()
/obj/machinery/atmospherics/valve/attackby(var/obj/item/W as obj, var/mob/user as mob)
if (!W.iswrench())
return ..()
if (istype(src, /obj/machinery/atmospherics/valve/digital))
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it's too complicated.</span>")
return TRUE
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)
to_chat(user, "<span class='warning'>You cannot unwrench \the [src], it is too exerted due to internal pressure.</span>")
add_fingerprint(user)
return TRUE
playsound(src.loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if (do_after(user, 40/W.toolspeed, act_target = src))
user.visible_message( \
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
return TRUE
/obj/machinery/atmospherics/valve/examine(mob/user)
..()
to_chat(user, "It is [open ? "open" : "closed"].")
@@ -0,0 +1,91 @@
/datum/pipe_network
var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network
var/volume = 0 //caches the total volume for atmos machines to use in gas calculations
var/list/obj/machinery/atmospherics/normal_members = list()
var/list/datum/pipeline/line_members = list()
//membership roster to go through for updates and what not
var/update = 1
//var/datum/gas_mixture/air_transient = null
/*
/datum/pipe_network/New()
//air_transient = new()
..()*/
/datum/pipe_network/process()
//Equalize gases amongst pipe if called for
if(update)
update = 0
reconcile_air() //equalize_gases(gases)
//Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
//for(var/datum/pipeline/line_member in line_members)
// line_member.process()
/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
//Purpose: Generate membership roster
//Notes: Assuming that members will add themselves to appropriate roster in network_expand()
if(!start_normal)
qdel(src)
start_normal.network_expand(src, reference)
update_network_gases()
if((normal_members.len>0)||(line_members.len>0))
START_PROCESSING_PIPENET(src)
else
qdel(src)
/datum/pipe_network/proc/merge(datum/pipe_network/giver)
if(giver==src) return 0
normal_members |= giver.normal_members
line_members |= giver.line_members
for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
normal_member.reassign_network(giver, src)
for(var/datum/pipeline/line_member in giver.line_members)
line_member.network = src
update_network_gases()
return 1
/datum/pipe_network/proc/update_network_gases()
//Go through membership roster and make sure gases is up to date
gases = list()
volume = 0
for(var/obj/machinery/atmospherics/normal_member in normal_members)
var/result = normal_member.return_network_air(src)
if(result) gases += result
for(var/datum/pipeline/line_member in line_members)
gases += line_member.air
for(var/datum/gas_mixture/air in gases)
volume += air.volume
/datum/pipe_network/proc/reconcile_air()
equalize_gases(gases)
/datum/pipe_network/Destroy(force = FALSE)
STOP_PROCESSING_PIPENET(src)
for (var/datum/pipeline/pipeline in line_members)
pipeline.network = null
line_members = null
for (var/obj/machinery/atmospherics/thing in normal_members)
thing.reassign_network(src, null)
normal_members = null
return ..()
+220
View File
@@ -0,0 +1,220 @@
/datum/pipeline
var/datum/gas_mixture/air
var/list/obj/machinery/atmospherics/pipe/members
var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
var/datum/pipe_network/network
var/alert_pressure = 0
/datum/pipeline/Destroy()
if(network)
QDEL_NULL(network)
if(air && air.volume)
temporarily_store_air()
QDEL_NULL(air)
for (var/obj/machinery/atmospherics/pipe/thing in members)
thing.parent = null
members = null
return ..()
/datum/pipeline/process()//This use to be called called from the pipe networks
//Check to see if pressure is within acceptable limits
var/pressure = air.return_pressure()
if(pressure > alert_pressure)
for(var/obj/machinery/atmospherics/pipe/member in members)
if(!member.check_pressure(pressure))
break //Only delete 1 pipe per process
/datum/pipeline/proc/temporarily_store_air()
//Update individual gas_mixtures by volume ratio
for(var/obj/machinery/atmospherics/pipe/member in members)
member.air_temporary = new
member.air_temporary.copy_from(air)
member.air_temporary.volume = member.volume
member.air_temporary.multiply(member.volume / air.volume)
/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
air = new
var/list/possible_expansions = list(base)
members = list(base)
edges = list()
var/volume = base.volume
base.parent = src
alert_pressure = base.alert_pressure
if(base.air_temporary)
air = base.air_temporary
base.air_temporary = null
else
air = new
while(possible_expansions.len>0)
for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
var/list/result = borderline.pipeline_expansion()
var/edge_check = result.len
if(result.len>0)
for(var/obj/machinery/atmospherics/pipe/item in result)
if(!members.Find(item))
members += item
possible_expansions += item
volume += item.volume
item.parent = src
alert_pressure = min(alert_pressure, item.alert_pressure)
if(item.air_temporary)
air.merge(item.air_temporary)
edge_check--
if(edge_check>0)
edges += borderline
possible_expansions -= borderline
air.volume = volume
/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(new_network.line_members.Find(src))
return 0
new_network.line_members += src
network = new_network
for(var/obj/machinery/atmospherics/pipe/edge in edges)
for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
result.network_expand(new_network, edge)
return 1
/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference)
if(!network)
network = new /datum/pipe_network
network.build_network(src, null)
//technically passing these parameters should not be allowed
//however pipe_network.build_network(..) and pipeline.network_extend(...)
// were setup to properly handle this case
return network
/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
air_sample.volume = mingle_volume
if(istype(target) && target.zone)
//Have to consider preservation of group statuses
var/datum/gas_mixture/turf_copy = new
turf_copy.copy_from(target.zone.air)
turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
equalize_gases(list(air_sample, turf_copy))
air.merge(air_sample)
turf_copy.subtract(target.zone.air)
target.zone.air.merge(turf_copy)
else
var/datum/gas_mixture/turf_air = target.return_air()
equalize_gases(list(air_sample, turf_air))
air.merge(air_sample)
//turf_air already modified by equalize_gases()
if(network)
network.update = 1
/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
var/total_heat_capacity = air.heat_capacity()
var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
if(istype(target, /turf/simulated))
var/turf/simulated/modeled_location = target
if(modeled_location.blocks_air)
if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - modeled_location.temperature
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
air.temperature -= heat/total_heat_capacity
modeled_location.temperature += heat/modeled_location.heat_capacity
else
var/delta_temperature = 0
var/sharer_heat_capacity = 0
if(modeled_location.zone)
delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
else
delta_temperature = (air.temperature - modeled_location.air.temperature)
sharer_heat_capacity = modeled_location.air.heat_capacity()
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
self_temperature_delta = -heat/total_heat_capacity
sharer_temperature_delta = heat/sharer_heat_capacity
else
return 1
air.temperature += self_temperature_delta
if(modeled_location.zone)
modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
else
modeled_location.air.temperature += sharer_temperature_delta
else
if((target.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - target.temperature
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
air.temperature -= heat/total_heat_capacity
if(network)
network.update = 1
//surface must be the surface area in m^2
/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity)
var/gas_density = air.total_moles/air.volume
thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
// We only get heat from the star on the exposed surface area.
// If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
// Previously, the temperature would enter equilibrium at 26C or 294K.
// Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
// It currently should stabilise at 129.6K or -143.6C
heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
air.add_thermal_energy(heat_gain)
if(network)
network.update = 1
+156
View File
@@ -0,0 +1,156 @@
/obj/machinery/atmospherics/pipe/simple/heat_exchanging
desc_info = "This radiates heat from the pipe's gas to space, cooling it down."
icon = 'icons/atmos/heat.dmi'
icon_state = "intact"
pipe_icon = "hepipe"
color = "#404040"
level = 2
connect_types = CONNECT_TYPE_HE
layer = 2.41
var/initialize_directions_he
var/surface = 2 //surface area in m^2
var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh
appearance_flags = KEEP_TOGETHER
minimum_temperature_difference = 20
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
buckle_lying = 1
volume = ATMOS_DEFAULT_VOLUME_HE_PIPE
// BubbleWrap
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/Initialize()
. = ..()
initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
// BubbleWrap END
color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
add_filter("glow", 1, list(type="drop_shadow", x = 0, y = 0, offset = 0, size = 4))
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_directions_he)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
if(target.initialize_directions_he & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
if(target.initialize_directions_he & get_dir(target,src))
node2 = target
break
if(!node1 && !node2)
qdel(src)
return
queue_icon_update()
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process()
if(!parent)
..()
else
var/datum/gas_mixture/pipe_air = return_air()
if(istype(loc, /turf/simulated/))
var/environment_temperature = 0
if(loc:blocks_air)
environment_temperature = loc:temperature
else
var/datum/gas_mixture/environment = loc.return_air()
environment_temperature = environment.temperature
if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
parent.temperature_interact(loc, volume, thermal_conductivity)
else if(istype(loc, /turf/space/))
parent.radiate_heat_to_space(surface, 1)
if(istype(buckled, /mob/living))
var/mob/living/M = buckled
var/hc = pipe_air.heat_capacity()
var/avg_temp = (pipe_air.temperature * hc + M.bodytemperature * 3500) / (hc + 3500)
pipe_air.temperature = avg_temp
M.bodytemperature = avg_temp
var/heat_limit = 1000
var/mob/living/carbon/human/H = buckled
if(istype(H) && H.species)
heat_limit = H.species.heat_level_3
if(pipe_air.temperature > heat_limit + 1)
M.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat")
//fancy radiation glowing
if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
if(abs(pipe_air.temperature - icon_temperature) > 10)
icon_temperature = pipe_air.temperature
var/scale = max((icon_temperature - 500) / 1500, 0)
var/h_r = heat2color_r(icon_temperature)
var/h_g = heat2color_g(icon_temperature)
var/h_b = heat2color_b(icon_temperature)
if(icon_temperature < 2000) //scale up overlay until 2000K
h_r = 64 + (h_r - 64)*scale
h_g = 64 + (h_g - 64)*scale
h_b = 64 + (h_b - 64)*scale
var/scale_color = rgb(h_r, h_g, h_b)
var/list/animate_targets = get_above_oo() + src
for (var/thing in animate_targets)
var/atom/movable/AM = thing
animate(AM, color = scale_color, time = 2 SECONDS, easing = SINE_EASING)
animate_filter("glow", list(color = scale_color, time = 2 SECONDS, easing = LINEAR_EASING))
set_light(min(3, scale*2.5), min(3, scale*2.5), scale_color)
else
set_light(0)
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
icon = 'icons/atmos/junction.dmi'
icon_state = "intact"
pipe_icon = "hejunction"
level = 2
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE
minimum_temperature_difference = 300
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
// BubbleWrap
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/Initialize()
. = ..()
switch (dir)
if (SOUTH)
initialize_directions = NORTH
initialize_directions_he = SOUTH
if (NORTH)
initialize_directions = SOUTH
initialize_directions_he = NORTH
if (EAST)
initialize_directions = WEST
initialize_directions_he = EAST
if (WEST)
initialize_directions = EAST
initialize_directions_he = WEST
// BubbleWrap END
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
if(target.initialize_directions_he & get_dir(target,src))
node2 = target
break
if(!node1 && !node2)
qdel(src)
return
queue_icon_update()
+706
View File
@@ -0,0 +1,706 @@
// internal pipe, don't actually place or use these
obj/machinery/atmospherics/pipe/mains_component
var/obj/machinery/atmospherics/mains_pipe/parent_pipe
var/list/obj/machinery/atmospherics/pipe/mains_component/nodes = new()
New(loc)
..(loc)
parent_pipe = loc
check_pressure(pressure)
var/datum/gas_mixture/environment = loc.loc.return_air()
var/pressure_difference = pressure - environment.return_pressure()
if(pressure_difference > parent_pipe.maximum_pressure)
mains_burst()
else if(pressure_difference > parent_pipe.fatigue_pressure)
//TODO: leak to turf, doing pfshhhhh
if(prob(5))
mains_burst()
else return 1
pipeline_expansion()
return nodes
disconnect(obj/machinery/atmospherics/reference)
if(nodes.Find(reference))
nodes.Remove(reference)
proc/mains_burst()
parent_pipe.burst()
obj/machinery/atmospherics/mains_pipe
icon = 'icons/obj/atmospherics/mainspipe.dmi'
layer = 2.4 //under wires with their 2.5
force = 20
var/volume = 0
var/alert_pressure = 80*ONE_ATMOSPHERE
var/initialize_mains_directions = 0
var/list/obj/machinery/atmospherics/mains_pipe/nodes = new()
var/obj/machinery/atmospherics/pipe/mains_component/supply
var/obj/machinery/atmospherics/pipe/mains_component/scrubbers
var/obj/machinery/atmospherics/pipe/mains_component/aux
var/minimum_temperature_difference = 300
var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
var/maximum_pressure = 70*ONE_ATMOSPHERE
var/fatigue_pressure = 55*ONE_ATMOSPHERE
alert_pressure = 55*ONE_ATMOSPHERE
New()
..()
supply = new(src)
supply.volume = volume
supply.nodes.len = nodes.len
scrubbers = new(src)
scrubbers.volume = volume
scrubbers.nodes.len = nodes.len
aux = new(src)
aux.volume = volume
aux.nodes.len = nodes.len
hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
invisibility = i ? 101 : 0
update_icon()
proc/burst()
for(var/obj/machinery/atmospherics/pipe/mains_component/pipe in contents)
burst()
proc/check_pressure(pressure)
var/datum/gas_mixture/environment = loc.return_air()
var/pressure_difference = pressure - environment.return_pressure()
if(pressure_difference > maximum_pressure)
burst()
else if(pressure_difference > fatigue_pressure)
//TODO: leak to turf, doing pfshhhhh
if(prob(5))
burst()
else return 1
disconnect()
..()
for(var/obj/machinery/atmospherics/pipe/mains_component/node in nodes)
node.disconnect()
Destroy()
disconnect()
return ..()
atmos_init()
for(var/i = 1 to nodes.len)
var/obj/machinery/atmospherics/mains_pipe/node = nodes[i]
if(node)
supply.nodes[i] = node.supply
scrubbers.nodes[i] = node.scrubbers
aux.nodes[i] = node.aux
obj/machinery/atmospherics/mains_pipe/simple
name = "mains pipe"
desc = "A one meter section of 3-line mains pipe"
dir = SOUTH
initialize_mains_directions = SOUTH|NORTH
New()
nodes.len = 2
..()
switch(dir)
if(SOUTH || NORTH)
initialize_mains_directions = SOUTH|NORTH
if(EAST || WEST)
initialize_mains_directions = EAST|WEST
if(NORTHEAST)
initialize_mains_directions = NORTH|EAST
if(NORTHWEST)
initialize_mains_directions = NORTH|WEST
if(SOUTHEAST)
initialize_mains_directions = SOUTH|EAST
if(SOUTHWEST)
initialize_mains_directions = SOUTH|WEST
proc/normalize_dir()
if(dir==3)
set_dir(1)
else if(dir==12)
set_dir(4)
update_icon()
if(nodes[1] && nodes[2])
icon_state = "intact[invisibility ? "-f" : "" ]"
//var/node1_direction = get_dir(src, node1)
//var/node2_direction = get_dir(src, node2)
//set_dir(node1_direction|node2_direction)
else
if(!nodes[1]&&!nodes[2])
qdel(src) //TODO: silent deleting looks weird
var/have_node1 = nodes[1]?1:0
var/have_node2 = nodes[2]?1:0
icon_state = "exposed[have_node1][have_node2][invisibility ? "-f" : "" ]"
atmos_init()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_mains_directions)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[2] = target
break
..() // initialize internal pipes
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
hidden
level = 1
icon_state = "intact-f"
visible
level = 2
icon_state = "intact"
obj/machinery/atmospherics/mains_pipe/manifold
name = "manifold pipe"
desc = "A manifold composed of mains pipes"
dir = SOUTH
initialize_mains_directions = EAST|NORTH|WEST
volume = 105
New()
nodes.len = 3
..()
initialize_mains_directions = (NORTH|SOUTH|EAST|WEST) & ~dir
atmos_init()
var/connect_directions = initialize_mains_directions
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
connect_directions &= ~direction
break
if (nodes[1])
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[2] = target
connect_directions &= ~direction
break
if (nodes[2])
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,direction))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[3] = target
connect_directions &= ~direction
break
if (nodes[3])
break
..() // initialize internal pipes
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
update_icon()
icon_state = "manifold[invisibility ? "-f" : "" ]"
hidden
level = 1
icon_state = "manifold-f"
visible
level = 2
icon_state = "manifold"
obj/machinery/atmospherics/mains_pipe/manifold4w
name = "manifold pipe"
desc = "A manifold composed of mains pipes"
dir = SOUTH
initialize_mains_directions = EAST|NORTH|WEST|SOUTH
volume = 105
New()
nodes.len = 4
..()
atmos_init()
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,NORTH))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,SOUTH))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[2] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,EAST))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[3] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,WEST))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[3] = target
break
..() // initialize internal pipes
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
update_icon()
icon_state = "manifold4w[invisibility ? "-f" : "" ]"
hidden
level = 1
icon_state = "manifold4w-f"
visible
level = 2
icon_state = "manifold4w"
obj/machinery/atmospherics/mains_pipe/split
name = "mains splitter"
desc = "A splitter for connecting to a single pipe off a mains."
var/obj/machinery/atmospherics/pipe/mains_component/split_node
var/obj/machinery/atmospherics/node3
var/icon_type
New()
nodes.len = 2
..()
initialize_mains_directions = turn(dir, 90) | turn(dir, -90)
initialize_directions = dir // actually have a normal connection too
atmos_init()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 90)
node2_dir = turn(dir, -90)
node3_dir = dir
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[2] = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
..() // initialize internal pipes
// bind them
spawn(5)
if(node3 && split_node)
var/datum/pipe_network/N1 = node3.return_network(src)
var/datum/pipe_network/N2 = split_node.return_network(split_node)
if(N1 && N2)
N1.merge(N2)
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
update_icon()
icon_state = "split-[icon_type][invisibility ? "-f" : "" ]"
return_network(A)
return split_node.return_network(A)
supply
icon_type = "supply"
New()
..()
split_node = supply
hidden
level = 1
icon_state = "split-supply-f"
visible
level = 2
icon_state = "split-supply"
scrubbers
icon_type = "scrubbers"
New()
..()
split_node = scrubbers
hidden
level = 1
icon_state = "split-scrubbers-f"
visible
level = 2
icon_state = "split-scrubbers"
aux
icon_type = "aux"
New()
..()
split_node = aux
hidden
level = 1
icon_state = "split-aux-f"
visible
level = 2
icon_state = "split-aux"
obj/machinery/atmospherics/mains_pipe/split3
name = "triple mains splitter"
desc = "A splitter for connecting to the 3 pipes on a mainline."
var/obj/machinery/atmospherics/supply_node
var/obj/machinery/atmospherics/scrubbers_node
var/obj/machinery/atmospherics/aux_node
New()
nodes.len = 1
..()
initialize_mains_directions = dir
initialize_directions = cardinal & ~dir // actually have a normal connection too
atmos_init()
var/node1_dir
var/supply_node_dir
var/scrubbers_node_dir
var/aux_node_dir
node1_dir = dir
aux_node_dir = turn(dir, 180)
if(dir & (NORTH|SOUTH))
supply_node_dir = EAST
scrubbers_node_dir = WEST
else
supply_node_dir = SOUTH
scrubbers_node_dir = NORTH
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src, node1_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,supply_node_dir))
if(target.initialize_directions & get_dir(target,src))
supply_node = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,scrubbers_node_dir))
if(target.initialize_directions & get_dir(target,src))
scrubbers_node = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,aux_node_dir))
if(target.initialize_directions & get_dir(target,src))
aux_node = target
break
..() // initialize internal pipes
// bind them
spawn(5)
if(supply_node)
var/datum/pipe_network/N1 = supply_node.return_network(src)
var/datum/pipe_network/N2 = supply.return_network(supply)
if(N1 && N2)
N1.merge(N2)
if(scrubbers_node)
var/datum/pipe_network/N1 = scrubbers_node.return_network(src)
var/datum/pipe_network/N2 = scrubbers.return_network(scrubbers)
if(N1 && N2)
N1.merge(N2)
if(aux_node)
var/datum/pipe_network/N1 = aux_node.return_network(src)
var/datum/pipe_network/N2 = aux.return_network(aux)
if(N1 && N2)
N1.merge(N2)
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
update_icon()
icon_state = "split-t[invisibility ? "-f" : "" ]"
return_network(obj/machinery/atmospherics/reference)
var/obj/machinery/atmospherics/A
A = supply_node.return_network(reference)
if(!A)
A = scrubbers_node.return_network(reference)
if(!A)
A = aux_node.return_network(reference)
return A
hidden
level = 1
icon_state = "split-t-f"
visible
level = 2
icon_state = "split-t"
obj/machinery/atmospherics/mains_pipe/cap
name = "pipe cap"
desc = "A cap for the end of a mains pipe"
dir = SOUTH
initialize_directions = SOUTH
volume = 35
New()
nodes.len = 1
..()
initialize_mains_directions = dir
update_icon()
icon_state = "cap[invisibility ? "-f" : ""]"
atmos_init()
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
..()
var/turf/T = src.loc // hide if turf is not intact
if(level == 1 && !T.is_plating()) hide(1)
update_icon()
hidden
level = 1
icon_state = "cap-f"
visible
level = 2
icon_state = "cap"
//TODO: Get Mains valves working!
/*
obj/machinery/atmospherics/mains_pipe/valve
icon_state = "mvalve0"
name = "mains shutoff valve"
desc = "A mains pipe valve"
var/open = 1
dir = SOUTH
initialize_mains_directions = SOUTH|NORTH
New()
nodes.len = 2
..()
initialize_mains_directions = dir | turn(dir, 180)
update_icon(animation)
var/turf/simulated/floor = loc
var/hide = istype(floor) ? floor.intact : 0
level = 1
for(var/obj/machinery/atmospherics/mains_pipe/node in nodes)
if(node.level == 2)
hide = 0
level = 2
break
if(animation)
flick("[hide?"h":""]mvalve[src.open][!src.open]",src)
else
icon_state = "[hide?"h":""]mvalve[open]"
atmos_init()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_mains_directions)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node1_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[1] = target
break
for(var/obj/machinery/atmospherics/mains_pipe/target in get_step(src,node2_dir))
if(target.initialize_mains_directions & get_dir(target,src))
nodes[2] = target
break
if(open)
..() // initialize internal pipes
update_icon()
proc/normalize_dir()
if(dir==3)
set_dir(1)
else if(dir==12)
set_dir(4)
proc/open()
if(open) return 0
open = 1
update_icon()
atmos_init()
return 1
proc/close()
if(!open) return 0
open = 0
update_icon()
for(var/obj/machinery/atmospherics/pipe/mains_component/node in src)
for(var/obj/machinery/atmospherics/pipe/mains_component/o in node.nodes)
o.disconnect(node)
o.build_network()
return 1
attack_ai(mob/user as mob)
return
attack_paw(mob/user as mob)
return attack_hand(user)
attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (open)
close()
else
open()
digital // can be controlled by AI
name = "digital mains valve"
desc = "A digitally controlled valve."
icon_state = "dvalve0"
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if(!src.allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
..()
//Radio remote control
proc
set_frequency(new_frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
atmos_init()
..()
if(frequency)
set_frequency(frequency)
update_icon(animation)
var/turf/simulated/floor = loc
var/hide = istype(floor) ? floor.intact : 0
level = 1
for(var/obj/machinery/atmospherics/mains_pipe/node in nodes)
if(node.level == 2)
hide = 0
level = 2
break
if(animation)
flick("[hide?"h":""]dvalve[src.open][!src.open]",src)
else
icon_state = "[hide?"h":""]dvalve[open]"
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!open)
open()
if("valve_close")
if(open)
close()
if("valve_toggle")
if(open)
close()
else
open()
*/
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@
density = 1
anchored = 1
/obj/machinery/computer/artillerycontrol/machinery_process()
/obj/machinery/computer/artillerycontrol/process()
if(src.reload<180)
src.reload++
+3 -4
View File
@@ -27,7 +27,6 @@
/obj/machinery/gateway/centerstation
density = 1
icon_state = "offcenter"
use_power = 1
//warping vars
var/list/linked_gateways = list()
@@ -56,7 +55,7 @@ obj/machinery/gateway/centerstation/process()
return
if(active)
use_power(5000)
use_power_oneoff(5000)
/obj/machinery/gateway/centerstation/proc/detect()
@@ -129,7 +128,7 @@ obj/machinery/gateway/centerstation/process()
if(dest)
M.forceMove(dest.loc)
M.set_dir(SOUTH)
use_power(5000)
use_power_oneoff(5000)
return
@@ -144,7 +143,7 @@ obj/machinery/gateway/centerstation/process()
/obj/machinery/gateway/centeraway
density = 1
icon_state = "offcenter"
use_power = 0
use_power = POWER_USE_OFF
var/calibrated = 1
var/list/linked_gateways = list() //a list of the connected gateway chunks
var/ready = 0
+2 -1
View File
@@ -107,6 +107,7 @@ STOCK_ITEM_LARGE(dispenser, 2.5)
var/type = pickweight(dispensers)
var/obj/machinery/chemical_dispenser/CD = new type(L)
CD.anchored = FALSE
CD.update_use_power(POWER_USE_OFF)
for (var/cart in CD.cartridges)
if (prob(90))
CD.cartridges -= cart
@@ -145,4 +146,4 @@ STOCK_ITEM_LARGE(exosuit, 1.2) //A randomly generated exosuit in a very variable
new /mob/living/heavy_vehicle/premade/random/extra(L)
STOCK_ITEM_LARGE(unusualcrate, 0.1) //Like from the unknown object random event
new /obj/structure/closet/crate/loot(L)
new /obj/structure/closet/crate/loot(L)
+2 -1
View File
@@ -294,6 +294,7 @@ STOCK_ITEM_COMMON(charger, 2)
var/newtype = pick(/obj/machinery/cell_charger, /obj/machinery/recharger)
var/obj/machinery/ma = new newtype(L)
ma.anchored = FALSE
ma.update_use_power(POWER_USE_OFF)
STOCK_ITEM_COMMON(spacesuit, 2)
new /obj/item/clothing/suit/space(L)
@@ -525,4 +526,4 @@ STOCK_ITEM_COMMON(camera, 1)
new /obj/item/device/camera_film(L)
STOCK_ITEM_COMMON(nothing, 0)
// do nothing
// do nothing
@@ -14,7 +14,7 @@
density = 1
anchored = 1
use_power = 0
use_power = POWER_USE_OFF
idle_power_usage = 5 // Power used when turned on, but not processing anything
active_power_usage = 1000 // Power used when turned on and actively cooking something
@@ -116,7 +116,7 @@
return
stat ^= POWEROFF // Toggles power
use_power = (stat & POWEROFF) ? 0 : 2 // If on, use active power, else use no power
update_use_power(stat & POWEROFF ? POWER_USE_OFF : POWER_USE_ACTIVE)
if(user)
user.visible_message("[user] turns [src] [use_power ? "on" : "off"].", "You turn [use_power ? "on" : "off"] [src].")
playsound(src, 'sound/machines/click.ogg', 40, 1)
@@ -317,7 +317,7 @@
return TRUE
/obj/machinery/appliance/machinery_process()
/obj/machinery/appliance/process()
if (cooking_power > 0 && cooking)
for (var/i in cooking_objs)
do_cooking_tick(i)
@@ -639,6 +639,6 @@
if(isscanner(P))
scan_rating += P.rating - 1
active_power_usage = initial(active_power_usage) - scan_rating * 25 // 25W less per tier
change_power_consumption(initial(active_power_usage) - scan_rating * 25, POWER_USE_ACTIVE)
heating_power = initial(heating_power) + cap_rating * 50 // + 50W per tier
cooking_coeff = (1 + (scan_rating + cap_rating) / 20) // +20% per tier
@@ -109,7 +109,7 @@
set_temp = text2num(desired_temp) + T0C
to_chat(user, SPAN_NOTICE("You set [src] to [round(set_temp-T0C)]C."))
stat &= ~POWEROFF
use_power = !(stat & POWEROFF) // will be updated again after heat_up
update_use_power(stat & POWEROFF ? POWER_USE_OFF : POWER_USE_IDLE)
if(wasoff != (stat & POWEROFF))
activation_message(user)
playsound(src, 'sound/machines/click.ogg', 40, 1)
@@ -121,7 +121,7 @@
/obj/machinery/appliance/cooker/update_icon()
overlays.Cut()
var/image/light
if (use_power == 2 && !stat)
if (use_power == POWER_USE_ACTIVE && !stat)
light = image(icon, "light_on")
else
light = image(icon, "light_off")
@@ -129,7 +129,7 @@
light.pixel_y = light_y
overlays += light
/obj/machinery/appliance/cooker/machinery_process()
/obj/machinery/appliance/cooker/process()
var/datum/gas_mixture/loc_air = loc.return_air()
if (stat || (use_power != 2)) // if we're not actively heating
temperature -= min(loss, temperature - loc_air.temperature)
@@ -160,15 +160,15 @@
/obj/machinery/appliance/cooker/proc/heat_up()
if (temperature < set_temp)
if (use_power == 1 && ((set_temp - temperature) > 5))
if (use_power == POWER_USE_IDLE && ((set_temp - temperature) > 5))
playsound(src, 'sound/machines/click.ogg', 20, 1)
use_power = 2 //If we're heating we use the active power
update_use_power(POWER_USE_ACTIVE)
update_icon()
temperature += heating_power / resistance
update_cooking_power()
return TRUE
if (use_power == 2)
use_power = 1
if (use_power == POWER_USE_ACTIVE)
update_use_power(POWER_USE_IDLE)
playsound(src, 'sound/machines/click.ogg', 20, 1)
update_icon()
@@ -107,7 +107,7 @@ fundamental differences
..()
stat |= POWEROFF
playsound(src, 'sound/machines/click.ogg', 40, 1)
use_power = 0
update_use_power(POWER_USE_OFF)
CI.reset()
update_icon()
@@ -118,7 +118,7 @@ fundamental differences
icon_state = off_icon
/obj/machinery/appliance/mixer/machinery_process()
/obj/machinery/appliance/mixer/process()
if (!stat)
for (var/i in cooking_objs)
do_cooking_tick(i)
@@ -46,7 +46,7 @@
//Set temperature of oil
oil.set_temperature(temperature)
/obj/machinery/appliance/cooker/fryer/machinery_process()
/obj/machinery/appliance/cooker/fryer/process()
. = ..()
//Set temperature of oil
oil.set_temperature(temperature)
+1 -2
View File
@@ -14,7 +14,6 @@
var/gib_time = 40 // Time from starting until meat appears
var/gib_throw_dir = WEST // Direction to spit meat and gibs in.
use_power = 1
idle_power_usage = 2
active_power_usage = 500
@@ -174,7 +173,7 @@
if(!occupant)
visible_message(SPAN_DANGER("You hear a loud metallic grinding sound."))
return
use_power(1000)
use_power_oneoff(1000)
visible_message(SPAN_DANGER("You hear a loud [occupant.isSynthetic() ? "metallic" : "squelchy"] grinding sound."))
operating = TRUE
update_icon()
+1 -1
View File
@@ -16,7 +16,7 @@
icon_state = "icecream_vat"
density = 1
anchored = 0
use_power = 0
use_power = POWER_USE_OFF
flags = OPENCONTAINER | NOREACT
var/list/product_types = list()
@@ -7,7 +7,6 @@
layer = 2.9
density = 1
anchored = 1
use_power = 1
idle_power_usage = 5
active_power_usage = 100
flags = NOREACT
@@ -194,7 +193,7 @@
if (S.dried_type)
return TRUE
/obj/machinery/smartfridge/drying_rack/machinery_process()
/obj/machinery/smartfridge/drying_rack/process()
..()
if(length(contents))
dry()
@@ -209,7 +208,7 @@
SSvueui.check_uis_for_change(src)
return
/obj/machinery/smartfridge/machinery_process()
/obj/machinery/smartfridge/process()
if(stat & (BROKEN|NOPOWER))
seconds_electrified = 0
return
@@ -234,7 +233,7 @@
else if (mod == -1) //GOING DOWN
thermal_energy_change = max(-active_power_usage,I.reagents.get_thermal_energy_change(r_temperature,cooling_temperature))
I.reagents.add_thermal_energy(thermal_energy_change)
use_power(active_power_usage)
use_power_oneoff(active_power_usage)
/obj/machinery/smartfridge/power_change()
..()
@@ -84,7 +84,7 @@
return 1
/obj/machinery/dnaforensics/machinery_process()
/obj/machinery/dnaforensics/process()
if(scanning)
if(!bloodsamp || bloodsamp.loc != src)
bloodsamp = null
+1 -2
View File
@@ -20,7 +20,6 @@ log transactions
icon = 'icons/obj/terminals.dmi'
icon_state = "atm"
anchored = 1
use_power = 1
idle_power_usage = 10
var/datum/money_account/authenticated_account
var/number_incorrect_tries = 0
@@ -64,7 +63,7 @@ log transactions
var/mutable_appearance/card_overlay = mutable_appearance(icon, "atm-cardin", EFFECTS_ABOVE_LIGHTING_LAYER)
add_overlay(card_overlay)
/obj/machinery/atm/machinery_process()
/obj/machinery/atm/process()
if(stat & NOPOWER)
cut_overlays()
set_light(FALSE)
+1 -2
View File
@@ -5,7 +5,6 @@
icon = 'icons/obj/terminals.dmi'
icon_state = "kitchenterminal"
anchored = 1
use_power = 1
idle_power_usage = 10
var/machine_id = ""
var/list/items = list()
@@ -39,7 +38,7 @@
add_overlay(screen_overlay)
set_light(1.4, 1, COLOR_CYAN)
/obj/machinery/orderterminal/machinery_process()
/obj/machinery/orderterminal/process()
if(stat & NOPOWER)
cut_overlays()
set_light(FALSE)
+2 -2
View File
@@ -12,7 +12,7 @@
/datum/event/brand_intelligence/start()
for(var/obj/machinery/vending/V in SSmachinery.processing_machines)
for(var/obj/machinery/vending/V in SSmachinery.processing)
if(isNotStationLevel(V.z)) continue
vendingMachines.Add(V)
@@ -52,4 +52,4 @@
/datum/event/brand_intelligence/end(var/faked)
for(var/obj/machinery/vending/infectedMachine in infectedVendingMachines)
infectedMachine.shut_up = 1
infectedMachine.shoot_inventory = 0
infectedMachine.shoot_inventory = 0
+3 -3
View File
@@ -21,7 +21,7 @@
/datum/event/electrical_storm/start()
..()
valid_apcs = list()
for(var/obj/machinery/power/apc/A in SSmachinery.all_machines)
for(var/obj/machinery/power/apc/A in SSmachinery.machinery)
if(A.z in affecting_z)
valid_apcs.Add(A)
endWhen = (severity * 60) + startWhen
@@ -29,7 +29,7 @@
/datum/event/electrical_storm/start()
..()
valid_apcs = list()
for(var/obj/machinery/power/apc/A in SSmachinery.all_machines)
for(var/obj/machinery/power/apc/A in SSmachinery.machinery)
if(A.z in affecting_z)
valid_apcs.Add(A)
endWhen = (severity * 60) + startWhen
@@ -71,4 +71,4 @@
for (var/zlevel in affecting_z)
if(zlevel in current_map.station_levels)
command_announcement.Announce("The [location_name()] has cleared the electrical storm. Please repair any electrical overloads.", "Electrical Storm Alert")
break
break
+1 -1
View File
@@ -88,7 +88,7 @@
/datum/event/ionstorm/tick()
if(botEmagChance)
for(var/obj/machinery/bot/bot in SSmachinery.all_machines)
for(var/obj/machinery/bot/bot in SSmachinery.machinery)
if(prob(botEmagChance))
bot.emag_act(1)
+2 -2
View File
@@ -20,7 +20,7 @@
Notifications will be sent as updates occur.<br>"
var/my_department = "[station_name()] firewall subroutines"
for(var/obj/machinery/message_server/MS in SSmachinery.processing_machines)
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
if(!MS.active) continue
MS.send_rc_message("Executive Officer's Desk", my_department, message, "", "", 2)
@@ -61,6 +61,6 @@
var/my_department = "[station_name()] firewall subroutines"
for(var/obj/machinery/message_server/MS in SSmachinery.processing_machines)
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
if(!MS.active) continue
MS.send_rc_message("Executive Officer's Desk", my_department, message, "", "", 2)
+1 -1
View File
@@ -50,7 +50,7 @@
if(areas && areas.len > 0)
var/my_department = "[station_name()] firewall subroutines"
var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [worldtime2text()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.<br>"
for(var/obj/machinery/message_server/MS in SSmachinery.processing_machines)
for(var/obj/machinery/message_server/MS in SSmachinery.processing)
MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2)
for(var/mob/living/silicon/ai/A in player_list)
to_chat(A, "<span class='danger'>Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].</span>")
+1 -1
View File
@@ -17,7 +17,7 @@
/datum/event/spider_infestation/start()
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSmachinery.processing_machines)
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in SSmachinery.processing)
if(!temp_vent.welded && temp_vent.network && isStationLevel(temp_vent.loc.z))
if(temp_vent.network.normal_members.len > 50)
vents += temp_vent
+1 -1
View File
@@ -48,7 +48,7 @@
/datum/event/vent_clog/setup()
endWhen = rand(25, 100)
for(var/obj/machinery/atmospherics/unary/vent_scrubber/temp_vent in SSmachinery.processing_machines)
for(var/obj/machinery/atmospherics/unary/vent_scrubber/temp_vent in SSmachinery.processing)
if(!temp_vent)
continue
if(isStationLevel(temp_vent.z))
@@ -28,7 +28,7 @@
if(count_drones() >= config.max_maint_drones)
return "The maximum number of active drones has been reached"
var/has_active_fabricator = FALSE
for(var/obj/machinery/drone_fabricator/DF in SSmachinery.all_machines)
for(var/obj/machinery/drone_fabricator/DF in SSmachinery.machinery)
if((DF.stat & NOPOWER) || !DF.produce_drones || DF.drone_progress < 100)
continue
has_active_fabricator = TRUE
@@ -40,7 +40,7 @@
/datum/ghostspawner/simplemob/maintdrone/spawn_mob(mob/user)
var/obj/machinery/drone_fabricator/fabricator
var/list/all_fabricators = list()
for(var/obj/machinery/drone_fabricator/DF in SSmachinery.all_machines)
for(var/obj/machinery/drone_fabricator/DF in SSmachinery.machinery)
if((DF.stat & NOPOWER) || !DF.produce_drones || DF.drone_progress < 100)
continue
all_fabricators[DF.fabricator_tag] = DF
@@ -84,4 +84,4 @@
to_chat(user, SPAN_WARNING("The fabricator isn't ready to produce another drone, try again."))
return FALSE
return TRUE
return TRUE
+1 -1
View File
@@ -207,7 +207,7 @@
radio = new(src)
if(!camera)
camera = new /obj/machinery/camera(src)
camera = new /obj/machinery/camera(src, 0, TRUE, TRUE)
camera.c_tag = name
camera.replace_networks(list(NETWORK_MECHS))
+7 -8
View File
@@ -6,7 +6,6 @@
icon_screen = "holocontrolw"
light_color = LIGHT_COLOR_CYAN
use_power = 1
active_power_usage = 8000 //8kW for the scenery + 500W per holoitem
circuit = /obj/item/circuitboard/holodeckcontrol
@@ -186,7 +185,7 @@
if (stat != oldstat && active && (stat & NOPOWER))
emergencyShutdown()
/obj/machinery/computer/HolodeckControl/machinery_process()
/obj/machinery/computer/HolodeckControl/process()
for(var/item in holographic_objs) // do this first, to make sure people don't take items out when power is down.
if(!(get_turf(item) in linkedholodeck))
derez(item, 0)
@@ -204,13 +203,13 @@
if(inoperable())
return
if(active)
use_power(item_power_usage * (holographic_objs.len + holographic_mobs.len))
use_power_oneoff(item_power_usage * (holographic_objs.len + holographic_mobs.len))
if(!checkInteg(linkedholodeck))
damaged = 1
loadProgram(current_map.holodeck_programs["turnoff"], 0)
active = 0
use_power = 1
update_use_power(POWER_USE_IDLE)
for(var/mob/M in range(10,src))
M.show_message("The holodeck overloads!")
@@ -256,7 +255,7 @@
linkedholodeck.gravitychange(TRUE)
active = 0
use_power = 1
update_use_power(POWER_USE_IDLE)
/obj/machinery/computer/HolodeckControl/proc/loadProgram(var/datum/holodeck_program/HP, var/check_delay = 1)
@@ -277,7 +276,7 @@
last_change = world.time
active = 1
use_power = 2
update_use_power(POWER_USE_ACTIVE)
for(var/item in holographic_objs)
derez(item)
@@ -347,7 +346,7 @@
last_gravity_change = world.time
active = 1
use_power = 1
update_use_power(POWER_USE_IDLE)
if(A.has_gravity())
A.gravitychange(FALSE)
@@ -362,7 +361,7 @@
linkedholodeck.gravitychange(TRUE)
active = 0
use_power = 1
update_use_power(POWER_USE_IDLE)
/obj/machinery/computer/HolodeckControl/proc/togglelock(var/mob/user)
if(allowed(user))
+1 -1
View File
@@ -367,7 +367,7 @@
var/eventstarted = 0
anchored = 1.0
use_power = 0 // reason is because the holodeck already takes power so this can be powered as a result.
use_power = POWER_USE_OFF // reason is because the holodeck already takes power so this can be powered as a result.
/obj/machinery/readybutton/attack_ai(mob/user as mob)
to_chat(user, "The station AI is not to interact with these devices!")
@@ -145,7 +145,7 @@
to_chat(user, SPAN_NOTICE("You take all filled honeycombs out."))
return
/obj/machinery/beehive/machinery_process()
/obj/machinery/beehive/process()
if(closed && !smoked && bee_count)
pollinate_flowers()
update_icon()
@@ -211,4 +211,4 @@
user.visible_message(SPAN_NOTICE("\The [user] constructs a beehive."), SPAN_NOTICE("You construct a beehive."))
new /obj/machinery/beehive(get_turf(user))
qdel(src)
return
return
+1 -2
View File
@@ -37,7 +37,6 @@
icon_state = "hydrotray3"
density = 1
anchored = 1
use_power = 1
var/obj/item/seeds/seed // Currently loaded seed packet.
var/obj/item/disk/botany/loaded_disk //Currently loaded data disk.
@@ -50,7 +49,7 @@
var/failed_task = 0
var/disk_needs_genes = 0
/obj/machinery/botany/machinery_process()
/obj/machinery/botany/process()
..()
if(!active) return
-1
View File
@@ -24,7 +24,6 @@
icon_state = SEED_NOUN_SEEDS
density = 1
anchored = 1
use_power = 1
idle_power_usage = 100
var/list/datum/seed_pile/piles = list()
@@ -107,7 +107,7 @@
else
return 0
/obj/machinery/apiary/machinery_process()
/obj/machinery/apiary/process()
if(swarming > 0)
swarming -= 1
@@ -1,4 +1,4 @@
/obj/machinery/portable_atmospherics/hydroponics/machinery_process()
/obj/machinery/portable_atmospherics/hydroponics/process()
// Handle nearby smoke if any.
for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
+2 -2
View File
@@ -3,7 +3,7 @@
desc = "A mound of earth. You could plant some seeds here."
icon_state = "soil"
density = 0
use_power = 0
use_power = POWER_USE_OFF
mechanical = 0
tray_light = 0
waterlevel = 0
@@ -74,7 +74,7 @@
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/die()
qdel(src)
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/machinery_process()
/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/process()
if(!seed)
qdel(src)
return
@@ -60,7 +60,7 @@
var/area/A = get_area(src)
if(A)
if(A.powered(EQUIP) && assembly.give_power(power_amount))
A.use_power(power_amount, EQUIP)
A.use_power_oneoff(power_amount, EQUIP)
// give_power() handles CELLRATE on its own.
// For implants.
@@ -251,7 +251,7 @@
/obj/item/integrated_circuit/output/video_camera/Initialize()
. = ..()
camera = new(src)
camera = new(src, 0, TRUE, TRUE)
on_data_written()
/obj/item/integrated_circuit/output/video_camera/Destroy()
@@ -405,4 +405,4 @@
audible_message("<span class='notice'>\The [src] beeps, out of paper.</span>")
return
else
audible_message("<span class='notice'>\The [src] beeps, out of paper.</span>")
audible_message("<span class='notice'>\The [src] beeps, out of paper.</span>")
+1 -1
View File
@@ -140,7 +140,7 @@
// If an opaque movable atom moves around we need to potentially update visibility.
/turf/Entered(atom/movable/Obj, atom/OldLoc)
. = ..()
. = ..(Obj, OldLoc)
if (Obj && Obj.opacity && !has_opaque_atom)
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
+2 -2
View File
@@ -113,7 +113,7 @@
SSatoms.InitializeAtoms(atoms) // The atoms should have been getting queued there. This flushes the queue.
SSmachinery.setup_template_powernets(cables)
SSmachinery.setup_powernets_for_cables(cables)
SSmachinery.setup_atmos_machinery(atmos_machines)
if(notsuspended)
SSmachinery.wake()
@@ -181,4 +181,4 @@
var/datum/map_template/M = new template()
M.load(get_turf(mark), TRUE)
qdel(mark)
LAZYCLEARLIST(subtemplates_to_spawn)
LAZYCLEARLIST(subtemplates_to_spawn)
+3 -3
View File
@@ -5,7 +5,7 @@
/obj/machinery/mining
icon = 'icons/obj/mining_drill.dmi'
anchored = FALSE
use_power = 0 //The drill takes power directly from a cell.
use_power = POWER_USE_OFF //The drill takes power directly from a cell.
density = TRUE
layer = MOB_LAYER + 0.1 //So it draws over mobs in the tile north of it.
@@ -65,7 +65,7 @@
QDEL_NULL(spark_system)
return ..()
/obj/machinery/mining/drill/machinery_process()
/obj/machinery/mining/drill/process()
if(need_player_check)
return
@@ -570,4 +570,4 @@
connected.supports -= src
connected.check_supports()
connected = null
connected = null
+6 -8
View File
@@ -11,7 +11,6 @@
icon_state = "production_console"
density = FALSE
anchored = TRUE
use_power = 1
idle_power_usage = 15
active_power_usage = 50
@@ -47,7 +46,7 @@
if(!machine)
var/area/A = get_area(src)
var/best_distance = INFINITY
for(var/obj/machinery/mineral/processing_unit/checked_machine in SSmachinery.all_machines)
for(var/obj/machinery/mineral/processing_unit/checked_machine in SSmachinery.machinery)
if(id)
if(checked_machine.id == id)
machine = checked_machine
@@ -327,7 +326,6 @@
var/list/ores_stored[0]
var/static/list/alloy_data
var/active = 0
use_power = 1
idle_power_usage = 15
active_power_usage = 150
@@ -384,7 +382,7 @@
return ..()
/obj/machinery/mineral/processing_unit/machinery_process()
/obj/machinery/mineral/processing_unit/process()
..()
if(!src.output || !src.input)
@@ -444,7 +442,7 @@
if(console)
var/ore/Ore = ore_data[needs_metal]
console.points += Ore.worth
use_power(100)
use_power_oneoff(100)
ores_stored[needs_metal] -= A.requires[needs_metal]
total += A.requires[needs_metal]
total = max(1, round(total * A.product_mod)) //Always get at least one sheet.
@@ -468,7 +466,7 @@
for(var/i = 0, i < can_make, i += 2)
if(console)
console.points += O.worth * 2
use_power(100)
use_power_oneoff(100)
ores_stored[metal] -= 2
sheets += 2
console.output_mats[M] += 1
@@ -484,7 +482,7 @@
for(var/i = 0, i < can_make, i++)
if(console)
console.points += O.worth
use_power(100)
use_power_oneoff(100)
ores_stored[metal] -= 1
sheets++
if(console)
@@ -493,7 +491,7 @@
else
if(console)
console.points -= O.worth * 3 //reee wasting our materials!
use_power(500)
use_power_oneoff(500)
ores_stored[metal] -= 1
sheets++
if(console)
+2 -3
View File
@@ -6,7 +6,6 @@
icon_state = "coinpress0"
density = TRUE
anchored = TRUE
use_power = 1
idle_power_usage = 15
active_power_usage = 50
var/pressing
@@ -50,14 +49,14 @@
src.visible_message(SPAN_NOTICE("\The [src] begins to print out a modsuit."))
pressing = TRUE
update_icon()
use_power(500)
use_power_oneoff(500)
qdel(W)
spawn(300)
ping("\The [src] pings, \"Module successfuly produced!\"")
new outcome_path(get_turf(src))
use_power(500)
use_power_oneoff(500)
pressing = FALSE
update_icon()
+3 -5
View File
@@ -8,7 +8,6 @@
density = FALSE
anchored = TRUE
var/obj/machinery/mineral/stacking_machine/machine
use_power = 1
idle_power_usage = 15
active_power_usage = 50
@@ -37,7 +36,7 @@
if(!machine)
var/area/A = get_area(src)
var/best_distance = INFINITY
for(var/obj/machinery/mineral/stacking_machine/checked_machine in SSmachinery.all_machines)
for(var/obj/machinery/mineral/stacking_machine/checked_machine in SSmachinery.machinery)
if(id)
if(checked_machine.id == id)
machine = checked_machine
@@ -127,7 +126,6 @@
var/list/stack_storage = list()
var/list/stack_paths = list()
var/stack_amt = 50 // Amount to stack before releasing
use_power = 1
idle_power_usage = 15
active_power_usage = 50
@@ -175,7 +173,7 @@
return
return ..()
/obj/machinery/mineral/stacking_machine/machinery_process()
/obj/machinery/mineral/stacking_machine/process()
if(!console)
return
if(stat & BROKEN)
@@ -199,4 +197,4 @@
if(stack_storage[sheet] >= stack_amt)
new sheet(output, stack_amt)
stack_storage[sheet] -= stack_amt
intent_message(MACHINE_SOUND)
intent_message(MACHINE_SOUND)
+1 -2
View File
@@ -7,7 +7,6 @@
icon_state = "unloader"
density = TRUE
anchored = TRUE
use_power = 1
idle_power_usage = 15
active_power_usage = 50
var/turf/input
@@ -48,7 +47,7 @@
return
return ..()
/obj/machinery/mineral/unloading_machine/machinery_process()
/obj/machinery/mineral/unloading_machine/process()
..()
if(src.output && src.input)
if(locate(/obj/structure/ore_box, input))
+1 -1
View File
@@ -978,7 +978,7 @@ var/list/total_extraction_beacons = list()
var/obj/machinery/anti_bluespace/AB = found_inhibitor
if(T.z != AB.z || get_dist(T, AB) > 8 || (AB.stat & (NOPOWER | BROKEN)))
continue
AB.use_power(AB.active_power_usage)
AB.use_power_oneoff(AB.active_power_usage)
to_chat(user, SPAN_WARNING("A nearby bluespace inhibitor interferes with \the [src]!"))
return
to_chat(user, SPAN_NOTICE("You start attaching the pack to \the [A]..."))
+2 -2
View File
@@ -32,7 +32,7 @@
break
START_PROCESSING(SSprocessing, src)
/obj/machinery/mineral/mint/machinery_process()
/obj/machinery/mineral/mint/process()
if(input)
var/obj/item/stack/O
O = locate(/obj/item/stack, get_turf(input))
@@ -204,4 +204,4 @@
processing = FALSE
coinsToProduce = temp_coins
src.updateUsrDialog()
return
return
@@ -518,7 +518,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
//If we hit the limit without finding a valid one, then the best one we found is selected
var/list/found_vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/v in SSmachinery.processing_machines)
for(var/obj/machinery/atmospherics/unary/vent_pump/v in SSmachinery.processing)
if(!v.welded && v.z == ZLevel)
found_vents.Add(v)
+7 -7
View File
@@ -306,7 +306,7 @@ var/list/ai_verbs_default = list(
/obj/machinery/ai_powersupply
name = "power supply"
active_power_usage = 50000 // Station AIs use significant amounts of power. This, when combined with charged SMES should mean AI lasts for 1hr without external power.
use_power = 2
use_power = POWER_USE_ACTIVE
power_channel = EQUIP
var/mob/living/silicon/ai/powered_ai
invisibility = 100
@@ -317,13 +317,13 @@ var/list/ai_verbs_default = list(
forceMove(powered_ai.loc)
..()
use_power(1) // Just incase we need to wake up the power system.
use_power_oneoff(1) // Just incase we need to wake up the power system.
/obj/machinery/ai_powersupply/Destroy()
. = ..()
powered_ai = null
/obj/machinery/ai_powersupply/machinery_process()
/obj/machinery/ai_powersupply/process()
if(!powered_ai || powered_ai.stat == DEAD)
qdel(src)
return
@@ -331,14 +331,14 @@ var/list/ai_verbs_default = list(
qdel(src)
return
if(powered_ai.APU_power)
use_power = 0
update_use_power(POWER_USE_OFF)
return
if(!powered_ai.anchored)
loc = powered_ai.loc
use_power = 0
use_power(50000) // Less optimalised but only called if AI is unwrenched. This prevents usage of wrenching as method to keep AI operational without power. Intellicard is for that.
update_use_power(POWER_USE_OFF)
use_power_oneoff(50000) // Less optimalised but only called if AI is unwrenched. This prevents usage of wrenching as method to keep AI operational without power. Intellicard is for that.
if(powered_ai.anchored)
use_power = 2
update_use_power(POWER_USE_ACTIVE)
/mob/living/silicon/ai/rejuvenate()
return // TODO: Implement AI rejuvination
@@ -14,7 +14,7 @@
density = TRUE
anchored = TRUE
use_power = TRUE
use_power = POWER_USE_IDLE
idle_power_usage = 20
active_power_usage = 5000
@@ -43,7 +43,7 @@
if(stat & NOPOWER)
icon_state = "drone_fab_nopower"
/obj/machinery/drone_fabricator/machinery_process()
/obj/machinery/drone_fabricator/process()
if(!ROUND_IS_STARTED)
return
@@ -57,7 +57,7 @@
to_chat(user, SPAN_WARNING("\The [src] is empty. Put something inside it first."))
if(response == "Sync")
var/success = FALSE
for(var/obj/machinery/r_n_d/server/S in SSmachinery.all_machines)
for(var/obj/machinery/r_n_d/server/S in SSmachinery.machinery)
for(var/id in files.known_tech) //Uploading
var/datum/tech/T = files.known_tech[id]
S.files.AddTech2Known(T)
@@ -160,7 +160,7 @@
common_radio = radio
if(!camera)
camera = new /obj/machinery/camera(src)
camera = new /obj/machinery/camera(src, 0, TRUE, TRUE)
camera.c_tag = real_name
if(!scrambled_codes)
camera.replace_networks(list(NETWORK_STATION, NETWORK_ROBOTS))
@@ -219,7 +219,7 @@
. = ..()
radio = new radio_type(src)
camera = new /obj/machinery/camera(src)
camera = new /obj/machinery/camera(src, 0, TRUE, TRUE)
camera.c_tag = "spiderbot-[real_name]"
camera.replace_networks(list("SS13"))
@@ -98,10 +98,10 @@
icon = 'icons/obj/telescience.dmi'
icon_state = "pad-idle"
anchored = TRUE
use_power = TRUE
use_power = POWER_USE_IDLE
/obj/machinery/vannatusk_spawner/power_change()
..()
spark(src, 3, alldirs)
new /mob/living/simple_animal/hostile/vannatusk(get_turf(src))
qdel(src)
qdel(src)
@@ -32,7 +32,7 @@ var/global/datum/ntnet/ntnet_global = new()
/datum/ntnet/New()
if(ntnet_global && (ntnet_global != src))
ntnet_global = src // There can be only one.
for(var/obj/machinery/ntnet_relay/R in SSmachinery.all_machines)
for(var/obj/machinery/ntnet_relay/R in SSmachinery.machinery)
relays.Add(R)
R.NTNet = src
build_software_lists()
@@ -163,4 +163,4 @@ var/global/datum/ntnet/ntnet_global = new()
add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.")
if(NTNET_SYSTEMCONTROL)
setting_systemcontrol = !setting_systemcontrol
add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
@@ -2,7 +2,7 @@
/obj/machinery/ntnet_relay
name = "NTNet Quantum Relay"
desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile."
use_power = 2
use_power = POWER_USE_ACTIVE
active_power_usage = 20000 //20kW, appropriate for machine that keeps massive cross-Zlevel wireless network operational.
idle_power_usage = 100
icon_state = "ntnet"
@@ -48,11 +48,11 @@
else
add_overlay("ntnet_o_ok")
/obj/machinery/ntnet_relay/machinery_process()
/obj/machinery/ntnet_relay/process()
if(operable())
use_power = 2
update_use_power(POWER_USE_ACTIVE)
else
use_power = 1
update_use_power(POWER_USE_IDLE)
if(dos_overload)
dos_overload = max(0, dos_overload - dos_dissipate)
@@ -35,7 +35,7 @@
power_usage += tesla_link.passive_charging_rate
battery_module.battery.give(tesla_link.passive_charging_rate * CELLRATE)
A.use_power(power_usage, EQUIP)
A.use_power_oneoff(power_usage, EQUIP)
return TRUE
@@ -62,4 +62,4 @@
power_has_failed = FALSE
update_icon()
return
power_failure()
power_failure()
@@ -385,7 +385,7 @@ Command action procs
/proc/is_relay_online()
for(var/obj/machinery/bluespacerelay/M in SSmachinery.all_machines)
for(var/obj/machinery/bluespacerelay/M in SSmachinery.machinery)
if(M.stat == 0)
return TRUE
return FALSE
@@ -92,7 +92,7 @@
return TRUE
else if(href_list["toggledoor"])
for(var/obj/machinery/door/blast/M in SSmachinery.all_machines)
for(var/obj/machinery/door/blast/M in SSmachinery.machinery)
if(M.id == href_list["toggledoor"])
if(M.density)
M.open()
+2 -2
View File
@@ -62,7 +62,7 @@
invisibility = i ? 101 : 0
queue_icon_update()
/obj/machinery/atmospherics/pipe/zpipe/machinery_process()
/obj/machinery/atmospherics/pipe/zpipe/process()
if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
..()
else
@@ -291,4 +291,4 @@
/obj/machinery/atmospherics/pipe/zpipe/up/purple
color = PIPE_COLOR_PURPLE
/obj/machinery/atmospherics/pipe/zpipe/down/purple
color = PIPE_COLOR_PURPLE
color = PIPE_COLOR_PURPLE
+1 -1
View File
@@ -6,7 +6,7 @@
var/tmp/atom/movable/openspace/multiplier/shadower // Overlay used to multiply color of all OO overlays at once.
/turf/Entered(atom/movable/thing, turf/oldLoc)
. = ..()
. = ..(thing, oldLoc)
if (thing.bound_overlay || thing.no_z_overlay || !TURF_IS_MIMICING(above))
return
above.update_mimic()
+3 -3
View File
@@ -19,7 +19,7 @@
log_debug("\The [src] given an unepxected req_one_access: [req_one_access]")
if(monitored_alarm_ids)
for(var/obj/machinery/alarm/alarm in SSmachinery.processing_machines)
for(var/obj/machinery/alarm/alarm in SSmachinery.processing)
if(alarm.alarm_id && (alarm.alarm_id in monitored_alarm_ids))
monitored_alarms += alarm
// machines may not yet be ordered at this point
@@ -31,7 +31,7 @@
if(href_list["alarm"])
if(ui_ref)
var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : SSmachinery.processing_machines)
var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms.len ? monitored_alarms : SSmachinery.processing)
if(alarm)
var/datum/topic_state/TS = generate_state(alarm)
alarm.ui_interact(usr, master_ui = ui_ref, state = TS)
@@ -42,7 +42,7 @@
var/alarms[0]
// TODO: Move these to a cache, similar to cameras
for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : SSmachinery.processing_machines))
for(var/obj/machinery/alarm/alarm in (monitored_alarms.len ? monitored_alarms : SSmachinery.processing))
alarms[++alarms.len] = list("name" = sanitize(alarm.name), "ref"= "\ref[alarm]", "danger" = max(alarm.danger_level, alarm.alarm_area.atmosalm))
data["alarms"] = alarms
+1 -1
View File
@@ -51,7 +51,7 @@
var/turf/T = get_turf(ui_host())
if(!T) // Safety check
return
for(var/obj/machinery/power/sensor/S in SSpower.all_sensors)
for(var/obj/machinery/power/sensor/S in SSmachinery.all_sensors)
if((T && S.loc.z == T.z) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
+4 -4
View File
@@ -11,7 +11,7 @@
// SMES DATA (simplified view)
var/list/smeslist[0]
for(var/obj/machinery/power/smes/buildable/SMES in SSpower.rcon_smes_units)
for(var/obj/machinery/power/smes/buildable/SMES in SSmachinery.rcon_smes_units)
smeslist.Add(list(list(
"charge" = round(SMES.Percentage()),
"input_set" = SMES.input_attempt,
@@ -25,7 +25,7 @@
data["smes_info"] = smeslist
// BREAKER DATA (simplified view)
var/list/breakerlist[0]
for(var/obj/machinery/power/breakerbox/BR in SSpower.rcon_breaker_units)
for(var/obj/machinery/power/breakerbox/BR in SSmachinery.rcon_breaker_units)
breakerlist.Add(list(list(
"RCON_tag" = BR.RCon_tag,
"enabled" = BR.on
@@ -79,7 +79,7 @@
SMES.set_output(SMES.output_level_max)
if(href_list["toggle_breaker"])
var/obj/machinery/power/breakerbox/toggle = SSpower.rcon_breaker_units_by_tag[href_list["toggle_breaker"]]
var/obj/machinery/power/breakerbox/toggle = SSmachinery.rcon_breaker_units_by_tag[href_list["toggle_breaker"]]
if(toggle)
if(toggle.update_locked)
to_chat(usr, "The breaker box was recently toggled. Please wait before toggling it again.")
@@ -100,4 +100,4 @@
if(!tag)
return
return SSpower.rcon_smes_units_by_tag[tag]
return SSmachinery.rcon_smes_units_by_tag[tag]
+1 -1
View File
@@ -21,7 +21,7 @@
if(known)
layer = EFFECTS_ABOVE_LIGHTING_LAYER
for(var/obj/machinery/computer/ship/helm/H in SSmachinery.all_machines)
for(var/obj/machinery/computer/ship/helm/H in SSmachinery.machinery)
H.get_known_sectors()
update_icon()
@@ -15,7 +15,7 @@
/obj/machinery/computer/ship/sensors/proc/find_sensors()
if(!linked)
return
for(var/obj/machinery/shipsensors/S in SSmachinery.all_machines)
for(var/obj/machinery/shipsensors/S in SSmachinery.machinery)
if(linked.check_ownership(S))
sensors = S
break
@@ -102,7 +102,7 @@
new/obj/item/paper/(get_turf(src), O.get_scan_data(usr), "paper (Sensor Scan - [O])")
return TOPIC_HANDLED
/obj/machinery/computer/ship/sensors/machinery_process()
/obj/machinery/computer/ship/sensors/process()
..()
if(!linked)
return
@@ -180,11 +180,11 @@
if(!use_power && (health == 0 || !in_vacuum()))
return // No turning on if broken or misplaced.
if(!use_power) //need some juice to kickstart
use_power(idle_power_usage*5)
use_power_oneoff(idle_power_usage*5)
update_use_power(!use_power)
queue_icon_update()
/obj/machinery/shipsensors/machinery_process()
/obj/machinery/shipsensors/process()
..()
if(use_power) //can't run in non-vacuum
if(!in_vacuum())
@@ -207,7 +207,7 @@
/obj/machinery/shipsensors/proc/set_range(nrange)
range = nrange
active_power_usage = (1500 * (range**2)) //Exponential increase, also affects speed of overheating
change_power_consumption(1500 * (range**2), POWER_USE_ACTIVE)
/obj/machinery/shipsensors/emp_act(severity)
if(!use_power)
@@ -36,12 +36,12 @@
/datum/ship_engine/gas_thruster/toggle()
if(nozzle.use_power)
nozzle.update_use_power(0)
nozzle.update_use_power(POWER_USE_OFF)
else
if(nozzle.blockage)
if(nozzle.check_blockage())
return
nozzle.update_use_power(1)
nozzle.update_use_power(POWER_USE_IDLE)
if(nozzle.stat & NOPOWER)//try again
nozzle.power_change()
if(nozzle.is_on())//if everything is in working order, start booting!
@@ -61,7 +61,7 @@
density = 1
atmos_canpass = CANPASS_NEVER
use_power = 0
use_power = POWER_USE_OFF
power_channel = EQUIP
idle_power_usage = 21600 //6 Wh per tick for default 2 capacitor. Gives them a reason to turn it off, really to nerf backup battery
@@ -148,7 +148,7 @@
/obj/machinery/atmospherics/unary/engine/power_change()
. = ..()
if(stat & NOPOWER)
update_use_power(0)
update_use_power(POWER_USE_OFF)
/obj/machinery/atmospherics/unary/engine/update_use_power()
. = ..()
@@ -185,9 +185,9 @@
/obj/machinery/atmospherics/unary/engine/proc/burn()
if(!is_on())
return 0
if(!check_fuel() || (0 < use_power(charge_per_burn)) || check_blockage())
if(!check_fuel() || (0 < use_power_oneoff(charge_per_burn)) || check_blockage())
audible_message(src,"<span class='warning'>[src] coughs once and goes silent!</span>")
update_use_power(0)
update_use_power(POWER_USE_OFF)
return 0
var/datum/gas_mixture/removed = air_contents.remove_ratio(volume_per_burn * thrust_limit / air_contents.volume)

Some files were not shown because too many files have changed in this diff Show More