mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-24 05:30:05 +01:00
Adds a new INHALE reagent transfer method and applies it to smoking and smoke inhalation. Nitrous oxide (the reagent version) inhalation causes brain damage. (#87306)
## About The Pull Request Adds the ``INHALE`` transfer method. Smoking and smoke exposure now uses this method. Makes a few sensible inhalation effects for current behaviours. Adds a unit test amongst the rest of the exposure method tests. Nitrous oxide does brain damage on inhalation based on volume inhaled. ## Why It's Good For The Game Smoke and smoking being based on ingestion rather than inhaling was always weird to me. It'd be nice to have a specific method for smoking instead of a method shared by drinking. Many of our smokables make sense as indigestibles, obviously, but maybe we'd like a chem you can ONLY smoke. ~~Also, I walked out of a job interview and up the street to see a guy throwing his empty nitrous canisters around and yelling at passerbys, so shout out to that fucking guy with this PR.~~ ## Changelog 🆑 code: Introduces a INHALE method for reagent transfer. Cigarettes and smoke reactions use this new method. balance: Nitrous oxide now brain damage if you inhale it. So don't do that. /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
This commit is contained in:
co-authored by
SyncIt21
Ghom
parent
c148dde3c4
commit
f5099185c8
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
Reference in New Issue
Block a user