diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index 314d8f5ecf2..28172587e79 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -25,7 +25,7 @@ // Reagent exposure methods. /// Used for splashing. #define TOUCH (1<<0) -/// Used for ingesting the reagents. Food, drinks, inhaling smoke. +/// Used for ingesting the reagents. Food and drinks. #define INGEST (1<<1) /// Used by foams, sprays, and blob attacks. #define VAPOR (1<<2) @@ -35,6 +35,8 @@ #define INJECT (1<<4) /// Exclusive to just plumbing. if set we use the round robin technique else we use proportional #define LINEAR (1<<5) +/// Used by smoke or inhaling from a source. Smoke and cigarettes. +#define INHALE (1<<6) /// When returned by on_mob_life(), on_mob_dead(), overdose_start() or overdose_processed(), will cause the mob to updatehealth() afterwards #define UPDATE_MOB_HEALTH 1 diff --git a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm index e651c8a3e24..0bc59ded98d 100644 --- a/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/fluid_spread/effects_smoke.dm @@ -391,7 +391,7 @@ var/fraction = (seconds_per_tick SECONDS) / initial(lifetime) reagents.copy_to(smoker, reagents.total_volume, fraction) - reagents.expose(smoker, INGEST, fraction) + reagents.expose(smoker, INHALE, fraction) return TRUE /// Helper to quickly create a cloud of reagent smoke diff --git a/code/game/objects/items/cigarettes.dm b/code/game/objects/items/cigarettes.dm index 74f2ae417c8..aab4f59fce3 100644 --- a/code/game/objects/items/cigarettes.dm +++ b/code/game/objects/items/cigarettes.dm @@ -444,12 +444,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM return how_long_have_we_been_smokin += seconds_per_tick * (1 SECONDS) - reagents.expose(smoker, INGEST, min(to_smoke / reagents.total_volume, 1)) + reagents.expose(smoker, INHALE, min(to_smoke / reagents.total_volume, 1)) var/obj/item/organ/lungs/lungs = smoker.get_organ_slot(ORGAN_SLOT_LUNGS) if(lungs && IS_ORGANIC_ORGAN(lungs)) var/smoker_resistance = HAS_TRAIT(smoker, TRAIT_SMOKER) ? 0.5 : 1 smoker.adjustOrganLoss(ORGAN_SLOT_LUNGS, lung_harm * smoker_resistance) - if(!reagents.trans_to(smoker, to_smoke, methods = INGEST, ignore_stomach = TRUE)) + if(!reagents.trans_to(smoker, to_smoke, methods = INHALE, ignore_stomach = TRUE)) reagents.remove_all(to_smoke) /obj/item/cigarette/process(seconds_per_tick) @@ -992,7 +992,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM e.start(src) qdel(src) - if(!reagents.trans_to(vaper, REAGENTS_METABOLISM, methods = INGEST, ignore_stomach = TRUE)) + if(!reagents.trans_to(vaper, REAGENTS_METABOLISM, methods = INHALE, ignore_stomach = TRUE)) reagents.remove_all(REAGENTS_METABOLISM) /obj/item/vape/process(seconds_per_tick) diff --git a/code/game/objects/items/drug_items.dm b/code/game/objects/items/drug_items.dm index d25c9571455..7f31b155a26 100644 --- a/code/game/objects/items/drug_items.dm +++ b/code/game/objects/items/drug_items.dm @@ -44,6 +44,8 @@ reagent_flags = TRANSPARENT spillable = FALSE list_reagents = list(/datum/reagent/drug/blastoff = 10) + reagent_consumption_method = INHALE + consumption_sound = 'sound/effects/spray2.ogg' /obj/item/reagent_containers/cup/blastoff_ampoule/update_icon_state() . = ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index ff8406ac4ca..ca6096914fd 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -622,7 +622,7 @@ /** Handles exposing a mob to reagents. * - * If the methods include INGEST the mob tastes the reagents. + * If the methods include INGEST or INHALE, the mob tastes the reagents. * If the methods include VAPOR it incorporates permiability protection. */ /mob/living/expose_reagents(list/reagents, datum/reagents/source, methods=TOUCH, volume_modifier=1, show_message=TRUE) @@ -630,7 +630,7 @@ if(. & COMPONENT_NO_EXPOSE_REAGENTS) return - if(methods & INGEST) + if(methods & (INGEST | INHALE)) taste(source) var/touch_protection = (methods & VAPOR) ? getarmor(null, BIO) * 0.01 : 0 diff --git a/code/modules/reagents/chemistry/holder/holder.dm b/code/modules/reagents/chemistry/holder/holder.dm index 625d4e11807..09d0554691b 100644 --- a/code/modules/reagents/chemistry/holder/holder.dm +++ b/code/modules/reagents/chemistry/holder/holder.dm @@ -779,7 +779,7 @@ * * Arguments * - Atom/target: What mob/turf/object is being exposed to reagents? This is your reaction target. - * - Methods: What reaction type is the reagent itself going to call on the reaction target? Types are TOUCH, INGEST, VAPOR, PATCH, and INJECT. + * - Methods: What reaction type is the reagent itself going to call on the reaction target? Types are TOUCH, INGEST, VAPOR, PATCH, INJECT and INHALE. * - Volume_modifier: What is the reagent volume multiplied by when exposed? Note that this is called on the volume of EVERY reagent in the base body, so factor in your Maximum_Volume if necessary! * - Show_message: Whether to display anything to mobs when they are exposed. * - list/datum/reagent/r_to_expose: list of reagents to expose. if null will expose the reagents present in this holder instead diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index b0ee1e35ffa..f17dbf7fe9e 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -422,7 +422,7 @@ return var/mob/living/carbon/victim = exposed_mob - if(methods & (TOUCH|VAPOR)) + if(methods & (TOUCH|VAPOR|INHALE)) //check for protection //actually handle the pepperspray effects if (!victim.is_pepper_proof()) // you need both eye and mouth protection @@ -562,7 +562,7 @@ return var/mob/living/carbon/victim = exposed_mob - if(methods & (TOUCH | VAPOR)) + if(methods & (TOUCH | VAPOR | INHALE)) var/tear_proof = victim.is_eyes_covered() if (!tear_proof) to_chat(exposed_mob, span_warning("Your eyes sting!")) @@ -948,7 +948,7 @@ /datum/reagent/consumable/liquidelectricity/enriched/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume) //can't be on life because of the way blood works. . = ..() - if(!(methods & (INGEST|INJECT|PATCH)) || !iscarbon(exposed_mob)) + if(!(methods & (INGEST|INJECT|PATCH|INHALE)) || !iscarbon(exposed_mob)) return var/mob/living/carbon/exposed_carbon = exposed_mob diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index d0fe8be2135..87866b354e3 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -355,7 +355,7 @@ if(!iscarbon(exposed_mob) || (exposed_mob.stat == DEAD)) return - if(methods & (INGEST|VAPOR|INJECT)) + if(methods & (INGEST|VAPOR|INJECT|INHALE)) exposed_mob.adjust_nutrition(-5) if(show_message) to_chat(exposed_mob, span_warning("Your stomach feels empty and cramps!")) @@ -954,7 +954,7 @@ exposed_mob.visible_message(span_warning("[exposed_mob]'s body does not react...")) return - if(iscarbon(exposed_mob) && !(methods & INGEST)) //simplemobs can still be splashed + if(iscarbon(exposed_mob) && !(methods & (INGEST|INHALE))) //simplemobs can still be splashed return ..() if(HAS_TRAIT(exposed_mob, TRAIT_HUSK)) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 36492caacdc..68f5dca1e43 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -42,7 +42,7 @@ continue exposed_mob.ForceContractDisease(strain) - else if((methods & VAPOR) && (strain.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)) + else if((methods & (VAPOR|INHALE)) && (strain.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)) if(!strain.has_required_infectious_organ(exposed_mob, ORGAN_SLOT_LUNGS)) continue @@ -51,7 +51,7 @@ exposed_mob.ContactContractDisease(strain) if(data && data["resistances"]) - if(methods & (INGEST|INJECT)) //have to inject or ingest it. no curefoam/cheap curesprays + if(methods & (INGEST|INJECT|INHALE)) //have to inject, inhale or ingest it. no curefoam/cheap curesprays for(var/stuff in exposed_mob.diseases) var/datum/disease/infection = stuff if(infection.GetDiseaseID() in data["resistances"]) @@ -1452,7 +1452,7 @@ var/obj/item/organ/liver/liver = exposed_mob.get_organ_slot(ORGAN_SLOT_LIVER) if(liver && HAS_TRAIT(liver, TRAIT_HUMAN_AI_METABOLISM)) return - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) + if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new /datum/disease/transformation/robot(), FALSE, TRUE) /datum/reagent/xenomicrobes @@ -1464,7 +1464,7 @@ /datum/reagent/xenomicrobes/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) + if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new /datum/disease/transformation/xeno(), FALSE, TRUE) /datum/reagent/fungalspores @@ -1477,7 +1477,7 @@ /datum/reagent/fungalspores/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) + if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new /datum/disease/tuberculosis(), FALSE, TRUE) /datum/reagent/snail @@ -1490,7 +1490,7 @@ /datum/reagent/snail/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) + if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new /datum/disease/gastrolosis(), FALSE, TRUE) /datum/reagent/fluorosurfactant//foam precursor @@ -1586,10 +1586,13 @@ /datum/reagent/nitrous_oxide/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume) . = ..() - if(methods & VAPOR) + if(methods & (VAPOR|INHALE)) // apply 2 seconds of drowsiness per unit applied, with a min duration of 4 seconds var/drowsiness_to_apply = max(round(reac_volume, 1) * 2 SECONDS, 4 SECONDS) exposed_mob.adjust_drowsiness(drowsiness_to_apply) + if(methods & INHALE) + exposed_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.25 * reac_volume, required_organ_flag = affected_organ_flags) + exposed_mob.adjust_hallucinations(10 SECONDS * reac_volume) /datum/reagent/nitrous_oxide/on_mob_metabolize(mob/living/affected_mob) . = ..() @@ -2612,7 +2615,7 @@ /datum/reagent/gondola_mutation_toxin/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0) . = ..() - if((methods & (PATCH|INGEST|INJECT)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) + if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & VAPOR) && prob(min(reac_volume,100)*(1 - touch_protection)))) exposed_mob.ForceContractDisease(new gondola_disease, FALSE, TRUE) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 6160f9a4196..1c340cbc657 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -54,7 +54,7 @@ . = ..() if(!exposed_mob.can_mutate()) return //No robots, AIs, aliens, Ians or other mobs should be affected by this. - if(((methods & VAPOR) && prob(min(33, reac_volume))) || (methods & (INGEST|PATCH|INJECT))) + if(((methods & VAPOR) && prob(min(33, reac_volume))) || (methods & (INGEST|PATCH|INJECT|INHALE))) exposed_mob.random_mutate_unique_identity() exposed_mob.random_mutate_unique_features() if(prob(98)) @@ -258,7 +258,7 @@ /datum/reagent/toxin/zombiepowder/on_mob_metabolize(mob/living/holder_mob) . = ..() holder_mob.adjustOxyLoss(0.5*REM, FALSE, required_biotype = affected_biotype, required_respiration_type = affected_respiration_type) - if((data?["method"] & INGEST) && holder_mob.stat != DEAD) + if((data?["method"] & (INGEST|INHALE)) && holder_mob.stat != DEAD) holder_mob.fakedeath(type) /datum/reagent/toxin/zombiepowder/on_mob_end_metabolize(mob/living/affected_mob) @@ -268,10 +268,10 @@ /datum/reagent/toxin/zombiepowder/on_transfer(atom/target_atom, methods, trans_volume) . = ..() var/datum/reagent/zombiepowder = target_atom.reagents.has_reagent(/datum/reagent/toxin/zombiepowder) - if(!zombiepowder || !(methods & INGEST)) + if(!zombiepowder || !(methods & (INGEST|INHALE))) return LAZYINITLIST(zombiepowder.data) - zombiepowder.data["method"] |= INGEST + zombiepowder.data["method"] |= (INGEST|INHALE) /datum/reagent/toxin/zombiepowder/on_mob_life(mob/living/affected_mob, seconds_per_tick, times_fired) . = ..() @@ -1089,7 +1089,7 @@ if(liver && HAS_TRAIT(liver, TRAIT_HUMAN_AI_METABOLISM)) return reac_volume = round(reac_volume,0.1) - if(methods & INGEST) + if(methods & (INGEST|INHALE)) exposed_carbon.adjustBruteLoss(min(6*toxpwr, reac_volume * toxpwr), required_bodytype = affected_bodytype) return if(methods & INJECT) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 368d299fb40..b4493eb2ae4 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -19,6 +19,10 @@ var/gulp_size = 5 ///Whether the 'bottle' is made of glass or not so that milk cartons dont shatter when someone gets hit by it. var/isGlass = FALSE + ///What kind of chem transfer method does this cup use. Defaults to INGEST + var/reagent_consumption_method = INGEST + ///What sound does our consumption play on consuming from the container? + var/consumption_sound = 'sound/items/drink.ogg' /obj/item/reagent_containers/cup/examine(mob/user) . = ..() @@ -86,9 +90,9 @@ SEND_SIGNAL(src, COMSIG_GLASS_DRANK, target_mob, user) var/fraction = min(gulp_size/reagents.total_volume, 1) - reagents.trans_to(target_mob, gulp_size, transferred_by = user, methods = INGEST) + reagents.trans_to(target_mob, gulp_size, transferred_by = user, methods = reagent_consumption_method) checkLiked(fraction, target_mob) - playsound(target_mob.loc,'sound/items/drink.ogg', rand(10,50), TRUE) + playsound(target_mob.loc, consumption_sound, rand(10,50), TRUE) if(!iscarbon(target_mob)) return var/mob/living/carbon/carbon_drinker = target_mob diff --git a/code/modules/unit_tests/reagent_mob_expose.dm b/code/modules/unit_tests/reagent_mob_expose.dm index 844b863c037..d6ed81292a9 100644 --- a/code/modules/unit_tests/reagent_mob_expose.dm +++ b/code/modules/unit_tests/reagent_mob_expose.dm @@ -58,6 +58,13 @@ syringe.melee_attack_chain(human, human) TEST_ASSERT_EQUAL(human.health, 80, "Human health did not update after injection from syringe") + // INHALE + TEST_ASSERT_NULL(human.has_status_effect(/datum/status_effect/hallucination), "Human is drowsy at the start of testing") + drink.reagents.clear_reagents() + drink.reagents.add_reagent(/datum/reagent/nitrous_oxide, 10) + drink.reagents.trans_to(human, 10, methods = INHALE) + TEST_ASSERT_NOTNULL(human.has_status_effect(/datum/status_effect/hallucination), "Human is not drowsy after exposure to vapors") + /datum/unit_test/reagent_mob_expose/Destroy() SSmobs.ignite() return ..()