diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm index 3d24c1a3306..ea0ee8803cf 100644 --- a/code/__defines/chemistry.dm +++ b/code/__defines/chemistry.dm @@ -62,9 +62,10 @@ #define MAT_SOLVENT_MODERATE 2 #define MAT_SOLVENT_STRONG 3 -#define DIRTINESS_STERILE -2 -#define DIRTINESS_CLEAN -1 -#define DIRTINESS_NEUTRAL 0 +#define DIRTINESS_DECONTAMINATE -3 +#define DIRTINESS_STERILE -2 +#define DIRTINESS_CLEAN -1 +#define DIRTINESS_NEUTRAL 0 #define DEFAULT_GAS_ACCELERANT /decl/material/gas/hydrogen #define DEFAULT_GAS_OXIDIZER /decl/material/gas/oxygen diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index a458bf40693..b4776030e65 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -197,11 +197,6 @@ #define WRINKLES_WRINKLY 1 #define WRINKLES_NONE 2 -//detergent states for clothes -#define SMELL_DEFAULT 0 -#define SMELL_CLEAN 1 -#define SMELL_STINKY 2 - //Shuttle mission stages #define SHUTTLE_MISSION_PLANNED 1 #define SHUTTLE_MISSION_STARTED 2 diff --git a/code/datums/extensions/scent/_scent.dm b/code/datums/extensions/scent/_scent.dm index b7ef9d3873d..3b1a52e50ee 100644 --- a/code/datums/extensions/scent/_scent.dm +++ b/code/datums/extensions/scent/_scent.dm @@ -6,7 +6,7 @@ Scent intensity *****/ /decl/scent_intensity - var/cooldown = 5 MINUTES + var/cooldown = 5 MINUTES var/intensity = 1 /decl/scent_intensity/proc/PrintMessage(var/mob/user, var/descriptor, var/scent) @@ -121,18 +121,24 @@ To add a scent extension to an atom using a reagent's info, where R. is the reag *****/ /proc/set_scent_by_reagents(var/atom/smelly_atom) + var/decl/material/smelliest = get_smelliest_reagent(smelly_atom.reagents) + if(smelliest) + set_extension(smelly_atom, /datum/extension/scent/custom, smelliest.scent, smelliest.scent_intensity, smelliest.scent_descriptor, smelliest.scent_range) + +// Returns the smelliest reagent of a reagent holder. +/proc/get_smelliest_reagent(var/datum/reagents/holder) var/decl/material/smelliest var/decl/material/scent_intensity - if(!smelly_atom.reagents || !smelly_atom.reagents.total_volume) + if(!holder || !holder.total_volume) return - for(var/reagent_type in smelly_atom.reagents.reagent_volumes) + for(var/reagent_type in holder.reagent_volumes) var/decl/material/R = GET_DECL(reagent_type) if(!R.scent) continue var/decl/scent_intensity/SI = GET_DECL(R.scent_intensity) - var/r_scent_intensity = REAGENT_VOLUME(smelly_atom.reagents, reagent_type) * SI.intensity + var/r_scent_intensity = REAGENT_VOLUME(holder, reagent_type) * SI.intensity if(r_scent_intensity > scent_intensity) smelliest = R - scent_intensity = r_scent_intensity - if(smelliest) - set_extension(smelly_atom, /datum/extension/scent/custom, smelliest.scent, smelliest.scent_intensity, smelliest.scent_descriptor, smelliest.scent_range) \ No newline at end of file + scent_intensity = r_scent_intensity + + return smelliest \ No newline at end of file diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 49bdaf4bba7..a36d4b5ab5b 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -1,37 +1,169 @@ #define WASHER_STATE_CLOSED 1 -#define WASHER_STATE_FULL 2 +#define WASHER_STATE_LOADED 2 #define WASHER_STATE_RUNNING 4 #define WASHER_STATE_BLOODY 8 -// WASHER_STATE_RUNNING implies WASHER_STATE_CLOSED | WASHER_STATE_FULL +// WASHER_STATE_RUNNING implies WASHER_STATE_CLOSED | WASHER_STATE_LOADED // if you break this assumption, you must update the icon file // other states are independent. /obj/machinery/washing_machine name = "washing machine" + desc = "A commerical washing machine used to wash clothing items and linens. It requires detergent for efficient washing." icon = 'icons/obj/machines/washing_machine.dmi' icon_state = "wm_00" density = TRUE anchored = TRUE construct_state = /decl/machine_construction/default/panel_closed uncreated_component_parts = null - stat_immune = 0 + stat_immune = NOSCREEN var/state = 0 - var/gibs_ready = 0 - var/obj/crayon - var/obj/item/chems/pill/detergent/detergent + var/gibs_ready = FALSE obj_flags = OBJ_FLAG_ANCHORABLE clicksound = "button" clickvol = 40 + var/list/wash_whitelist = list(/obj/item/clothing/under, + /obj/item/clothing/mask, + /obj/item/clothing/head, + /obj/item/clothing/gloves, + /obj/item/clothing/shoes, + /obj/item/clothing/suit, + /obj/item/bedsheet, + /obj/item/underwear) + + var/max_item_size = ITEM_SIZE_LARGE + + var/list/wash_blacklist = list(/obj/item/clothing/suit/space, + /obj/item/clothing/suit/syndicatefake, + /obj/item/clothing/suit/bomb_suit, + /obj/item/clothing/suit/armor, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/smokable/cigarette, + /obj/item/clothing/head/helmet) + // Power idle_power_usage = 10 active_power_usage = 150 -/obj/machinery/washing_machine/Destroy() - QDEL_NULL(crayon) - QDEL_NULL(detergent) +/obj/machinery/washing_machine/Initialize(mapload, d, populate_parts) + create_reagents(100) + . = ..() + +/obj/machinery/washing_machine/examine(mob/user) . = ..() + to_chat(user, SPAN_NOTICE("The detergent port is [atom_flags & ATOM_FLAG_OPEN_CONTAINER ? "open" : "closed"].")) + +/obj/machinery/washing_machine/proc/wash() + if(operable()) + var/list/washing_atoms = get_contained_external_atoms() + var/amount_per_atom = FLOOR(reagents.total_volume / length(washing_atoms)) + + if(amount_per_atom > 0) + var/decl/material/smelliest = get_smelliest_reagent(reagents) + for(var/atom/A as anything in get_contained_external_atoms()) + + // Handles washing, decontamination, dyeing, etc. + reagents.trans_to(A, amount_per_atom) + + if(istype(A, /obj/item/clothing)) + var/obj/item/clothing/C = A + C.ironed_state = WRINKLES_WRINKLY + if(smelliest) + C.change_smell(smelliest) + + // Clear out whatever remains of the reagents. + reagents.clear_reagents() + + if(locate(/mob/living) in src) + gibs_ready = TRUE + + state &= ~WASHER_STATE_RUNNING + update_use_power(POWER_USE_IDLE) + +/obj/machinery/washing_machine/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/chems/pill/detergent)) + if(!(atom_flags & ATOM_FLAG_OPEN_CONTAINER)) + to_chat(user, SPAN_WARNING("Open the detergent port first!")) + return + if(reagents.total_volume >= reagents.maximum_volume) + to_chat(user, SPAN_WARNING("The detergent port is full!")) + return + if(!user.try_unequip(W)) + return + // Directly transfer to the holder to avoid touch reactions. + W.reagents?.trans_to_holder(reagents, W.reagents.total_volume) + to_chat(user, SPAN_NOTICE("You dissolve \the [W] in the detergent port.")) + qdel(W) + return TRUE + + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("\The [src] is currently running.")) + return TRUE + + // If the detergent port is open and the item is an open container, assume we're trying to fill the detergent port. + if(!(state & WASHER_STATE_CLOSED) && !((atom_flags & W.atom_flags) & ATOM_FLAG_OPEN_CONTAINER)) + var/list/washing_atoms = get_contained_external_atoms() + if(length(washing_atoms) < 5) + if(istype(W, /obj/item/holder)) // Mob holder + for(var/mob/living/doggy in W) + doggy.forceMove(src) + qdel(W) + state |= WASHER_STATE_LOADED + update_icon() + return TRUE + + // An empty whitelist implies all items can be washed. + else if((!length(wash_whitelist) || is_type_in_list(W, wash_whitelist)) && !is_type_in_list(W, wash_blacklist)) + if(W.w_class > max_item_size) + to_chat(user, SPAN_WARNING("\The [W] is too large for \the [src]!")) + return + if(!user.try_unequip(W, src)) + return + state |= WASHER_STATE_LOADED + update_icon() + else + to_chat(user, SPAN_WARNING("You can't put \the [W] in \the [src].")) + return + else + to_chat(user, SPAN_NOTICE("\The [src] is full.")) + return TRUE + + return ..() + +/obj/machinery/washing_machine/physical_attack_hand(mob/user) + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("\The [src] is currently running.")) + return TRUE + if(state & WASHER_STATE_CLOSED) + state &= ~WASHER_STATE_CLOSED + if(gibs_ready) + gibs_ready = FALSE + var/mob/M = locate(/mob/living) in src + if(M) + M.gib() + dump_contents() + state &= ~WASHER_STATE_LOADED + update_icon() + return TRUE + state |= WASHER_STATE_CLOSED + update_icon() + return TRUE + +/obj/machinery/washing_machine/verb/climb_out() + set name = "Climb out" + set category = "Object" + set src in usr.loc + + if(!CanPhysicallyInteract(usr)) + return + if(state & WASHER_STATE_CLOSED) + to_chat(usr, SPAN_WARNING("\The [src] is closed.")) + return + if(!do_after(usr, 2 SECONDS, src)) + return + if(!(state & WASHER_STATE_CLOSED)) + usr.dropInto(loc) /obj/machinery/washing_machine/verb/start() set name = "Start Washing" @@ -41,24 +173,28 @@ if(!CanPhysicallyInteract(usr)) return - if(!anchored) - to_chat(usr, "\The [src] must be secured to the floor.") - return + start_washing(usr) +/obj/machinery/washing_machine/proc/start_washing(mob/user) if(state & WASHER_STATE_RUNNING) - to_chat(usr, "\The [src] is already running.") - return - if(!(state & WASHER_STATE_FULL)) - to_chat(usr, "Load \the [src] first!") + to_chat(user, SPAN_WARNING("\The [src] is already running!")) return if(!(state & WASHER_STATE_CLOSED)) - to_chat(usr, "You must first close the machine.") + to_chat(user, SPAN_WARNING("You must first close \the [src].")) + return + if(!(state & WASHER_STATE_LOADED)) + to_chat(user, SPAN_WARNING("Load \the [src] first!!")) + return + if(!operable()) + to_chat(user, SPAN_WARNING("\The [src] isn't functioning!")) return - if(stat & NOPOWER) - to_chat(usr, SPAN_WARNING("\The [src] is unpowered.")) + if(!reagents.total_volume) + to_chat(user, SPAN_WARNING("There are no cleaning products loaded in \the [src]!")) return + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + state |= WASHER_STATE_RUNNING if(locate(/mob/living) in src) state |= WASHER_STATE_BLOODY @@ -66,44 +202,55 @@ update_use_power(POWER_USE_ACTIVE) addtimer(CALLBACK(src, /obj/machinery/washing_machine/proc/wash), 20 SECONDS) -/obj/machinery/washing_machine/proc/wash() - for(var/atom/A as anything in get_contained_external_atoms()) - if(detergent) - A.clean_blood() - if(isitem(A)) - var/obj/item/I = A - if(detergent) - I.decontaminate() - if(crayon && iscolorablegloves(I)) - var/obj/item/clothing/gloves/C = I - C.color = crayon.color - if(istype(A, /obj/item/clothing)) - var/obj/item/clothing/C = A - C.ironed_state = WRINKLES_WRINKLY - if(detergent) - C.change_smell(SMELL_CLEAN) - addtimer(CALLBACK(C, /obj/item/clothing/proc/change_smell), detergent.smell_clean_time, TIMER_UNIQUE | TIMER_OVERRIDE) - QDEL_NULL(detergent) - - if(locate(/mob/living) in src) - gibs_ready = 1 - state &= ~WASHER_STATE_RUNNING - update_use_power(POWER_USE_IDLE) + return TRUE -/obj/machinery/washing_machine/verb/climb_out() - set name = "Climb out" +/obj/machinery/washing_machine/verb/toggle_port() + set name = "Toggle Detergent Port" set category = "Object" - set src in usr.loc + set src in oview(1) if(!CanPhysicallyInteract(usr)) return - if(state & WASHER_STATE_CLOSED) - to_chat(usr, SPAN_WARNING("\The [src] is closed.")) - return - if(!do_after(usr, 2 SECONDS, src)) + + toggle_detergent_port(usr) + +/obj/machinery/washing_machine/proc/toggle_detergent_port(mob/user) + if(state & WASHER_STATE_RUNNING) + to_chat(user, SPAN_WARNING("You can't open the detergent port while \the [src] is running!")) return - if(!(state & WASHER_STATE_CLOSED)) - usr.dropInto(loc) + + if(atom_flags & ATOM_FLAG_OPEN_CONTAINER) + atom_flags &= ~ATOM_FLAG_OPEN_CONTAINER + to_chat(user, SPAN_NOTICE("You close the detergent port on \the [src].")) + else + atom_flags |= ATOM_FLAG_OPEN_CONTAINER + to_chat(user, SPAN_NOTICE("You open the detergent port on \the [src].")) + + return TRUE + +/obj/machinery/washing_machine/get_alt_interactions(mob/user) + . = ..() + LAZYADD(., /decl/interaction_handler/start_washer) + LAZYADD(., /decl/interaction_handler/toggle_open/washing_machine) + +/decl/interaction_handler/start_washer + name = "Start washer" + expected_target_type = /obj/machinery/washing_machine + +/decl/interaction_handler/start_washer/is_possible(obj/machinery/washing_machine/washer, mob/user) + . = ..() + if(.) + return washer.operable() && !(washer.state & WASHER_STATE_RUNNING) + +/decl/interaction_handler/start_washer/invoked(obj/machinery/washing_machine/washer, mob/user) + return washer.start_washing(user) + +/decl/interaction_handler/toggle_open/washing_machine + name = "Toggle detergent port" + expected_target_type = /obj/machinery/washing_machine + +/decl/interaction_handler/toggle_open/washing_machine/invoked(obj/machinery/washing_machine/washer, mob/user) + return washer.toggle_detergent_port(user) /obj/machinery/washing_machine/on_update_icon() icon_state = "wm_[state][panel_open]" @@ -116,101 +263,19 @@ /obj/machinery/washing_machine/components_are_accessible(path) return !(state & WASHER_STATE_RUNNING) && ..() -/obj/machinery/washing_machine/attackby(obj/item/W, mob/user) - if(!(state & WASHER_STATE_CLOSED)) - if(!crayon && IS_PEN(W)) - if(!user.try_unequip(W, src)) - return - crayon = W - return TRUE - if(!detergent && istype(W,/obj/item/chems/pill/detergent)) - if(!user.try_unequip(W, src)) - return - detergent = W - return TRUE - if(istype(W, /obj/item/holder)) // Mob holder - for(var/mob/living/doggy in W) - doggy.forceMove(src) - qdel(W) - state |= WASHER_STATE_FULL - update_icon() - return TRUE - - else if(istype(W,/obj/item/clothing/under) || \ - istype(W,/obj/item/clothing/mask) || \ - istype(W,/obj/item/clothing/head) || \ - istype(W,/obj/item/clothing/gloves) || \ - istype(W,/obj/item/clothing/shoes) || \ - istype(W,/obj/item/clothing/suit) || \ - istype(W,/obj/item/bedsheet) || \ - istype(W,/obj/item/underwear/)) - - //YES, it's hardcoded... saves a var/can_be_washed for every single clothing item. - if ( istype(W,/obj/item/clothing/suit/space ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/syndicatefake ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/bomb_suit ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/armor ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/suit/armor ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/mask/gas ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/mask/smokable/cigarette ) ) - to_chat(user, "This item does not fit.") - return - if ( istype(W,/obj/item/clothing/head/helmet ) ) - to_chat(user, "This item does not fit.") - return +/obj/machinery/washing_machine/autoclave + name = "autoclave" + desc = "An industrial washing machine used to sterilize and decontaminate items. It requires detergent for efficient decontamination." - if(contents.len < 5) - if(!(state & WASHER_STATE_CLOSED)) - if(!user.try_unequip(W, src)) - return - state |= WASHER_STATE_FULL - update_icon() - else - to_chat(user, SPAN_NOTICE("You can't put the item in right now.")) - else - to_chat(user, SPAN_NOTICE("\The [src] is full.")) - return TRUE - - if(state & WASHER_STATE_RUNNING) - to_chat(user, SPAN_WARNING("\The [src] is currently running.")) - return TRUE + wash_whitelist = list() + wash_blacklist = list() - return ..() + max_item_size = ITEM_SIZE_HUGE -/obj/machinery/washing_machine/physical_attack_hand(mob/user) - if(state & WASHER_STATE_RUNNING) - to_chat(user, SPAN_WARNING("\The [src] is busy.")) - return TRUE - if(state & WASHER_STATE_CLOSED) - state &= ~WASHER_STATE_CLOSED - if(gibs_ready) - gibs_ready = 0 - var/mob/M = locate(/mob/living) in src - if(M) - M.gib() - dump_contents() - state &= ~WASHER_STATE_FULL - update_icon() - crayon = null - detergent = null - return TRUE - state |= WASHER_STATE_CLOSED - update_icon() - return TRUE + idle_power_usage = 10 + active_power_usage = 300 #undef WASHER_STATE_CLOSED -#undef WASHER_STATE_FULL +#undef WASHER_STATE_LOADED #undef WASHER_STATE_RUNNING #undef WASHER_STATE_BLOODY \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/machinery/household.dm b/code/game/objects/items/weapons/circuitboards/machinery/household.dm index bcc108137fc..db7de25060f 100644 --- a/code/game/objects/items/weapons/circuitboards/machinery/household.dm +++ b/code/game/objects/items/weapons/circuitboards/machinery/household.dm @@ -90,6 +90,17 @@ /obj/item/stock_parts/matter_bin = 1, /obj/item/pipe = 1) +/obj/item/stock_parts/circuitboard/autoclave + name = "circuitboard (autoclave)" + build_path = /obj/machinery/washing_machine/autoclave + board_type = "machine" + origin_tech = "{'engineering':3, 'biotech':2}" + req_components = list( + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/matter_bin = 2, + /obj/item/pipe = 1) + /obj/item/stock_parts/circuitboard/vending name = "circuitboard (vending machine)" build_path = /obj/machinery/vending/assist diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm index 782c800064e..6ea54072f55 100644 --- a/code/game/objects/items/weapons/soap.dm +++ b/code/game/objects/items/weapons/soap.dm @@ -12,7 +12,7 @@ throwforce = 0 throw_speed = 4 throw_range = 20 - material = /decl/material/liquid/cleaner + material = /decl/material/liquid/cleaner/soap max_health = 5 var/key_data @@ -105,13 +105,15 @@ /obj/item/soap/attackby(var/obj/item/I, var/mob/user) if(istype(I, /obj/item/key)) - if(!key_data) + if(key_data) + to_chat(user, SPAN_WARNING("\The [src] already has a key imprint.")) + else to_chat(user, SPAN_NOTICE("You imprint \the [I] into \the [src].")) var/obj/item/key/K = I key_data = K.key_data update_icon() - return - ..() + return TRUE + return ..() /obj/item/soap/on_update_icon() . = ..() diff --git a/code/game/objects/structures/ironing_board.dm b/code/game/objects/structures/ironing_board.dm index fe42db90178..2016ff845b8 100644 --- a/code/game/objects/structures/ironing_board.dm +++ b/code/game/objects/structures/ironing_board.dm @@ -150,4 +150,5 @@ name = "ironing board" desc = "A collapsed ironing board that can be carried around." icon = 'icons/obj/structures/ironing.dmi' + icon_state = "folded" structure_form_type = /obj/structure/bed/roller/ironingboard \ No newline at end of file diff --git a/code/modules/ZAS/Contaminants.dm b/code/modules/ZAS/Contaminants.dm index 4d99a5c6c09..0ab5091a175 100644 --- a/code/modules/ZAS/Contaminants.dm +++ b/code/modules/ZAS/Contaminants.dm @@ -114,13 +114,14 @@ var/global/image/contamination_overlay = image('icons/effects/contamination.dmi' /mob/living/carbon/human/proc/contaminant_head_protected() //Checks if the head is adequately sealed. var/obj/item/head = get_equipped_item(slot_head_str) - if(head) - if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) - if(head.item_flags & ITEM_FLAG_NO_CONTAMINATION) - return 1 - else if(head.body_parts_covered & SLOT_EYES) - return 1 - return 0 + if(!head) + return FALSE + // If strict protection is on, you must have a head item with ITEM_FLAG_NO_CONTAMINATION. + if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) + if(!(head.item_flags & ITEM_FLAG_NO_CONTAMINATION)) + return FALSE + // Regardless, the head item must cover the face and head. Eyes are checked seperately above. + return BIT_TEST_ALL(head.body_parts_covered, SLOT_HEAD|SLOT_FACE) /mob/living/carbon/human/proc/contaminant_suit_protected() //Checks if the suit is adequately sealed. @@ -130,11 +131,11 @@ var/global/image/contamination_overlay = image('icons/effects/contamination.dmi' if(!istype(protection)) continue if(vsc.contaminant_control.STRICT_PROTECTION_ONLY && !(protection.item_flags & ITEM_FLAG_NO_CONTAMINATION)) - return 0 + return FALSE coverage |= protection.body_parts_covered if(vsc.contaminant_control.STRICT_PROTECTION_ONLY) - return 1 + return TRUE return BIT_TEST_ALL(coverage, SLOT_UPPER_BODY|SLOT_LOWER_BODY|SLOT_LEGS|SLOT_FEET|SLOT_ARMS|SLOT_HANDS) diff --git a/code/modules/clothing/_clothing.dm b/code/modules/clothing/_clothing.dm index 2cb413e41d0..1dedcd609ab 100644 --- a/code/modules/clothing/_clothing.dm +++ b/code/modules/clothing/_clothing.dm @@ -17,7 +17,6 @@ var/blood_overlay_type = "uniformblood" var/visible_name = "Unknown" var/ironed_state = WRINKLES_DEFAULT - var/smell_state = SMELL_DEFAULT var/move_trail = /obj/effect/decal/cleanable/blood/tracks/footprints // if this item covers the feet, the footprints it should leave var/volume_multiplier = 1 var/markings_icon // simple colored overlay that would be applied to the icon @@ -105,8 +104,14 @@ if(LAZYLEN(new_overlays)) add_overlay(new_overlays) -/obj/item/clothing/proc/change_smell(smell = SMELL_DEFAULT) - smell_state = smell +// Used by washing machines to temporarily make clothes smell +/obj/item/clothing/proc/change_smell(decl/material/odorant, time = 10 MINUTES) + if(!odorant || !odorant.scent) + remove_extension(src, /datum/extension/scent) + return + + set_extension(src, /datum/extension/scent/custom, odorant.scent, odorant.scent_intensity, odorant.scent_descriptor, odorant.scent_range) + addtimer(CALLBACK(src, /obj/item/clothing/proc/change_smell), time, TIMER_UNIQUE | TIMER_OVERRIDE) /obj/item/clothing/proc/get_fibers() . = "material from \a [name]" @@ -192,12 +197,6 @@ if(WRINKLES_NONE) to_chat(user, "It's completely wrinkle-free!") - switch(smell_state) - if(SMELL_CLEAN) - to_chat(user, "It smells clean!") - if(SMELL_STINKY) - to_chat(user, "It's quite stinky!") - var/rags = RAG_COUNT(src) if(rags) to_chat(user, SPAN_SUBTLE("With a sharp object, you could cut \the [src] up into [rags] rag\s.")) diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 5bed5fbad53..dc96ba35557 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -137,7 +137,7 @@ /obj/item/clothing/head/chem_hood name = "chemical hood" - desc = "A hood that protects the head from chemical comtaminants." + desc = "A hood that protects the head from chemical contaminants." icon = 'icons/clothing/head/chem_hood.dmi' permeability_coefficient = 0 armor = list( @@ -146,7 +146,7 @@ ) flags_inv = HIDEEARS|BLOCK_HEAD_HAIR item_flags = ITEM_FLAG_THICKMATERIAL - body_parts_covered = SLOT_HEAD|SLOT_EARS + body_parts_covered = SLOT_HEAD|SLOT_EARS|SLOT_FACE siemens_coefficient = 0.9 matter = list( /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT, diff --git a/code/modules/fabrication/designs/general/designs_general.dm b/code/modules/fabrication/designs/general/designs_general.dm index f14dba7c369..e4b7a8c647a 100644 --- a/code/modules/fabrication/designs/general/designs_general.dm +++ b/code/modules/fabrication/designs/general/designs_general.dm @@ -167,4 +167,9 @@ path = /obj/item/stack/package_wrap/gift /datum/fabricator_recipe/network_pos - path = /obj/item/network_pos \ No newline at end of file + path = /obj/item/network_pos +/datum/fabricator_recipe/clothes_iron + path = /obj/item/ironingiron + +/datum/fabricator_recipe/ironing_board + path = /obj/item/roller/ironingboard diff --git a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm index 9da9958314b..e3113f148e1 100644 --- a/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm +++ b/code/modules/fabrication/designs/imprinter/designs_misc_circuits.dm @@ -341,6 +341,9 @@ /datum/fabricator_recipe/imprinter/circuit/washer path = /obj/item/stock_parts/circuitboard/washer +/datum/fabricator_recipe/imprinter/circuit/autoclave + path = /obj/item/stock_parts/circuitboard/autoclave + /datum/fabricator_recipe/imprinter/circuit/microwave path = /obj/item/stock_parts/circuitboard/microwave diff --git a/code/modules/locks/key.dm b/code/modules/locks/key.dm index 70a2f9869b7..b4ded50c995 100644 --- a/code/modules/locks/key.dm +++ b/code/modules/locks/key.dm @@ -4,21 +4,20 @@ icon = 'icons/obj/items/key.dmi' icon_state = "keys" w_class = ITEM_SIZE_TINY - material = DEFAULT_FURNITURE_MATERIAL + material = /decl/material/solid/metal/brass + material_alteration = MAT_FLAG_ALTERATION_COLOR | MAT_FLAG_ALTERATION_NAME | MAT_FLAG_ALTERATION_DESC var/key_data = "" -/obj/item/key/Initialize(mapload,var/data) - . = ..(mapload) - if(data) - key_data = data +/obj/item/key/Initialize(var/mapload, var/material_key, var/new_key_data) + . = ..(mapload, material_key) + if(new_key_data) + key_data = new_key_data /obj/item/key/proc/get_data(var/mob/user) return key_data /obj/item/key/soap - name = "soap key" - desc = "a fragile key made using a bar of soap." - material = /decl/material/liquid/cleaner + material = /decl/material/liquid/cleaner/soap var/uses = 0 /obj/item/key/soap/get_data(var/mob/user) diff --git a/code/modules/locks/lock_construct.dm b/code/modules/locks/lock_construct.dm index 393fd09c1a1..beacb06758b 100644 --- a/code/modules/locks/lock_construct.dm +++ b/code/modules/locks/lock_construct.dm @@ -14,7 +14,7 @@ lock_data = generateRandomString(round(material.integrity/50)) /obj/item/lock_construct/attackby(var/obj/item/I, var/mob/user) - if(istype(I,/obj/item/key)) + if(istype(I, /obj/item/key)) var/obj/item/key/K = I if(!K.key_data) to_chat(user, SPAN_NOTICE("You fashion \the [I] to unlock \the [src].")) diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm index 4cd7ceb25aa..da7ec8fbe50 100644 --- a/code/modules/materials/_materials.dm +++ b/code/modules/materials/_materials.dm @@ -226,6 +226,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) var/fruit_descriptor // String added to fruit desc if this chemical is present. var/dirtiness = DIRTINESS_NEUTRAL // How dirty turfs are after being exposed to this material. Negative values cause a cleaning/sterilizing effect. + var/decontamination_dose = 0 // Amount required for a decontamination effect, if any. var/solvent_power = MAT_SOLVENT_NONE var/solvent_melt_dose = 0 var/solvent_max_damage = 0 @@ -572,6 +573,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/gas_overlay) else if(defoliant && istype(O, /obj/effect/vine)) qdel(O) else + if(dirtiness <= DIRTINESS_DECONTAMINATE) + if(amount >= decontamination_dose && istype(O, /obj/item)) + var/obj/item/I = O + if(I.contaminated) + I.decontaminate() if(dirtiness <= DIRTINESS_STERILE) O.germ_level -= min(REAGENT_VOLUME(holder, type)*20, O.germ_level) O.was_bloodied = null diff --git a/code/modules/reagents/chems/chems_cleaner.dm b/code/modules/reagents/chems/chems_cleaner.dm index 2b977a8380b..5bd2e9454e5 100644 --- a/code/modules/reagents/chems/chems_cleaner.dm +++ b/code/modules/reagents/chems/chems_cleaner.dm @@ -9,3 +9,31 @@ turf_touch_threshold = 0.1 uid = "chem_cleaner" exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/contaminant_cleaner + name = "akaline detergent" + lore_text = "A highly akaline hydrazine based detergent. Able to clean contaminants, but may release ammonia gas if used in open air." + taste_description = "bleach" + vapor_products = list(/decl/material/gas/ammonia = 0.5) + color = "#213799" + touch_met = 5 + toxicity = 5 + scent = "clean linen" + scent_descriptor = SCENT_DESC_FRAGRANCE + value = 0.25 + dirtiness = DIRTINESS_DECONTAMINATE + decontamination_dose = 5 + turf_touch_threshold = 0.1 + uid = "chem_contaminant_cleaner" + exoplanet_rarity_gas = MAT_RARITY_EXOTIC + +/decl/material/liquid/cleaner/soap + name = "soap" + lore_text = "A soft solid compound used to clean things. Usually derived from oil or fat." + taste_description = "waxy blandness" + color = COLOR_BEIGE + uid = "chem_soap" + melting_point = 323 + ignition_point = 353 + boiling_point = 373 + accelerant_value = 0.3 diff --git a/code/modules/reagents/chems/chems_nutriment.dm b/code/modules/reagents/chems/chems_nutriment.dm index 79add600924..1e04eee2dd2 100644 --- a/code/modules/reagents/chems/chems_nutriment.dm +++ b/code/modules/reagents/chems/chems_nutriment.dm @@ -10,9 +10,16 @@ uid = "chem_nutriment" exoplanet_rarity_gas = MAT_RARITY_NOWHERE // Please, no more animal protein or glowsap or corn oil atmosphere. + // Technically a room-temperature solid, but saves + // repathing it to /solid all over the codebase. + melting_point = 323 + ignition_point = 353 + boiling_point = 373 + accelerant_value = 0.65 + var/nutriment_factor = 10 // Per unit var/hydration_factor = 0 // Per unit - var/injectable = 0 + var/injectable = FALSE /decl/material/liquid/nutriment/mix_data(var/datum/reagents/reagents, var/list/newdata, var/newamount) @@ -102,6 +109,8 @@ taste_description = "egg" color = "#ffffaa" uid = "chem_nutriment_egg" + melting_point = 273 + boiling_point = 373 //vegetamarian alternative that is safe for vegans to ingest//rewired it from its intended nutriment/protein/egg/softtofu because it would not actually work, going with plan B, more recipes. @@ -120,6 +129,8 @@ color = "#ffff00" fruit_descriptor = "rich" uid = "chem_nutriment_honey" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/flour name = "flour" @@ -145,6 +156,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_batter" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/batter/touch_turf(var/turf/T, var/amount, var/datum/reagents/holder) ..() @@ -257,6 +270,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_soysauce" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/ketchup name = "ketchup" @@ -267,6 +282,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_ketchup" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/banana_cream name = "banana cream" @@ -276,6 +293,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_bananacream" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/barbecue name = "barbecue sauce" @@ -286,6 +305,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_bbqsauce" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/garlicsauce name = "garlic sauce" @@ -296,6 +317,8 @@ exoplanet_rarity_plant = MAT_RARITY_NOWHERE exoplanet_rarity_gas = MAT_RARITY_NOWHERE uid = "chem_nutriment_garlicsauce" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/rice name = "rice" @@ -326,6 +349,8 @@ color = "#801e28" fruit_descriptor = "sweet" uid = "chem_nutriment_cherryjelly" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/cornoil name = "corn oil" @@ -336,6 +361,8 @@ color = "#302000" slipperiness = 8 uid = "chem_nutriment_cornoil" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/sprinkles name = "sprinkles" @@ -369,6 +396,8 @@ color = "#e8dfd0" taste_mult = 3 uid = "chem_nutriment_vinegar" + melting_point = 273 + boiling_point = 373 /decl/material/liquid/nutriment/mayo name = "mayonnaise" diff --git a/code/modules/reagents/reactions/reaction_drugs.dm b/code/modules/reagents/reactions/reaction_drugs.dm index 03eac2e230b..854f479a657 100644 --- a/code/modules/reagents/reactions/reaction_drugs.dm +++ b/code/modules/reagents/reactions/reaction_drugs.dm @@ -191,6 +191,12 @@ mix_message = "The solution becomes slick and soapy." result_amount = 2 +/decl/chemical_reaction/contaminant_cleaner + name = "Akaline Detergent" + result = /decl/material/liquid/contaminant_cleaner + required_reagents = list(/decl/material/solid/sodium = 1, /decl/material/liquid/surfactant = 1) + result_amount = 2 + /decl/chemical_reaction/plantbgone name = "Plant-B-Gone" result = /decl/material/liquid/weedkiller diff --git a/code/modules/reagents/reactions/reaction_other.dm b/code/modules/reagents/reactions/reaction_other.dm index 6088fb606f1..f7dd8eb027a 100644 --- a/code/modules/reagents/reactions/reaction_other.dm +++ b/code/modules/reagents/reactions/reaction_other.dm @@ -13,7 +13,7 @@ /decl/chemical_reaction/soap_key/on_reaction(var/datum/reagents/holder) var/obj/item/soap/S = holder.get_reaction_loc(chemical_reaction_flags) if(istype(S) && S.key_data) - var/obj/item/key/soap/key = new(get_turf(S), S.key_data) + var/obj/item/key/soap/key = new(get_turf(S), null, S.key_data) key.uses = strength ..() diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 712e8426a1c..176964aaaaf 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -259,14 +259,13 @@ name = "detergent pod" desc = "Put in water to get space cleaner. Do not eat. Really." icon_state = "pod21" - var/smell_clean_time = 10 MINUTES // Don't overwrite the custom name. /obj/item/chems/pill/detergent/update_container_name() return /obj/item/chems/pill/detergent/populate_reagents() - reagents.add_reagent(/decl/material/gas/ammonia, 30) + reagents.add_reagent(/decl/material/liquid/contaminant_cleaner, 30) /obj/item/chems/pill/pod name = "master flavorpod item" diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm index eada8b40341..b3facf35c84 100644 --- a/code/modules/vehicles/cargo_train.dm +++ b/code/modules/vehicles/cargo_train.dm @@ -6,19 +6,20 @@ on = 0 powered = 1 locked = 0 - load_item_visible = 1 load_offset_x = 0 buckle_pixel_shift = list("x" = 0, "y" = 0, "z" = 7) - - var/car_limit = 3 //how many cars an engine can pull before performance degrades charge_use = 1 KILOWATTS active_engines = 1 + var/car_limit = 3 //how many cars an engine can pull before performance degrades var/obj/item/key/cargo_train/key /obj/item/key/cargo_train - name = "key" - desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"." + desc = "A small key on a yellow fob reading \"Choo Choo!\"." + material = /decl/material/solid/metal/steel + matter = list( + /decl/material/solid/organic/plastic = MATTER_AMOUNT_REINFORCEMENT + ) icon = 'icons/obj/vehicles.dmi' icon_state = "train_keys" w_class = ITEM_SIZE_TINY diff --git a/mods/persistence/modules/clothing/_clothing.dm b/mods/persistence/modules/clothing/_clothing.dm index 1f6e33b8a39..35be9cc2473 100644 --- a/mods/persistence/modules/clothing/_clothing.dm +++ b/mods/persistence/modules/clothing/_clothing.dm @@ -1,5 +1,5 @@ /obj/item/clothing/Initialize() - // Call on_attached on each accessory to allow for the addition of verbs etc. + // Call on_attached on each accessory to allow for the addition of verbs etc. if(persistent_id) if(islist(starting_accessories)) starting_accessories.Cut() @@ -16,7 +16,6 @@ SAVED_VAR(/obj/item/clothing, tint) SAVED_VAR(/obj/item/clothing, accessories) SAVED_VAR(/obj/item/clothing, ironed_state) -SAVED_VAR(/obj/item/clothing, smell_state) //Underwears are dumb SAVED_VAR(/obj/item/underwear, icon)