diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm index a1cdd1566c4..9b437705c2f 100644 --- a/code/controllers/subsystem/materials.dm +++ b/code/controllers/subsystem/materials.dm @@ -20,7 +20,7 @@ SUBSYSTEM_DEF(materials) var/list/rigid_stack_recipes = list( new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE), new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE), - new /datum/stack_recipe("Sink", /obj/structure/sink/greyscale, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE), + new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, one_per_turf = TRUE, on_floor = TRUE, applies_mats = TRUE), new /datum/stack_recipe("Floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE), ) diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 7ac4659af53..1c443b2f611 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -242,11 +242,11 @@ ///has one pipe input that only takes, example is manual output pipe /datum/component/plumbing/simple_demand - demand_connects = NORTH + demand_connects = SOUTH ///has one pipe output that only supplies. example is liquid pump and manual input pipe /datum/component/plumbing/simple_supply - supply_connects = NORTH + supply_connects = SOUTH ///input and output, like a holding tank /datum/component/plumbing/tank diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 17e69a1388b..ff36c94453a 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -90,7 +90,8 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 50), \ new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 50), \ - new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 50) + new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS), \ + new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time= 2 SECONDS) )) /obj/item/stack/sheet/metal diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 43d28beb709..0e1c273fe14 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -1404,3 +1404,15 @@ /obj/item/storage/box/petridish/PopulateContents() for(var/i in 1 to 7) new /obj/item/petri_dish(src) + +/obj/item/storage/box/plumbing + name = "box of plumbing supplies" + desc = "Contains a small supply of pipes, water recyclers, and metal to connect to the rest of the station." + +/obj/item/storage/box/plumbing/PopulateContents() + var/list/items_inside = list( + /obj/item/stock_parts/water_recycler = 2, + /obj/item/stack/ducts/fifty = 1, + /obj/item/stack/sheet/metal/ten = 1, + ) + generate_items_inside(items_inside, src) diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 998a0d581e2..e80853e34b1 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -1,26 +1,39 @@ #define SHOWER_FREEZING "freezing" +#define SHOWER_FREEZING_TEMP 100 #define SHOWER_NORMAL "normal" +#define SHOWER_NORMAL_TEMP 300 #define SHOWER_BOILING "boiling" +#define SHOWER_BOILING_TEMP 400 + /obj/machinery/shower name = "shower" - desc = "The HS-451. Installed in the 2550s by the Nanotrasen Hygiene Division." + desc = "The HS-452. Installed in the 2550s by the Nanotrasen Hygiene Division, now with 2560 lead compliance! Passively replenishes itself with water when not in use." icon = 'icons/obj/watercloset.dmi' icon_state = "shower" density = FALSE use_power = NO_POWER_USE + ///Is the shower on or off? var/on = FALSE + ///What temperature the shower reagents are set to. var/current_temperature = SHOWER_NORMAL + ///What sound will be played on loop when the shower is on and pouring water. var/datum/looping_sound/showering/soundloop + ///What reagent should the shower be filled with when initially built. var/reagent_id = /datum/reagent/water + ///How much reagent capacity should the shower begin with when built. var/reaction_volume = 200 /obj/machinery/shower/Initialize() . = ..() create_reagents(reaction_volume) reagents.add_reagent(reagent_id, reaction_volume) - soundloop = new(list(src), FALSE) + AddComponent(/datum/component/plumbing/simple_demand) + +/obj/machinery/shower/examine(mob/user) + . = ..() + . += "[reagents.total_volume]/[reagents.maximum_volume] liquids remaining." /obj/machinery/shower/Destroy() QDEL_NULL(soundloop) @@ -28,6 +41,9 @@ return ..() /obj/machinery/shower/interact(mob/M) + if(reagents.total_volume < 5) + to_chat(M,"\The [src] is dry.") + return FALSE on = !on update_icon() handle_mist() @@ -69,7 +85,9 @@ /obj/machinery/shower/update_overlays() . = ..() if(on) - . += mutable_appearance('icons/obj/watercloset.dmi', "water", ABOVE_MOB_LAYER) + var/mutable_appearance/water_falling = mutable_appearance('icons/obj/watercloset.dmi', "water", ABOVE_MOB_LAYER) + water_falling.color = mix_color_from_reagents(reagents.reagent_list) + . += water_falling /obj/machinery/shower/proc/handle_mist() // If there is no mist, and the shower was turned on (on a non-freezing temp): make mist in 5 seconds @@ -84,7 +102,8 @@ /obj/machinery/shower/proc/make_mist() var/obj/effect/mist/mist = locate() in loc if(!mist && on && current_temperature != SHOWER_FREEZING) - new /obj/effect/mist(loc) + var/obj/effect/mist/new_mist = new /obj/effect/mist(loc) + new_mist.color = mix_color_from_reagents(reagents.reagent_list) /obj/machinery/shower/proc/clear_mist() var/obj/effect/mist/mist = locate() in loc @@ -101,19 +120,27 @@ A.wash(CLEAN_RAD | CLEAN_TYPE_WEAK) // Clean radiation non-instantly A.wash(CLEAN_WASH) SEND_SIGNAL(A, COMSIG_ADD_MOOD_EVENT, "shower", /datum/mood_event/nice_shower) - reagents.expose(A, TOUCH, reaction_volume) - + reagents.expose(A, TOUCH) + reagents.expose(A, VAPOR) if(isliving(A)) check_heat(A) /obj/machinery/shower/process() - if(on) + if(on && reagents.total_volume >= 5) + reagents.remove_any(5) wash_atom(loc) for(var/am in loc) var/atom/movable/movable_content = am + reagents.expose(movable_content, TOUCH, reaction_volume) if(!ismopable(movable_content)) // Mopables will be cleaned anyways by the turf wash above wash_atom(movable_content) else + reagents.add_reagent(reagent_id, 1) + on = FALSE + soundloop.stop() + handle_mist() + update_icon() + if(reagents.total_volume == reagents.maximum_volume) return PROCESS_KILL /obj/machinery/shower/deconstruct(disassembled = TRUE) @@ -134,6 +161,31 @@ to_chat(L, "[src] is searing!") +/obj/structure/showerframe + name = "shower frame" + icon = 'icons/obj/watercloset.dmi' + icon_state = "shower_frame" + desc = "A shower frame, that needs a water recycler to finish construction." + anchored = FALSE + +/obj/structure/showerframe/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/stock_parts/water_recycler)) + qdel(I) + var/obj/machinery/shower/new_shower = new /obj/machinery/shower(loc) + new_shower.setDir(dir) + qdel(src) + return + return ..() + +/obj/structure/showerframe/Initialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + +/obj/structure/showerframe/proc/can_be_rotated(mob/user, rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return !anchored + /obj/effect/mist name = "mist" icon = 'icons/obj/watercloset.dmi' diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index ded293a1168..30bd5c63b16 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -245,12 +245,31 @@ name = "sink" icon = 'icons/obj/watercloset.dmi' icon_state = "sink" - desc = "A sink used for washing one's hands and face." + desc = "A sink used for washing one's hands and face. Passively reclaims water over time." anchored = TRUE - var/busy = FALSE //Something's being washed at the moment - var/dispensedreagent = /datum/reagent/water // for whenever plumbing happens + ///Something's being washed at the moment + var/busy = FALSE + ///What kind of reagent is produced by this sink by default? (We now have actual plumbing, Arcane, August 2020) + var/dispensedreagent = /datum/reagent/water + ///Material to drop when broken or deconstructed. var/buildstacktype = /obj/item/stack/sheet/metal + ///Number of sheets of material to drop when broken or deconstructed. var/buildstackamount = 1 + ///Does the sink have a water recycler to recollect it's water supply? + var/has_water_reclaimer = TRUE + ///Has the water reclamation begun? + var/reclaiming = FALSE + +/obj/structure/sink/Initialize(mapload, bolt) + . = ..() + if(has_water_reclaimer) + create_reagents(100, NO_REACT) + reagents.add_reagent(dispensedreagent, 100) + AddComponent(/datum/component/plumbing/simple_demand, bolt) + +/obj/structure/sink/examine(mob/user) + . = ..() + . += "[reagents.total_volume]/[reagents.maximum_volume] liquids remaining." /obj/structure/sink/attack_hand(mob/living/user) . = ..() @@ -262,10 +281,13 @@ return if(!Adjacent(user)) return - + if(reagents.total_volume < 5) + to_chat(user, "The sink has no more contents left!") + return if(busy) to_chat(user, "Someone's already washing here!") return + process_check() var/selected_area = parse_zone(user.zone_selected) var/washing_face = 0 if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)) @@ -279,6 +301,8 @@ return busy = FALSE + reagents.remove_any(5) + reagents.expose(user, TOUCH) if(washing_face) SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_FACE_ACT, CLEAN_WASH) @@ -301,9 +325,13 @@ if(istype(O, /obj/item/reagent_containers)) var/obj/item/reagent_containers/RG = O + process_check() + if(reagents.total_volume <= 0) + to_chat(user, "\The [src] is dry.") + return FALSE if(RG.is_refillable()) if(!RG.reagents.holder_full()) - RG.reagents.add_reagent(dispensedreagent, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this)) + reagents.trans_to(RG, RG.amount_per_transfer_from_this, transfered_by = user) to_chat(user, "You fill [RG] from [src].") return TRUE to_chat(user, "\The [RG] is full.") @@ -322,7 +350,10 @@ return if(istype(O, /obj/item/mop)) - O.reagents.add_reagent(dispensedreagent, 5) + if(reagents.total_volume <= 0) + to_chat(user, "\The [src] is dry.") + return FALSE + reagents.trans_to(O, 5, transfered_by = user) to_chat(user, "You wet [O] in [src].") playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) return @@ -359,8 +390,6 @@ busy = FALSE O.wash(CLEAN_WASH) O.acid_level = 0 - create_reagents(5) - reagents.add_reagent(dispensedreagent, 5) reagents.expose(O, TOUCH) user.visible_message("[user] washes [O] using [src].", \ "You wash [O] using [src].") @@ -373,6 +402,12 @@ drop_materials() ..() +/obj/structure/sink/process() + if(has_water_reclaimer && reagents.total_volume < reagents.maximum_volume) + reagents.add_reagent(dispensedreagent, 1) + else + return PROCESS_KILL + /obj/structure/sink/proc/drop_materials() if(buildstacktype) new buildstacktype(loc,buildstackamount) @@ -381,6 +416,12 @@ var/datum/material/M = i new M.sheet_type(loc, FLOOR(custom_materials[M] / MINERAL_MATERIAL_AMOUNT, 1)) +/obj/structure/sink/proc/process_check() + if(!reclaiming) + reclaiming = TRUE + START_PROCESSING(SSfluids, src) + process() + /obj/structure/sink/kitchen name = "kitchen sink" icon_state = "sink_alt" @@ -411,6 +452,34 @@ material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS buildstacktype = null +/obj/structure/sinkframe + name = "sink frame" + icon = 'icons/obj/watercloset.dmi' + icon_state = "sink_frame" + desc = "A sink frame, that needs a water recycler to finish construction." + anchored = FALSE + material_flags = MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS + +/obj/structure/sinkframe/ComponentInitialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + +/obj/structure/sinkframe/proc/can_be_rotated(mob/user, rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return !anchored + +/obj/structure/sinkframe/attackby(obj/item/I, mob/living/user, params) + if(istype(I, /obj/item/stock_parts/water_recycler)) + qdel(I) + var/obj/structure/sink/greyscale/new_sink = new /obj/structure/sink/greyscale(loc) + new_sink.has_water_reclaimer = TRUE + new_sink.set_custom_materials(custom_materials) + new_sink.setDir(dir) + qdel(src) + return + return ..() + //Shower Curtains// //Defines used are pre-existing in layers.dm// diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 74de0985fd6..731d86f7505 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -48,8 +48,6 @@ var/unwrenchable = TRUE ///Have we been visited by a bee recently, so bees dont overpollinate one plant var/recent_bee_visit = FALSE - ///If the tray is connected to other trays via irrigation hoses - var/using_irrigation = FALSE ///The last user to add a reagent to the tray, mostly for logging purposes. var/mob/lastuser ///If the tray generates nutrients and water on its own @@ -68,6 +66,14 @@ icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "hydrotray3" +/obj/machinery/hydroponics/constructable/ComponentInitialize() + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + AddComponent(/datum/component/plumbing/simple_demand) + +/obj/machinery/hydroponics/constructable/proc/can_be_rotated(mob/user, rotation_type) + return !anchored + /obj/machinery/hydroponics/constructable/RefreshParts() var/tmp_capacity = 0 for (var/obj/item/stock_parts/matter_bin/M in component_parts) @@ -97,33 +103,11 @@ // handle opening the panel if(default_deconstruction_screwdriver(user, icon_state, icon_state, I)) return - - // handle deconstructing the machine, if permissible - if(I.tool_behaviour == TOOL_CROWBAR && using_irrigation) - to_chat(user, "Disconnect the hoses first!") - return - else if(default_deconstruction_crowbar(I)) + if(default_deconstruction_crowbar(I)) return return ..() -/obj/machinery/hydroponics/proc/FindConnected() - var/list/connected = list() - var/list/processing_atoms = list(src) - - while(processing_atoms.len) - var/atom/a = processing_atoms[1] - for(var/step_dir in GLOB.cardinals) - var/obj/machinery/hydroponics/h = locate() in get_step(a, step_dir) - // Soil plots aren't dense - if(h && h.using_irrigation && h.density && !(h in connected) && !(h in processing_atoms)) - processing_atoms += h - - processing_atoms -= a - connected += a - - return connected - /obj/machinery/hydroponics/bullet_act(obj/projectile/Proj) //Works with the Somatoray to modify plant variables. if(!myseed) return ..() @@ -321,8 +305,6 @@ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "gaia_blessing")) set_light(3) - update_icon_hoses() - if(myseed) update_icon_plant() update_icon_lights() @@ -336,15 +318,6 @@ return -/obj/machinery/hydroponics/proc/update_icon_hoses() - var/n = 0 - for(var/Dir in GLOB.cardinals) - var/obj/machinery/hydroponics/t = locate() in get_step(src,Dir) - if(t && t.using_irrigation && using_irrigation) - n += Dir - - icon_state = "hoses-[n]" - /obj/machinery/hydroponics/proc/update_icon_plant() var/mutable_appearance/plant_overlay = mutable_appearance(myseed.growing_icon, layer = OBJ_LAYER + 0.01) if(dead) @@ -567,7 +540,6 @@ var/list/trays = list(src)//makes the list just this in cases of syringes and compost etc var/target = myseed ? myseed.plantname : src var/visi_msg = "" - var/irrigate = 0 //How am I supposed to irrigate pill contents? var/transfer_amount if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill)) @@ -584,35 +556,21 @@ visi_msg="[user] injects [target] with [syr]" if(syr.reagents.total_volume <= syr.amount_per_transfer_from_this) syr.mode = 0 - else if(istype(reagent_source, /obj/item/reagent_containers/spray/)) - visi_msg="[user] sprays [target] with [reagent_source]" - playsound(loc, 'sound/effects/spray3.ogg', 50, TRUE, -6) - irrigate = 1 - else if(transfer_amount) // Droppers, cans, beakers, what have you. - visi_msg="[user] uses [reagent_source] on [target]" - irrigate = 1 // Beakers, bottles, buckets, etc. if(reagent_source.is_drainable()) playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE) - if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation) - trays = FindConnected() - if (trays.len > 1) - visi_msg += ", setting off the irrigation system" - if(visi_msg) visible_message("[visi_msg].") - var/split = round(transfer_amount/trays.len) - for(var/obj/machinery/hydroponics/H in trays) //cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener //This was originally in apply_chemicals, but due to apply_chemicals only holding nutrients, we handle it here now. if(reagent_source.reagents.has_reagent(/datum/reagent/water, 1)) - var/water_amt = reagent_source.reagents.get_reagent_amount(/datum/reagent/water) * split / reagent_source.reagents.total_volume + var/water_amt = reagent_source.reagents.get_reagent_amount(/datum/reagent/water) * transfer_amount / reagent_source.reagents.total_volume H.adjustWater(round(water_amt)) reagent_source.reagents.remove_reagent(/datum/reagent/water, water_amt) - reagent_source.reagents.trans_to(H.reagents, split, transfered_by = user) + reagent_source.reagents.trans_to(H.reagents, transfer_amount, transfered_by = user) if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill)) qdel(reagent_source) lastuser = user @@ -751,18 +709,6 @@ else if(default_unfasten_wrench(user, O)) return - else if((O.tool_behaviour == TOOL_WIRECUTTER) && unwrenchable) - if (!anchored) - to_chat(user, "Anchor the tray first!") - return - using_irrigation = !using_irrigation - O.play_tool_sound(src) - user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \ - "You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.") - for(var/obj/machinery/hydroponics/h in range(1,src)) - h.update_icon() - return - else if(istype(O, /obj/item/shovel/spade)) if(!myseed && !weedlevel) to_chat(user, "[src] doesn't have any plants or weeds!") @@ -822,11 +768,6 @@ if (!unwrenchable) // case also covered by NODECONSTRUCT checks in default_unfasten_wrench return CANT_UNFASTEN - if (using_irrigation) - if (!silent) - to_chat(user, "Disconnect the hoses first!") - return FAILED_UNFASTEN - return ..() /obj/machinery/hydroponics/attack_hand(mob/user) @@ -865,6 +806,9 @@ /obj/machinery/hydroponics/AltClick(mob/user) . = ..() + if(!anchored) + update_icon() + return FALSE var/warning = alert(user, "Are you sure you wish to empty the tray's nutrient beaker?","Empty Tray Nutrients?", "Yes", "No") if(warning == "Yes" && user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) reagents.clear_reagents() @@ -953,14 +897,6 @@ var/mob/living/simple_animal/hostile/C = new chosen C.faction = list("plants") -////////////////////////////////////////////////////////////////////////////////// -/obj/machinery/hydroponics/irrigated //Pre-Irrigated trays! Maybe map a couple on each map, just so they get used? - using_irrigation = TRUE - -/obj/machinery/hydroponics/irrigated/Initialize() - . = ..() - update_icon() //Visually hooks up all the pipes. - /////////////////////////////////////////////////////////////////////////////// /obj/machinery/hydroponics/soil //Not actually hydroponics at all! Honk! name = "soil" @@ -974,9 +910,6 @@ flags_1 = NODECONSTRUCT_1 unwrenchable = FALSE -/obj/machinery/hydroponics/soil/update_icon_hoses() - return // Has no hoses - /obj/machinery/hydroponics/soil/update_icon_lights() return // Has no lights diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 13840f96384..e4331d4cdbd 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -206,6 +206,13 @@ if(M.blood_volume) M.blood_volume += 0.1 // water is good for you! +///For weird backwards situations where water manages to get added to trays nutrients, as opposed to being snowflaked away like usual. +/datum/reagent/water/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray) + if(chems.has_reagent(src.type, 1)) + mytray.adjustWater(round(chems.get_reagent_amount(src.type) * 1)) + //You don't belong in this world, monster! + chems.remove_reagent(/datum/reagent/water, chems.get_reagent_amount(src.type)) + /datum/reagent/water/holywater name = "Holy Water" description = "Water blessed by some deity." @@ -217,7 +224,6 @@ // Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits. Also ALSO increases instability. /datum/reagent/water/holywater/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray) - . = ..() if(chems.has_reagent(src.type, 1)) mytray.adjustWater(round(chems.get_reagent_amount(src.type) * 1)) mytray.adjustHealth(round(chems.get_reagent_amount(src.type) * 0.1)) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index dc91bdf897d..8623b88620d 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -1,14 +1,25 @@ /obj/structure/reagent_dispensers name = "Dispenser" desc = "..." - icon = 'icons/obj/objects.dmi' + icon = 'icons/obj/chemical_tanks.dmi' icon_state = "water" density = TRUE anchored = FALSE pressure_resistance = 2*ONE_ATMOSPHERE max_integrity = 300 - var/tank_volume = 1000 //In units, how much the dispenser can hold - var/reagent_id = /datum/reagent/water //The ID of the reagent that the dispenser uses + ///In units, how much the dispenser can hold + var/tank_volume = 1000 + ///The ID of the reagent that the dispenser uses + var/reagent_id = /datum/reagent/water + ///Can you turn this into a plumbing tank? + var/can_be_tanked = TRUE + ///Is this source self-replenishing? + var/refilling = FALSE + +/obj/structure/reagent_dispensers/examine(mob/user) + . = ..() + if(can_be_tanked) + . += "Use a sheet of metal to convert this into a plumbing-compatible tank." /obj/structure/reagent_dispensers/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) . = ..() @@ -18,7 +29,18 @@ /obj/structure/reagent_dispensers/attackby(obj/item/W, mob/user, params) if(W.is_refillable()) - return 0 //so we can refill them via their afterattack. + return FALSE //so we can refill them via their afterattack. + if(istype(W, /obj/item/stack/sheet/metal) && can_be_tanked) + var/obj/item/stack/sheet/metal/metal_stack = W + metal_stack.use(1) + var/obj/structure/reagent_dispensers/plumbed/storage/new_tank = new /obj/structure/reagent_dispensers/plumbed/storage(drop_location()) + new_tank.reagents.maximum_volume = reagents.maximum_volume + reagents.trans_to(new_tank, reagents.total_volume) + new_tank.name = "stationary [name]" + new_tank.update_overlays() + new_tank.anchored = anchored + qdel(src) + return FALSE else return ..() @@ -201,10 +223,11 @@ reagent_id = /datum/reagent/consumable/nutraslop /obj/structure/reagent_dispensers/plumbed - name = "stationairy water tank" + name = "stationary water tank" anchored = TRUE - icon_state = "water_stationairy" - desc = "A stationairy, plumbed, water tank." + icon_state = "water_stationary" + desc = "A stationary, plumbed, water tank." + can_be_tanked = FALSE /obj/structure/reagent_dispensers/plumbed/wrench_act(mob/living/user, obj/item/I) ..() @@ -215,9 +238,31 @@ AddComponent(/datum/component/plumbing/simple_supply) /obj/structure/reagent_dispensers/plumbed/storage - name = "stationairy storage tank" - icon_state = "tank_stationairy" + name = "stationary storage tank" + icon_state = "tank_stationary" reagent_id = null //start empty /obj/structure/reagent_dispensers/plumbed/storage/ComponentInitialize() - AddComponent(/datum/component/plumbing/tank) + . = ..() + AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS, null, CALLBACK(src, .proc/can_be_rotated)) + +/obj/structure/reagent_dispensers/plumbed/storage/update_overlays() + . = ..() + if(reagents) + if(reagents.total_volume) + var/mutable_appearance/tank_color = mutable_appearance('icons/obj/chemical_tanks.dmi', "tank_chem_overlay") + tank_color.color = mix_color_from_reagents(reagents.reagent_list) + add_overlay(tank_color) + else + cut_overlays() + +/obj/structure/reagent_dispensers/plumbed/storage/proc/can_be_rotated(mob/user, rotation_type) + if(anchored) + to_chat(user, "It is fastened to the floor!") + return !anchored + +/obj/structure/reagent_dispensers/plumbed/fuel + name = "stationary fuel tank" + icon_state = "fuel_stationary" + desc = "A stationary, plumbed, fuel tank." + reagent_id = /datum/reagent/fuel diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 3006723d902..9cde16cddb9 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -350,12 +350,20 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good desc = "A large piece of equipment used to open a window into the subspace dimension." custom_materials = list(/datum/material/iron=50) +// Misc. Parts + /obj/item/stock_parts/card_reader name = "card reader" icon_state = "card_reader" desc = "A small magnetic card reader, used for devices that take and transmit holocredits." custom_materials = list(/datum/material/iron=50, /datum/material/glass=10) +/obj/item/stock_parts/water_recycler + name = "water recycler" + icon_state = "water_recycler" + desc = "A chemical reclaimation component, which serves to re-accumulate and filter water over time." + custom_materials = list(/datum/material/plastic=200, /datum/material/iron=50) + /obj/item/research//Makes testing much less of a pain -Sieve name = "research" icon = 'icons/obj/stock_parts.dmi' diff --git a/icons/obj/chemical_tanks.dmi b/icons/obj/chemical_tanks.dmi new file mode 100644 index 00000000000..034bb01f753 Binary files /dev/null and b/icons/obj/chemical_tanks.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 67bc5769c58..eeb04500565 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/icons/obj/stock_parts.dmi b/icons/obj/stock_parts.dmi index 75e025185d4..a27f07f3337 100644 Binary files a/icons/obj/stock_parts.dmi and b/icons/obj/stock_parts.dmi differ diff --git a/icons/obj/watercloset.dmi b/icons/obj/watercloset.dmi index b61bf2927ab..19c8b83fa8e 100644 Binary files a/icons/obj/watercloset.dmi and b/icons/obj/watercloset.dmi differ