Adds Hereditary Manifold Sickness, a Chronic Illness Quirk (#75035)

## About The Pull Request

Adds a new quirk called Chronic Illness. It provides a -12 score as it's
a pretty life-altering quirk, but could give way to interesting RP.

- Hereditary Manifold Sickness (HMS) can not be cured, it can only be
delayed and treated using a new unmakable vaccine called
"Sansufentanyl". You spawn with 6 pills and are able to order crates
containing 12 more from cargo as it's proprietary to Interdyne.

- HMS has 5 stages total.
Stage 1 does nothing
Stage 2 gives minor effects 
Stage 3 becomes debilitating
Stage 4 is a danger zone.

Upon reaching Stage 5, there are 4 possibilities, 1 is a recovery back
to stage 1, and the other 3 are deaths which I won't explain here to
avoid ruining it. (read the code I guess.)

This also adds a new traitor objective to infect someone with HMS.

- [x] Correcting the chronic aspect.

- [x] Add traitor objective.

- [x] Tweaking for fairness.

## Why It's Good For The Game

HMS is a new quirk that gives a much more hardcore junky or tumor
playstyle. Neglecting HMS can mean the end of your shift. it's not
something you want to mess with.

It puts a reliance on cargo rather than medical for a quirk and gives a
use case for money. (price may be tweaked still). I think it'd be
interesting to see if people will start mugging or robbing the vault
more to get their life-saving medication.

## Changelog
🆑
add: Interdyne has released a new medication to treat those who are in
the wrong timeline!
add: Interdyne has also realized this is VERY profitable! They've begun
arming their operatives with an autoinjector.
/🆑

---------

Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com>
This commit is contained in:
Charlotte
2023-05-24 09:03:15 +12:00
committed by GitHub
co-authored by Tom
parent 69c5d26d40
commit 97665d4e54
16 changed files with 379 additions and 7 deletions
@@ -163,3 +163,6 @@
/// From /obj/structure/geyser/attackby() : (obj/structure/geyser/geyser)
#define COMSIG_LIVING_DISCOVERED_GEYSER "living_discovered_geyser"
/// For when someone is injected with the EHMS virus from /datum/traitor_objective_category/infect
#define COMSIG_AFTER_INJECT "after_inject"
+3
View File
@@ -10,6 +10,7 @@
#define CURABLE (1<<0)
#define CAN_CARRY (1<<1)
#define CAN_RESIST (1<<2)
#define CHRONIC (1<<3)
//Spread Flags
#define DISEASE_SPREAD_SPECIAL (1<<0)
@@ -34,3 +35,5 @@
#define DISEASE_SEVERITY_DANGEROUS "Dangerous"
/// Diseases that can quickly kill an unprepared victim (fungal tb, gbs)
#define DISEASE_SEVERITY_BIOHAZARD "BIOHAZARD"
/// Diseases that are uncurable (hms)
#define DISEASE_SEVERITY_UNCURABLE "Uncurable"
+13 -7
View File
@@ -67,12 +67,16 @@
var/slowdown = affected_mob.reagents.has_reagent(/datum/reagent/medicine/spaceacillin) ? 0.5 : 1 // spaceacillin slows stage speed by 50%
if(has_cure())
if(SPT_PROB(cure_chance, seconds_per_tick))
update_stage(max(stage - 1, 1))
if(disease_flags & CURABLE && SPT_PROB(cure_chance, seconds_per_tick))
cure()
return FALSE
if(disease_flags & CHRONIC && SPT_PROB(cure_chance, seconds_per_tick))
src.stage = 1
to_chat(affected_mob, span_notice("Your chronic illness is alleviated a little, though it can't be cured!"))
return
else
if(SPT_PROB(cure_chance, seconds_per_tick))
update_stage(max(stage - 1, 1))
if(disease_flags & CURABLE && SPT_PROB(cure_chance, seconds_per_tick))
cure()
return FALSE
else if(SPT_PROB(stage_prob*slowdown, seconds_per_tick))
update_stage(min(stage + 1, max_stages))
@@ -83,7 +87,7 @@
stage = new_stage
/datum/disease/proc/has_cure()
if(!(disease_flags & CURABLE))
if(!(disease_flags & CURABLE | CHRONIC))
return FALSE
. = cures.len
@@ -191,6 +195,8 @@
//Use this to compare severities
/proc/get_disease_severity_value(severity)
switch(severity)
if(DISEASE_SEVERITY_UNCURABLE)
return 0
if(DISEASE_SEVERITY_POSITIVE)
return 1
if(DISEASE_SEVERITY_NONTHREAT)
+91
View File
@@ -0,0 +1,91 @@
/datum/disease/chronic_illness
name = "Hereditary Manifold Sickness"
max_stages = 5
spread_text = "Unspread Illness"
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
disease_flags = CHRONIC
process_dead = TRUE
stage_prob = 0.25
cure_text = "Sansufentanyl"
cures = list(/datum/reagent/medicine/sansufentanyl)
infectivity = 0
agent = "Quantum Entanglement"
viable_mobtypes = list(/mob/living/carbon/human)
desc = "A disease discovered in an Interdyne laboratory caused by subjection to timesteam correction technology."
severity = DISEASE_SEVERITY_UNCURABLE
var/heartswap = TRUE
/datum/disease/chronic_illness/stage_act(seconds_per_tick, times_fired)
. = ..()
if(!.)
return
switch(stage)
if(1)
carrier = FALSE // Go fuck yourself
if(2)
if(SPT_PROB(0.5, seconds_per_tick))
to_chat(affected_mob, span_warning("You feel dizzy."))
affected_mob.adjust_confusion(6 SECONDS)
if(SPT_PROB(0.5, seconds_per_tick))
to_chat(affected_mob, span_notice("You look at your hand. Your vision blurs."))
affected_mob.set_eye_blur_if_lower(10 SECONDS)
if(3)
if(SPT_PROB(0.5, seconds_per_tick))
to_chat(affected_mob, span_danger("You feel a very sharp pain in your chest!"))
if(prob(45))
affected_mob.vomit(20,TRUE)
if(SPT_PROB(0.5, seconds_per_tick))
to_chat(affected_mob, span_userdanger("[pick("You feel your heart slowing...", "You relax and slow your heartbeat.")]"))
affected_mob.adjustStaminaLoss(70, FALSE)
if(SPT_PROB(1, seconds_per_tick))
to_chat(affected_mob, span_danger("You feel a buzzing in your brain."))
SEND_SOUND(affected_mob, sound('sound/weapons/flash_ring.ogg'))
if(SPT_PROB(0.5, seconds_per_tick))
affected_mob.adjustBruteLoss(1)
if(4)
if(prob(30))
affected_mob.playsound_local(affected_mob, 'sound/effects/singlebeat.ogg', 100, FALSE, use_reverb = FALSE)
if(SPT_PROB(1, seconds_per_tick))
to_chat(affected_mob, span_danger("You feel a gruesome pain in your chest!"))
if(prob(75))
affected_mob.vomit(45,TRUE)
if(SPT_PROB(1, seconds_per_tick))
affected_mob.adjustStaminaLoss(100, FALSE)
affected_mob.visible_message(span_warning("[affected_mob] collapses!"))
if(prob(30))
to_chat(affected_mob, span_danger("Your vision blurs as you faint!"))
affected_mob.AdjustSleeping(10)
if(SPT_PROB(0.5, seconds_per_tick))
to_chat(affected_mob, span_danger("[pick("You feel as though your atoms are accelerating in place.", "You feel like you're being torn apart!")]"))
affected_mob.emote("scream")
affected_mob.adjustBruteLoss(10)
if(5)
switch(rand(1,4))
if(1)
to_chat(affected_mob, span_notice("You feel your atoms begin to realign. You're safe. For now."))
stage = 1
if(2)
to_chat(affected_mob, span_boldwarning("There is no place for you in this timeline."))
affected_mob.adjustStaminaLoss(100, forced = TRUE)
playsound(affected_mob.loc, 'sound/magic/repulse.ogg', 100, FALSE)
affected_mob.emote("scream")
for(var/mob/living/viewers in viewers(3, affected_mob.loc))
viewers.flash_act()
new /obj/effect/decal/cleanable/plasma(affected_mob.loc)
new /obj/effect/decal/cleanable/ash(affected_mob.loc)
affected_mob.visible_message(span_warning("[affected_mob] is erased from the timeline!"), span_userdanger("You are ripped from the timeline!"))
qdel(affected_mob)
if(3)
affected_mob.visible_message(span_warning("[affected_mob] is torn apart!"), span_userdanger("Your atoms accelerate into criticality!"))
affected_mob.gib()
if(4)
if(heartswap == TRUE)
heartswap = FALSE
if(affected_mob.stat == CONSCIOUS)
affected_mob.visible_message(span_danger("[affected_mob] clutches at [affected_mob.p_their()] chest as if [affected_mob.p_their()] heart is stopping!"), \
span_userdanger("You feel a horrible pain as your heart is replaced with one from another dimension!"))
var/obj/item/organ/internal/heart/cursed/cheart = new /obj/item/organ/internal/heart/cursed()
cheart.replace_into(affected_mob)
playsound(affected_mob, 'sound/hallucinations/far_noise.ogg', 50, 1)
stage = 3
+17
View File
@@ -897,6 +897,23 @@
return
quirk_holder.add_mood_event("wrong_cigs", /datum/mood_event/wrong_brand)
/datum/quirk/item_quirk/chronic_illness
name = "Chronic Illness"
desc = "You have a chronic illness that requires constant medication to keep under control."
icon = FA_ICON_DISEASE
value = -12
gain_text = span_danger("You feel a bit off today.")
lose_text = span_notice("You feel a bit better today.")
medical_record_text = "Patient has a chronic illness that requires constant medication to keep under control."
hardcore_value = 12
mail_goodies = list(/obj/item/storage/pill_bottle/sansufentanyl)
/datum/quirk/item_quirk/chronic_illness/add_unique(client/client_source)
var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness()
quirk_holder.ForceContractDisease(hms)
give_item_to_holder(/obj/item/storage/pill_bottle/sansufentanyl, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK),flavour_text = "You've been provided with medication to help manage your condition. Take it regularly to avoid complications.")
give_item_to_holder(/obj/item/healthanalyzer/disease, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK))
/datum/quirk/unstable
name = "Unstable"
desc = "Due to past troubles, you are unable to recover your sanity if you lose it. Be very careful managing your mood!"
+2
View File
@@ -210,6 +210,8 @@ Medical HUD! Basic mode needs suit sensors on.
holder.icon_state = "huddead"
else
switch(virus_threat)
if(DISEASE_SEVERITY_UNCURABLE)
holder.icon_state = "hudill6"
if(DISEASE_SEVERITY_BIOHAZARD)
holder.icon_state = "hudill5"
if(DISEASE_SEVERITY_DANGEROUS)
@@ -547,6 +547,54 @@
woundscan(user, patient, src)
/obj/item/healthanalyzer/disease
name = "disease state analyzer"
icon_state = "adv_spectrometer"
desc = "A disease status analyzer to determine the state of an infection to encourage responsible medication consumption."
/proc/diseasescan(mob/user, mob/living/carbon/patient, obj/item/healthanalyzer/wound/scanner)
if(!istype(patient) || user.incapacitated())
return
var/render_list = ""
for(var/thing in patient.diseases)
var/datum/disease/D = thing
if(!(D.visibility_flags & HIDDEN_SCANNER))
render_list += "<span class='alert ml-1'><b>Warning: [D.form] detected</b>\n\
<div class='ml-2'>Name: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]</div>\
</span>"
if(render_list == "")
if(istype(scanner))
// Only emit the cheerful scanner message if this scan came from a scanner
playsound(scanner, 'sound/machines/ping.ogg', 50, FALSE)
to_chat(user, span_notice("\The [scanner] makes a happy ping and briefly displays a smiley face with several exclamation points! It's really excited to report that [patient] has no diseases!"))
else
to_chat(user, "<span class='notice ml-1'>No diseases detected in subject.</span>")
else
to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO)
/obj/item/healthanalyzer/disease/attack_self(mob/user)
playsound(src, 'sound/machines/ping.ogg', 50, FALSE)
var/list/encouragements = list("encourages you to take your medication", "briefly displays a spinning cartoon heart", "reasures you about your condition", \
"reminds you that everyone is doing their best", "displays a message wishing you well", "displays a message saying how proud it is that you're taking care of yourself", "formally absolves you of all your sins")
to_chat(user, span_notice("\The [src] makes a happy ping and [pick(encouragements)]!"))
/obj/item/healthanalyzer/disease/attack(mob/living/carbon/patient, mob/living/carbon/human/user)
if(!user.can_read(src) || user.is_blind())
return
add_fingerprint(user)
user.visible_message(span_notice("[user] scans [patient] for diseases."), span_notice("You scan [patient] for diseases."))
if(!istype(user))
playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE)
to_chat(user, span_notice("\The [src] makes a sad buzz and briefly displays a frowny face, indicating it can't scan [patient]."))
return
diseasescan(user, user, src)
#undef SCANMODE_HEALTH
#undef SCANMODE_WOUND
#undef SCANMODE_COUNT
@@ -502,6 +502,14 @@
for(var/i in 1 to 5)
new /obj/item/reagent_containers/pill/stimulant(src)
/obj/item/storage/pill_bottle/sansufentanyl
name = "bottle of experimental medication"
desc = "A bottle of pills developed by Interdyne Pharmaceuticals. They're used to treat Hereditary Manifold Sickness."
/obj/item/storage/pill_bottle/sansufentanyl/PopulateContents()
for(var/i in 1 to 6)
new /obj/item/reagent_containers/pill/sansufentanyl(src)
/obj/item/storage/pill_bottle/mining
name = "bottle of patches"
desc = "Contains patches used to treat brute and burn damage."
@@ -0,0 +1,160 @@
/datum/traitor_objective_category/infect
name = "Infect with Disease"
objectives = list(
/datum/traitor_objective/target_player/infect = 1,
)
/datum/traitor_objective/target_player/infect
name = "Infect %TARGET% the %JOB TITLE%"
description = "Infect your target with the experimental Hereditary Manifold Sickness."
abstract_type = /datum/traitor_objective/target_player
progression_minimum = 20 MINUTES
progression_reward = list(8 MINUTES, 14 MINUTES)
telecrystal_reward = list(1, 2)
var/heads_of_staff = FALSE
duplicate_type = /datum/traitor_objective/target_player
var/obj/item/reagent_containers/hypospray/medipen/manifoldinjector/ehms
/datum/traitor_objective/target_player/infect/supported_configuration_changes()
. = ..()
. += NAMEOF(src, objective_period)
. += NAMEOF(src, maximum_objectives_in_period)
/datum/traitor_objective/target_player/infect/generate_ui_buttons(mob/user)
var/list/buttons = list()
if(!ehms)
buttons += add_ui_button("", "Pressing this will materialize a EHMS autoinjector into your hand, which you must inject into the target to succeed.", "paper-plane", "summon_pen")
return buttons
/datum/traitor_objective/target_player/infect/ui_perform_action(mob/living/user, action)
. = ..()
switch(action)
if("summon_pen")
if(ehms)
return
ehms = new(user.drop_location())
user.put_in_hands(ehms)
ehms.balloon_alert(user, "the injector materializes in your hand")
RegisterSignal(ehms, COMSIG_AFTER_INJECT, PROC_REF(on_injected))
AddComponent(/datum/component/traitor_objective_register, ehms, \
succeed_signals = null, \
fail_signals = list(COMSIG_PARENT_QDELETING), \
penalty = TRUE)
/datum/traitor_objective/target_player/infect/proc/on_injected(datum/source, mob/living/user, mob/living/injected)
SIGNAL_HANDLER
if(injected != target)
fail_objective()
return
if(injected == target)
succeed_objective()
return
/datum/traitor_objective/target_player/infect/generate_objective(datum/mind/generating_for, list/possible_duplicates)
var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
for(var/datum/objective/task as anything in handler.primary_objectives)
if(!istype(task.target, /datum/mind))
continue
already_targeting += task.target //Removing primary objective kill targets from the list
var/parent_type = type2parent(type)
//don't roll head of staff types if you haven't completed the normal version
if(heads_of_staff && !handler.get_completion_count(parent_type))
// Locked if they don't have any of the risky bug room objective completed
return FALSE
var/list/possible_targets = list()
var/try_target_late_joiners = FALSE
if(generating_for.late_joiner)
try_target_late_joiners = TRUE
for(var/datum/mind/possible_target as anything in get_crewmember_minds())
if(possible_target in already_targeting)
continue
var/target_area = get_area(possible_target.current)
if(possible_target == generating_for)
continue
if(!ishuman(possible_target.current))
continue
if(possible_target.current.stat == DEAD)
continue
var/datum/antagonist/traitor/traitor = possible_target.has_antag_datum(/datum/antagonist/traitor)
if(traitor && traitor.uplink_handler.telecrystals >= 0)
continue
if(!HAS_TRAIT(SSstation, STATION_TRAIT_LATE_ARRIVALS) && istype(target_area, /area/shuttle/arrival))
continue
//removes heads of staff from being targets from non heads of staff assassinations, and vice versa
if(heads_of_staff)
if(!(possible_target.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND))
continue
else
if((possible_target.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND))
continue
possible_targets += possible_target
for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
possible_targets -= objective.target
if(try_target_late_joiners)
var/list/all_possible_targets = possible_targets.Copy()
for(var/datum/mind/possible_target as anything in all_possible_targets)
if(!possible_target.late_joiner)
possible_targets -= possible_target
if(!possible_targets.len)
possible_targets = all_possible_targets
special_target_filter(possible_targets)
if(!possible_targets.len)
return FALSE //MISSION FAILED, WE'LL GET EM NEXT TIME
var/datum/mind/target_mind = pick(possible_targets)
target = target_mind.current
replace_in_name("%TARGET%", target.real_name)
replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
RegisterSignal(target, COMSIG_LIVING_DEATH, PROC_REF(on_target_death))
return TRUE
/datum/traitor_objective/target_player/infect/ungenerate_objective()
UnregisterSignal(target, COMSIG_LIVING_DEATH)
target = null
///proc for checking for special states that invalidate a target
/datum/traitor_objective/target_player/infect/proc/special_target_filter(list/possible_targets)
return
/datum/traitor_objective/target_player/infect/proc/on_target_qdeleted()
SIGNAL_HANDLER
if(objective_state == OBJECTIVE_STATE_INACTIVE)
//don't take an objective target of someone who is already obliterated
fail_objective()
/datum/traitor_objective/target_player/infect/proc/on_target_death()
SIGNAL_HANDLER
if(objective_state == OBJECTIVE_STATE_INACTIVE)
//don't take an objective target of someone who is already dead
fail_objective()
/obj/item/reagent_containers/hypospray/medipen/manifoldinjector
name = "EHMS autoinjector"
desc = "Experimental Hereditary Manifold Sickness autoinjector."
icon_state = "tbpen"
inhand_icon_state = "tbpen"
base_icon_state = "tbpen"
var/used = 0
volume = 30
amount_per_transfer_from_this = 30
list_reagents = list(/datum/reagent/medicine/sansufentanyl = 20)
/obj/item/reagent_containers/hypospray/medipen/manifoldinjector/attack(mob/living/affected_mob, mob/living/carbon/human/user)
inject(affected_mob, user)
if(used == 0)
var/datum/disease/chronic_illness/hms = new /datum/disease/chronic_illness()
affected_mob.ForceContractDisease(hms)
used = 1
SEND_SIGNAL(src, COMSIG_AFTER_INJECT, user, affected_mob)
+6
View File
@@ -112,6 +112,12 @@
for(var/i in 1 to 10)
var/item = pick(contains)
new item(C)
/datum/supply_pack/medical/experimentalmedicine
name = "Experimental Medicine Crate"
desc = "A crate containing the medication required for living with Hereditary Manifold Sickness, Sansufentanyl."
cost = CARGO_CRATE_VALUE * 2
contains = list(/obj/item/storage/pill_bottle/sansufentanyl = 2)
crate_name = "experimental medicine crate"
/datum/supply_pack/medical/surgery
name = "Surgical Supplies Crate"
@@ -662,6 +662,7 @@
/obj/machinery/smartfridge/chemistry/virology/preloaded
initial_contents = list(
/obj/item/storage/pill_bottle/sansufentanyl = 2,
/obj/item/reagent_containers/syringe/antiviral = 4,
/obj/item/reagent_containers/cup/bottle/cold = 1,
/obj/item/reagent_containers/cup/bottle/flu_virion = 1,
@@ -120,6 +120,24 @@
. = TRUE
..()
/datum/reagent/medicine/sansufentanyl
name = "Sansufentanyl"
description = "Temporary side effects include - nausea, dizziness, impaired motor coordination."
color = "#07e4d1"
ph = 6.2
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED
/datum/reagent/medicine/sansufentanyl/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired)
affected_mob.adjust_confusion_up_to(3 SECONDS * REM * seconds_per_tick, 5 SECONDS)
affected_mob.adjust_dizzy_up_to(6 SECONDS * REM * seconds_per_tick, 12 SECONDS)
affected_mob.adjustStaminaLoss(1 * REM * seconds_per_tick)
if(SPT_PROB(10, seconds_per_tick))
to_chat(affected_mob, "You feel confused and disoriented.")
if(prob(30))
SEND_SOUND(affected_mob, sound('sound/weapons/flash_ring.ogg'))
..()
/datum/reagent/medicine/cryoxadone
name = "Cryoxadone"
description = "A chemical mixture with almost magical healing powers. Its main limitation is that the patient's body temperature must be under 270K for it to metabolise correctly."
@@ -143,6 +143,12 @@
list_reagents = list(/datum/reagent/medicine/mannitol = 14)
rename_with_volume = TRUE
/obj/item/reagent_containers/pill/sansufentanyl
name = "sansufentanyl pill"
desc = "Used to treat Hereditary Manifold Sickness. Temporary side effects include - nausea, dizziness, impaired motor coordination."
icon_state = "pill19"
list_reagents = list(/datum/reagent/medicine/sansufentanyl = 5)
//Lower quantity mannitol pills (50u pills heal 250 brain damage, 5u pills heal 25)
/obj/item/reagent_containers/pill/mannitol/braintumor
desc = "Used to treat symptoms for brain tumors."
+1
View File
@@ -82,6 +82,7 @@
premium = list(
/obj/item/reagent_containers/medigel/synthflesh = 2,
/obj/item/storage/pill_bottle/psicodine = 2,
/obj/item/storage/pill_bottle/sansufentanyl = 1,
)
default_price = 50
extra_price = 100
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

+2
View File
@@ -1086,6 +1086,7 @@
#include "code\datums\diseases\anxiety.dm"
#include "code\datums\diseases\beesease.dm"
#include "code\datums\diseases\brainrot.dm"
#include "code\datums\diseases\chronic_illness.dm"
#include "code\datums\diseases\cold.dm"
#include "code\datums\diseases\cold9.dm"
#include "code\datums\diseases\death_sandwich_poisoning.dm"
@@ -2699,6 +2700,7 @@
#include "code\modules\antagonists\traitor\objectives\destroy_item.dm"
#include "code\modules\antagonists\traitor\objectives\eyesnatching.dm"
#include "code\modules\antagonists\traitor\objectives\hack_comm_console.dm"
#include "code\modules\antagonists\traitor\objectives\infect.dm"
#include "code\modules\antagonists\traitor\objectives\kidnapping.dm"
#include "code\modules\antagonists\traitor\objectives\kill_pet.dm"
#include "code\modules\antagonists\traitor\objectives\locate_weakpoint.dm"