mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-27 17:41:50 +00:00
## About The Pull Request 1. Rather than checking every life tick to try to spread via air, it checks every breath tick. IE, every 8 seconds. 2. Wearing a mask now protects you from catching airborne diseases, rather than only protecting you from spreading it. 3. Wearing a mask is no longer guaranteed effective (unless on internals), it now scales based on BIO armor. This is doubly effectively for people wearing a mask to stop spreading to others vs wearing a mask to block spreading to them. ## Why It's Good For The Game Wearing any kind of mask means airborne viruses will never spread, but also wearing any kind of mask on the opposite end is pointless unless on internals. Kinda silly. This PR unifies those behaviors. Wearing a mask to stop spread is still rewarded, as BIO armor is doubly effective at stopping a spread attempt as blocking a spread attempt. Ultimately the goal of this is to give players a realistic way to protect themselves against airborne transmission vectors besides staying on internals 100% of the time. ## Changelog 🆑 Melbert balance: Wearing a mask can now prevent you from being spread airborne diseases. Prior, it only stopped you from spreading it yourself. balance: Wearing a mask no longer 100% guarantees you don't spread viruses to others people - it now scales on the masks BIO armor. Get a sterile mask from Medical for max safety. balance: Wearing a mask to stop you from spreading to other people is doubly effective than wearing a mask to prevent spread to yourself - Mask up for the greater good! balance: Passive airborne virus spread attempts are now done every time you breathe (every eight seconds), rather than every two seconds. The chance of spread is the same, though - it has been scaled up to accommodate. code: Cleaned up a fair bid of airborne-transmission-code. Report any oddities. /🆑
187 lines
5.6 KiB
Plaintext
187 lines
5.6 KiB
Plaintext
|
|
/mob/living/proc/HasDisease(datum/disease/D)
|
|
for(var/thing in diseases)
|
|
var/datum/disease/DD = thing
|
|
if(D.IsSame(DD))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
|
|
/mob/living/proc/CanContractDisease(datum/disease/D)
|
|
if(stat == DEAD && !D.process_dead)
|
|
return FALSE
|
|
|
|
if(D.GetDiseaseID() in disease_resistances)
|
|
return FALSE
|
|
|
|
if(HasDisease(D))
|
|
return FALSE
|
|
|
|
if(!(D.infectable_biotypes & mob_biotypes))
|
|
return FALSE
|
|
|
|
if(!D.is_viable_mobtype(type))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
|
|
/mob/living/proc/ContactContractDisease(datum/disease/D)
|
|
if(!CanContractDisease(D))
|
|
return FALSE
|
|
D.try_infect(src)
|
|
|
|
|
|
/mob/living/carbon/ContactContractDisease(datum/disease/disease, target_zone)
|
|
if(!CanContractDisease(disease))
|
|
return FALSE
|
|
|
|
var/passed = TRUE
|
|
|
|
var/head_chance = 80
|
|
var/body_chance = 100
|
|
var/hands_chance = 35/2
|
|
var/feet_chance = 15/2
|
|
|
|
if(prob(15/disease.spreading_modifier))
|
|
return
|
|
|
|
if(satiety>0 && prob(satiety/2)) // positive satiety makes it harder to contract the disease.
|
|
return
|
|
|
|
if(!target_zone)
|
|
target_zone = pick_weight(list(
|
|
BODY_ZONE_HEAD = head_chance,
|
|
BODY_ZONE_CHEST = body_chance,
|
|
BODY_ZONE_R_ARM = hands_chance,
|
|
BODY_ZONE_L_ARM = hands_chance,
|
|
BODY_ZONE_R_LEG = feet_chance,
|
|
BODY_ZONE_L_LEG = feet_chance,
|
|
))
|
|
else
|
|
target_zone = check_zone(target_zone)
|
|
|
|
if(ishuman(src))
|
|
var/mob/living/carbon/human/infecting_human = src
|
|
|
|
if(HAS_TRAIT(infecting_human, TRAIT_VIRUS_RESISTANCE) && prob(75))
|
|
return
|
|
|
|
switch(target_zone)
|
|
if(BODY_ZONE_HEAD)
|
|
if(isobj(infecting_human.head))
|
|
passed = prob(100-infecting_human.head.get_armor_rating(BIO))
|
|
if(passed && isobj(infecting_human.wear_mask))
|
|
passed = prob(100-infecting_human.wear_mask.get_armor_rating(BIO))
|
|
if(passed && isobj(infecting_human.wear_neck))
|
|
passed = prob(100-infecting_human.wear_neck.get_armor_rating(BIO))
|
|
if(BODY_ZONE_CHEST)
|
|
if(isobj(infecting_human.wear_suit))
|
|
passed = prob(100-infecting_human.wear_suit.get_armor_rating(BIO))
|
|
if(passed && isobj(infecting_human.w_uniform))
|
|
passed = prob(100-infecting_human.w_uniform.get_armor_rating(BIO))
|
|
if(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
|
|
if(isobj(infecting_human.wear_suit) && infecting_human.wear_suit.body_parts_covered&HANDS)
|
|
passed = prob(100-infecting_human.wear_suit.get_armor_rating(BIO))
|
|
if(passed && isobj(infecting_human.gloves))
|
|
passed = prob(100-infecting_human.gloves.get_armor_rating(BIO))
|
|
if(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
|
if(isobj(infecting_human.wear_suit) && infecting_human.wear_suit.body_parts_covered&FEET)
|
|
passed = prob(100-infecting_human.wear_suit.get_armor_rating(BIO))
|
|
if(passed && isobj(infecting_human.shoes))
|
|
passed = prob(100-infecting_human.shoes.get_armor_rating(BIO))
|
|
|
|
if(passed)
|
|
disease.try_infect(src)
|
|
|
|
/**
|
|
* Handle being contracted a disease via airborne transmission
|
|
*
|
|
* * disease - the disease datum that's infecting us
|
|
*/
|
|
/mob/living/proc/contract_airborne_disease(datum/disease/disease)
|
|
if(!can_be_spread_airborne_disease())
|
|
return FALSE
|
|
if(!prob(min((50 * disease.spreading_modifier - 1), 50)))
|
|
return FALSE
|
|
if(!disease.has_required_infectious_organ(src, ORGAN_SLOT_LUNGS))
|
|
return FALSE
|
|
return ForceContractDisease(disease)
|
|
|
|
//Proc to use when you 100% want to try to infect someone (ignoreing protective clothing and such), as long as they aren't immune
|
|
/mob/living/proc/ForceContractDisease(datum/disease/D, make_copy = TRUE, del_on_fail = FALSE)
|
|
if(!CanContractDisease(D))
|
|
if(del_on_fail)
|
|
qdel(D)
|
|
return FALSE
|
|
if(!D.try_infect(src, make_copy))
|
|
if(del_on_fail)
|
|
qdel(D)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
|
|
/mob/living/carbon/human/CanContractDisease(datum/disease/disease)
|
|
if(dna)
|
|
if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !disease.bypasses_immunity)
|
|
return FALSE
|
|
if(disease.required_organ)
|
|
if(!disease.has_required_infectious_organ(src, disease.required_organ))
|
|
return FALSE
|
|
|
|
return ..()
|
|
|
|
/// Checks if this mob can currently spread air based diseases.
|
|
/// Nondeterministic
|
|
/mob/living/proc/can_spread_airborne_diseases()
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
if(HAS_TRAIT(src, TRAIT_NOBREATH))
|
|
return FALSE
|
|
if(losebreath >= 1)
|
|
return FALSE
|
|
// I don't know how you are spreading via air with no head but sure
|
|
if(!get_bodypart(BODY_ZONE_HEAD))
|
|
return TRUE
|
|
// Check both hat and mask for bio protection
|
|
// Anything above 50 individually is a shoe-in, and stacking two items at 25 is also a shoe-in
|
|
var/obj/item/clothing/hat = is_mouth_covered(ITEM_SLOT_HEAD)
|
|
var/obj/item/clothing/mask = is_mouth_covered(ITEM_SLOT_MASK)
|
|
var/total_prot = 2 * (hat?.get_armor_rating(BIO) + mask?.get_armor_rating(BIO))
|
|
if(prob(total_prot))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/mob/living/carbon/can_spread_airborne_diseases()
|
|
if(internal || external)
|
|
return FALSE
|
|
|
|
return ..()
|
|
|
|
/// Checks if this mob can currently be infected by air based diseases
|
|
/// Nondeterministic
|
|
/mob/living/proc/can_be_spread_airborne_disease()
|
|
if(HAS_TRAIT(src, TRAIT_NOBREATH))
|
|
return FALSE
|
|
if(losebreath >= 1)
|
|
return FALSE
|
|
// Spaceacillin for infection resistance
|
|
if(HAS_TRAIT(src, TRAIT_VIRUS_RESISTANCE) && prob(75))
|
|
return FALSE
|
|
// Bio check for head AND mask
|
|
// Meaning if we're masked up and wearing a dome, we are very likely never getting sick
|
|
var/obj/item/clothing/hat = is_mouth_covered(ITEM_SLOT_HEAD)
|
|
var/obj/item/clothing/mask = is_mouth_covered(ITEM_SLOT_MASK)
|
|
var/total_prot = (hat?.get_armor_rating(BIO) + mask?.get_armor_rating(BIO))
|
|
if(prob(total_prot))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/mob/living/carbon/can_be_spread_airborne_disease()
|
|
// Using an isolated air supply is also effective
|
|
if((internal || external) && prob(75))
|
|
return FALSE
|
|
|
|
return ..()
|