diff --git a/aurorastation.dme b/aurorastation.dme index 005fa13f1de..6ec0b12b4aa 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1380,6 +1380,7 @@ #include "code\modules\atmospherics\components\valve.dm" #include "code\modules\atmospherics\components\binary_devices\binary_atmos_base.dm" #include "code\modules\atmospherics\components\binary_devices\circulator.dm" +#include "code\modules\atmospherics\components\binary_devices\oxyregenerator.dm" #include "code\modules\atmospherics\components\binary_devices\passive_gate.dm" #include "code\modules\atmospherics\components\binary_devices\pump.dm" #include "code\modules\atmospherics\components\binary_devices\volume_pump.dm" diff --git a/code/game/objects/items/weapons/circuitboards/machinery/miscboards.dm b/code/game/objects/items/weapons/circuitboards/machinery/miscboards.dm index 5510a9bd9e2..b80fe75a2b8 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/miscboards.dm +++ b/code/game/objects/items/weapons/circuitboards/machinery/miscboards.dm @@ -1,5 +1,5 @@ #ifndef T_BOARD -#error T_BOARD macro is not defined but we need it! +#error T_BOARD macro is not defined but we need it! #endif //Stuff that doesn't fit into any category goes here @@ -167,7 +167,7 @@ desc = "The circuitboard for a holopad." build_path = /obj/machinery/hologram/holopad origin_tech = list(TECH_MAGNET = 3, TECH_ENGINEERING = 2) - board_type = "machine" + board_type = "machine" req_components = list( "/obj/item/stock_parts/capacitor" = 2, "/obj/item/stock_parts/scanning_module" = 1) @@ -193,4 +193,13 @@ "/obj/item/reagent_containers/syringe" = 1, "/obj/item/stock_parts/matter_bin" = 1, "/obj/item/stock_parts/manipulator" = 1, - "/obj/item/stock_parts/scanning_module" = 1) \ No newline at end of file + "/obj/item/stock_parts/scanning_module" = 1) +/obj/item/circuitboard/oxyregenerator + name = "circuit board (oxygen regenerator)" + build_path = /obj/machinery/atmospherics/binary/oxyregenerator + board_type = "machine" + origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + req_components = list( + "/obj/item/stock_parts/micro_laser" = 1, + "/obj/item/stock_parts/manipulator" = 1, + "/obj/item/stock_parts/matter_bin" = 1) diff --git a/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm b/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm index 8ee54f0dd8d..1099704f6ea 100644 --- a/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm +++ b/code/modules/atmospherics/components/binary_devices/binary_atmos_base.dm @@ -133,7 +133,10 @@ 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")) + if(src.anchored) + if(!allowed(user)) + to_chat(user, SPAN_WARNING("Access denied.")) + return + Topic(src, list("power" = "1")) + else + . = ..() diff --git a/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm b/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm new file mode 100644 index 00000000000..7e2427362ff --- /dev/null +++ b/code/modules/atmospherics/components/binary_devices/oxyregenerator.dm @@ -0,0 +1,193 @@ +/obj/machinery/atmospherics/binary/oxyregenerator + name ="oxygen regenerator" + desc = "A machine for breaking bonds in carbon dioxide and releasing pure oxygen." + icon = 'icons/atmos/oxyregenerator.dmi' + icon_state = "off" + level = 1 + density = TRUE + use_power = POWER_USE_OFF + obj_flags = OBJ_FLAG_ROTATABLE + idle_power_usage = 200 //internal circuitry, friction losses and stuff + power_rating = 10000 + + component_types = list( + /obj/item/circuitboard/oxyregenerator, + /obj/item/stock_parts/matter_bin, + /obj/item/stock_parts/manipulator, + /obj/item/stock_parts/micro_laser, + ) + + var/target_pressure = 10*ONE_ATMOSPHERE + var/id = null + var/power_setting = 1 //power consumption setting, 1 through five + var/carbon_stored = 0 + var/carbon_efficiency = 0.5 + var/intake_power_efficiency = 1 + var/const/carbon_moles_per_piece = 50 //One 12g per mole * 50 = 600 g chunk of coal + var/phase = "filling"//"filling", "processing", "releasing" + var/datum/gas_mixture/inner_tank = new + var/tank_volume = 400//Litres + +/obj/machinery/atmospherics/binary/oxyregenerator/Initialize() + . = ..() + anchored = TRUE + RefreshParts() + anchor_helper() + +/obj/machinery/atmospherics/binary/oxyregenerator/RefreshParts() + carbon_efficiency = initial(carbon_efficiency) + intake_power_efficiency = initial(intake_power_efficiency) + power_rating = 1 + + for(var/obj/item/stock_parts/P in component_parts) + if(ismatterbin(P)) + carbon_efficiency += (0.25 * P.rating) - 0.25 + else if(ismanipulator(P)) + intake_power_efficiency -= (0.1 * P.rating) - 0.1 + else if(ismicrolaser(P)) + power_rating -= (0.05 * P.rating) - 0.05 + + carbon_efficiency = clamp(carbon_efficiency, initial(carbon_efficiency), 5) + intake_power_efficiency = clamp(intake_power_efficiency, 0.1, initial(intake_power_efficiency)) + power_rating = clamp(power_rating, 0.1, 1) + power_rating *= initial(power_rating) + ..() + +/obj/machinery/atmospherics/binary/oxyregenerator/examine(user) + . = ..() + to_chat(user,"Its outlet port is to the [dir2text(dir)]") + +/obj/machinery/atmospherics/binary/oxyregenerator/attackby(obj/item/O as obj, mob/user as mob) + if(O.iswrench()) + playsound(src.loc, 'sound/items/Ratchet.ogg', 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") + + anchor_helper() + +/obj/machinery/atmospherics/binary/oxyregenerator/proc/anchor_helper() + 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) + +/obj/machinery/atmospherics/binary/oxyregenerator/attack_hand(mob/user) + . = ..() + ui_interact(user) + +/obj/machinery/atmospherics/binary/oxyregenerator/process() + . = ..() + if((inoperable()) || !use_power) + return + + var/power_draw = -1 + last_power_draw = 0 + //TODO Add overlay with F-P-R letter to display current state + if (phase == "filling")//filling tank + var/pressure_delta = target_pressure - inner_tank.return_pressure() + if (pressure_delta > 0.01 && air1.temperature > 0) + var/transfer_moles = calculate_transfer_moles(air1, inner_tank, pressure_delta) + power_draw = pump_gas(src, air1, inner_tank, transfer_moles, power_rating*power_setting) * intake_power_efficiency + if (power_draw >= 0) + last_power_draw = power_draw + use_power_oneoff(power_draw) + if(network1) + network1.update = 1 + if (air1.return_pressure() < 0.1 * ONE_ATMOSPHERE || inner_tank.return_pressure() >= target_pressure * 0.95)//if pipe is good as empty or tank is full + phase = "processing" + + if (phase == "processing")//processing CO2 in tank + if (inner_tank.gas[GAS_CO2]) + var/co2_intake = clamp(inner_tank.gas[GAS_CO2], 0, power_setting * 0.1) + last_flow_rate = co2_intake + inner_tank.adjust_gas(GAS_CO2, -co2_intake, 1) + var/datum/gas_mixture/new_oxygen = new + new_oxygen.adjust_gas(GAS_OXYGEN, co2_intake) + new_oxygen.temperature = T20C+30 //it's sort of hot after molecular bond breaking + inner_tank.merge(new_oxygen) + carbon_stored += co2_intake * carbon_efficiency + while (carbon_stored >= carbon_moles_per_piece) + carbon_stored -= carbon_moles_per_piece + var/material/M = SSmaterials.get_material_by_name(MATERIAL_GRAPHITE) + M.place_sheet(get_turf(src), 1, M.name) + power_draw = power_rating * co2_intake + last_power_draw = power_draw + use_power_oneoff(power_draw) + else + phase = "releasing" + + if (phase == "releasing")//releasing processed gas mix + power_draw = -1 + var/pressure_delta = target_pressure - air2.return_pressure() + if (pressure_delta > 0.01 && inner_tank.temperature > 0) + var/transfer_moles = calculate_transfer_moles(inner_tank, air2, pressure_delta, (network2)? network2.volume : 0) + power_draw = pump_gas(src, inner_tank, air2, transfer_moles, power_rating*power_setting) + if (power_draw >= 0) + last_power_draw = power_draw + use_power_oneoff(power_draw) + if(network2) + network2.update = 1 + else//can't push outside harder than target pressure. Device is not intended to be used as a pump after all + phase = "filling" + if (inner_tank.return_pressure() <= 0.1) + phase = "filling" + +/obj/machinery/atmospherics/binary/oxyregenerator/update_icon() + if(stat & (BROKEN|NOPOWER)) + icon_state = "off" + else + icon_state = "[use_power ? "on" : "off"]" + +/obj/machinery/atmospherics/binary/oxyregenerator/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) + var/data[0] + data["on"] = use_power ? 1 : 0 + data["powerSetting"] = power_setting + data["gasProcessed"] = last_flow_rate + data["air1Pressure"] = round(air1.return_pressure()) + data["air2Pressure"] = round(air2.return_pressure()) + data["tankPressure"] = round(inner_tank.return_pressure()) + data["targetPressure"] = round(target_pressure) + data["phase"] = phase + if (inner_tank.total_moles > 0) + data["co2"] = round(100 * inner_tank.gas[GAS_CO2]/inner_tank.total_moles) + data["o2"] = round(100 * inner_tank.gas[GAS_OXYGEN]/inner_tank.total_moles) + else + data["co2"] = 0 + data["o2"] = 0 + // 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) + ui = new(user, src, ui_key, "oxyregenerator.tmpl", "Oxygen Regeneration System", 440, 300) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/atmospherics/binary/oxyregenerator/Topic(href, href_list) + if(..()) + return 1 + if(href_list["power"]) + update_use_power(!use_power) + update_icon() + return 1 + if(href_list["setPower"]) //setting power to 0 is redundant anyways + power_setting = clamp(text2num(href_list["setPower"]), 1, 5) + return 1 diff --git a/code/modules/research/designs/circuit/machine_circuits.dm b/code/modules/research/designs/circuit/machine_circuits.dm index e4441053b22..90976f4f112 100644 --- a/code/modules/research/designs/circuit/machine_circuits.dm +++ b/code/modules/research/designs/circuit/machine_circuits.dm @@ -235,4 +235,9 @@ /datum/design/circuit/machine/iv_drip name = "IV drip" req_tech = list(TECH_DATA = 1, TECH_BIO = 2) - build_path = /obj/item/circuitboard/iv_drip \ No newline at end of file + build_path = /obj/item/circuitboard/iv_drip + +/datum/design/circuit/oxyregenerator + name = "oxygen regenerator" + req_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 2) + build_path = /obj/item/circuitboard/oxyregenerator diff --git a/html/changelogs/fluffyghost-portoxyregenerator.yml b/html/changelogs/fluffyghost-portoxyregenerator.yml new file mode 100644 index 00000000000..54c3f2319c9 --- /dev/null +++ b/html/changelogs/fluffyghost-portoxyregenerator.yml @@ -0,0 +1,42 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: Fluffyghost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Ported oxygen regenerator from Bay." + - bugfix: "Resolved an issue where binary atmos items could not be rotated with alt-click despite the description saying so." diff --git a/icons/atmos/oxyregenerator.dmi b/icons/atmos/oxyregenerator.dmi new file mode 100644 index 00000000000..f40b94096e1 Binary files /dev/null and b/icons/atmos/oxyregenerator.dmi differ diff --git a/nano/templates/oxyregenerator.tmpl b/nano/templates/oxyregenerator.tmpl new file mode 100644 index 00000000000..19cb4fdd7c9 --- /dev/null +++ b/nano/templates/oxyregenerator.tmpl @@ -0,0 +1,136 @@ +
+
+ Status: +
+
+ {{:helper.link('On', 'power', {'power' : 1}, data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', {'power' : 1}, data.on ? null : 'selected')}} +
+
+ +
+
+ Power Level: +
+
+ {{:helper.link('1', null, {'setPower' : 1}, (data.powerSetting == 1)? 'selected' : null)}} + {{:helper.link('2', null, {'setPower' : 2}, (data.powerSetting == 2)? 'selected' : null)}} + {{:helper.link('3', null, {'setPower' : 3}, (data.powerSetting == 3)? 'selected' : null)}} + {{:helper.link('4', null, {'setPower' : 4}, (data.powerSetting == 4)? 'selected' : null)}} + {{:helper.link('5', null, {'setPower' : 5}, (data.powerSetting == 5)? 'selected' : null)}} +
+
+ + +{{if data.phase == "filling"}} +
+
+ Processing phase: +
+
+ filling inner tank +
+
+
+
+ Input pressure: +
+
+ {{:data.air1Pressure}} kPa +
+
+
+
+ Tank pressure: +
+
+ {{:data.tankPressure}} kPa +
+
+
+
+ Target tank pressure: +
+
+ {{:data.targetPressure}} kPa +
+
+{{/if}} + +{{if data.phase == "processing"}} +
+
+ Processing phase: +
+
+ processing gas mix +
+
+
+
+ Processing rate: +
+
+ {{:data.gasProcessed}} moles +
+
+
+
+ Tank pressure: +
+
+ {{:data.tankPressure}} kPa +
+
+
+
+ CO2 content: +
+
+ {{:data.co2}} % +
+
+
+
+ O2 content: +
+
+ {{:data.o2}} % +
+
+{{/if}} + + +{{if data.phase == "releasing"}} +
+
+ Processing phase: +
+
+ releasing processed gas mix +
+
+
+
+ Tank pressure: +
+
+ {{:data.tankPressure}} kPa +
+
+
+
+ Output Pressure: +
+
+ {{:data.air2Pressure}} kPa +
+
+
+
+ Target release pressure: +
+
+ {{:data.targetPressure}} kPa +
+
+{{/if}}