From 3bf620006b20034541eaf772b1bd0cbf63de7375 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:49:04 +0200 Subject: [PATCH] [MIRROR] Moves cleaning to an atom proc to afterattack signal [MDB IGNORE] (#16813) * Moves cleaning to an atom proc to afterattack signal * Fixing conflict! Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: GoldenAlpharex --- code/__DEFINES/cleaning.dm | 3 + code/__DEFINES/dcs/signals/signals_janitor.dm | 3 - code/datums/components/cleaner.dm | 68 +++++++++++-------- code/game/atoms.dm | 18 +---- code/game/objects/items.dm | 19 ++++-- code/game/objects/items/clown_items.dm | 21 ++---- .../items/devices/forcefieldprojector.dm | 2 +- code/game/objects/items/mop.dm | 35 +++------- code/game/objects/structures/window.dm | 14 ++++ code/modules/mining/equipment/resonator.dm | 4 +- .../mob/living/simple_animal/bot/cleanbot.dm | 13 ++-- .../reagents/reagent_containers/cups/_cup.dm | 6 +- .../reagents/reagent_containers/misc.dm | 39 +++++------ 13 files changed, 122 insertions(+), 123 deletions(-) diff --git a/code/__DEFINES/cleaning.dm b/code/__DEFINES/cleaning.dm index c74fd5e46b1..7c954602215 100644 --- a/code/__DEFINES/cleaning.dm +++ b/code/__DEFINES/cleaning.dm @@ -1,6 +1,9 @@ // Cleaning flags +///Whether we should not attempt to clean. +#define DO_NOT_CLEAN "do_not_clean" + // Different kinds of things that can be cleaned. // Use these when overriding the wash proc or registering for the clean signals to check if your thing should be cleaned /// Cleans blood off of the cleanable atom. diff --git a/code/__DEFINES/dcs/signals/signals_janitor.dm b/code/__DEFINES/dcs/signals/signals_janitor.dm index 54e69e926e4..56ca8c96750 100644 --- a/code/__DEFINES/dcs/signals/signals_janitor.dm +++ b/code/__DEFINES/dcs/signals/signals_janitor.dm @@ -5,9 +5,6 @@ ///Returned by cleanable components when they are cleaned. #define COMPONENT_CLEANED (1<<0) -///Called from a cleaning tool to start cleaning something. -#define COMSIG_START_CLEANING "start_cleaning" - // Vacuum signals /// Called on a bag being attached to a vacuum parent #define COMSIG_VACUUM_BAG_ATTACH "comsig_vacuum_bag_attach" diff --git a/code/datums/components/cleaner.dm b/code/datums/components/cleaner.dm index b1232dbf8f9..2d10b32307d 100644 --- a/code/datums/components/cleaner.dm +++ b/code/datums/components/cleaner.dm @@ -14,6 +14,8 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan var/skill_duration_modifier_offset /// Determines what this cleaner can wash off, [the available options are found here](code/__DEFINES/cleaning.html). var/cleaning_strength + /// Gets called before you start cleaning, returns TRUE/FALSE whether the clean should actually wash tiles, or DO_NOT_CLEAN to not clean at all. + var/datum/callback/pre_clean_callback /// Gets called when something is successfully cleaned. var/datum/callback/on_cleaned_callback @@ -21,26 +23,44 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan base_cleaning_duration = 3 SECONDS, skill_duration_modifier_offset = 0, cleaning_strength = CLEAN_SCRUB, + datum/callback/pre_clean_callback = null, datum/callback/on_cleaned_callback = null, ) src.base_cleaning_duration = base_cleaning_duration src.skill_duration_modifier_offset = skill_duration_modifier_offset src.cleaning_strength = cleaning_strength + src.pre_clean_callback = pre_clean_callback src.on_cleaned_callback = on_cleaned_callback /datum/component/cleaner/Destroy(force, silent) + if(pre_clean_callback) + QDEL_NULL(pre_clean_callback) if(on_cleaned_callback) QDEL_NULL(on_cleaned_callback) return ..() /datum/component/cleaner/RegisterWithParent() - RegisterSignal(parent, COMSIG_START_CLEANING, .proc/on_start_cleaning) + if(isbot(parent)) + RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, .proc/on_unarmed_attack) + return + RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/on_afterattack) /datum/component/cleaner/UnregisterFromParent() - UnregisterSignal(parent, COMSIG_START_CLEANING) + if(isbot(parent)) + UnregisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK) + return + UnregisterSignal(parent, COMSIG_ITEM_AFTERATTACK) /** - * Handles the COMSIG_START_CLEANING signal by calling the clean proc. + * Handles the COMSIG_LIVING_UNARMED_ATTACK signal used for cleanbots + * Redirects to afterattack, while setting parent (the bot) as user. + */ +/datum/component/cleaner/proc/on_unarmed_attack(datum/source, atom/target, proximity_flags, modifiers) + SIGNAL_HANDLER + return on_afterattack(source, target, parent, proximity_flags, modifiers) + +/** + * Handles the COMSIG_ITEM_AFTERATTACK signal by calling the clean proc. * * Arguments * * source the datum that sent the signal to start cleaning @@ -48,8 +68,15 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan * * user the person doing the cleaning * * clean_target set this to false if the target should not be washed and if experience should not be awarded to the user */ -/datum/component/cleaner/proc/on_start_cleaning(datum/source, atom/target, mob/living/user, clean_target) +/datum/component/cleaner/proc/on_afterattack(datum/source, atom/target, mob/user, proximity_flag, click_parameters) SIGNAL_HANDLER + if(!proximity_flag) + return + var/clean_target + if(pre_clean_callback) + clean_target = pre_clean_callback?.Invoke(source, target, user) + if(clean_target == DO_NOT_CLEAN) + return INVOKE_ASYNC(src, .proc/clean, source, target, user, clean_target) //signal handlers can't have do_afters inside of them /** @@ -64,9 +91,7 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan * * clean_target set this to false if the target should not be washed and if experience should not be awarded to the user */ /datum/component/cleaner/proc/clean(datum/source, atom/target, mob/living/user, clean_target = TRUE) - //add the cleaning overlay - var/already_cleaning = HAS_TRAIT(target, CURRENTLY_CLEANING) //tracks if atom had the cleaning trait when you started cleaning - if(!already_cleaning) //add the trait and overlay + if(!HAS_TRAIT(target, CURRENTLY_CLEANING)) //add the trait and overlay ADD_TRAIT(target, CURRENTLY_CLEANING, src) if(target.plane > GLOB.cleaning_bubbles_lower.plane) //check if the higher overlay is necessary target.add_overlay(GLOB.cleaning_bubbles_higher) @@ -82,31 +107,20 @@ GLOBAL_DATUM_INIT(cleaning_bubbles_higher, /mutable_appearance, mutable_appearan var/cleaning_duration = base_cleaning_duration if(user.mind) //higher cleaning skill can make the duration shorter //offsets the multiplier you get from cleaning skill, but doesn't allow the duration to be longer than the base duration - cleaning_duration = cleaning_duration * min(user.mind.get_skill_modifier(/datum/skill/cleaning, SKILL_SPEED_MODIFIER)+skill_duration_modifier_offset,1) + cleaning_duration = (cleaning_duration * min(user.mind.get_skill_modifier(/datum/skill/cleaning, SKILL_SPEED_MODIFIER)+skill_duration_modifier_offset, 1)) //do the cleaning user.visible_message(span_notice("[user] starts to clean [target]!"), span_notice("You start to clean [target]...")) if(do_after(user, cleaning_duration, target = target)) user.visible_message(span_notice("[user] finishes cleaning [target]!"), span_notice("You finish cleaning [target].")) if(clean_target) - if(isturf(target)) //cleaning the floor and every bit of filth on top of it - for(var/obj/effect/decal/cleanable/cleanable_decal in target) //it's important to do this before you wash all of the cleanables off - user.mind?.adjust_experience(/datum/skill/cleaning, round(cleanable_decal.beauty / CLEAN_SKILL_BEAUTY_ADJUSTMENT)) - else if(istype(target, /obj/structure/window)) //window cleaning - target.set_opacity(initial(target.opacity)) - target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) - var/obj/structure/window/window = target - if(window.bloodied) - for(var/obj/effect/decal/cleanable/blood/iter_blood in window) - window.vis_contents -= iter_blood - qdel(iter_blood) - window.bloodied = FALSE - user.mind?.adjust_experience(/datum/skill/cleaning, round(CLEAN_SKILL_GENERIC_WASH_XP)) - target.wash(cleaning_strength) - on_cleaned_callback?.Invoke(source, target, user, clean_target) + for(var/obj/effect/decal/cleanable/cleanable_decal in target) //it's important to do this before you wash all of the cleanables off + user.mind?.adjust_experience(/datum/skill/cleaning, round(cleanable_decal.beauty / CLEAN_SKILL_BEAUTY_ADJUSTMENT)) + if(target.wash(cleaning_strength)) + user.mind?.adjust_experience(/datum/skill/cleaning, round(CLEAN_SKILL_GENERIC_WASH_XP)) + on_cleaned_callback?.Invoke(source, target, user) //remove the cleaning overlay - if(!already_cleaning) - target.cut_overlay(GLOB.cleaning_bubbles_lower) - target.cut_overlay(GLOB.cleaning_bubbles_higher) - REMOVE_TRAIT(target, CURRENTLY_CLEANING, src) + target.cut_overlay(GLOB.cleaning_bubbles_lower) + target.cut_overlay(GLOB.cleaning_bubbles_higher) + REMOVE_TRAIT(target, CURRENTLY_CLEANING, src) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 55b8567a2e2..fe975b6f7c3 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1167,15 +1167,14 @@ */ /atom/proc/wash(clean_types) SHOULD_CALL_PARENT(TRUE) - - . = FALSE if(SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, clean_types) & COMPONENT_CLEANED) - . = TRUE + return TRUE // Basically "if has washable coloration" if(length(atom_colours) >= WASHABLE_COLOUR_PRIORITY && atom_colours[WASHABLE_COLOUR_PRIORITY]) remove_atom_colour(WASHABLE_COLOUR_PRIORITY) return TRUE + return FALSE /** * call back when a var is edited on this atom @@ -2079,16 +2078,3 @@ if(caller && (caller.pass_flags & pass_flags_self)) return TRUE . = !density - -/** - * Starts cleaning something by sending the COMSIG_START_CLEANING signal. - * This signal is received by the [cleaner component](code/datums/components/cleaner.html). - * - * Arguments - * * source the datum to send the signal from - * * target the thing being cleaned - * * user the person doing the cleaning - * * clean_target set this to false if the target should not be washed and if experience should not be awarded to the user - */ -/atom/proc/start_cleaning(datum/source, atom/target, mob/living/user, clean_target = TRUE) - SEND_SIGNAL(source, COMSIG_START_CLEANING, target, user, clean_target) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 939bd522ce4..abda121ce3d 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -320,11 +320,20 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons /obj/item/proc/add_weapon_description() AddElement(/datum/element/weapon_description) -/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self) - if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside)) - return 0 - else - return 1 +/** + * Checks if an item is allowed to be used on an atom/target + * Returns TRUE if allowed. + * + * Args: + * target_self - Whether we will check if we (src) are in target, preventing people from using items on themselves. + * not_inside - Whether target (or target's loc) has to be a turf. + */ +/obj/item/proc/check_allowed_items(atom/target, not_inside = FALSE, target_self = FALSE) + if(!target_self && (src in target)) + return FALSE + if(not_inside && !isturf(target.loc) && !isturf(target)) + return FALSE + return TRUE /obj/item/blob_act(obj/structure/blob/B) if(B && B.loc == loc) diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 7fe6479e60c..fbe70c40948 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -33,7 +33,7 @@ /obj/item/soap/Initialize(mapload) . = ..() AddComponent(/datum/component/slippery, 80) - AddComponent(/datum/component/cleaner, cleanspeed, 0.1, on_cleaned_callback=CALLBACK(src, .proc/decreaseUses)) //less scaling for soapies + AddComponent(/datum/component/cleaner, cleanspeed, 0.1, pre_clean_callback=CALLBACK(src, .proc/should_clean), on_cleaned_callback=CALLBACK(src, .proc/decreaseUses)) //less scaling for soapies /obj/item/soap/examine(mob/user) . = ..() @@ -116,6 +116,9 @@ new /obj/effect/particle_effect/fluid/foam(loc) return (TOXLOSS) +/obj/item/soap/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner) + return check_allowed_items(atom_to_clean) + /** * Decrease the number of uses the bar of soap has. * @@ -141,25 +144,11 @@ /obj/item/soap/nanotrasen/cyborg/noUses(mob/user) to_chat(user, span_warning("The soap has ran out of chemicals")) -/obj/item/soap/afterattack(atom/target, mob/user, proximity) - . = ..() - if(!proximity || !check_allowed_items(target)) - return - if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH) //washing that potty mouth of yours - var/mob/living/carbon/human/human_target = target - user.visible_message(span_warning("\the [user] washes \the [target]'s mouth out with [src.name]!"), span_notice("You wash \the [target]'s mouth out with [src.name]!")) //washes mouth out with soap sounds better than 'the soap' here if(user.zone_selected == "mouth") - if(human_target.lip_style) - user.mind?.adjust_experience(/datum/skill/cleaning, CLEAN_SKILL_GENERIC_WASH_XP) - human_target.update_lips(null) - decreaseUses(src, target, user) - return - start_cleaning(src, target, user) //normal cleaning - /obj/item/soap/nanotrasen/cyborg/afterattack(atom/target, mob/user, proximity) if(uses <= 0) to_chat(user, span_warning("No good, you need to recharge!")) return - . = ..() + return ..() /* diff --git a/code/game/objects/items/devices/forcefieldprojector.dm b/code/game/objects/items/devices/forcefieldprojector.dm index 0ff6a8eb5a2..c6ef851c69d 100644 --- a/code/game/objects/items/devices/forcefieldprojector.dm +++ b/code/game/objects/items/devices/forcefieldprojector.dm @@ -23,7 +23,7 @@ /obj/item/forcefield_projector/afterattack(atom/target, mob/user, proximity_flag) . = ..() - if(!check_allowed_items(target, 1)) + if(!check_allowed_items(target, not_inside = TRUE)) return if(istype(target, /obj/structure/projected_forcefield)) var/obj/structure/projected_forcefield/F = target diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index f2ddba89d9b..b123398e652 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -23,7 +23,7 @@ /obj/item/mop/Initialize(mapload) . = ..() - AddComponent(/datum/component/cleaner, mopspeed, on_cleaned_callback=CALLBACK(src, .proc/apply_reagents)) + AddComponent(/datum/component/cleaner, mopspeed, pre_clean_callback=CALLBACK(src, .proc/should_clean), on_cleaned_callback=CALLBACK(src, .proc/apply_reagents)) create_reagents(max_reagent_volume) GLOB.janitor_devices += src AddElement(/datum/element/liquids_interaction, on_interaction_callback = /obj/item/mop/.proc/attack_on_liquids_turf) //SKYRAT EDIT ADDITION - Liquids @@ -32,6 +32,15 @@ GLOB.janitor_devices -= src return ..() +///Checks whether or not we should clean. +/obj/item/mop/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner) + if(istype(atom_to_clean, /obj/item/reagent_containers/cup/bucket) || istype(atom_to_clean, /obj/structure/janitorialcart)) + return DO_NOT_CLEAN + if(reagents.total_volume < 0.1) + to_chat(cleaner, span_warning("Your mop is dry!")) + return DO_NOT_CLEAN + return reagents.has_chemical_flag(REAGENT_CLEANS, 1) + /** * Applies reagents to the cleaned floor and removes them from the mop. * @@ -44,31 +53,9 @@ reagents.expose(cleaned_turf, TOUCH, 10) //Needed for proper floor wetting. var/val2remove = 1 if(cleaner?.mind) - val2remove = round(cleaner.mind.get_skill_modifier(/datum/skill/cleaning, SKILL_SPEED_MODIFIER),0.1) + val2remove = round(cleaner.mind.get_skill_modifier(/datum/skill/cleaning, SKILL_SPEED_MODIFIER), 0.1) reagents.remove_any(val2remove) //reaction() doesn't use up the reagents -/obj/item/mop/afterattack(atom/A, mob/user, proximity) - . = ..() - //SKYRAT EDIT ADDITION - if(.) - return - //SKYRAT EDIT END - if(!proximity) - return - - if(reagents.total_volume < 0.1) - to_chat(user, span_warning("Your mop is dry!")) - return - - var/turf/T = get_turf(A) - - if(istype(A, /obj/item/reagent_containers/cup/bucket) || istype(A, /obj/structure/janitorialcart)) - return - - if(T) - var/should_clean = reagents.has_chemical_flag(REAGENT_CLEANS, 1) - start_cleaning(src, T, user, clean_target = should_clean) - /obj/item/mop/cyborg/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NODROP, CYBORG_ITEM_TRAIT) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 1049ec6db49..86683743bae 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -348,6 +348,20 @@ else set_opacity(initial(opacity)) +/obj/structure/window/wash(clean_types) + . = ..() + if(!(clean_types & CLEAN_SCRUB)) + return + set_opacity(initial(opacity)) + remove_atom_colour(WASHABLE_COLOUR_PRIORITY) + for(var/atom/movable/cleanables as anything in src) + if(cleanables == src) + continue + if(!cleanables.wash(clean_types)) + continue + vis_contents -= cleanables + bloodied = FALSE + /obj/structure/window/Destroy() set_density(FALSE) air_update_turf(TRUE, FALSE) diff --git a/code/modules/mining/equipment/resonator.dm b/code/modules/mining/equipment/resonator.dm index ef7ddc83161..2f1e7731bc8 100644 --- a/code/modules/mining/equipment/resonator.dm +++ b/code/modules/mining/equipment/resonator.dm @@ -43,9 +43,9 @@ user.changeNext_move(CLICK_CD_MELEE) /obj/item/resonator/pre_attack(atom/target, mob/user, params) - if(check_allowed_items(target, TRUE)) + if(check_allowed_items(target, not_inside = TRUE)) create_resonance(target, user) - . = ..() + return ..() //resonance field, crushes rock, damages mobs /obj/effect/temp_visual/resonance diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index e4b7531ec8f..d2dcf0905aa 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -97,6 +97,7 @@ /mob/living/simple_animal/bot/cleanbot/Initialize(mapload) . = ..() + AddComponent(/datum/component/cleaner, CLEANBOT_CLEANING_TIME, \ on_cleaned_callback = CALLBACK(src, /atom/.proc/update_appearance, UPDATE_ICON)) @@ -121,7 +122,7 @@ /mob/living/simple_animal/bot/cleanbot/examine(mob/user) . = ..() if(!weapon) - return + return . . += "[span_warning("Is that \a [weapon] taped to it...?")]" if(ascended && user.stat == CONSCIOUS && user.client) @@ -239,9 +240,9 @@ if(bot_cover_flags & BOT_COVER_EMAGGED) //Emag functions var/mob/living/carbon/victim = locate(/mob/living/carbon) in loc if(victim && victim == target) - UnarmedAttack(victim) // Acid spray + UnarmedAttack(victim, proximity_flag = TRUE) // Acid spray if(isopenturf(loc) && prob(15)) // Wets floors and spawns foam randomly - UnarmedAttack(src) + UnarmedAttack(src, proximity_flag = TRUE) else if(prob(5)) audible_message("[src] makes an excited beeping booping sound!") @@ -267,7 +268,7 @@ shuffle = TRUE //Shuffle the list the next time we scan so we dont both go the same way. path = list() else - UnarmedAttack(target) //Rather than check at every step of the way, let's check before we do an action, so we can rescan before the other bot. + UnarmedAttack(target, proximity_flag = TRUE) //Rather than check at every step of the way, let's check before we do an action, so we can rescan before the other bot. if(QDELETED(target)) //We done here. target = null mode = BOT_IDLE @@ -333,12 +334,10 @@ /mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers) if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED)) return - . = ..() if(ismopable(attack_target)) mode = BOT_CLEANING update_icon_state() - var/turf/turf_to_clean = get_turf(attack_target) - start_cleaning(src, turf_to_clean, src) + . = ..() target = null mode = BOT_IDLE diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 16e3f4ab9cd..376d3462098 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -98,9 +98,9 @@ if(LAZYLEN(diseases_to_add)) AddComponent(/datum/component/infective, diseases_to_add) -/obj/item/reagent_containers/cup/afterattack(obj/target, mob/living/user, proximity) +/obj/item/reagent_containers/cup/afterattack(atom/target, mob/user, proximity_flag, click_parameters) . = ..() - if((!proximity) || !check_allowed_items(target,target_self=1)) + if((!proximity_flag) || !check_allowed_items(target, target_self = TRUE)) return if(!spillable) @@ -133,7 +133,7 @@ target.update_appearance() /obj/item/reagent_containers/cup/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters) - if((!proximity_flag) || !check_allowed_items(target,target_self=1)) + if((!proximity_flag) || !check_allowed_items(target, target_self = TRUE)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN if(!spillable) diff --git a/code/modules/reagents/reagent_containers/misc.dm b/code/modules/reagents/reagent_containers/misc.dm index 894458433e1..b8ebc89fafe 100644 --- a/code/modules/reagents/reagent_containers/misc.dm +++ b/code/modules/reagents/reagent_containers/misc.dm @@ -131,29 +131,30 @@ /obj/item/reagent_containers/cup/rag/Initialize(mapload) . = ..() - AddComponent(/datum/component/cleaner, 3 SECONDS) + AddComponent(/datum/component/cleaner, 3 SECONDS, pre_clean_callback=CALLBACK(src, .proc/should_clean)) /obj/item/reagent_containers/cup/rag/suicide_act(mob/user) user.visible_message(span_suicide("[user] is smothering [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return (OXYLOSS) -/obj/item/reagent_containers/cup/rag/afterattack(atom/A as obj|turf|area, mob/living/user,proximity) - . = ..() - if(!proximity) +/obj/item/reagent_containers/cup/rag/afterattack(atom/target, mob/living/user, proximity_flag, click_parameters) + if(!proximity_flag) return - if(iscarbon(A) && reagents?.total_volume) - var/mob/living/carbon/C = A - var/reagentlist = pretty_string_from_reagent_list(reagents.reagent_list) - var/log_object = "containing [reagentlist]" - if(user.combat_mode && !C.is_mouth_covered()) - reagents.trans_to(C, reagents.total_volume, transfered_by = user, methods = INGEST) - C.visible_message(span_danger("[user] smothers \the [C] with \the [src]!"), span_userdanger("[user] smothers you with \the [src]!"), span_hear("You hear some struggling and muffled cries of surprise.")) - log_combat(user, C, "smothered", src, log_object) - else - reagents.expose(C, TOUCH) - reagents.clear_reagents() - C.visible_message(span_notice("[user] touches \the [C] with \the [src].")) - log_combat(user, C, "touched", src, log_object) + if(!iscarbon(target) || !reagents?.total_volume) + return ..() + var/mob/living/carbon/carbon_target = target + var/reagentlist = pretty_string_from_reagent_list(reagents.reagent_list) + var/log_object = "containing [reagentlist]" + if(user.combat_mode && !carbon_target.is_mouth_covered()) + reagents.trans_to(carbon_target, reagents.total_volume, transfered_by = user, methods = INGEST) + carbon_target.visible_message(span_danger("[user] smothers \the [carbon_target] with \the [src]!"), span_userdanger("[user] smothers you with \the [src]!"), span_hear("You hear some struggling and muffled cries of surprise.")) + log_combat(user, carbon_target, "smothered", src, log_object) + else + reagents.expose(carbon_target, TOUCH) + reagents.clear_reagents() + carbon_target.visible_message(span_notice("[user] touches \the [carbon_target] with \the [src].")) + log_combat(user, carbon_target, "touched", src, log_object) - else if(istype(A) && (src in user)) - start_cleaning(src, A, user) +///Checks whether or not we should clean. +/obj/item/reagent_containers/cup/rag/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner) + return (src in cleaner)