From 0a81ea5bf9625a2c76be527dd34df97dca65af97 Mon Sep 17 00:00:00 2001 From: Dani Glore Date: Mon, 31 Oct 2022 07:04:52 -0400 Subject: [PATCH] Internals Bugfixes & Internals-Compatible Helmets (#70750) * Core internals refactor. Add open/close_internals procs to /obj/item/tank. Add open/close_internals, can_breathe_internals, and invalid_internals procs to /mob/living/carbon. Fixed bug in human_stripping.dm preventing changing internals for breathing tube users. Fixed bug in /obj/item/tank/toggle_internals that was auto-adjusting non-internals masks. Fixed bug in slements/strippable that caused two mobs to breathe from the same internals. --- code/__DEFINES/obj_flags.dm | 2 + code/datums/outfit.dm | 3 +- code/game/objects/items/tanks/tank_types.dm | 10 ++ code/game/objects/items/tanks/tanks.dm | 86 +++++----- .../changeling/powers/mutations.dm | 2 +- code/modules/antagonists/cult/cult_items.dm | 2 +- code/modules/antagonists/ert/ert.dm | 2 +- code/modules/clothing/head/hardhat.dm | 2 +- code/modules/clothing/masks/_masks.dm | 13 +- code/modules/clothing/masks/breath.dm | 2 +- .../clothing/spacesuits/_spacesuits.dm | 2 +- code/modules/clothing/suits/bio.dm | 2 +- .../mob/living/carbon/carbon_defines.dm | 3 + code/modules/mob/living/carbon/human/human.dm | 16 +- .../living/carbon/human/human_stripping.dm | 32 ++-- .../mob/living/carbon/human/inventory.dm | 40 ++++- .../carbon/human/species_types/plasmamen.dm | 2 +- code/modules/mob/living/carbon/inventory.dm | 154 +++++++++++++++++- code/modules/mob/living/carbon/life.dm | 27 +-- code/modules/mod/mod_activation.dm | 3 + code/modules/mod/mod_control.dm | 2 +- code/modules/mod/mod_theme.dm | 56 +++---- 22 files changed, 336 insertions(+), 127 deletions(-) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 55767531ee7..6255473288b 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -65,6 +65,8 @@ #define CASTING_CLOTHES (1<<19) ///Moths can't eat the clothing that has this flag. #define INEDIBLE_CLOTHING (1<<20) +/// Headgear/helmet allows internals +#define HEADINTERNALS (1<<21) /// Integrity defines for clothing (not flags but close enough) #define CLOTHING_PRISTINE 0 // We have no damage on the clothing diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 05445b164e5..a8856c6d51a 100644 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -245,8 +245,7 @@ if(!visualsOnly) apply_fingerprints(H) if(internals_slot) - H.internal = H.get_item_by_slot(internals_slot) - H.update_action_buttons_icon() + H.open_internals(H.get_item_by_slot(internals_slot)) if(implants) for(var/implant_type in implants) var/obj/item/implant/I = SSwardrobe.provide_type(implant_type, H) diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm index 4e7ed2205f2..af726452d1b 100644 --- a/code/game/objects/items/tanks/tank_types.dm +++ b/code/game/objects/items/tanks/tank_types.dm @@ -8,6 +8,16 @@ * Generic */ +/// Allows carbon to toggle internals via AltClick of the equipped tank. +/obj/item/tank/internals/AltClick(mob/user) + ..() + if((loc == user) && user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE, need_hands = TRUE)) + toggle_internals(user) + +/obj/item/tank/internals/examine(mob/user) + . = ..() + . += span_notice("Alt-click the tank to toggle the valve.") + /* * Oxygen */ diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm index a034883b8ea..ada95172adb 100644 --- a/code/game/objects/items/tanks/tanks.dm +++ b/code/game/objects/items/tanks/tanks.dm @@ -44,38 +44,42 @@ var/list/explosion_info /// List containing reactions happening inside our tank. var/list/reaction_info + /// Mob that is currently breathing from the tank. + var/mob/living/carbon/breathing_mob = null + +/// Closes the tank if dropped while open. +/obj/item/tank/dropped(mob/living/user, silent) + . = ..() + // Close open air tank if its current user got sent to the shadowrealm. + if (QDELETED(breathing_mob)) + breathing_mob = null + return + // Close open air tank if it got dropped by it's current user. + if (loc != breathing_mob) + breathing_mob.cutoff_internals() + +/// Closes the tank if given to another mob while open. +/obj/item/tank/equipped(mob/living/user, slot, initial) + . = ..() + // Close open air tank if it was equipped by a mob other than the current user. + if (breathing_mob && (user != breathing_mob)) + breathing_mob.cutoff_internals() + +/// Called by carbons after they connect the tank to their breathing apparatus. +/obj/item/tank/proc/after_internals_opened(mob/living/carbon/carbon_target) + breathing_mob = carbon_target + +/// Called by carbons after they disconnect the tank from their breathing apparatus. +/obj/item/tank/proc/after_internals_closed(mob/living/carbon/carbon_target) + breathing_mob = null + +/// Attempts to toggle the mob's internals on or off using this tank. Returns TRUE if successful. +/obj/item/tank/proc/toggle_internals(mob/living/carbon/mob_target) + return mob_target.toggle_internals(src) /obj/item/tank/ui_action_click(mob/user) toggle_internals(user) -/obj/item/tank/proc/toggle_internals(mob/user) - var/mob/living/carbon/human/H = user - if(!istype(H)) - return - - if(H.internal == src) - to_chat(H, span_notice("You close [src] valve.")) - H.internal = null - else - if(!H.getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - if(!H.wear_mask) - to_chat(H, span_warning("You need a mask!")) - return - var/is_clothing = isclothing(H.wear_mask) - if(is_clothing && H.wear_mask.mask_adjusted) - H.wear_mask.adjustmask(H) - if(!is_clothing || !(H.wear_mask.clothing_flags & MASKINTERNALS)) - to_chat(H, span_warning("[H.wear_mask] can't use [src]!")) - return - - if(H.internal) - to_chat(H, span_notice("You switch your internals to [src].")) - else - to_chat(H, span_notice("You open [src] valve.")) - H.internal = src - H.update_action_buttons_icon() - - /obj/item/tank/Initialize(mapload) . = ..() @@ -110,8 +114,8 @@ /obj/item/tank/examine(mob/user) var/obj/icon = src . = ..() - if(istype(src.loc, /obj/item/assembly)) - icon = src.loc + if(istype(loc, /obj/item/assembly)) + icon = loc if(!in_range(src, user) && !isobserver(user)) if(icon == src) . += span_notice("If you want any more information you'll need to get closer.") @@ -145,21 +149,21 @@ return ..() /obj/item/tank/suicide_act(mob/user) - var/mob/living/carbon/human/H = user + var/mob/living/carbon/human/human_user = user user.visible_message(span_suicide("[user] is putting [src]'s valve to [user.p_their()] lips! It looks like [user.p_theyre()] trying to commit suicide!")) playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3) - if(!QDELETED(H) && air_contents && air_contents.return_pressure() >= 1000) - ADD_TRAIT(H, TRAIT_DISFIGURED, TRAIT_GENERIC) - H.inflate_gib() + if(!QDELETED(human_user) && air_contents && air_contents.return_pressure() >= 1000) + ADD_TRAIT(human_user, TRAIT_DISFIGURED, TRAIT_GENERIC) + human_user.inflate_gib() return MANUAL_SUICIDE else to_chat(user, span_warning("There isn't enough pressure in [src] to commit suicide with...")) return SHAME -/obj/item/tank/attackby(obj/item/W, mob/user, params) +/obj/item/tank/attackby(obj/item/attacking_item, mob/user, params) add_fingerprint(user) - if(istype(W, /obj/item/assembly_holder)) - bomb_assemble(W, user) + if(istype(attacking_item, /obj/item/assembly_holder)) + bomb_assemble(attacking_item, user) return TRUE return ..() @@ -187,10 +191,10 @@ "releasePressure" = round(distribute_pressure) ) - var/mob/living/carbon/C = user - if(!istype(C)) - C = loc.loc - if(istype(C) && C.internal == src) + var/mob/living/carbon/carbon_user = user + if(!istype(carbon_user)) + carbon_user = loc + if(istype(carbon_user) && (carbon_user.external == src || carbon_user.internal == src)) .["connected"] = TRUE /obj/item/tank/ui_act(action, params) diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 5941d8a7812..69164f77f2b 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -507,7 +507,7 @@ inhand_icon_state = null desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front." item_flags = DROPDEL - clothing_flags = STOPSPRESSUREDAMAGE + clothing_flags = STOPSPRESSUREDAMAGE | HEADINTERNALS armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 90, ACID = 90) flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index e42ca256f9d..1f463daa1ee 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -266,7 +266,7 @@ Striking a noncultist, however, will tear their flesh."} icon_state = "cult_helmet" inhand_icon_state = null armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT | HEADINTERNALS flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index c9f820e094a..744089dc72a 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -232,7 +232,7 @@ return if(isplasmaman(H)) H.equipOutfit(plasmaman_outfit) - H.internal = H.get_item_for_held_index(2) + H.open_internals(H.get_item_for_held_index(2)) H.equipOutfit(outfit) diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index fa1d68287e0..82fbc1314ed 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -102,7 +102,7 @@ dog_fashion = null name = "atmospheric technician's firefighting helmet" desc = "A firefighter's helmet, able to keep the user cool in any situation." - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | PLASMAMAN_HELMET_EXEMPT + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | PLASMAMAN_HELMET_EXEMPT | HEADINTERNALS flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT heat_protection = HEAD max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index 21980eb2328..ecb91664299 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -62,12 +62,12 @@ M.update_worn_mask() //Proc that moves gas/breath masks out of the way, disabling them and allowing pill/food consumption -/obj/item/clothing/mask/proc/adjustmask(mob/living/user) +/obj/item/clothing/mask/proc/adjustmask(mob/living/carbon/user) if(user?.incapacitated()) return mask_adjusted = !mask_adjusted if(!mask_adjusted) - src.icon_state = initial(icon_state) + icon_state = initial(icon_state) clothing_flags |= visor_flags flags_inv |= visor_flags_inv flags_cover |= visor_flags_cover @@ -81,9 +81,14 @@ flags_cover &= ~visor_flags_cover if(adjusted_flags) slot_flags = adjusted_flags - if(user) + if(!istype(user)) + return + // Update the mob if it's wearing the mask. + if(user.wear_mask == src) user.wear_mask_update(src, toggle_off = mask_adjusted) - user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off. + if(loc == user) + // Update action button icon for adjusted mask, if someone is holding it. + user.update_action_buttons_icon() /** * Proc called in lungs.dm to act if wearing a mask with filters, used to reduce the filters durability, return a changed gas mixture depending on the filter status diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm index b4d26e64824..eb9fc996d4e 100644 --- a/code/modules/clothing/masks/breath.dm +++ b/code/modules/clothing/masks/breath.dm @@ -22,7 +22,7 @@ /obj/item/clothing/mask/breath/AltClick(mob/user) ..() - if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user))) + if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user))) adjustmask(user) /obj/item/clothing/mask/breath/examine(mob/user) diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index e8efcca6512..d18e830b606 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -9,7 +9,7 @@ icon_state = "spaceold" inhand_icon_state = "space_helmet" desc = "A special helmet with solar UV shielding to protect your eyes from harmful rays." - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT | HEADINTERNALS armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 80, ACID = 70) flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm index fed14ffe204..de9111c7377 100644 --- a/code/modules/clothing/suits/bio.dm +++ b/code/modules/clothing/suits/bio.dm @@ -6,7 +6,7 @@ worn_icon = 'icons/mob/clothing/head/bio.dmi' icon_state = "bio" inhand_icon_state = "bio_hood" - clothing_flags = THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT + clothing_flags = THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT | HEADINTERNALS armor = list(MELEE = 0, BULLET = 0, LASER = 0,ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 30, ACID = 100) flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDEFACE|HIDESNOUT resistance_flags = ACID_PROOF diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 5076e56cabc..2b83e74e643 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -36,7 +36,10 @@ var/obj/item/back = null var/obj/item/clothing/mask/wear_mask = null var/obj/item/clothing/neck/wear_neck = null + /// Equipped air tank. Never set this manually. var/obj/item/tank/internal = null + /// "External" air tank. Never set this manually. Not required to stay directly equipped on the mob (i.e. could be a machine or MOD suit module). + var/obj/item/tank/external = null var/obj/item/clothing/head = null ///only used by humans diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 9549fc8e852..4113f5ded04 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -81,15 +81,13 @@ /mob/living/carbon/human/get_status_tab_items() . = ..() - if (internal) - var/datum/gas_mixture/internal_air = internal.return_air() - if (!internal_air) - QDEL_NULL(internal) - else - . += "" - . += "Internal Atmosphere Info: [internal.name]" - . += "Tank Pressure: [internal_air.return_pressure()]" - . += "Distribution Pressure: [internal.distribute_pressure]" + var/obj/item/tank/target_tank = internal || external + if(target_tank) + var/datum/gas_mixture/internal_air = target_tank.return_air() + . += "" + . += "Internal Atmosphere Info: [target_tank.name]" + . += "Tank Pressure: [internal_air.return_pressure()]" + . += "Distribution Pressure: [target_tank.distribute_pressure]" if(istype(wear_suit, /obj/item/clothing/suit/space)) var/obj/item/clothing/suit/space/S = wear_suit . += "Thermal Regulator: [S.thermal_on ? "on" : "off"]" diff --git a/code/modules/mob/living/carbon/human/human_stripping.dm b/code/modules/mob/living/carbon/human/human_stripping.dm index 35fb3cc60b0..9557af35b3f 100644 --- a/code/modules/mob/living/carbon/human/human_stripping.dm +++ b/code/modules/mob/living/carbon/human/human_stripping.dm @@ -185,13 +185,11 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( return var/mob/living/carbon/carbon_source = source - - var/obj/item/clothing/mask = carbon_source.wear_mask - if (!istype(mask)) - return - - if ((mask.clothing_flags & MASKINTERNALS) && istype(item, /obj/item/tank)) - return isnull(carbon_source.internal) ? "enable_internals" : "disable_internals" + if (carbon_source.can_breathe_internals() && istype(item, /obj/item/tank)) + if(carbon_source.internal != item) + return "enable_internals" + else + return "disable_internals" /proc/strippable_alternate_action_internals(obj/item/item, atom/source, mob/user) var/obj/item/tank/tank = item @@ -202,28 +200,26 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list( if (!istype(carbon_source)) return - var/obj/item/clothing/mask = carbon_source.wear_mask - if (!istype(mask) || !(mask.clothing_flags & MASKINTERNALS)) + if (!carbon_source.can_breathe_internals()) return carbon_source.visible_message( - span_danger("[user] tries to [isnull(carbon_source.internal) ? "open": "close"] the valve on [source]'s [item.name]."), - span_userdanger("[user] tries to [isnull(carbon_source.internal) ? "open": "close"] the valve on your [item.name]."), + span_danger("[user] tries to [(carbon_source.internal != item) ? "open" : "close"] the valve on [source]'s [item.name]."), + span_userdanger("[user] tries to [(carbon_source.internal != item) ? "open" : "close"] the valve on your [item.name]."), ignored_mobs = user, ) - to_chat(user, span_notice("You try to [isnull(carbon_source.internal) ? "open": "close"] the valve on [source]'s [item.name]...")) + to_chat(user, span_notice("You try to [(carbon_source.internal != item) ? "open" : "close"] the valve on [source]'s [item.name]...")) if(!do_mob(user, carbon_source, INTERNALS_TOGGLE_DELAY)) return - if(carbon_source.internal) - carbon_source.internal = null - - // This isn't meant to be FALSE, it correlates to the icon's name. + if (carbon_source.internal == item) + carbon_source.close_internals() + // This isn't meant to be FALSE, it correlates to the item's name. else if (!QDELETED(item)) - if((carbon_source.wear_mask?.clothing_flags & MASKINTERNALS) || carbon_source.getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - carbon_source.internal = item + if(!carbon_source.try_open_internals(item)) + return carbon_source.visible_message( span_danger("[user] [isnull(carbon_source.internal) ? "closes": "opens"] the valve on [source]'s [item.name]."), diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 4bfaf0c4dc3..0ce04a2d71d 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -287,11 +287,44 @@ if((I.body_parts_covered & FEET) || (I.flags_inv | I.transparent_protection) & HIDESHOES) SEND_SIGNAL(src, COMSIG_CARBON_UNEQUIP_SHOECOVER, I, force, newloc, no_move, invdrop, silent) +/mob/living/carbon/human/toggle_internals(obj/item/tank, is_external = FALSE) + // Just close the tank if it's the one the mob already has open. + var/obj/item/existing_tank = is_external ? external : internal + if(tank == existing_tank) + return toggle_close_internals(is_external) + // Use breathing tube regardless of mask. + if(can_breathe_tube()) + return toggle_open_internals(tank, is_external) + // Use mask in absence of tube. + if(isclothing(wear_mask) && ((wear_mask.visor_flags & MASKINTERNALS) || (wear_mask.clothing_flags & MASKINTERNALS))) + // Adjust dishevelled breathing mask back onto face. + if (wear_mask.mask_adjusted) + wear_mask.adjustmask(src) + return toggle_open_internals(tank, is_external) + // Use helmet in absence of tube or valid mask. + if(can_breathe_helmet()) + return toggle_open_internals(tank, is_external) + // Notify user of missing valid breathing apparatus. + if (wear_mask) + // Invalid mask + to_chat(src, span_warning("[wear_mask] can't use [tank]!")) + else if (head) + // Invalid headgear + to_chat(src, span_warning("[head] isn't airtight! You need a mask!")) + else + // Not wearing any breathing apparatus. + to_chat(src, span_warning("You need a mask!")) + +/// Returns TRUE if the tank successfully toggles open/closed. Opens the tank only if a breathing apparatus is found. +/mob/living/carbon/human/toggle_externals(obj/item/tank) + return toggle_internals(tank, TRUE) + /mob/living/carbon/human/wear_mask_update(obj/item/I, toggle_off = 1) if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(I.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR))) update_body_parts() - if(toggle_off && internal && !getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - internal = null + // Close internal air tank if mask was the only breathing apparatus. + if(invalid_internals()) + cutoff_internals() if(I.flags_inv & HIDEEYES) update_worn_glasses() sec_hud_set_security_status() @@ -300,6 +333,9 @@ /mob/living/carbon/human/head_update(obj/item/I, forced) if((I.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || forced) update_body_parts() + // Close internal air tank if helmet was the only breathing apparatus. + if (invalid_internals()) + cutoff_internals() if(I.flags_inv & HIDEEYES || forced) update_worn_glasses() if(I.flags_inv & HIDEEARS || forced) diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index d28c0f183ba..74632cf42ff 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -116,7 +116,7 @@ /datum/species/plasmaman/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only = FALSE) if(job.plasmaman_outfit) equipping.equipOutfit(job.plasmaman_outfit, visuals_only) - equipping.internal = equipping.get_item_for_held_index(2) + equipping.open_internals(equipping.get_item_for_held_index(2)) /datum/species/plasmaman/random_name(gender,unique,lastname) if(unique) diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index cdc068ae8a4..372ba2584e7 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -168,13 +168,161 @@ // Not an else-if because we're probably equipped in another slot if(I == internal && (QDELETED(src) || QDELETED(I) || I.loc != src)) - internal = null + cutoff_internals() if(!QDELETED(src)) update_action_buttons_icon(status_only = TRUE) update_equipment_speed_mods() -//handle stuff to update when a mob equips/unequips a mask. +/// Returns TRUE if an air tank compatible helmet is equipped. +/mob/living/carbon/proc/can_breathe_helmet() + if (isclothing(head) && (head.clothing_flags & HEADINTERNALS)) + return TRUE + +/// Returns TRUE if an air tank compatible mask is equipped. +/mob/living/carbon/proc/can_breathe_mask() + if (isclothing(wear_mask) && (wear_mask.clothing_flags & MASKINTERNALS)) + return TRUE + +/// Returns TRUE if a breathing tube is equipped. +/mob/living/carbon/proc/can_breathe_tube() + if (getorganslot(ORGAN_SLOT_BREATHING_TUBE)) + return TRUE + +/// Returns TRUE if an air tank compatible mask or breathing tube is equipped. +/mob/living/carbon/proc/can_breathe_internals() + return can_breathe_tube() || can_breathe_mask() || can_breathe_helmet() + +/// Returns truthy if air tank is open and mob lacks apparatus, or if the tank moved away from the mob. +/mob/living/carbon/proc/invalid_internals() + return (internal || external) && (!can_breathe_internals() || (internal && internal.loc != src)) + +/** + * Open the internal air tank without checking for any breathing apparatus. + * Returns TRUE if the air tank was opened successfully. + * Closes any existing tanks before opening another one. + * + * Arguments: + * * tank - The given tank to open and start breathing from. + * * is_external - A boolean which indicates if the air tank must be equipped, or stored elsewhere. + */ +/mob/living/carbon/proc/open_internals(obj/item/tank/target_tank, is_external = FALSE) + if (!target_tank) + return + close_all_airtanks() + if (is_external) + external = target_tank + else + internal = target_tank + target_tank.after_internals_opened(src) + update_action_buttons_icon() + return TRUE + +/** + * Opens the given internal air tank if a breathing apparatus is found. Returns TRUE if successful, FALSE otherwise. + * Returns TRUE if the tank was opened successfully. + * + * Arguments: + * * tank - The given tank we will attempt to toggle open and start breathing from. + * * is_external - A boolean which indicates if the air tank must be equipped, or stored elsewhere. + */ +/mob/living/carbon/proc/try_open_internals(obj/item/tank/target_tank, is_external = FALSE) + if (!can_breathe_internals()) + return + return open_internals(target_tank, is_external) + +/** + * Actually closes the active internal or external air tank. + * Returns TRUE if the tank was opened successfully. + * + * Arguments: + * * is_external - A boolean which indicates if the air tank must be equipped, or stored elsewhere. + */ +/mob/living/carbon/proc/close_internals(is_external = FALSE) + var/obj/item/tank/target_tank = is_external ? external : internal + if (!target_tank) + return + if (is_external) + external = null + else + internal = null + target_tank.after_internals_closed(src) + update_action_buttons_icon() + return TRUE + +/// Close the the currently open external (that's EX-ternal) air tank. Returns TREUE if successful. +/mob/living/carbon/proc/close_externals() + return close_internals(TRUE) + +/// Quickly/lazily close all airtanks without any returns or notifications. +/mob/living/carbon/proc/close_all_airtanks() + if (external) + close_externals() + if (internal) + close_internals() + +/** + * Prepares to open the internal air tank and notifies the mob in chat. + * Handles displaying messages to the user before doing the actual opening. + * Returns TRUE if the tank was opened/closed successfully. + * + * Arguments: + * * tank - The given tank to toggle open and start breathing from. + * * is_external - A boolean which indicates if the air tank must be equipped, or stored elsewhere. + */ +/mob/living/carbon/proc/toggle_open_internals(obj/item/tank/target_tank, is_external = FALSE) + if (!target_tank) + return + if(internal || (is_external && external)) + to_chat(src, span_notice("You switch your internals to [target_tank].")) + else + to_chat(src, span_notice("You open [target_tank] valve.")) + return open_internals(target_tank, is_external) + +/** + * Prepares to close the currently open internal air tank and notifies in chat. + * Handles displaying messages to the user before doing the actual closing. + * Returns TRUE if + * + * Arguments: + * * is_external - A boolean which indicates if the air tank must be equipped, or stored elsewhere. + */ +/mob/living/carbon/proc/toggle_close_internals(is_external = FALSE) + if (!internal && !external) + return + to_chat(src, span_notice("You close [is_external ? external : internal] valve.")) + return close_internals(is_external) + +/// Prepares emergency disconnect from open air tanks and notifies in chat. Usually called after mob suddenly unequips breathing apparatus. +/mob/living/carbon/proc/cutoff_internals() + if (!external && !internal) + return + to_chat(src, span_notice("Your internals disconnect from [external || internal] and the valve closes.")) + close_all_airtanks() + +/** + * Toggles the given internal air tank open, or close the currently open one, if a compatible breathing apparatus is found. + * Returns TRUE if the tank was opened successfully. + * + * Arguments: + * * tank - The given tank to toggle open and start breathing from internally. + */ +/mob/living/carbon/proc/toggle_internals(obj/item/tank) + // Carbons can't open their own internals tanks. + return FALSE + +/** + * Toggles the given external (that's EX-ternal) air tank open, or close the currently open one, if a compatible breathing apparatus is found. + * Returns TRUE if the tank was opened successfully. + * + * Arguments: + * * tank - The given tank to toggle open and start breathing from externally. + */ +/mob/living/carbon/proc/toggle_externals(obj/item/tank) + // Carbons can't open their own externals tanks. + return FALSE + +/// Handle stuff to update when a mob equips/unequips a mask. /mob/living/proc/wear_mask_update(obj/item/I, toggle_off = 1) update_worn_mask() @@ -184,7 +332,7 @@ update_tint() update_worn_mask() -//handle stuff to update when a mob equips/unequips a headgear. +/// Handle stuff to update when a mob equips/unequips a headgear. /mob/living/carbon/proc/head_update(obj/item/I, forced) if(isclothing(I)) var/obj/item/clothing/C = I diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index c23cd0524fe..ca99f79556a 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -151,7 +151,7 @@ failed_last_breath = TRUE throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy) return FALSE - + var/safe_oxy_min = 16 var/safe_co2_max = 10 var/safe_plas_max = 0.05 @@ -303,21 +303,26 @@ return TRUE -//Fourth and final link in a breath chain +/// Fourth and final link in a breath chain /mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath) // The air you breathe out should match your body temperature breath.temperature = bodytemperature +/// Attempts to take a breath from the external or internal air tank. /mob/living/carbon/proc/get_breath_from_internal(volume_needed) - if(internal) - if(internal.loc != src) - internal = null - else if ((!wear_mask || !(wear_mask.clothing_flags & MASKINTERNALS)) && !getorganslot(ORGAN_SLOT_BREATHING_TUBE)) - internal = null - else - . = internal.remove_air_volume(volume_needed) - if(!.) - return FALSE //to differentiate between no internals and active, but empty internals + if(invalid_internals()) + // Unexpectely lost breathing apparatus and ability to breathe from the internal air tank. + cutoff_internals() + return + if (external) + . = external.remove_air_volume(volume_needed) + else if (internal) + . = internal.remove_air_volume(volume_needed) + else + // Return without taking a breath if there is no air tank. + return + // To differentiate between no internals and active, but empty internals. + return . || FALSE /mob/living/carbon/proc/handle_blood(delta_time, times_fired) return diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index a236206b5e1..be7ca18a5a6 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -220,6 +220,9 @@ wearer.update_worn_mask() wearer.update_worn_glasses() wearer.update_body_parts() + // Close internal air tank if MOD helmet is unsealed and was the only breathing apparatus. + if (!seal && wearer?.invalid_internals()) + wearer.cutoff_internals() /// Finishes the suit's activation, starts processing /obj/item/mod/control/proc/finish_activation(on) diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 5a91fe0fcba..3b1de22a052 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -444,7 +444,7 @@ icon_state = "[skin]-control[active ? "-sealed" : ""]" return ..() -/obj/item/mod/control/proc/set_wearer(mob/user) +/obj/item/mod/control/proc/set_wearer(mob/living/carbon/human/user) wearer = user SEND_SIGNAL(src, COMSIG_MOD_WEARER_SET, wearer) RegisterSignal(wearer, COMSIG_ATOM_EXITED, .proc/on_exit) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index e5a5454874f..2890908f613 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -55,7 +55,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -79,7 +79,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -126,7 +126,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -174,7 +174,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR, UNSEALED_COVER = HEADCOVERSMOUTH, @@ -228,7 +228,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -293,7 +293,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -318,7 +318,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -424,7 +424,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -449,7 +449,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -509,7 +509,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -564,7 +564,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -613,7 +613,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, @@ -665,7 +665,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -720,7 +720,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -768,7 +768,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -824,7 +824,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -849,7 +849,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -905,7 +905,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1014,7 +1014,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|CASTING_CLOTHES, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -1066,7 +1066,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1120,7 +1120,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -1170,7 +1170,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1195,7 +1195,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, ), @@ -1247,7 +1247,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1298,7 +1298,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1343,7 +1343,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = NECK_LAYER, UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -1389,7 +1389,7 @@ HELMET_FLAGS = list( UNSEALED_LAYER = null, UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, - SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH, @@ -1437,7 +1437,7 @@ "debug" = list( HELMET_FLAGS = list( UNSEALED_LAYER = null, - UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT, + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF,