mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
Asthma quirk, inhalers - Electric Boogaloo (#92747)
## About The Pull Request Revival of https://github.com/tgstation/tgstation/pull/79691 A while back, I made this PR, but lost motivation after diving too deep into the code soup of can_breathe and related procs. Now, I have removed those parts, and have simplified that part of the code to the point I think it's ready for review. Many reviews from the previous PR have been addressed in this PR. <hr> <details> <summary>Details</summary> Asthma is a 4 point negative quirk that emulates real life asthma. It works by slowly decreasing the amount of pressure each breath you take receives, until your lungs completely seal, ensuring death if you dont get oxyloss meds/windpipe surgery. Inflammation (the tracker for intensity) increases whenever you breathe smoke, use a cigarette, metabolize histimine, or suffer an asthma attack. Asthma attacks have a low chance of happening every second, starting 10 minutes after you spawn and with a 20-30 grace period between attacks. They are "diseases" that cant be outright cured by albuterol, only put into remission. They increase inflammation at varying rates depending on their severity, with extreme asthma attacks being a immediate threat to your life while mild ones might not even cause inflammation. The response to these is always the same - use your inhaler before you start choking. Asthmatics start with a rescue inhaler, a low-capacity inhaler loaded with albuterol, which I will get to later. Albuterol is a new medicine thats a little tricky to make but still doable. It can be efficiently created with inverse convermol, or transmutated from salbutamol and convermol. The opposite is true, with albuterol able to be turned into salbutamol. Two canisters are available in chemvends. Upon use, it increases the virtual pressure of all breaths taken by 40%. This allows for you to breathe in lower pressure environments, as well as enhancing the effects of things like healium. It's OD causes your diaphram to spasm, causing sporadic losebreath and forced breathing. Inhalers are a fancy new reagent application apparatus that uses the INHALE reagent bitflag. Inhalers themselves are rather unremarkable, they are merely the method of using inhaler canisters (they also have a rotary display approximating the uses left in a canister - just like real life inhalers). Inhaler canisters are the reagent containers, and are generally low capacity. They can only be used in a inhaler, and contain aerosolized chemicals. Inhaler canisters and inhalers are unlocked from chemical synthesis, and are printable for cheap from a medlathe. In order to use a inhaler, one must uncover the mouth of a carbon and wait a few seconds (its faster if its a self-application) before a small amount of the reagents are delivered via the INHALE bitflag. This only works on things currently breathing - if theyre dead, have no lungs, or just, arent breathing - it will fail. This includes asthmatics with 100% inflammation. </details> <img width="181" height="74" alt="282863233-77a7cd6b-44d2-458e-9966-06d485df1521" src="https://github.com/user-attachments/assets/293b6659-0834-4e9a-b033-cc3b0cfde18e" /> <img width="1465" height="202" alt="282863346-2a247736-0c3a-43b0-a60b-7cff10ce4963" src="https://github.com/user-attachments/assets/5d9a13dc-b7b2-4de2-adda-8fbc8276e667" /> Sprites are not mine; they are from swanni and I can NOT sprite for the life of me ## Why It's Good For The Game 1. Asthma is just cool. One of my favorite features on bay was the fact lung damage required you to turn up the pressure on your O2 tank to survive, and this does precisely that. 2. Its always fun to add new ways to interact with atmos as a player that arent grossly broken, and I fail to see how a 40% increase of gas intake will really affect balance too badly. 3. Inhalers are badass. ## Changelog 🆑 add: Asthma quirk, based on IRL asthma add: Inhalers, a new reagent administering method that uses INHALE add: Albuterol, a new reagent that increases the amount of gas you inhale by 40% balance: Inverse convermol now forms once the reaction is done, not on metabolize /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> # Conflicts: # code/datums/quirks/negative_quirks/allergic.dm # code/game/objects/items/devices/scanners/health_analyzer.dm
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
#define ALERT_TOO_MUCH_NITRO "too_much_nitro"
|
||||
#define ALERT_NOT_ENOUGH_NITRO "not_enough_nitro"
|
||||
|
||||
#define ALERT_BRONCHODILATION "bronchodilation"
|
||||
|
||||
#define ALERT_NOT_ENOUGH_WATER "not_enough_water"
|
||||
|
||||
/** Mob related */
|
||||
|
||||
@@ -179,3 +179,6 @@
|
||||
|
||||
/// From /mob/living/carbon/proc/set_blood_type : (mob/living/carbon/user, datum/blood_type, update_cached_blood_dna_info)
|
||||
#define COMSIG_CARBON_CHANGED_BLOOD_TYPE "carbon_set_blood_type"
|
||||
|
||||
//from base of [/obj/effect/particle_effect/fluid/smoke/proc/smoke_mob]: (seconds_per_tick)
|
||||
#define COMSIG_CARBON_EXPOSED_TO_SMOKE "carbon_exposed_to_smoke"
|
||||
|
||||
@@ -18,6 +18,8 @@ DEFINE_BITFIELD(visibility_flags, list(
|
||||
#define CAN_CARRY (1<<1)
|
||||
#define CAN_RESIST (1<<2)
|
||||
#define CHRONIC (1<<3)
|
||||
/// Instead of instantly curing the disease, cures will simply reduce the stage
|
||||
#define INCREMENTAL_CURE (1<<4)
|
||||
|
||||
//Spread Flags
|
||||
#define DISEASE_SPREAD_SPECIAL (1<<0)
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#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.
|
||||
/// Used by smoke or inhaling from a source. Smoke, cigarettes, and inhalers.
|
||||
#define INHALE (1<<6)
|
||||
|
||||
///Smoke machines are both touch and inhaling
|
||||
|
||||
@@ -199,6 +199,16 @@
|
||||
|
||||
//End gas alerts
|
||||
|
||||
/atom/movable/screen/alert/bronchodilated
|
||||
name = "Bronchodilated"
|
||||
desc = "You feel like your lungs are larger than usual! You're taking deeper breaths!"
|
||||
icon_state = "bronchodilated"
|
||||
|
||||
/atom/movable/screen/alert/bronchoconstricted
|
||||
name = "Bronchocontracted"
|
||||
desc = "You feel like your lungs are smaller than usual! You might need a higher pressure environment/internals to breathe!"
|
||||
icon_state = "bronchoconstricted"
|
||||
|
||||
/atom/movable/screen/alert/gross
|
||||
name = "Grossed out."
|
||||
desc = "That was kind of gross..."
|
||||
|
||||
@@ -134,11 +134,13 @@
|
||||
update_stage(1)
|
||||
to_chat(affected_mob, span_notice("Your chronic illness is alleviated a little, though it can't be cured!"))
|
||||
return
|
||||
if(SPT_PROB(cure_mod, seconds_per_tick))
|
||||
update_stage(max(stage - 1, 1))
|
||||
if(disease_flags & CURABLE && SPT_PROB(cure_mod, seconds_per_tick))
|
||||
cure()
|
||||
return FALSE
|
||||
if(disease_flags & INCREMENTAL_CURE)
|
||||
if (!update_stage(stage - 1))
|
||||
return FALSE
|
||||
else
|
||||
cure()
|
||||
return FALSE
|
||||
|
||||
if(stage == max_stages && stage_peaked != TRUE) //mostly a sanity check in case we manually set a virus to max stages
|
||||
stage_peaked = TRUE
|
||||
@@ -257,6 +259,10 @@
|
||||
// BUBBER EDIT ADDITION END - DISEASE OUTBREAK UPDATES
|
||||
if(new_stage == max_stages && !(stage_peaked)) //once a virus has hit its peak, set it to have done so
|
||||
stage_peaked = TRUE
|
||||
if (stage <= 0)
|
||||
cure()
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/disease/proc/has_cure()
|
||||
if(!(disease_flags & (CURABLE | CHRONIC)))
|
||||
|
||||
262
code/datums/diseases/asthma_attack.dm
Normal file
262
code/datums/diseases/asthma_attack.dm
Normal file
@@ -0,0 +1,262 @@
|
||||
/datum/disease/asthma_attack
|
||||
form = "Bronchitis"
|
||||
name = "Asthma attack"
|
||||
desc = "Subject is undergoing a autoimmune response which threatens to close the esophagus and halt all respiration, leading to death. \
|
||||
Minor asthma attacks may disappear on their own, but all are dangerous."
|
||||
cure_text = "Albuterol/Surgical intervention"
|
||||
cures = list(/datum/reagent/medicine/albuterol)
|
||||
agent = "Inflammatory"
|
||||
viable_mobtypes = list(/mob/living/carbon/human)
|
||||
disease_flags = CURABLE
|
||||
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
|
||||
spread_text = "Inflammatory"
|
||||
visibility_flags = HIDDEN_PANDEMIC
|
||||
bypasses_immunity = TRUE
|
||||
disease_flags = CURABLE|INCREMENTAL_CURE
|
||||
required_organ = ORGAN_SLOT_LUNGS
|
||||
infectable_biotypes = MOB_ROBOTIC|MOB_ORGANIC|MOB_MINERAL|MOB_UNDEAD
|
||||
|
||||
/// The world.time after which we will begin remission.
|
||||
var/time_to_start_remission
|
||||
|
||||
/// The max time, after initial infection, it will take for us to begin remission
|
||||
var/max_time_til_remission
|
||||
/// The min time, after initial infection, it will take for us to begin remission
|
||||
var/min_time_til_remission
|
||||
|
||||
/// Are we in remission, where we stop progressing and instead slowly degrade in intensity until we remove ourselves?
|
||||
var/in_remission = FALSE
|
||||
|
||||
/// The current progress to stage demotion. Resets to 0 and reduces our stage by 1 when it exceeds [progress_needed_to_demote]. Only increases when in remission.
|
||||
var/progress_to_stage_demotion = 0
|
||||
/// The amount of demotion progress we receive per second while in remission.
|
||||
var/progress_to_demotion_per_second = 1
|
||||
/// Once [progress_to_stage_demotion] exceeds or meets this, we reduce our stage.
|
||||
var/progress_needed_to_demote = 10
|
||||
|
||||
/// Do we alert ghosts when we are applied?
|
||||
var/alert_ghosts = FALSE
|
||||
|
||||
/// A assoc list of (severity -> string), where string will be suffixed to our name in (suffix) format.
|
||||
var/static/list/severity_to_suffix = list(
|
||||
DISEASE_SEVERITY_MEDIUM = "Minor",
|
||||
DISEASE_SEVERITY_HARMFUL = "Moderate",
|
||||
DISEASE_SEVERITY_DANGEROUS = "Severe",
|
||||
DISEASE_SEVERITY_BIOHAZARD = "EXTREME",
|
||||
)
|
||||
/// A assoc list of (stringified number -> number), where the key is the stage and the number is how much inflammation we will cause the asthmatic per second.
|
||||
var/list/stage_to_inflammation_per_second
|
||||
|
||||
/datum/disease/asthma_attack/New()
|
||||
. = ..()
|
||||
|
||||
suffix_name()
|
||||
|
||||
time_to_start_remission = world.time + rand(min_time_til_remission, max_time_til_remission)
|
||||
|
||||
/datum/disease/asthma_attack/try_infect(mob/living/infectee, make_copy)
|
||||
if (!get_asthma_quirk())
|
||||
return FALSE
|
||||
if (HAS_TRAIT(infectee, TRAIT_NOBREATH))
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/// Adds our suffix via [severity_to_suffix] in the format of (suffix) to our name.
|
||||
/datum/disease/asthma_attack/proc/suffix_name()
|
||||
name += " ([severity_to_suffix[severity]])"
|
||||
|
||||
/// Returns the asthma quirk of our victim. As we can only be applied to asthmatics, this should never return null.
|
||||
/datum/disease/asthma_attack/proc/get_asthma_quirk(mob/living/target = affected_mob)
|
||||
RETURN_TYPE(/datum/quirk/item_quirk/asthma)
|
||||
|
||||
return (locate(/datum/quirk/item_quirk/asthma) in target.quirks)
|
||||
|
||||
/datum/disease/asthma_attack/stage_act(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return
|
||||
|
||||
if (HAS_TRAIT(affected_mob, TRAIT_NOBREATH))
|
||||
cure()
|
||||
return FALSE
|
||||
|
||||
var/datum/quirk/item_quirk/asthma/asthma_quirk = get_asthma_quirk()
|
||||
var/inflammation = stage_to_inflammation_per_second["[stage]"]
|
||||
if (inflammation)
|
||||
asthma_quirk.adjust_inflammation(inflammation * seconds_per_tick)
|
||||
|
||||
if (!(world.time >= time_to_start_remission))
|
||||
return
|
||||
|
||||
if (!in_remission)
|
||||
in_remission = TRUE
|
||||
stage_prob = 0
|
||||
name += " (Remission)"
|
||||
desc += " <i>The attack has entered remission. It will slowly decrease in intensity before vanishing.</i>"
|
||||
progress_to_stage_demotion += (progress_to_demotion_per_second * seconds_per_tick)
|
||||
if (progress_to_stage_demotion >= progress_needed_to_demote)
|
||||
progress_to_stage_demotion = 0
|
||||
update_stage(stage - 1)
|
||||
|
||||
// TYPES OF ASTHMA ATTACK
|
||||
|
||||
/datum/disease/asthma_attack/minor
|
||||
severity = DISEASE_SEVERITY_MEDIUM
|
||||
stage_prob = 4
|
||||
|
||||
max_time_til_remission = 120 SECONDS
|
||||
min_time_til_remission = 80 SECONDS
|
||||
max_stages = 3
|
||||
|
||||
cure_chance = 20
|
||||
|
||||
stage_to_inflammation_per_second = list(
|
||||
"2" = 0.3,
|
||||
"3" = 0.6,
|
||||
)
|
||||
|
||||
/datum/disease/asthma_attack/minor/stage_act(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
if (SPT_PROB(5, seconds_per_tick))
|
||||
to_chat(affected_mob, span_warning(pick("Mucous runs down the back of your throat.", "You swallow excess mucus.")))
|
||||
|
||||
/datum/disease/asthma_attack/moderate
|
||||
severity = DISEASE_SEVERITY_HARMFUL
|
||||
stage_prob = 5
|
||||
|
||||
max_time_til_remission = 120 SECONDS
|
||||
min_time_til_remission = 80 SECONDS
|
||||
max_stages = 4
|
||||
|
||||
cure_chance = 20
|
||||
|
||||
stage_to_inflammation_per_second = list(
|
||||
"2" = 1,
|
||||
"3" = 2,
|
||||
"4" = 4,
|
||||
)
|
||||
|
||||
/datum/disease/asthma_attack/moderate/stage_act(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
if (SPT_PROB(15, seconds_per_tick))
|
||||
to_chat(affected_mob, span_warning(pick("Mucous runs down the back of your throat.", "You swallow excess mucus.")))
|
||||
|
||||
if (stage < 4 || !SPT_PROB(10, seconds_per_tick))
|
||||
return
|
||||
to_chat(affected_mob, span_warning("You briefly choke on the mucus piling in your throat!"))
|
||||
affected_mob.losebreath++
|
||||
|
||||
|
||||
/datum/disease/asthma_attack/severe
|
||||
severity = DISEASE_SEVERITY_DANGEROUS
|
||||
stage_prob = 6
|
||||
|
||||
max_time_til_remission = 80 SECONDS
|
||||
min_time_til_remission = 60 SECONDS
|
||||
max_stages = 5
|
||||
|
||||
cure_chance = 20
|
||||
|
||||
stage_to_inflammation_per_second = list(
|
||||
"2" = 1,
|
||||
"3" = 3,
|
||||
"4" = 6,
|
||||
"5" = 8,
|
||||
)
|
||||
|
||||
visibility_flags = HIDDEN_SCANNER
|
||||
alert_ghosts = TRUE
|
||||
|
||||
/datum/disease/asthma_attack/severe/stage_act(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
if (stage > 1)
|
||||
visibility_flags &= ~HIDDEN_SCANNER // revealed
|
||||
|
||||
if (SPT_PROB(15, seconds_per_tick))
|
||||
to_chat(affected_mob, span_warning(pick("Mucous runs down the back of your throat.", "You swallow excess mucus.")))
|
||||
else if (SPT_PROB(20, seconds_per_tick))
|
||||
affected_mob.emote("cough")
|
||||
|
||||
if (stage < 4 || !SPT_PROB(15, seconds_per_tick))
|
||||
return
|
||||
to_chat(affected_mob, span_warning("You briefly choke on the mucus piling in your throat!"))
|
||||
affected_mob.losebreath++
|
||||
|
||||
/datum/disease/asthma_attack/critical
|
||||
severity = DISEASE_SEVERITY_BIOHAZARD
|
||||
stage_prob = 85
|
||||
|
||||
max_time_til_remission = 60 SECONDS // this kills you extremely quickly, so its fair
|
||||
min_time_til_remission = 40 SECONDS
|
||||
max_stages = 6
|
||||
|
||||
cure_chance = 30
|
||||
|
||||
stage_to_inflammation_per_second = list(
|
||||
"1" = 5,
|
||||
"2" = 6,
|
||||
"3" = 7,
|
||||
"4" = 10,
|
||||
"5" = 20,
|
||||
"6" = 500, // youre fucked frankly
|
||||
)
|
||||
|
||||
/// Have we warned our user of the fact they are at stage 5? If no, and are at or above stage five, we send a warning and set this to true.
|
||||
var/warned_user = FALSE
|
||||
/// Have we ever reached our max stage? If no, and we are at our max stage, we send a ominous message warning them of their imminent demise.
|
||||
var/max_stage_reached = FALSE
|
||||
|
||||
/datum/disease/asthma_attack/critical/stage_act(seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
if (stage < 5)
|
||||
if (SPT_PROB(75, seconds_per_tick))
|
||||
to_chat(affected_mob, span_warning(pick("Mucous runs down the back of your throat.", "You swallow excess mucus.")))
|
||||
|
||||
var/wheeze_chance
|
||||
if (!warned_user && stage >= 5)
|
||||
to_chat(affected_mob, span_userdanger("You feel like your lungs are filling with fluid! It's getting incredibly hard to breathe!"))
|
||||
warned_user = TRUE
|
||||
|
||||
switch (stage)
|
||||
if (1)
|
||||
wheeze_chance = 0
|
||||
if (2)
|
||||
wheeze_chance = 20
|
||||
if (3)
|
||||
wheeze_chance = 40
|
||||
if (4)
|
||||
wheeze_chance = 60
|
||||
if (5)
|
||||
wheeze_chance = 80
|
||||
if (!in_remission)
|
||||
stage_prob = 10 // slow it down significantly
|
||||
if (6)
|
||||
if (!max_stage_reached)
|
||||
max_stage_reached = TRUE
|
||||
to_chat(affected_mob, span_userdanger("You feel your windpipe squeeze shut!"))
|
||||
wheeze_chance = 0
|
||||
if (SPT_PROB(10, seconds_per_tick))
|
||||
affected_mob.emote("gag")
|
||||
var/datum/quirk/item_quirk/asthma/asthma_quirk = get_asthma_quirk()
|
||||
asthma_quirk.adjust_inflammation(INFINITY)
|
||||
|
||||
if (SPT_PROB(wheeze_chance, seconds_per_tick))
|
||||
affected_mob.emote("wheeze")
|
||||
|
||||
if (stage < 4 || !SPT_PROB(15, seconds_per_tick))
|
||||
return
|
||||
to_chat(affected_mob, span_warning("You briefly choke on the mucus piling in your throat!"))
|
||||
affected_mob.losebreath++
|
||||
@@ -22,6 +22,7 @@
|
||||
/datum/reagent/medicine/diphenhydramine,
|
||||
/datum/reagent/medicine/sansufentanyl,
|
||||
/datum/reagent/medicine/salglu_solution,
|
||||
/datum/reagent/medicine/albuterol,
|
||||
/datum/reagent/medicine/coagulant //Bubber edit: adds coagulant
|
||||
)
|
||||
var/allergy_string
|
||||
|
||||
249
code/datums/quirks/negative_quirks/asthma.dm
Normal file
249
code/datums/quirks/negative_quirks/asthma.dm
Normal file
@@ -0,0 +1,249 @@
|
||||
/datum/quirk/item_quirk/asthma
|
||||
name = "Asthma"
|
||||
desc = "You suffer from asthma, a inflammatory disorder that causes your airpipe to squeeze shut! Be careful around smoke!"
|
||||
icon = FA_ICON_LUNGS_VIRUS
|
||||
value = -4 // trivialized by NOBREATH but still quite dangerous
|
||||
gain_text = span_danger("You have a harder time breathing.")
|
||||
lose_text = span_notice("You suddenly feel like your lungs just got a lot better at breathing!")
|
||||
medical_record_text = "Patient suffers from asthma."
|
||||
hardcore_value = 2
|
||||
quirk_flags = QUIRK_HUMAN_ONLY
|
||||
mail_goodies = list(/obj/item/reagent_containers/inhaler_canister/albuterol)
|
||||
|
||||
/// At this percentage of inflammation, our lung pressure mult reaches 0. From 0-1.
|
||||
var/hit_max_mult_at_inflammation_percent = 0.9
|
||||
|
||||
/// Current inflammation of the lungs.
|
||||
var/inflammation = 0
|
||||
/// Highest possible inflammation. Interacts with [hit_max_mult_at_inflammation_percent]
|
||||
var/max_inflammation = 500
|
||||
|
||||
/// The amount [inflammation] reduces every second while our owner is off stasis and alive.
|
||||
var/passive_inflammation_reduction = 0.15
|
||||
|
||||
/// The amount of inflammation we will receive when our owner breathes smoke.
|
||||
var/inflammation_on_smoke = 7.5
|
||||
|
||||
/// If our owner is metabolizing histamine, inflammation will increase by this per tick.
|
||||
var/histamine_inflammation = 2
|
||||
/// If our owner is ODing on histamine, inflammation will increase by this per tick.
|
||||
var/histamine_OD_inflammation = 10 // allergic reactions tend to fuck people up
|
||||
|
||||
/// A tracker variable for how much albuterol has been inhaled.
|
||||
var/inhaled_albuterol = 0
|
||||
/// If [inhaled_albuterol] is above 0, we will reduce inflammation by this much per tick.
|
||||
var/albuterol_inflammation_reduction = 3
|
||||
/// When albuterol is inhaled, inflammation will be reduced via (inhaled_albuterol * albuterol_inflammation_reduction * albuterol_immediate_reduction_mult)
|
||||
var/albuterol_immediate_reduction_mult = 4
|
||||
|
||||
/// The current asthma attack trying to kill our owner.
|
||||
var/datum/disease/asthma_attack/current_attack
|
||||
/// Can we cause an asthma attack?
|
||||
COOLDOWN_DECLARE(next_attack_cooldown)
|
||||
|
||||
/// world.time + this is the time the first attack can happen. Used on spawn.
|
||||
var/time_first_attack_can_happen = 10 MINUTES
|
||||
|
||||
/// After an attack ends, this is the minimum time we must wait before we attack again.
|
||||
var/min_time_between_attacks = 15 MINUTES
|
||||
/// After an attack ends, this is the maximum time we must wait before we attack again.
|
||||
var/max_time_between_attacks = 25 MINUTES
|
||||
|
||||
/// Every second, an asthma attack can happen via this probability. 0-1.
|
||||
var/chance_for_attack_to_happen_per_second = 0.05
|
||||
|
||||
/// Assoc list of (/datum/disease/asthma_attack typepath -> number). Used in pickweight for when we pick a random asthma attack to apply.
|
||||
var/static/list/asthma_attack_rarities = list(
|
||||
/datum/disease/asthma_attack/minor = 300,
|
||||
/datum/disease/asthma_attack/moderate = 400,
|
||||
/datum/disease/asthma_attack/severe = 100,
|
||||
/datum/disease/asthma_attack/critical = 1, // this can quickly kill you, so its rarity is justified
|
||||
)
|
||||
|
||||
/datum/quirk/item_quirk/asthma/add_unique(client/client_source)
|
||||
. = ..()
|
||||
|
||||
var/obj/item/inhaler/albuterol/asthma/rescue_inhaler = new(get_turf(quirk_holder))
|
||||
give_item_to_holder(rescue_inhaler, list(LOCATION_BACKPACK, LOCATION_HANDS), flavour_text = "You can use this to quickly relieve the symptoms of your asthma.")
|
||||
|
||||
RegisterSignal(quirk_holder, COMSIG_CARBON_EXPOSED_TO_SMOKE, PROC_REF(holder_exposed_to_smoke))
|
||||
RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(organ_removed))
|
||||
RegisterSignal(quirk_holder, COMSIG_ATOM_EXPOSE_REAGENTS, PROC_REF(exposed_to_reagents))
|
||||
RegisterSignal(quirk_holder, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(on_full_heal))
|
||||
RegisterSignal(quirk_holder, COMSIG_LIVING_LIFE, PROC_REF(on_life))
|
||||
|
||||
COOLDOWN_START(src, next_attack_cooldown, time_first_attack_can_happen)
|
||||
|
||||
/datum/quirk/item_quirk/asthma/remove()
|
||||
. = ..()
|
||||
|
||||
current_attack?.cure()
|
||||
UnregisterSignal(quirk_holder, COMSIG_CARBON_EXPOSED_TO_SMOKE, COMSIG_CARBON_LOSE_ORGAN, COMSIG_ATOM_EXPOSE_REAGENTS, COMSIG_LIVING_POST_FULLY_HEAL, COMSIG_LIVING_LIFE)
|
||||
|
||||
/datum/quirk/item_quirk/asthma/proc/on_life(mob/living/source, seconds_per_tick, times_fired)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (quirk_holder.stat == DEAD)
|
||||
return
|
||||
|
||||
if (HAS_TRAIT(quirk_holder, TRAIT_STASIS) || HAS_TRAIT(quirk_holder, TRAIT_NO_TRANSFORM))
|
||||
return
|
||||
|
||||
var/obj/item/organ/lungs/holder_lungs = quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
if (isnull(holder_lungs))
|
||||
return
|
||||
|
||||
adjust_inflammation(-passive_inflammation_reduction * seconds_per_tick)
|
||||
|
||||
var/datum/reagent/toxin/histamine/holder_histamine = quirk_holder.reagents.has_reagent(/datum/reagent/toxin/histamine)
|
||||
if (holder_histamine)
|
||||
if (holder_histamine.overdosed) // uh oh!
|
||||
if (SPT_PROB(15, seconds_per_tick))
|
||||
to_chat(quirk_holder, span_boldwarning("You feel your neck swelling, squeezing on your windpipe more and more!"))
|
||||
adjust_inflammation(histamine_OD_inflammation * seconds_per_tick)
|
||||
else
|
||||
if (SPT_PROB(5, seconds_per_tick))
|
||||
to_chat(quirk_holder, span_warning("You find yourself wheezing a little harder as your neck swells..."))
|
||||
adjust_inflammation(histamine_inflammation * seconds_per_tick)
|
||||
|
||||
var/datum/reagent/medicine/albuterol/albuterol = quirk_holder.reagents.has_reagent(/datum/reagent/medicine/albuterol)
|
||||
if (!albuterol) // sanity - couldve been purged. can be 0 or null which is why we just use a !
|
||||
inhaled_albuterol = 0
|
||||
else
|
||||
inhaled_albuterol = min(albuterol.volume, inhaled_albuterol)
|
||||
|
||||
if (inhaled_albuterol > 0)
|
||||
adjust_inflammation(-(albuterol_inflammation_reduction * seconds_per_tick))
|
||||
|
||||
// asthma attacks dont happen if theres no client, because they can just kill you and some need immediate response
|
||||
else if (quirk_holder.client && isnull(current_attack) && COOLDOWN_FINISHED(src, next_attack_cooldown) && SPT_PROB(chance_for_attack_to_happen_per_second, seconds_per_tick))
|
||||
do_asthma_attack()
|
||||
|
||||
/// Causes an asthma attack via infecting our owner with the attack disease. Notifies ghosts.
|
||||
/datum/quirk/item_quirk/asthma/proc/do_asthma_attack()
|
||||
var/datum/disease/asthma_attack/typepath = pick_weight(asthma_attack_rarities)
|
||||
|
||||
current_attack = new typepath
|
||||
current_attack.infect(quirk_holder, make_copy = FALSE) // dont leave make_copy on TRUE. worst mistake ive ever made
|
||||
RegisterSignal(current_attack, COMSIG_QDELETING, PROC_REF(attack_deleting))
|
||||
|
||||
if (current_attack.alert_ghosts)
|
||||
notify_ghosts("[quirk_holder] is having an asthma attack: [current_attack.name]!", source = quirk_holder, notify_flags = NOTIFY_CATEGORY_NOFLASH, header = "Asthma attack!")
|
||||
|
||||
/// Setter proc for [inflammation]. Adjusts the amount by lung health, adjusts pressure mult, gives feedback messages if silent is FALSE.
|
||||
/datum/quirk/item_quirk/asthma/proc/adjust_inflammation(amount, silent = FALSE)
|
||||
var/old_inflammation = inflammation
|
||||
|
||||
var/obj/item/organ/lungs/holder_lungs = quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
var/health_mult = get_lung_health_mult(holder_lungs)
|
||||
if (amount > 0) // make it worse
|
||||
amount *= (2 - health_mult)
|
||||
else // reduce the reduction
|
||||
amount *= health_mult
|
||||
|
||||
var/old_pressure_mult = get_pressure_mult()
|
||||
inflammation = (clamp(inflammation + amount, 0, max_inflammation))
|
||||
var/difference = (old_inflammation - inflammation)
|
||||
if (difference != 0)
|
||||
var/new_pressure_mult = get_pressure_mult()
|
||||
var/pressure_difference = new_pressure_mult - old_pressure_mult
|
||||
|
||||
holder_lungs?.adjust_received_pressure_mult(pressure_difference)
|
||||
|
||||
if (!silent)
|
||||
INVOKE_ASYNC(src, PROC_REF(do_inflammation_change_feedback), difference)
|
||||
|
||||
/// Setter proc for [inhaled_albuterol]. Adjusts inflammation immediately.
|
||||
/datum/quirk/item_quirk/asthma/proc/adjust_albuterol_levels(adjustment)
|
||||
if (adjustment > 0)
|
||||
var/obj/item/organ/lungs/holder_lungs = quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
|
||||
if (isnull(holder_lungs) || holder_lungs.received_pressure_mult <= 0) // it didnt go into the lungs get fucked
|
||||
return
|
||||
|
||||
adjust_inflammation(-(albuterol_inflammation_reduction * albuterol_immediate_reduction_mult))
|
||||
|
||||
inhaled_albuterol += adjustment
|
||||
|
||||
/// Returns the pressure mult to be applied to our lungs.
|
||||
/datum/quirk/item_quirk/asthma/proc/get_pressure_mult()
|
||||
var/virtual_max = (max_inflammation * hit_max_mult_at_inflammation_percent)
|
||||
|
||||
return (1 - (min(inflammation/virtual_max, 1)))
|
||||
|
||||
/// Sends feedback to our owner of which direction our asthma is intensifying/recovering.
|
||||
/datum/quirk/item_quirk/asthma/proc/do_inflammation_change_feedback(difference)
|
||||
var/change_mult = 1 + (difference / 300) // 300 is arbitrary
|
||||
if (difference > 0) // it decreased
|
||||
if (prob(1 * change_mult))
|
||||
// in my experience with asthma an inhaler causes a bunch of mucous and you tend to cough it up
|
||||
to_chat(quirk_holder, span_notice("The phlem in your throat forces you to cough!"))
|
||||
quirk_holder.emote("cough")
|
||||
|
||||
else if (difference < 0)// it increased
|
||||
if (prob(1 * change_mult))
|
||||
quirk_holder.emote("wheeze")
|
||||
if (prob(5 * change_mult))
|
||||
to_chat(quirk_holder, span_warning("You feel your windpipe tightening..."))
|
||||
|
||||
/// Returns the % of health our lungs have, from 1-0. Used in reducing recovery and intensifying inflammation.
|
||||
/datum/quirk/item_quirk/asthma/proc/get_lung_health_mult()
|
||||
var/mob/living/carbon/carbon_quirk_holder = quirk_holder
|
||||
var/obj/item/organ/lungs/holder_lungs = carbon_quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
if (isnull(holder_lungs))
|
||||
return 1
|
||||
if (holder_lungs.organ_flags & ORGAN_FAILING)
|
||||
return 0
|
||||
return (1 - (holder_lungs.damage / holder_lungs.maxHealth))
|
||||
|
||||
/// Signal proc for when we are exposed to smoke. Increases inflammation.
|
||||
/datum/quirk/item_quirk/asthma/proc/holder_exposed_to_smoke(datum/signal_source, seconds_per_tick)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
adjust_inflammation(inflammation_on_smoke * seconds_per_tick)
|
||||
|
||||
/// Signal proc for when our lungs are removed. Resets all our variables.
|
||||
/datum/quirk/item_quirk/asthma/proc/organ_removed(datum/signal_source, obj/item/organ/removed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (istype(removed, /obj/item/organ/lungs))
|
||||
reset_asthma()
|
||||
|
||||
/// Signal proc for when our owner receives reagents. If we receive albuterol via inhalation, we adjust inhaled albuterol by that amount. If we are smoking, we increase inflammation.
|
||||
/datum/quirk/item_quirk/asthma/proc/exposed_to_reagents(atom/source, list/reagents, datum/reagents/source_reagents, methods, show_message)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/final_total = 0
|
||||
|
||||
for (var/datum/reagent/reagent as anything in reagents)
|
||||
var/amount = reagents[reagent]
|
||||
if (istype(reagent, /datum/reagent/medicine/albuterol))
|
||||
adjust_albuterol_levels(amount)
|
||||
final_total += amount
|
||||
|
||||
if (!(methods & INHALE))
|
||||
return
|
||||
if (istype(source_reagents.my_atom, /obj/item/cigarette)) // smoking is bad, kids
|
||||
adjust_inflammation(inflammation_on_smoke * final_total * 5)
|
||||
|
||||
/// Signal proc for when our asthma attack qdels. Unsets our refs to it and resets [next_attack_cooldown].
|
||||
/datum/quirk/item_quirk/asthma/proc/attack_deleting(datum/signal_source)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(current_attack, COMSIG_QDELETING)
|
||||
current_attack = null
|
||||
|
||||
COOLDOWN_START(src, next_attack_cooldown, rand(min_time_between_attacks, max_time_between_attacks))
|
||||
|
||||
/// Signal handler for COMSIG_LIVING_POST_FULLY_HEAL. Heals our asthma.
|
||||
/datum/quirk/item_quirk/asthma/proc/on_full_heal(datum/signal_source, heal_flags)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (heal_flags & HEAL_ORGANS)
|
||||
reset_asthma()
|
||||
|
||||
/// Resets our asthma to normal. No inflammation, no pressure mult.
|
||||
/datum/quirk/item_quirk/asthma/proc/reset_asthma()
|
||||
inflammation = 0
|
||||
var/obj/item/organ/lungs/holder_lungs = quirk_holder.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
holder_lungs?.set_received_pressure_mult(holder_lungs::received_pressure_mult)
|
||||
@@ -124,6 +124,7 @@
|
||||
|
||||
smoker.smoke_delay = TRUE
|
||||
addtimer(VARSET_CALLBACK(smoker, smoke_delay, FALSE), 1 SECONDS)
|
||||
SEND_SIGNAL(smoker, COMSIG_CARBON_EXPOSED_TO_SMOKE, seconds_per_tick)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
|
||||
@@ -432,6 +432,30 @@
|
||||
Possible Cure: [disease.cure_text]</div>\
|
||||
</span>"
|
||||
|
||||
|
||||
// Lungs
|
||||
var/obj/item/organ/lungs/lungs = target.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
if (lungs)
|
||||
var/initial_pressure_mult = lungs::received_pressure_mult
|
||||
if (lungs.received_pressure_mult != initial_pressure_mult)
|
||||
var/tooltip
|
||||
var/dilation_text
|
||||
var/beginning_text = "Lung Dilation: "
|
||||
if (lungs.received_pressure_mult > initial_pressure_mult) // higher than usual
|
||||
beginning_text = span_blue("<b>[beginning_text]</b>")
|
||||
dilation_text = span_blue("[(lungs.received_pressure_mult * 100) - 100]%")
|
||||
tooltip = "Subject's lungs are dilated and breathing more air than usual. Increases the effectiveness of healium and other gases."
|
||||
else
|
||||
beginning_text = span_danger("<b>[beginning_text]</b>")
|
||||
if (lungs.received_pressure_mult <= 0) // lethal
|
||||
dilation_text = span_bolddanger("[lungs.received_pressure_mult * 100]%")
|
||||
tooltip = "Subject's lungs are completely shut. Subject is unable to breathe and requires emergency surgery. If asthmatic, perform asthmatic bypass surgery and adminster albuterol inhalant. Otherwise, replace lungs."
|
||||
else
|
||||
dilation_text = span_danger("[lungs.received_pressure_mult * 100]%")
|
||||
tooltip = "Subject's lungs are partially shut. If unable to breathe, administer a high-pressure internals tank or replace lungs. If asthmatic, inhaled albuterol or bypass surgery will likely help."
|
||||
|
||||
var/lung_message = beginning_text + conditional_tooltip(dilation_text, tooltip, TRUE)
|
||||
render_list += lung_message
|
||||
// SKYRAT EDIT ADDITION - Mutant stuff and DEATH CONSEQUENCES
|
||||
if(target.GetComponent(/datum/component/mutant_infection))
|
||||
render_list += span_userdanger("UNKNOWN PROTO-VIRAL INFECTION DETECTED. ISOLATE IMMEDIATELY.")
|
||||
|
||||
@@ -385,6 +385,11 @@
|
||||
return
|
||||
return user.dna.species.get_cough_sound(user)
|
||||
|
||||
/datum/emote/living/wheeze
|
||||
key = "wheeze"
|
||||
key_third_person = "wheezes"
|
||||
message = "wheezes!"
|
||||
emote_type = EMOTE_AUDIBLE
|
||||
|
||||
/datum/emote/living/pout
|
||||
key = "pout"
|
||||
|
||||
@@ -566,6 +566,87 @@
|
||||
if(need_mob_update)
|
||||
return UPDATE_MOB_HEALTH
|
||||
|
||||
/datum/reagent/medicine/albuterol
|
||||
name = "Albuterol"
|
||||
description = "A potent bronchodilator capable of increasing the amount of gas inhaled by the lungs. Is highly effective at shutting down asthma attacks, \
|
||||
but only when inhaled. Overdose causes over-dilation, resulting in reduced lung function. "
|
||||
taste_description = "bitter and salty air"
|
||||
overdose_threshold = 30
|
||||
color = "#8df5f0"
|
||||
metabolization_rate = REAGENTS_METABOLISM
|
||||
ph = 4
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
|
||||
default_container = /obj/item/reagent_containers/inhaler_canister
|
||||
|
||||
/// The decrement we will apply to the received_pressure_mult of our targets lungs.
|
||||
var/pressure_mult_increment = 0.4
|
||||
/// After this many cycles of overdose, we activate secondary effects.
|
||||
var/secondary_overdose_effect_cycle_threshold = 40
|
||||
/// We stop increasing stamina damage once we reach this number.
|
||||
var/maximum_od_stamina_damage = 80
|
||||
|
||||
/datum/reagent/medicine/albuterol/on_mob_metabolize(mob/living/affected_mob)
|
||||
. = ..()
|
||||
|
||||
if (!iscarbon(affected_mob))
|
||||
return
|
||||
|
||||
// has additional effects on asthma, but that's handled in the quirk
|
||||
|
||||
RegisterSignal(affected_mob, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(holder_lost_organ))
|
||||
RegisterSignal(affected_mob, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(holder_gained_organ))
|
||||
var/mob/living/carbon/carbon_mob = affected_mob
|
||||
var/obj/item/organ/lungs/holder_lungs = carbon_mob.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
holder_lungs?.adjust_received_pressure_mult(pressure_mult_increment)
|
||||
|
||||
/datum/reagent/medicine/albuterol/on_mob_end_metabolize(mob/living/affected_mob)
|
||||
. = ..()
|
||||
|
||||
if (!iscarbon(affected_mob))
|
||||
return
|
||||
|
||||
UnregisterSignal(affected_mob, list(COMSIG_CARBON_LOSE_ORGAN, COMSIG_CARBON_GAIN_ORGAN))
|
||||
var/mob/living/carbon/carbon_mob = affected_mob
|
||||
var/obj/item/organ/lungs/holder_lungs = carbon_mob.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
holder_lungs?.adjust_received_pressure_mult(-pressure_mult_increment)
|
||||
|
||||
/datum/reagent/medicine/albuterol/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired)
|
||||
. = ..()
|
||||
|
||||
if (!iscarbon(affected_mob))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/carbon_mob = affected_mob
|
||||
if (SPT_PROB(25, seconds_per_tick))
|
||||
carbon_mob.adjust_jitter_up_to(2 SECONDS, 20 SECONDS)
|
||||
if (SPT_PROB(35, seconds_per_tick))
|
||||
if (prob(60))
|
||||
carbon_mob.losebreath += 1
|
||||
to_chat(affected_mob, span_danger("Your diaphram spasms and you find yourself unable to breathe!"))
|
||||
else
|
||||
carbon_mob.breathe(seconds_per_tick, times_fired)
|
||||
to_chat(affected_mob, span_danger("Your diaphram spasms and you unintentionally take a breath!"))
|
||||
|
||||
if (current_cycle > secondary_overdose_effect_cycle_threshold)
|
||||
if (SPT_PROB(30, seconds_per_tick))
|
||||
carbon_mob.adjust_eye_blur_up_to(6 SECONDS, 30 SECONDS)
|
||||
if (carbon_mob.getStaminaLoss() < maximum_od_stamina_damage)
|
||||
carbon_mob.adjustStaminaLoss(seconds_per_tick)
|
||||
|
||||
/datum/reagent/medicine/albuterol/proc/holder_lost_organ(datum/source, obj/item/organ/lost)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (istype(lost, /obj/item/organ/lungs))
|
||||
var/obj/item/organ/lungs/holder_lungs = lost
|
||||
holder_lungs.adjust_received_pressure_mult(-pressure_mult_increment)
|
||||
|
||||
/datum/reagent/medicine/albuterol/proc/holder_gained_organ(datum/source, obj/item/organ/gained)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (istype(gained, /obj/item/organ/lungs))
|
||||
var/obj/item/organ/lungs/holder_lungs = gained
|
||||
holder_lungs.adjust_received_pressure_mult(pressure_mult_increment)
|
||||
|
||||
/datum/reagent/medicine/ephedrine
|
||||
name = "Ephedrine"
|
||||
description = "Increases resistance to batons and movement speed, giving you hand cramps. Overdose deals toxin damage and inhibits breathing."
|
||||
|
||||
@@ -179,7 +179,7 @@
|
||||
H_ion_release = -1
|
||||
rate_up_lim = 50
|
||||
purity_min = 0.25
|
||||
reaction_flags = REACTION_PH_VOL_CONSTANT
|
||||
reaction_flags = REACTION_PH_VOL_CONSTANT|REACTION_CLEAR_INVERSE
|
||||
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OXY
|
||||
|
||||
/datum/chemical_reaction/medicine/convermol/reaction_step(datum/reagents/holder, datum/equilibrium/reaction, delta_t, delta_ph, step_reaction_vol)
|
||||
|
||||
@@ -157,6 +157,51 @@
|
||||
required_reagents = list(/datum/reagent/medicine/sal_acid = 1, /datum/reagent/lithium = 1, /datum/reagent/aluminium = 1, /datum/reagent/bromine = 1, /datum/reagent/ammonia = 1)
|
||||
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_HEALING | REACTION_TAG_OXY
|
||||
|
||||
/datum/chemical_reaction/medicine/albuterol_creation
|
||||
results = list(/datum/reagent/medicine/albuterol = 15)
|
||||
required_reagents = list(/datum/reagent/lithium = 3, /datum/reagent/aluminium = 3, /datum/reagent/bromine = 3, /datum/reagent/inverse/healing/convermol = 1)
|
||||
reaction_tags = REACTION_TAG_MODERATE | REACTION_TAG_ORGAN | REACTION_TAG_OTHER
|
||||
required_temp = 400
|
||||
optimal_temp = 600
|
||||
overheat_temp = 900
|
||||
|
||||
/datum/chemical_reaction/medicine/salbutamol_to_albuterol
|
||||
results = list(/datum/reagent/medicine/albuterol = 4, /datum/reagent/medicine/sal_acid = 0.5, /datum/reagent/ammonia = 0.5)
|
||||
required_catalysts = list(/datum/reagent/toxin/acid = 1)
|
||||
required_reagents = list(/datum/reagent/medicine/salbutamol = 5, /datum/reagent/medicine/c2/convermol = 1)
|
||||
reaction_tags = REACTION_TAG_MODERATE | REACTION_TAG_ORGAN | REACTION_TAG_OTHER
|
||||
required_temp = 500
|
||||
optimal_temp = 610
|
||||
overheat_temp = 980
|
||||
thermic_constant = 75
|
||||
rate_up_lim = 10
|
||||
mix_message = "The solution rapidly changes colors, boiling into a pale blue."
|
||||
|
||||
/datum/chemical_reaction/medicine/albuterol_to_salbutamol
|
||||
results = list(/datum/reagent/medicine/salbutamol = 2, /datum/reagent/ammonia = 1)
|
||||
required_catalysts = list(/datum/reagent/toxin/acid = 1)
|
||||
required_reagents = list(/datum/reagent/medicine/albuterol = 3, /datum/reagent/oxygen = 1)
|
||||
reaction_tags = REACTION_TAG_EASY | REACTION_TAG_ORGAN | REACTION_TAG_OTHER
|
||||
required_temp = 300
|
||||
optimal_temp = 500
|
||||
overheat_temp = 800
|
||||
mix_message = "The solution breaks apart, turning a deeper blue."
|
||||
|
||||
/datum/chemical_reaction/medicine/albuterol_to_inverse_convermol
|
||||
results = list(/datum/reagent/inverse/healing/convermol = 1, /datum/reagent/lithium = 3, /datum/reagent/aluminium = 3, /datum/reagent/bromine = 3)
|
||||
required_catalysts = list(/datum/reagent/toxin/acid/fluacid = 1)
|
||||
required_reagents = list(/datum/reagent/medicine/albuterol = 5)
|
||||
reaction_tags = REACTION_TAG_MODERATE | REACTION_TAG_ORGAN | REACTION_TAG_OTHER
|
||||
required_temp = 900
|
||||
optimal_temp = 920
|
||||
overheat_temp = 990
|
||||
thermic_constant = 25
|
||||
mix_message = "The solution rapidly breaks apart, turning a mix of colors."
|
||||
|
||||
/datum/chemical_reaction/medicine/albuterol_to_inverse_convermol/overheated(datum/reagents/holder, datum/equilibrium/equilibrium, impure = FALSE)
|
||||
var/bonus = impure ? 2 : 1
|
||||
explode_smoke(holder, equilibrium, 7.5 * bonus, TRUE, TRUE)
|
||||
|
||||
/datum/chemical_reaction/medicine/ephedrine
|
||||
results = list(/datum/reagent/medicine/ephedrine = 4)
|
||||
required_reagents = list(/datum/reagent/consumable/sugar = 1, /datum/reagent/fuel/oil = 1, /datum/reagent/hydrogen = 1, /datum/reagent/diethylamine = 1)
|
||||
|
||||
314
code/modules/reagents/reagent_containers/inhaler.dm
Normal file
314
code/modules/reagents/reagent_containers/inhaler.dm
Normal file
@@ -0,0 +1,314 @@
|
||||
/obj/item/inhaler
|
||||
name = "inhaler"
|
||||
desc = "A small device capable of administering short bursts of aerosolized chemicals. Requires a canister to function."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
icon = 'icons/obj/medical/chemical.dmi'
|
||||
icon_state = "inhaler_generic"
|
||||
|
||||
custom_materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 0.1)
|
||||
|
||||
/// The currently installed canister, from which we get our reagents. Nullable.
|
||||
var/obj/item/reagent_containers/inhaler_canister/canister
|
||||
/// The path for our initial canister to be generated by. If not null, we start with that canister type.
|
||||
var/obj/item/reagent_containers/inhaler_canister/initial_casister_path
|
||||
|
||||
/// The underlay of our canister, if one is installed.
|
||||
var/mutable_appearance/canister_underlay
|
||||
/// The y offset to be applied to [canister_underlay].
|
||||
var/canister_underlay_y_offset = -2
|
||||
/// If true, we will show a rotary display with how many puffs we can be used for until the canister runs out.
|
||||
var/show_puffs_left = TRUE // this is how real inhalers work
|
||||
|
||||
/obj/item/inhaler/Initialize(mapload)
|
||||
. = ..()
|
||||
if (ispath(initial_casister_path, /obj/item/reagent_containers/inhaler_canister))
|
||||
set_canister(new initial_casister_path)
|
||||
|
||||
/obj/item/inhaler/Destroy(force)
|
||||
QDEL_NULL(canister)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/inhaler/handle_deconstruct(disassembled)
|
||||
. = ..()
|
||||
|
||||
canister?.forceMove(drop_location())
|
||||
|
||||
/obj/item/inhaler/proc/update_canister_underlay()
|
||||
if (isnull(canister))
|
||||
underlays -= canister_underlay
|
||||
canister_underlay = null
|
||||
else if (isnull(canister_underlay))
|
||||
canister_underlay = mutable_appearance(canister.icon, canister.icon_state)
|
||||
canister_underlay.pixel_z = canister_underlay_y_offset
|
||||
underlays += canister_underlay
|
||||
|
||||
/obj/item/inhaler/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
if (isnull(canister))
|
||||
return
|
||||
|
||||
. += span_blue("It seems to have <b>[canister]</b> inserted.")
|
||||
if (!show_puffs_left)
|
||||
return
|
||||
|
||||
var/puffs_left = canister.get_puffs_left()
|
||||
if (puffs_left > 0)
|
||||
puffs_left = span_blue("[puffs_left]")
|
||||
else
|
||||
puffs_left = span_danger("[puffs_left]")
|
||||
. += "Its rotary display shows its canister can be used [puffs_left] more times."
|
||||
|
||||
/obj/item/inhaler/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
|
||||
if (gone == canister)
|
||||
set_canister(null, move_canister = FALSE)
|
||||
|
||||
|
||||
/obj/item/inhaler/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
||||
if (!isliving(interacting_with))
|
||||
return ..() // default behavior
|
||||
var/mob/living/target_mob = interacting_with
|
||||
|
||||
if (!can_puff(target_mob, user))
|
||||
return NONE
|
||||
|
||||
var/puff_timer = 0
|
||||
|
||||
var/pre_use_visible_message
|
||||
var/pre_use_self_message
|
||||
var/pre_use_target_message
|
||||
|
||||
var/post_use_visible_message
|
||||
var/post_use_self_message
|
||||
var/post_use_target_message
|
||||
|
||||
if (target_mob == user) // no need for a target message
|
||||
puff_timer = canister.self_administer_delay
|
||||
|
||||
pre_use_visible_message = span_notice("[user] puts [src] to [user.p_their()] lips, fingers on the canister...")
|
||||
pre_use_self_message = span_notice("You put [src] to your lips and put pressure on the canister...")
|
||||
|
||||
post_use_visible_message = span_notice("[user] takes a puff of [src]!")
|
||||
post_use_self_message = span_notice("You take a puff of [src]!")
|
||||
else
|
||||
puff_timer = canister.other_administer_delay
|
||||
|
||||
pre_use_visible_message = span_warning("[user] tries to force [src] between [target_mob]'s lips...")
|
||||
pre_use_self_message = span_notice("You try to put [src] to [target_mob]'s lips...")
|
||||
pre_use_target_message = span_userdanger("[user] tries to force [src] between your lips!")
|
||||
|
||||
post_use_visible_message = span_warning("[user] forces [src] between [target_mob]'s lips and pushes the canister down!")
|
||||
post_use_self_message = span_notice("You force [src] between [target_mob]'s lips and press on the canister!")
|
||||
post_use_target_message = span_userdanger("[user] forces [src] between your lips and presses on the canister, filling your lungs with aerosol!")
|
||||
|
||||
if (puff_timer > 0)
|
||||
user.visible_message(pre_use_visible_message, ignored_mobs = list(user, target_mob))
|
||||
to_chat(user, pre_use_self_message)
|
||||
if (pre_use_target_message)
|
||||
to_chat(target_mob, pre_use_target_message)
|
||||
if (!do_after(user, puff_timer, src))
|
||||
return NONE
|
||||
if (!can_puff(target_mob, user)) // sanity
|
||||
return NONE
|
||||
|
||||
user.visible_message(post_use_visible_message, ignored_mobs = list(user, target_mob))
|
||||
to_chat(user, post_use_self_message)
|
||||
if (post_use_target_message)
|
||||
to_chat(target_mob, post_use_target_message)
|
||||
|
||||
canister.puff(user, target_mob)
|
||||
|
||||
/obj/item/inhaler/attack_self(mob/user, modifiers)
|
||||
try_remove_canister(user, modifiers)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/inhaler/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
|
||||
if (istype(tool, /obj/item/reagent_containers/inhaler_canister))
|
||||
return try_insert_canister(tool, user, modifiers)
|
||||
|
||||
return ..()
|
||||
|
||||
/// Tries to remove the canister, if any is inserted.
|
||||
/obj/item/inhaler/proc/try_remove_canister(mob/living/user, modifiers)
|
||||
if (isnull(canister))
|
||||
balloon_alert(user, "no canister inserted!")
|
||||
return FALSE
|
||||
|
||||
if (canister.removal_time > 0)
|
||||
balloon_alert(user, "removing canister...")
|
||||
if (!do_after(user, canister.removal_time, src))
|
||||
return FALSE
|
||||
|
||||
balloon_alert(user, "canister removed")
|
||||
playsound(src, canister.post_insert_sound, canister.post_insert_volume)
|
||||
set_canister(null, user)
|
||||
|
||||
// Tries to insert a canister, if none is already inserted.
|
||||
/obj/item/inhaler/proc/try_insert_canister(obj/item/reagent_containers/inhaler_canister/new_canister, mob/living/user, params)
|
||||
if (!isnull(canister))
|
||||
balloon_alert(user, "remove the existing canister!")
|
||||
return FALSE
|
||||
|
||||
balloon_alert(user, "inserting canister...")
|
||||
playsound(src, new_canister.pre_insert_sound, new_canister.pre_insert_volume)
|
||||
if (!do_after(user, new_canister.insertion_time, src))
|
||||
return FALSE
|
||||
playsound(src, new_canister.post_insert_sound, new_canister.post_insert_volume)
|
||||
balloon_alert(user, "canister inserted")
|
||||
set_canister(new_canister, user)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Setter proc for [canister]. Moves the existing canister out of the inhaler, while moving a new canister inside and registering it.
|
||||
/obj/item/inhaler/proc/set_canister(obj/item/reagent_containers/inhaler_canister/new_canister, mob/living/user, move_canister = TRUE)
|
||||
if (move_canister && !isnull(canister))
|
||||
if (iscarbon(loc))
|
||||
var/mob/living/carbon/carbon_loc = loc
|
||||
INVOKE_ASYNC(carbon_loc, TYPE_PROC_REF(/mob/living/carbon, put_in_hands), canister)
|
||||
else if (!isnull(loc))
|
||||
canister.forceMove(loc)
|
||||
|
||||
canister = new_canister
|
||||
canister?.forceMove(src)
|
||||
update_canister_underlay()
|
||||
|
||||
/// Determines if we can be used. Fails on no canister, empty canister, invalid targets, or non-breathing targets.
|
||||
/obj/item/inhaler/proc/can_puff(mob/living/target_mob, mob/living/user, silent = FALSE)
|
||||
if (isnull(canister))
|
||||
if (!silent)
|
||||
balloon_alert(user, "no canister!")
|
||||
return FALSE
|
||||
if (isnull(canister.reagents) || canister.reagents.total_volume <= 0)
|
||||
if (!silent)
|
||||
balloon_alert(user, "canister is empty!")
|
||||
return FALSE
|
||||
if (!iscarbon(target_mob)) // maybe mix this into a general has mouth check
|
||||
if (!silent)
|
||||
balloon_alert(user, "not breathing!")
|
||||
return FALSE
|
||||
var/mob/living/carbon/carbon_target = target_mob
|
||||
if (carbon_target.is_mouth_covered())
|
||||
if (!silent)
|
||||
balloon_alert(user, "expose the mouth!")
|
||||
return FALSE
|
||||
if (HAS_TRAIT(carbon_target, TRAIT_NOBREATH))
|
||||
if (!silent)
|
||||
balloon_alert(user, "not breathing!")
|
||||
return FALSE
|
||||
var/obj/item/organ/lungs/lungs = carbon_target.get_organ_slot(ORGAN_SLOT_LUNGS)
|
||||
if (isnull(lungs) || lungs.received_pressure_mult <= 0)
|
||||
if (!silent)
|
||||
balloon_alert(user, "not breathing!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/reagent_containers/inhaler_canister
|
||||
name = "inhaler canister"
|
||||
desc = "A small canister filled with aerosolized reagents for use in a inhaler."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
icon = 'icons/obj/medical/chemical.dmi'
|
||||
icon_state = "canister_generic"
|
||||
|
||||
reagent_flags = SEALED_CONTAINER|DRAINABLE|REFILLABLE
|
||||
has_variable_transfer_amount = FALSE
|
||||
|
||||
max_integrity = 60
|
||||
|
||||
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.2)
|
||||
|
||||
/// The sound that plays when we are used.
|
||||
var/puff_sound = 'sound/effects/spray.ogg'
|
||||
/// The volume of [puff_sound]
|
||||
var/puff_volume = 20
|
||||
|
||||
/// The sound that plays when someone TRIES to insert us.
|
||||
var/pre_insert_sound = 'sound/items/taperecorder/tape_flip.ogg'
|
||||
/// The sound that plays when we are removed or inserted.
|
||||
var/post_insert_sound = 'sound/items/taperecorder/taperecorder_close.ogg'
|
||||
|
||||
/// The volume of [pre_insert_sound]
|
||||
var/pre_insert_volume = 50
|
||||
/// The volume of [post_insert_sound]
|
||||
var/post_insert_volume = 50
|
||||
|
||||
/// The time it takes to insert us into a inhaler.
|
||||
var/insertion_time = 2 SECONDS
|
||||
/// The time it takes to remove us from a inhaler.
|
||||
var/removal_time = 0.5 SECONDS
|
||||
|
||||
/// The time it takes for us to be used on someone else.
|
||||
var/other_administer_delay = 3 SECONDS
|
||||
/// The time it takes for us to be used on our owner.
|
||||
var/self_administer_delay = 1 SECONDS
|
||||
|
||||
/// Called when a inhaler we are in is used on someone. Transfers reagents and plays the puff sound.
|
||||
/obj/item/reagent_containers/inhaler_canister/proc/puff(mob/living/user, mob/living/carbon/target)
|
||||
playsound(src, puff_sound, puff_volume, TRUE, -6)
|
||||
reagents.trans_to(target, amount_per_transfer_from_this, transferred_by = user, methods = INHALE)
|
||||
|
||||
/// Returns a integer approximating how many puffs we can be used for.
|
||||
/obj/item/reagent_containers/inhaler_canister/proc/get_puffs_left()
|
||||
return ROUND_UP(reagents.total_volume / amount_per_transfer_from_this)
|
||||
|
||||
/obj/item/reagent_containers/inhaler_canister/handle_deconstruct(disassembled)
|
||||
if (!reagents?.total_volume)
|
||||
return ..()
|
||||
|
||||
var/datum/reagents/smoke_reagents = new/datum/reagents() // Lets be safe first, our own reagents may be qdelled if we get deleted
|
||||
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/smoke = new()
|
||||
smoke_reagents.my_atom = src
|
||||
for (var/datum/reagent/reagent as anything in reagents.reagent_list)
|
||||
smoke_reagents.add_reagent(reagent.type, reagent.volume, added_purity = reagent.purity)
|
||||
reagents.remove_reagent(reagent.type, reagent.volume)
|
||||
if (smoke_reagents.reagent_list)
|
||||
smoke.set_up(1, holder = src, location = get_turf(src), carry = smoke_reagents)
|
||||
smoke.start(log = TRUE)
|
||||
visible_message(span_warning("[src] breaks open and sprays its aerosilized contents everywhere!"))
|
||||
else
|
||||
visible_message(span_warning("[src] breaks open - but is empty!"))
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/inhaler/medical
|
||||
icon_state = "inhaler_medical"
|
||||
|
||||
/obj/item/inhaler/salbutamol
|
||||
name = "salbutamol inhaler"
|
||||
icon_state = "inhaler_medical"
|
||||
initial_casister_path = /obj/item/reagent_containers/inhaler_canister/salbutamol
|
||||
|
||||
/obj/item/reagent_containers/inhaler_canister/salbutamol
|
||||
name = "salbutamol canister"
|
||||
icon_state = "canister_medical"
|
||||
list_reagents = list(/datum/reagent/medicine/salbutamol = 30)
|
||||
|
||||
/obj/item/inhaler/albuterol
|
||||
name = "albuterol inhaler"
|
||||
icon_state = "inhaler_medical"
|
||||
initial_casister_path = /obj/item/reagent_containers/inhaler_canister/albuterol
|
||||
|
||||
/obj/item/reagent_containers/inhaler_canister/albuterol
|
||||
name = "albuterol canister"
|
||||
desc = "A small canister filled with aerosolized reagents for use in a inhaler. This one contains albuterol, a potent bronchodilator that can stop \
|
||||
asthma attacks in their tracks."
|
||||
icon_state = "canister_medical"
|
||||
list_reagents = list(/datum/reagent/medicine/albuterol = 30)
|
||||
|
||||
/obj/item/reagent_containers/inhaler_canister/albuterol/asthma
|
||||
name = "low-pressure albuterol canister"
|
||||
desc = "A small canister filled with aerosolized reagents for use in a inhaler. This one contains albuterol, a potent bronchodilator that can stop \
|
||||
asthma attacks in their tracks. It seems to be a lower-pressure variant, and can only hold 20u."
|
||||
list_reagents = list(/datum/reagent/medicine/albuterol = 20)
|
||||
volume = 20
|
||||
|
||||
/obj/item/inhaler/albuterol/asthma
|
||||
name = "rescue inhaler"
|
||||
icon_state = "inhaler_generic"
|
||||
initial_casister_path = /obj/item/reagent_containers/inhaler_canister/albuterol/asthma
|
||||
@@ -128,6 +128,30 @@
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE
|
||||
|
||||
/datum/design/inhaler
|
||||
name = "Inhaler"
|
||||
desc = "A small device capable of administering short bursts of aerosolized chemicals. Requires a canister to function."
|
||||
id = "inhaler"
|
||||
build_path = /obj/item/inhaler/medical
|
||||
build_type = PROTOLATHE | AWAY_LATHE
|
||||
materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 0.1)
|
||||
category = list(
|
||||
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
|
||||
|
||||
/datum/design/inhaler_canister
|
||||
name = "Inhaler Canister"
|
||||
desc = "A small canister filled with aerosolized reagents for use in a inhaler."
|
||||
id = "inhaler_canister"
|
||||
build_path = /obj/item/reagent_containers/inhaler_canister
|
||||
build_type = PROTOLATHE | AWAY_LATHE
|
||||
materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 0.2)
|
||||
category = list(
|
||||
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
|
||||
|
||||
/datum/design/bluespacebodybag
|
||||
name = "Bluespace Body Bag"
|
||||
desc = "A bluespace body bag, powered by experimental bluespace technology. It can hold loads of bodies and the largest of creatures."
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
prereq_ids = list(TECHWEB_NODE_MEDBAY_EQUIP)
|
||||
design_ids = list(
|
||||
"med_spray_bottle",
|
||||
"inhaler",
|
||||
"inhaler_canister",
|
||||
"medigel",
|
||||
"medipen_refiller",
|
||||
"soda_dispenser",
|
||||
|
||||
96
code/modules/surgery/asthmatic_bypass.dm
Normal file
96
code/modules/surgery/asthmatic_bypass.dm
Normal file
@@ -0,0 +1,96 @@
|
||||
/datum/surgery/asthmatic_bypass
|
||||
name = "Asthmatic Bypass"
|
||||
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB
|
||||
requires_bodypart_type = NONE
|
||||
organ_to_manipulate = ORGAN_SLOT_LUNGS
|
||||
possible_locs = list(BODY_ZONE_CHEST)
|
||||
steps = list(
|
||||
/datum/surgery_step/incise,
|
||||
/datum/surgery_step/retract_skin,
|
||||
/datum/surgery_step/clamp_bleeders,
|
||||
/datum/surgery_step/incise,
|
||||
/datum/surgery_step/expand_windpipe,
|
||||
/datum/surgery_step/close,
|
||||
)
|
||||
|
||||
/datum/surgery/asthmatic_bypass/can_start(mob/user, mob/living/patient)
|
||||
. = ..()
|
||||
|
||||
if (!.)
|
||||
return
|
||||
|
||||
return (patient.has_quirk(/datum/quirk/item_quirk/asthma))
|
||||
|
||||
/datum/surgery_step/expand_windpipe
|
||||
name = "force open windpipe (retractor)"
|
||||
implements = list(
|
||||
TOOL_RETRACTOR = 80,
|
||||
TOOL_WIRECUTTER = 45,
|
||||
)
|
||||
time = 8 SECONDS
|
||||
repeatable = TRUE
|
||||
preop_sound = 'sound/items/handling/surgery/retractor1.ogg'
|
||||
success_sound = 'sound/items/handling/surgery/retractor2.ogg'
|
||||
|
||||
/// The amount of inflammation a failure or success of this surgery will reduce.
|
||||
var/inflammation_reduction = 75
|
||||
|
||||
/datum/surgery_step/expand_windpipe/preop(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery)
|
||||
display_results(
|
||||
user,
|
||||
target,
|
||||
span_notice("You start to stretch [target]'s windpipe, trying your best to avoid nearby blood vessels..."),
|
||||
span_notice("[user] begins to stretch [target]'s windpipe, taking care to avoid any nearby blood vessels."),
|
||||
span_notice("[user] begins to stretch [target]'s windpipe."),
|
||||
)
|
||||
display_pain(target, "You feel an agonizing stretching sensation in your neck!")
|
||||
|
||||
/datum/surgery_step/expand_windpipe/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = TRUE)
|
||||
if (!reduce_inflammation(user, target, tool, surgery))
|
||||
return
|
||||
|
||||
default_display_results = FALSE
|
||||
display_results(
|
||||
user,
|
||||
target,
|
||||
span_notice("You stretch [target]'s windpipe with [tool], managing to avoid the nearby blood vessels and arteries."),
|
||||
span_notice("[user] succeeds at stretching [target]'s windpipe with [tool], avoiding the nearby blood vessels and arteries."),
|
||||
span_notice("[user] finishes stretching [target]'s windpipe.")
|
||||
)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/surgery_step/expand_windpipe/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob)
|
||||
if (!reduce_inflammation(user, target, tool, surgery))
|
||||
return
|
||||
|
||||
display_results(
|
||||
user,
|
||||
target,
|
||||
span_bolddanger("You stretch [target]'s windpipe with [tool], but accidentally clip a few arteries!"),
|
||||
span_bolddanger("[user] succeeds at stretching [target]'s windpipe with [tool], but accidentally clips a few arteries!"),
|
||||
span_bolddanger("[user] finishes stretching [target]'s windpipe, but screws up!")
|
||||
)
|
||||
|
||||
target.losebreath++
|
||||
|
||||
if (iscarbon(target))
|
||||
var/mob/living/carbon/carbon_patient = target
|
||||
var/wound_bonus = tool.wound_bonus
|
||||
var/obj/item/bodypart/head/patient_chest = carbon_patient.get_bodypart(BODY_ZONE_CHEST)
|
||||
if (patient_chest)
|
||||
if (prob(30))
|
||||
carbon_patient.cause_wound_of_type_and_severity(WOUND_SLASH, patient_chest, WOUND_SEVERITY_MODERATE, WOUND_SEVERITY_CRITICAL, WOUND_PICK_LOWEST_SEVERITY, tool)
|
||||
patient_chest.receive_damage(brute = 10, wound_bonus = wound_bonus, sharpness = SHARP_EDGED, damage_source = tool)
|
||||
|
||||
return FALSE
|
||||
|
||||
/// Reduces the asthmatic's inflammation by [inflammation_reduction]. Called by both success and failure.
|
||||
/datum/surgery_step/expand_windpipe/proc/reduce_inflammation(mob/user, mob/living/target, obj/item/tool, datum/surgery/surgery)
|
||||
var/datum/quirk/item_quirk/asthma/asthma_quirk = locate(/datum/quirk/item_quirk/asthma) in target.quirks
|
||||
if (isnull(asthma_quirk))
|
||||
qdel(surgery) // not really an error cause quirks can get removed during surgery?
|
||||
return FALSE
|
||||
|
||||
asthma_quirk.adjust_inflammation(-inflammation_reduction)
|
||||
return TRUE
|
||||
@@ -324,6 +324,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ)
|
||||
lungs = new()
|
||||
lungs.Insert(src)
|
||||
lungs.set_organ_damage(0)
|
||||
lungs.received_pressure_mult = lungs::received_pressure_mult
|
||||
|
||||
var/obj/item/organ/heart/heart = get_organ_slot(ORGAN_SLOT_HEART)
|
||||
if(heart)
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
var/n2o_euphoria = EUPHORIA_LAST_FLAG
|
||||
var/healium_euphoria = EUPHORIA_LAST_FLAG
|
||||
|
||||
/// All incoming breaths will have their pressure multiplied against this. Higher values allow more air to be breathed at once,
|
||||
/// while lower values can cause suffocation in low pressure environments.
|
||||
var/received_pressure_mult = 1
|
||||
|
||||
var/oxy_breath_dam_min = MIN_TOXIC_GAS_DAMAGE
|
||||
var/oxy_breath_dam_max = MAX_TOXIC_GAS_DAMAGE
|
||||
@@ -168,6 +171,7 @@
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_NITRO)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_PLASMA)
|
||||
receiver.clear_alert(ALERT_NOT_ENOUGH_N2O)
|
||||
update_bronchodilation_alerts()
|
||||
|
||||
/obj/item/organ/lungs/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
|
||||
. = ..()
|
||||
@@ -648,7 +652,7 @@
|
||||
// Build out our partial pressures, for use as we go
|
||||
var/list/partial_pressures = list()
|
||||
for(var/gas_id in breath_gases)
|
||||
partial_pressures[gas_id] = breath.get_breath_partial_pressure(breath_gases[gas_id][MOLES])
|
||||
partial_pressures[gas_id] = breath.get_breath_partial_pressure(breath_gases[gas_id][MOLES] * received_pressure_mult)
|
||||
|
||||
// Treat gas as other types of gas
|
||||
for(var/list/conversion_packet in treat_as)
|
||||
@@ -1051,6 +1055,38 @@
|
||||
|
||||
#undef GAS_TOLERANCE
|
||||
|
||||
/// Adjusting proc for [received_pressure_mult]. Updates bronchodilation alerts.
|
||||
/obj/item/organ/lungs/proc/adjust_received_pressure_mult(adjustment)
|
||||
received_pressure_mult = max(received_pressure_mult + adjustment, 0)
|
||||
update_bronchodilation_alerts()
|
||||
|
||||
/// Setter proc for [received_pressure_mult]. Updates bronchodilation alerts.
|
||||
/obj/item/organ/lungs/proc/set_received_pressure_mult(new_value)
|
||||
received_pressure_mult = max(new_value, 0)
|
||||
update_bronchodilation_alerts()
|
||||
|
||||
#define LUNG_CAPACITY_ALERT_BUFFER 0.003
|
||||
/// Depending on [received_pressure_mult], gives either a bronchocontraction or bronchoconstriction alert to our owner (if we have one), or clears the alert
|
||||
/// if [received_pressure_mult] is near 1.
|
||||
/obj/item/organ/lungs/proc/update_bronchodilation_alerts()
|
||||
if (!owner)
|
||||
return
|
||||
|
||||
var/initial_value = initial(received_pressure_mult)
|
||||
|
||||
// you wont really notice if youre only breathing a bit more or a bit less
|
||||
var/dilated = (received_pressure_mult > (initial_value + LUNG_CAPACITY_ALERT_BUFFER))
|
||||
var/constricted = (received_pressure_mult < (initial_value - LUNG_CAPACITY_ALERT_BUFFER))
|
||||
|
||||
if (dilated)
|
||||
owner.throw_alert(ALERT_BRONCHODILATION, /atom/movable/screen/alert/bronchodilated)
|
||||
else if (constricted)
|
||||
owner.throw_alert(ALERT_BRONCHODILATION, /atom/movable/screen/alert/bronchoconstricted)
|
||||
else
|
||||
owner.clear_alert(ALERT_BRONCHODILATION)
|
||||
|
||||
#undef LUNG_CAPACITY_ALERT_BUFFER
|
||||
|
||||
/obj/item/organ/lungs/ethereal
|
||||
name = "aeration reticulum"
|
||||
desc = "These exotic lungs seem crunchier than most."
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
/obj/item/reagent_containers/medigel/synthflesh = 2,
|
||||
/obj/item/storage/pill_bottle/psicodine = 2,
|
||||
/obj/item/storage/pill_bottle/sansufentanyl = 1,
|
||||
/obj/item/inhaler/albuterol = 2,
|
||||
)
|
||||
default_price = 50
|
||||
extra_price = 100
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 180 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 79 KiB |
@@ -1543,6 +1543,7 @@
|
||||
#include "code\datums\diseases\adrenal_crisis.dm"
|
||||
#include "code\datums\diseases\anaphylaxis.dm"
|
||||
#include "code\datums\diseases\anxiety.dm"
|
||||
#include "code\datums\diseases\asthma_attack.dm"
|
||||
#include "code\datums\diseases\beesease.dm"
|
||||
#include "code\datums\diseases\brainrot.dm"
|
||||
#include "code\datums\diseases\chronic_illness.dm"
|
||||
@@ -1957,6 +1958,7 @@
|
||||
#include "code\datums\quirks\negative_quirks\all_nighter.dm"
|
||||
#include "code\datums\quirks\negative_quirks\allergic.dm"
|
||||
#include "code\datums\quirks\negative_quirks\anosmia.dm"
|
||||
#include "code\datums\quirks\negative_quirks\asthma.dm"
|
||||
#include "code\datums\quirks\negative_quirks\bad_back.dm"
|
||||
#include "code\datums\quirks\negative_quirks\bad_touch.dm"
|
||||
#include "code\datums\quirks\negative_quirks\big_hands.dm"
|
||||
@@ -6114,6 +6116,7 @@
|
||||
#include "code\modules\reagents\reagent_containers\cooler_jug.dm"
|
||||
#include "code\modules\reagents\reagent_containers\dropper.dm"
|
||||
#include "code\modules\reagents\reagent_containers\hypospray.dm"
|
||||
#include "code\modules\reagents\reagent_containers\inhaler.dm"
|
||||
#include "code\modules\reagents\reagent_containers\jerrycan.dm"
|
||||
#include "code\modules\reagents\reagent_containers\medigel.dm"
|
||||
#include "code\modules\reagents\reagent_containers\patch.dm"
|
||||
@@ -6401,6 +6404,7 @@
|
||||
#include "code\modules\station_goals\station_goal.dm"
|
||||
#include "code\modules\station_goals\vault_mutation.dm"
|
||||
#include "code\modules\surgery\amputation.dm"
|
||||
#include "code\modules\surgery\asthmatic_bypass.dm"
|
||||
#include "code\modules\surgery\autopsy.dm"
|
||||
#include "code\modules\surgery\blood_filter.dm"
|
||||
#include "code\modules\surgery\bone_mending.dm"
|
||||
|
||||
Reference in New Issue
Block a user