mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 18:22:14 +00:00
## About The Pull Request This has the potential to create a lot of needless mob updates which is not great. Now should only update a mob's clothing if it was actually washed. This PR 1) ensures that all wash() procs return a bitflag. 2) ensures that `wash()` proccalls which result in expensive operations like icon updates only do so when it is necessary ## Why It's Good For The Game Updating mob sprites is expensive, and doing it when nothing has been changed is bad. ## Changelog Nothing really player facing
204 lines
6.8 KiB
Plaintext
204 lines
6.8 KiB
Plaintext
/datum/component/infective
|
|
var/list/datum/disease/diseases //make sure these are the static, non-processing versions!
|
|
var/expire_time
|
|
var/required_clean_types = CLEAN_TYPE_DISEASE
|
|
/// The infection is weak and can only infect on consumption with small chance
|
|
var/is_weak = FALSE
|
|
/// Chance of weak infection on consumption
|
|
var/weak_infection_chance = 10
|
|
|
|
|
|
/datum/component/infective/Initialize(list/datum/disease/diseases, expire_in, weak = FALSE, weak_infection_chance = 10)
|
|
if(!ismovable(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
if(!islist(diseases))
|
|
diseases = list(diseases)
|
|
|
|
///Make sure the diseases list is populated with instances of diseases so that it doesn't have to be for each AddComponent call.
|
|
for(var/datum/disease/disease as anything in diseases)
|
|
if(!disease) //empty entry, remove.
|
|
diseases -= disease
|
|
if(ispath(disease, /datum/disease))
|
|
var/datum/disease/instance = new disease
|
|
diseases -= disease
|
|
diseases += instance
|
|
else if(!istype(disease))
|
|
stack_trace("found [isdatum(disease) ? "an instance of [disease.type]" : disease] inside the diseases list argument for [type]")
|
|
diseases -= disease
|
|
|
|
src.diseases = diseases
|
|
|
|
if(expire_in)
|
|
expire_time = world.time + expire_in
|
|
QDEL_IN(src, expire_in)
|
|
|
|
is_weak = weak
|
|
src.weak_infection_chance = weak_infection_chance
|
|
|
|
/datum/component/infective/Destroy()
|
|
QDEL_LIST(diseases)
|
|
return ..()
|
|
|
|
/datum/component/infective/RegisterWithParent()
|
|
if(is_weak && isitem(parent))
|
|
RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(try_infect_eat))
|
|
RegisterSignal(parent, COMSIG_PILL_CONSUMED, PROC_REF(try_infect_eat))
|
|
return
|
|
var/static/list/disease_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(try_infect_crossed),
|
|
)
|
|
AddComponent(/datum/component/connect_loc_behalf, parent, disease_connections)
|
|
|
|
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(clean))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, PROC_REF(try_infect_buckle))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(try_infect_collide))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_IMPACT_ZONE, PROC_REF(try_infect_impact_zone))
|
|
if(isitem(parent))
|
|
RegisterSignal(parent, COMSIG_ITEM_ATTACK_ZONE, PROC_REF(try_infect_attack_zone))
|
|
RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(try_infect_attack))
|
|
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(try_infect_equipped))
|
|
RegisterSignal(parent, COMSIG_FOOD_EATEN, PROC_REF(try_infect_eat))
|
|
RegisterSignal(parent, COMSIG_PILL_CONSUMED, PROC_REF(try_infect_eat))
|
|
if(istype(parent, /obj/item/reagent_containers/cup))
|
|
RegisterSignal(parent, COMSIG_GLASS_DRANK, PROC_REF(try_infect_drink))
|
|
if(isorgan(parent))
|
|
RegisterSignal(parent, COMSIG_ORGAN_IMPLANTED, PROC_REF(on_organ_insertion))
|
|
|
|
/datum/component/infective/UnregisterFromParent()
|
|
. = ..()
|
|
UnregisterSignal(parent, list(
|
|
COMSIG_FOOD_EATEN,
|
|
COMSIG_PILL_CONSUMED,
|
|
COMSIG_COMPONENT_CLEAN_ACT,
|
|
COMSIG_MOVABLE_BUMP,
|
|
COMSIG_MOVABLE_IMPACT_ZONE,
|
|
COMSIG_ITEM_ATTACK_ZONE,
|
|
COMSIG_ITEM_ATTACK,
|
|
COMSIG_ITEM_EQUIPPED,
|
|
COMSIG_GLASS_DRANK,
|
|
COMSIG_ORGAN_IMPLANTED,
|
|
))
|
|
qdel(GetComponent(/datum/component/connect_loc_behalf))
|
|
|
|
/datum/component/infective/proc/on_organ_insertion(obj/item/organ/target, mob/living/carbon/receiver)
|
|
SIGNAL_HANDLER
|
|
|
|
for(var/datum/disease/disease in diseases)
|
|
receiver.ForceContractDisease(disease)
|
|
|
|
qdel(src) // once organ is implanted delete the infective component
|
|
|
|
/datum/component/infective/proc/try_infect_eat(datum/source, mob/living/eater, mob/living/feeder)
|
|
SIGNAL_HANDLER
|
|
|
|
if(HAS_TRAIT(eater, TRAIT_STRONG_STOMACH))
|
|
return
|
|
|
|
eater.add_mood_event("disgust", /datum/mood_event/disgust/dirty_food)
|
|
|
|
for(var/datum/disease/disease as anything in diseases)
|
|
if(is_weak && !prob(weak_infection_chance))
|
|
continue
|
|
if(!disease.has_required_infectious_organ(eater, ORGAN_SLOT_STOMACH))
|
|
continue
|
|
|
|
eater.ForceContractDisease(disease)
|
|
|
|
if(!is_weak)
|
|
try_infect(feeder, BODY_ZONE_L_ARM)
|
|
|
|
/datum/component/infective/proc/try_infect_drink(datum/source, mob/living/drinker, mob/living/feeder)
|
|
SIGNAL_HANDLER
|
|
|
|
if(HAS_TRAIT(drinker, TRAIT_STRONG_STOMACH))
|
|
return
|
|
|
|
if(!is_weak)
|
|
var/appendage_zone = feeder.get_held_index_of_item(source)
|
|
appendage_zone = appendage_zone == 0 ? BODY_ZONE_CHEST : (IS_RIGHT_INDEX(appendage_zone) ? BODY_ZONE_R_ARM : BODY_ZONE_L_ARM)
|
|
try_infect(feeder, appendage_zone)
|
|
|
|
for(var/datum/disease/disease as anything in diseases)
|
|
if(is_weak && !prob(weak_infection_chance))
|
|
continue
|
|
if(!disease.has_required_infectious_organ(drinker, ORGAN_SLOT_STOMACH))
|
|
continue
|
|
|
|
drinker.ForceContractDisease(disease)
|
|
|
|
/datum/component/infective/proc/clean(datum/source, clean_types)
|
|
SIGNAL_HANDLER
|
|
|
|
. = NONE
|
|
if(clean_types & required_clean_types)
|
|
qdel(src)
|
|
return COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP
|
|
|
|
/datum/component/infective/proc/try_infect_buckle(datum/source, mob/M, force)
|
|
SIGNAL_HANDLER
|
|
|
|
if(isliving(M))
|
|
try_infect(M)
|
|
|
|
/datum/component/infective/proc/try_infect_collide(datum/source, atom/A)
|
|
SIGNAL_HANDLER
|
|
|
|
var/atom/movable/P = parent
|
|
if(P.throwing)
|
|
//this will be handled by try_infect_impact_zone()
|
|
return
|
|
if(isliving(A))
|
|
try_infect(A)
|
|
|
|
/datum/component/infective/proc/try_infect_impact_zone(datum/source, mob/living/target, hit_zone)
|
|
SIGNAL_HANDLER
|
|
|
|
try_infect(target, hit_zone)
|
|
|
|
/datum/component/infective/proc/try_infect_attack_zone(obj/item/source, mob/living/carbon/target, mob/living/user, hit_zone)
|
|
SIGNAL_HANDLER
|
|
|
|
try_infect(target, hit_zone)
|
|
|
|
/datum/component/infective/proc/try_infect_attack(obj/item/source, mob/living/target, mob/living/user)
|
|
SIGNAL_HANDLER
|
|
if(source.loc == user)
|
|
var/obj/item/bodypart/hand = user.get_active_hand()
|
|
try_infect(user, hand.body_zone)
|
|
|
|
/datum/component/infective/proc/try_infect_equipped(datum/source, mob/living/L, slot)
|
|
SIGNAL_HANDLER
|
|
|
|
var/old_bio_armor
|
|
if(isitem(parent))
|
|
//if you are putting an infective item on, it obviously will not protect you, so set its bio armor low enough that it will never block ContactContractDisease()
|
|
var/obj/item/equipped_item = parent
|
|
old_bio_armor = equipped_item.get_armor_rating(BIO)
|
|
equipped_item.set_armor_rating(BIO, 0)
|
|
|
|
try_infect(L, slot2body_zone(slot))
|
|
|
|
if(isitem(parent))
|
|
var/obj/item/equipped_item = parent
|
|
equipped_item.set_armor_rating(BIO, old_bio_armor)
|
|
|
|
/datum/component/infective/proc/try_infect_crossed(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
|
|
SIGNAL_HANDLER
|
|
|
|
if(isliving(arrived))
|
|
try_infect(arrived, BODY_ZONE_PRECISE_L_FOOT)
|
|
|
|
/datum/component/infective/proc/try_infect_streak(datum/source, list/directions, list/output_diseases)
|
|
SIGNAL_HANDLER
|
|
|
|
// This blood is not infectable / does not have a diseases list
|
|
if(!islist(output_diseases))
|
|
return
|
|
|
|
output_diseases |= diseases
|
|
|
|
/datum/component/infective/proc/try_infect(mob/living/L, target_zone)
|
|
for(var/V in diseases)
|
|
L.ContactContractDisease(V, target_zone)
|