diff --git a/code/modules/research/techweb/nodes/atmos_nodes.dm b/code/modules/research/techweb/nodes/atmos_nodes.dm index a61a6a6b094c1..b0e2f1598d1e5 100644 --- a/code/modules/research/techweb/nodes/atmos_nodes.dm +++ b/code/modules/research/techweb/nodes/atmos_nodes.dm @@ -11,6 +11,8 @@ "scrubber", "generic_tank", "oxygen_tank", + "nitrogen_tank", //DOPPLER EDIT ADDITION + "nitrogen_tank_belt", //DOPPLER EDIT ADDITION "plasma_tank", "plasmaman_tank_belt", "plasmarefiller", diff --git a/modular_doppler/modular_quirks/nitrogen_breather/equipping.dm b/modular_doppler/modular_quirks/nitrogen_breather/equipping.dm new file mode 100644 index 0000000000000..cb68d14168464 --- /dev/null +++ b/modular_doppler/modular_quirks/nitrogen_breather/equipping.dm @@ -0,0 +1,61 @@ +/datum/quirk/equipping + abstract_parent_type = /datum/quirk/equipping + quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE + icon = FA_ICON_BOX_OPEN + /// the items that will be equipped, formatted in the way of [item_path = list of slots it can be equipped to], will not equip over nodrop items + var/list/items = list() + /// the items that will be forcefully equipped, formatted in the way of [item_path = list of slots it can be equipped to], will equip over nodrop items + var/list/forced_items = list() + /// did we force drop any items? if so, they're in this list. useful for transferring any applicable contents into new items on roundstart + var/list/force_dropped_items = list() + +/datum/quirk/equipping/add_unique(client/client_source) + var/mob/living/carbon/carbon_holder = quirk_holder + if (!items || !carbon_holder) + return + var/list/equipped_items = list() + var/list/all_items = forced_items|items + for (var/obj/item/item_path as anything in all_items) + if (!ispath(item_path)) + continue + var/item = new item_path(carbon_holder.loc) + var/success = FALSE + // Checking for nodrop and seeing if there's an empty slot + for (var/slot as anything in all_items[item_path]) + success = force_equip_item(carbon_holder, item, slot, check_item = FALSE) + if (success) + break + // Checking for nodrop + for (var/slot as anything in all_items[item_path]) + success = force_equip_item(carbon_holder, item, slot) + if (success) + break + + if ((item_path in forced_items) && !success) + // Checking for nodrop failed, shove it into the first available slot, even if it has nodrop + for (var/slot as anything in all_items[item_path]) + success = force_equip_item(carbon_holder, item, slot, FALSE) + if (success) + break + equipped_items[item] = success + for (var/item as anything in equipped_items) + on_equip_item(item, equipped_items[item]) + +/datum/quirk/equipping/proc/force_equip_item(mob/living/carbon/target, obj/item/item, slot, check_nodrop = TRUE, check_item = TRUE) + var/obj/item/item_in_slot = target.get_item_by_slot(slot) + if (check_item && item_in_slot) + if (check_nodrop && HAS_TRAIT(item_in_slot, TRAIT_NODROP)) + return FALSE + target.dropItemToGround(item_in_slot, force = TRUE) + force_dropped_items += item_in_slot + RegisterSignal(item_in_slot, COMSIG_QDELETING, PROC_REF(dropped_items_cleanup)) + + return target.equip_to_slot_if_possible(item, slot, disable_warning = TRUE) // this should never not work tbh + +/datum/quirk/equipping/proc/dropped_items_cleanup(obj/item/source) + SIGNAL_HANDLER + + force_dropped_items -= source + +/datum/quirk/equipping/proc/on_equip_item(obj/item/equipped, success) + return diff --git a/modular_doppler/modular_quirks/nitrogen_breather/icons/belt.dmi b/modular_doppler/modular_quirks/nitrogen_breather/icons/belt.dmi new file mode 100644 index 0000000000000..b8ef83345d25a Binary files /dev/null and b/modular_doppler/modular_quirks/nitrogen_breather/icons/belt.dmi differ diff --git a/modular_doppler/modular_quirks/nitrogen_breather/icons/tank.dmi b/modular_doppler/modular_quirks/nitrogen_breather/icons/tank.dmi new file mode 100644 index 0000000000000..cf0847d4d67e2 Binary files /dev/null and b/modular_doppler/modular_quirks/nitrogen_breather/icons/tank.dmi differ diff --git a/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_lefthand.dmi b/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_lefthand.dmi new file mode 100644 index 0000000000000..c0aaa5b880584 Binary files /dev/null and b/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_lefthand.dmi differ diff --git a/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_righthand.dmi b/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_righthand.dmi new file mode 100644 index 0000000000000..e4c077d7c5ed0 Binary files /dev/null and b/modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_righthand.dmi differ diff --git a/modular_doppler/modular_quirks/nitrogen_breather/lungs.dm b/modular_doppler/modular_quirks/nitrogen_breather/lungs.dm new file mode 100644 index 0000000000000..6094ab1ef3250 --- /dev/null +++ b/modular_doppler/modular_quirks/nitrogen_breather/lungs.dm @@ -0,0 +1,9 @@ +/obj/item/organ/internal/lungs/nitrogen + name = "nitrogen lungs" + desc = "A set of lungs for breathing nitrogen." + safe_oxygen_min = 0 //Dont need oxygen + safe_oxygen_max = 2 //But it is quite toxic + safe_nitro_min = 10 // Atleast 10 nitrogen + oxy_damage_type = TOX + oxy_breath_dam_min = 6 + oxy_breath_dam_max = 20 diff --git a/modular_doppler/modular_quirks/nitrogen_breather/nitrogen_tanks.dm b/modular_doppler/modular_quirks/nitrogen_breather/nitrogen_tanks.dm new file mode 100644 index 0000000000000..a9f334602e9da --- /dev/null +++ b/modular_doppler/modular_quirks/nitrogen_breather/nitrogen_tanks.dm @@ -0,0 +1,67 @@ +/obj/item/tank/internals/nitrogen + name = "nitrogen tank" + desc = "A small tank of nitrogen, for crew who don't breathe the standard air mix." + icon_state = "oxygen_fr" + force = 10 + distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE + +/obj/item/tank/internals/nitrogen/populate_gas() + air_contents.assert_gas(/datum/gas/nitrogen) + air_contents.gases[/datum/gas/nitrogen][MOLES] = (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) + +/obj/item/tank/internals/nitrogen/full/populate_gas() + air_contents.assert_gas(/datum/gas/nitrogen) + air_contents.gases[/datum/gas/nitrogen][MOLES] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) + +/obj/item/tank/internals/nitrogen/belt + icon = 'modular_doppler/modular_quirks/nitrogen_breather/icons/tank.dmi' + worn_icon = 'modular_doppler/modular_quirks/nitrogen_breather/icons/belt.dmi' + lefthand_file = 'modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_lefthand.dmi' + righthand_file = 'modular_doppler/modular_quirks/nitrogen_breather/icons/tanks_righthand.dmi' + icon_state = "nitrogen_extended" + inhand_icon_state = "nitrogen" + slot_flags = ITEM_SLOT_BELT + force = 5 + volume = 24 + w_class = WEIGHT_CLASS_SMALL + +/obj/item/tank/internals/nitrogen/belt/full/populate_gas() + air_contents.assert_gas(/datum/gas/nitrogen) + air_contents.gases[/datum/gas/nitrogen][MOLES] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) + +/obj/item/tank/internals/nitrogen/belt/emergency + name = "emergency nitrogen tank" + desc = "Used for emergencies. Contains very little nitrogen, so try to conserve it until you actually need it." + icon_state = "nitrogen" + worn_icon_state = "nitrogen_extended" + volume = 3 + +/obj/item/tank/internals/nitrogen/belt/emergency/populate_gas() + air_contents.assert_gas(/datum/gas/nitrogen) + air_contents.gases[/datum/gas/nitrogen][MOLES] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) + +/datum/design/nitrogen_tank_belt + name = "Compact Nitrogen Tank" + desc = "A small, compact nitrogen tank that can fit on someones belt" + id = "nitrogen_tank_belt" // added one more requirment since the Jaws of Life are a bit OP + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*0.75) + build_path = /obj/item/tank/internals/nitrogen/belt + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_GAS_TANKS + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO + +/datum/design/nitrogen_tank + name = "Nitrogen Tank" + desc = "A full sized nitrogen tank" + id = "nitrogen_tank" // added one more requirment since the Jaws of Life are a bit OP + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT) + build_path = /obj/item/tank/internals/nitrogen/belt + category = list( + RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_GAS_TANKS + ) + departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO + + diff --git a/modular_doppler/modular_quirks/nitrogen_breather/quirk.dm b/modular_doppler/modular_quirks/nitrogen_breather/quirk.dm new file mode 100644 index 0000000000000..a0f3a8536c662 --- /dev/null +++ b/modular_doppler/modular_quirks/nitrogen_breather/quirk.dm @@ -0,0 +1,91 @@ +/datum/quirk/equipping/lungs + abstract_parent_type = /datum/quirk/equipping/lungs + icon = FA_ICON_LUNGS + var/obj/item/organ/internal/lungs/lungs_holding + var/obj/item/organ/internal/lungs/lungs_added + var/lungs_typepath = /obj/item/organ/internal/lungs + items = list(/obj/item/clothing/accessory/breathing = list(ITEM_SLOT_BACKPACK)) + var/breath_type = "oxygen" + +/datum/quirk/equipping/lungs/add(client/client_source) + var/mob/living/carbon/human/carbon_holder = quirk_holder + if (!istype(carbon_holder) || !lungs_typepath) + return + var/current_lungs = carbon_holder.get_organ_slot(ORGAN_SLOT_LUNGS) + if (istype(current_lungs, lungs_typepath)) + return + lungs_holding = current_lungs + if(!isnull(lungs_holding)) + lungs_holding.organ_flags |= ORGAN_FROZEN // stop decay on the old lungs + lungs_added = new lungs_typepath + lungs_added.Insert(carbon_holder, special = TRUE) + if(!isnull(lungs_holding)) + lungs_holding.moveToNullspace() // save them for later + +/datum/quirk/equipping/lungs/remove() + var/mob/living/carbon/carbon_holder = quirk_holder + if (!istype(carbon_holder) || !istype(lungs_holding)) + return + var/obj/item/organ/internal/lungs/lungs = carbon_holder.get_organ_slot(ORGAN_SLOT_LUNGS) + if (lungs != lungs_added && lungs != lungs_holding) + qdel(lungs_holding) + return + lungs_holding.Insert(carbon_holder, special = TRUE, movement_flags = DELETE_IF_REPLACED) + lungs_holding.organ_flags &= ~ORGAN_FROZEN + +/datum/quirk/equipping/lungs/on_equip_item(obj/item/equipped, success) + var/mob/living/carbon/human/human_holder = quirk_holder + if (!istype(equipped, /obj/item/clothing/accessory/breathing)) + return + var/obj/item/clothing/accessory/breathing/acc = equipped + acc.breath_type = breath_type + + var/obj/item/clothing/under/attach_to = human_holder?.w_uniform + if (attach_to && acc.can_attach_accessory(attach_to, human_holder)) + acc.attach(human_holder.w_uniform, human_holder) + +/obj/item/clothing/accessory/breathing + name = "breathing dogtag" + desc = "Dogtag that lists what you breathe." + icon_state = "allergy" + above_suit = FALSE + minimize_when_attached = TRUE + attachment_slot = CHEST + var/breath_type + +/obj/item/clothing/accessory/breathing/examine(mob/user) + . = ..() + . += "The dogtag reads: I breathe [breath_type]." + +/obj/item/clothing/accessory/breathing/accessory_equipped(obj/item/clothing/under/uniform, user) + . = ..() + RegisterSignal(uniform, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/obj/item/clothing/accessory/breathing/accessory_dropped(obj/item/clothing/under/uniform, user) + . = ..() + UnregisterSignal(uniform, COMSIG_ATOM_EXAMINE) + +/obj/item/clothing/accessory/breathing/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += "The dogtag reads: I breathe [breath_type]." + +/datum/quirk/equipping/lungs/nitrogen + name = "Nitrogen Breather" + desc = "You breathe nitrogen, even if you might not normally breathe it. Oxygen is poisonous." + icon = FA_ICON_LUNGS_VIRUS + medical_record_text = "Patient can only breathe nitrogen." + gain_text = "You suddenly have a hard time breathing anything but nitrogen." + lose_text = "You suddenly feel like you aren't bound to nitrogen anymore." + value = 0 + forced_items = list( + /obj/item/clothing/mask/breath = list(ITEM_SLOT_MASK), + /obj/item/tank/internals/nitrogen/belt/full = list(ITEM_SLOT_HANDS, ITEM_SLOT_LPOCKET, ITEM_SLOT_RPOCKET)) + lungs_typepath = /obj/item/organ/internal/lungs/nitrogen + breath_type = "nitrogen" + +/datum/quirk/equipping/lungs/nitrogen/on_equip_item(obj/item/equipped, success) + . = ..() + var/mob/living/carbon/carbon_holder = quirk_holder + if (!success || !istype(carbon_holder) || !istype(equipped, /obj/item/tank/internals)) + return + carbon_holder.internal = equipped diff --git a/tgstation.dme b/tgstation.dme index 4eee10ec5257d..660bd19830910 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6879,6 +6879,10 @@ #include "modular_doppler\modular_quirks\left_handed\left_handed.dm" #include "modular_doppler\modular_quirks\linguist\linguist.dm" #include "modular_doppler\modular_quirks\night_vision\night_vision.dm" +#include "modular_doppler\modular_quirks\nitrogen_breather\equipping.dm" +#include "modular_doppler\modular_quirks\nitrogen_breather\lungs.dm" +#include "modular_doppler\modular_quirks\nitrogen_breather\nitrogen_tanks.dm" +#include "modular_doppler\modular_quirks\nitrogen_breather\quirk.dm" #include "modular_doppler\modular_quirks\overwrites\musician.dm" #include "modular_doppler\modular_quirks\paycheck_rations\code\quirk.dm" #include "modular_doppler\modular_quirks\paycheck_rations\code\rationpacks.dm"