Files
Bubberstation/code/datums/components/infective.dm
SkyratBot 169c42a262 [MIRROR] Refactors connect_loc_behalf into a component (#7613)
* Refactors connect_loc_behalf into a component (#60678)

See title. Also refactors caltrops into a component because they use connect_loc_behalf which requires them to hold the state.

This also fixes COMPONENT_DUPE_SELECTIVE from just outright not working.

connect_loc_behalf doesn't make sense as an element because it tries to hold states. There is also no way to maintain current behaviour and not have the states that it needs.
Due to the fact that it tries to hold states, it means the code itself is a lot more buggy because it's a lot harder to successfully manage these states without runtimes or bugs. 

On metastation, there is only 2519 connect_loc_behalf components at roundstart. MrStonedOne has told me that datums take up this much space:
image

If we do the (oversimplified) math, there are only ever 5 variables that'll likely be changed on most connect_loc_behalf components at runtime:
connections,
tracked,
signal_atom,
parent,
signal_procs

This means that on metastation at roundstart, we take up this amount: (24 + 16 * 5) * 2519 = 261.97600 kilobytes
This is not really significant and the benefits of moving this to a component greatly outweighs the memory cost.

(Basically the memory cost is outweighed by the maint cost of tracking down issues with the thing. It's too buggy to be viable longterm basically)

* Update glass.dm

Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
Co-authored-by: Gandalf <jzo123@hotmail.com>
2021-08-17 20:29:11 +01:00

127 lines
4.3 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
/datum/component/infective/Initialize(list/datum/disease/_diseases, expire_in)
if(islist(_diseases))
diseases = _diseases
else
diseases = list(_diseases)
if(expire_in)
expire_time = world.time + expire_in
QDEL_IN(src, expire_in)
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
var/static/list/disease_connections = list(
COMSIG_ATOM_ENTERED = .proc/try_infect_crossed,
)
AddComponent(/datum/component/connect_loc_behalf, parent, disease_connections)
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean)
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/try_infect_buckle)
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, .proc/try_infect_collide)
RegisterSignal(parent, COMSIG_MOVABLE_IMPACT_ZONE, .proc/try_infect_impact_zone)
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_ZONE, .proc/try_infect_attack_zone)
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/try_infect_attack)
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/try_infect_equipped)
RegisterSignal(parent, COMSIG_FOOD_EATEN, .proc/try_infect_eat)
if(istype(parent, /obj/item/reagent_containers/food/drinks))
RegisterSignal(parent, COMSIG_DRINK_DRANK, .proc/try_infect_drink)
else if(istype(parent, /obj/item/reagent_containers/glass))
RegisterSignal(parent, COMSIG_GLASS_DRANK, .proc/try_infect_drink)
else if(istype(parent, /obj/effect/decal/cleanable/blood/gibs))
RegisterSignal(parent, COMSIG_GIBS_STREAK, .proc/try_infect_streak)
/datum/component/infective/proc/try_infect_eat(datum/source, mob/living/eater, mob/living/feeder)
SIGNAL_HANDLER
for(var/V in diseases)
eater.ForceContractDisease(V)
try_infect(feeder, BODY_ZONE_L_ARM)
/datum/component/infective/proc/try_infect_drink(datum/source, mob/living/drinker, mob/living/feeder)
SIGNAL_HANDLER
for(var/disease in diseases)
drinker.ForceContractDisease(disease)
var/appendage_zone = feeder.held_items.Find(source)
appendage_zone = appendage_zone == 0 ? BODY_ZONE_CHEST : appendage_zone % 2 ? BODY_ZONE_R_ARM : BODY_ZONE_L_ARM
try_infect(feeder, appendage_zone)
/datum/component/infective/proc/clean(datum/source, clean_types)
SIGNAL_HANDLER
. = NONE
if(clean_types & required_clean_types)
qdel(src)
return COMPONENT_CLEANED
/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(datum/source, mob/living/carbon/target, mob/living/user, hit_zone)
SIGNAL_HANDLER
try_infect(user, BODY_ZONE_L_ARM)
try_infect(target, hit_zone)
/datum/component/infective/proc/try_infect_attack(datum/source, mob/living/target, mob/living/user)
SIGNAL_HANDLER
if(!iscarbon(target)) //this case will be handled by try_infect_attack_zone
try_infect(target)
try_infect(user, BODY_ZONE_L_ARM)
/datum/component/infective/proc/try_infect_equipped(datum/source, mob/living/L, slot)
SIGNAL_HANDLER
var/old_permeability
if(isitem(parent))
//if you are putting an infective item on, it obviously will not protect you, so set its permeability high enough that it will never block ContactContractDisease()
var/obj/item/I = parent
old_permeability = I.permeability_coefficient
I.permeability_coefficient = 1.01
try_infect(L, slot2body_zone(slot))
if(isitem(parent))
var/obj/item/I = parent
I.permeability_coefficient = old_permeability
/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
output_diseases |= diseases
/datum/component/infective/proc/try_infect(mob/living/L, target_zone)
for(var/V in diseases)
L.ContactContractDisease(V, target_zone)