From 6a876e1994b97fb3b1b719fa67e7a457d80679c7 Mon Sep 17 00:00:00 2001 From: FloFluoro <3611705+FloFluoro@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:25:00 -0400 Subject: [PATCH] Standardize cleaning object behavior into "cleaning_act" proc (#19001) * Standardizes cleaning item functionality into "cleaning_act" proc * Culling commented-out code * Damp rag now checks for humans before cleaning * Change proc scoping, moved mop reagent check out of cleaning.dm * Adds can_clean and post_clean procs to handle mopping, removes ismop parameter * Adds can_clean() to cleaning objects/mobs * cleaning_act() now carries message strings as params * Refactored cleaning_act() for earlier returns and less redundancy * cleaning_act now runs on the target atom, instead of the cleaning object * Changed turf checks to overrides, rescoped clean_turf, lots of tidying * Removed cleaner param from post_clean, since it'll always be src * Code review tidying * Tidying.......... * Removed clean_turf and put its functionality in turf/simulated/cleaning_act(), added new param to keep track of original targeted object * Moved cleaning.dm from datums to code/game/objects * Added early return, defined cleanspeed in seconds --- code/game/gamemodes/cult/runes.dm | 8 +++ code/game/machinery/doors/door.dm | 22 +------- code/game/objects/cleaning.dm | 53 +++++++++++++++++++ code/game/objects/effects/decals/cleanable.dm | 8 +++ code/game/objects/items/weapons/mop.dm | 36 ++++++------- code/game/objects/items/weapons/soap.dm | 40 +++----------- code/game/turfs/simulated.dm | 12 +++++ .../detective_work/footprints_and_rag.dm | 15 +++--- .../mob/living/simple_animal/hostile/alien.dm | 16 +++--- paradise.dme | 1 + 10 files changed, 123 insertions(+), 88 deletions(-) create mode 100644 code/game/objects/cleaning.dm diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 2dd6444094b..77c4075081d 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -133,6 +133,14 @@ To draw a rune, use a ritual dagger. /obj/effect/rune/is_cleanable() return TRUE +/obj/effect/rune/cleaning_act(mob/user, atom/cleaner, cleanspeed = 5 SECONDS, text_verb = "scrub out", text_description = " with [cleaner].") + if(issimulatedturf(loc)) + var/turf/simulated/T = get_turf(src) + T.cleaning_act(user, cleaner, cleanspeed = cleanspeed, text_verb = text_verb, text_description = text_description, text_targetname = name) //Strings are deliberately "A = A" to avoid overrides + return + else + ..() + /* There are a few different procs each rune runs through when a cultist activates it. diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 0c442fd217e..d8646749a6d 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -249,27 +249,9 @@ /obj/machinery/door/proc/try_to_crowbar(mob/user, obj/item/I) return -/obj/machinery/door/proc/clean_cmag_ooze(obj/item/I, mob/user) //Emags are Engineering's problem, cmags are the janitor's problem - var/cleaning = FALSE - if(istype(I, /obj/item/reagent_containers/spray/cleaner)) - var/obj/item/reagent_containers/spray/cleaner/C = I - if(C.reagents.total_volume >= C.amount_per_transfer_from_this) - cleaning = TRUE - else - return - if(istype(I, /obj/item/soap)) - cleaning = TRUE - - if(!cleaning) - return - user.visible_message("[user] starts to clean the ooze off the access panel.", "You start to clean the ooze off the access panel.") - if(do_after(user, 50, target = src)) - user.visible_message("[user] cleans the ooze off [src].", "You clean the ooze off [src].") - REMOVE_TRAIT(src, TRAIT_CMAGGED, "clown_emag") - /obj/machinery/door/attackby(obj/item/I, mob/user, params) - if(HAS_TRAIT(src, TRAIT_CMAGGED)) - clean_cmag_ooze(I, user) + if(HAS_TRAIT(src, TRAIT_CMAGGED) && I.can_clean()) //If the cmagged door is being hit with cleaning supplies, don't open it, it's being cleaned! + return if(user.a_intent != INTENT_HARM && istype(I, /obj/item/twohanded/fireaxe)) try_to_crowbar(user, I) diff --git a/code/game/objects/cleaning.dm b/code/game/objects/cleaning.dm new file mode 100644 index 00000000000..60198d8e2df --- /dev/null +++ b/code/game/objects/cleaning.dm @@ -0,0 +1,53 @@ +#define CMAG_CLEANTIME 50 //The cleaning time for cmagged objects is locked to this, for balance reasons + + +//For handling standard click-to-clean items like soap and mops. + +//text_verb and text_description carry strings that, when pieced together by this proc, make the cleaning messages. +//text_verb is the verb that'll be used for cleaning, i.e. "User begins to [mop] the floor." + +//text_description by default appends the name of the cleaning object to the cleaning message, i.e. "User begins to clean the floor[ with soap.]" +//If text_description is ".", the sentence will end early (so you don't say "Lusty Xenomorph Maid begins to clean the floor with the Lusty Xenomorph Maid") + +//text_targetname is the name of the object being interacted with, i.e. "User begins to scrub out the [rune] with the damp rag." +//Can normally be left alone, but needs to be defined if the thing being cleaned isn't necessarily the thing being clicked on, +//such as /obj/effect/rune/cleaning_act() bouncing to turf/simulated/cleaning_act(). + +/atom/proc/cleaning_act(mob/user, atom/cleaner, cleanspeed = 5 SECONDS, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name) + var/is_cmagged = FALSE + + if(user.client && (src in user.client.screen)) //You can't clean items you're wearing for technical reasons + to_chat(user, "You need to take that [text_targetname] off before cleaning it.") + return FALSE + + if(HAS_TRAIT(src, TRAIT_CMAGGED)) //So we don't need a cleaning_act for every cmaggable object + is_cmagged = TRUE + text_verb = "clean the ooze off" + cleanspeed = CMAG_CLEANTIME + + user.visible_message("[user] begins to [text_verb] \the [text_targetname][text_description]") + if(!do_after(user, cleanspeed, target = src)) + return FALSE + + cleaner.post_clean(src, user) + + if(!cleaner.can_clean()) + return FALSE + + user.visible_message("You [text_verb] \the [text_targetname][text_description]") + + if(is_cmagged) //If we've cleaned a cmagged object + REMOVE_TRAIT(src, TRAIT_CMAGGED, "clown_emag") + return TRUE + else + //Generic cleaning functionality + var/obj/effect/decal/cleanable/C = locate() in src + qdel(C) + clean_blood() + return TRUE + +/atom/proc/can_clean() //For determining if a cleaning object can actually remove decals + return FALSE + +/atom/proc/post_clean(atom/target, mob/user) //For specific cleaning object behaviors after cleaning, such as mops making floors slippery. + return diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index ef10a43ff5e..fc66c80ed1a 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -7,6 +7,14 @@ if(mergeable_decal) return TRUE +/obj/effect/decal/cleanable/cleaning_act(mob/user, atom/cleaner, cleanspeed = 5 SECONDS, text_verb = "scrub out", text_description = " with [cleaner].") + if(issimulatedturf(loc)) + var/turf/simulated/T = get_turf(src) + T.cleaning_act(user, cleaner, cleanspeed = cleanspeed, text_verb = text_verb, text_description = text_description, text_targetname = name) //Strings are deliberately "A = A" to avoid overrides + return + else + ..() + //Add "bloodiness" of this blood's type, to the human's shoes //This is on /cleanable because fuck this ancient mess /obj/effect/decal/cleanable/blood/Crossed(atom/movable/O) diff --git a/code/game/objects/items/weapons/mop.dm b/code/game/objects/items/weapons/mop.dm index b25e31d3794..268e5d9e663 100644 --- a/code/game/objects/items/weapons/mop.dm +++ b/code/game/objects/items/weapons/mop.dm @@ -35,33 +35,27 @@ to_chat(user, "You wet [src] in [o].") playsound(loc, 'sound/effects/slosh.ogg', 25, 1) -/obj/item/mop/proc/clean(turf/simulated/A) - if(reagents.has_reagent("water", 1) || reagents.has_reagent("cleaner", 1) || reagents.has_reagent("holywater", 1)) - A.clean_blood() - for(var/obj/effect/O in A) - if(O.is_cleanable()) - qdel(O) - reagents.reaction(A, REAGENT_TOUCH, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. - reagents.remove_any(1) //reaction() doesn't use up the reagents - /obj/item/mop/afterattack(atom/A, mob/user, proximity) - if(!proximity) return - + if(!proximity) + return + if(istype(A, /obj/item/reagent_containers/glass/bucket) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/structure/mopbucket)) + return if(reagents.total_volume < 1) to_chat(user, "Your mop is dry!") return + A.cleaning_act(user, src, mopspeed, text_verb = "mop", text_description = ".") - var/turf/simulated/T = get_turf(A) +/obj/item/mop/can_clean() + if(reagents.has_reagent("water", 1) || reagents.has_reagent("cleaner", 1) || reagents.has_reagent("holywater", 1)) + return TRUE + else + return FALSE - if(istype(A, /obj/item/reagent_containers/glass/bucket) || istype(A, /obj/structure/janitorialcart) || istype(A, /obj/structure/mopbucket)) - return - - if(istype(T)) - user.visible_message("[user] begins to clean [T] with [src].", "You begin to clean [T] with [src]...") - - if(do_after(user, src.mopspeed, target = T)) - to_chat(user, "You finish mopping.") - clean(T) +/obj/item/mop/post_clean(atom/target, mob/user) + var/turf/T = get_turf(target) + if(issimulatedturf(T)) + reagents.reaction(T, REAGENT_TOUCH, 10) //10 is the multiplier for the reaction effect. probably needed to wet the floor properly. + reagents.remove_any(1) //reaction() doesn't use up the reagents /obj/effect/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/mop) || istype(I, /obj/item/soap)) diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm index b1b9fa2eb5b..e2ef0fb6487 100644 --- a/code/game/objects/items/weapons/soap.dm +++ b/code/game/objects/items/weapons/soap.dm @@ -18,43 +18,16 @@ AddComponent(/datum/component/slippery, src, 8 SECONDS, 100, 0, FALSE) /obj/item/soap/afterattack(atom/target, mob/user, proximity) - if(!proximity) return - //I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing. - //So this is a workaround. This also makes more sense from an IC standpoint. ~Carn - if(user.client && (target in user.client.screen)) - to_chat(user, "You need to take that [target.name] off before cleaning it.") - else if(target == user && user.a_intent == INTENT_GRAB && ishuman(target)) + if(!proximity) + return + if(target == user && user.a_intent == INTENT_GRAB && ishuman(target)) var/mob/living/carbon/human/muncher = user if(muncher && isdrask(muncher)) to_chat(user, "You take a bite of [src]. Delicious!") playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0) user.adjust_nutrition(2) - else if(istype(target, /obj/effect/decal/cleanable) || istype(target, /obj/effect/rune)) - user.visible_message("[user] begins to scrub \the [target.name] out with [src].") - if(do_after(user, cleanspeed, target = target) && target) - to_chat(user, "You scrub \the [target.name] out.") - if(issimulatedturf(target.loc)) - clean_turf(target.loc) - return - qdel(target) - else if(issimulatedturf(target)) - user.visible_message("[user] begins to clean \the [target.name] with [src].") - if(do_after(user, cleanspeed, target = target)) - to_chat(user, "You clean \the [target.name].") - clean_turf(target) - else - user.visible_message("[user] begins to clean \the [target.name] with [src].") - if(do_after(user, cleanspeed, target = target)) - to_chat(user, "You clean \the [target.name].") - var/obj/effect/decal/cleanable/C = locate() in target - qdel(C) - target.clean_blood() - -/obj/item/soap/proc/clean_turf(turf/simulated/T) - T.clean_blood() - for(var/obj/effect/O in T) - if(O.is_cleanable()) - qdel(O) + return + target.cleaning_act(user, src, cleanspeed) /obj/item/soap/attack(mob/target as mob, mob/user as mob) if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_selected == "mouth" ) @@ -62,6 +35,9 @@ return ..() +/obj/item/soap/can_clean() + return TRUE + /obj/item/soap/nanotrasen desc = "A Nanotrasen brand bar of soap. Smells of plasma." icon_state = "soapnt" diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 442ee9c6b44..f63c24dd90e 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -16,6 +16,18 @@ /turf/simulated/proc/burn_tile() return +/turf/simulated/cleaning_act(mob/user, atom/cleaner, cleanspeed = 50, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name) + if(!..()) + return + + if(!cleaner.can_clean()) + return + + clean_blood() + for(var/obj/effect/O in src) + if(O.is_cleanable()) + qdel(O) + /turf/simulated/water_act(volume, temperature, source) . = ..() diff --git a/code/modules/detective_work/footprints_and_rag.dm b/code/modules/detective_work/footprints_and_rag.dm index 39486444e81..92ce57b5936 100644 --- a/code/modules/detective_work/footprints_and_rag.dm +++ b/code/modules/detective_work/footprints_and_rag.dm @@ -33,11 +33,10 @@ else ..() -/obj/item/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user as mob,proximity) - if(!proximity) return - if(istype(A) && (src in user)) - user.visible_message("[user] starts to wipe down [A] with [src]!") - if(do_after(user, wipespeed, target = A)) - user.visible_message("[user] finishes wiping off [A]!") - A.clean_blood() - return +/obj/item/reagent_containers/glass/rag/afterattack(atom/target, mob/user, proximity) + if(!proximity || ishuman(target)) //Human check so we don't clean the person we're trying to ether + return + target.cleaning_act(user, src, wipespeed) + +/obj/item/reagent_containers/glass/rag/can_clean() + return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index ae3167612dd..423753aa5b2 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -151,14 +151,16 @@ icon_state = "maid" icon_living = "maid" icon_dead = "maid_dead" + var/cleanspeed = 15 /mob/living/simple_animal/hostile/alien/maid/AttackingTarget() - if(ismovable(target)) - if(istype(target, /obj/effect/decal/cleanable)) - visible_message("\The [src] cleans up \the [target].") - qdel(target) - return TRUE - var/atom/movable/M = target - M.clean_blood() + if(ishuman(target)) + var/atom/movable/H = target + H.clean_blood() visible_message("\The [src] polishes \the [target].") return TRUE + target.cleaning_act(src, src, cleanspeed, text_description = ".") //LXM is both the user and the cleaning implement itself. Wow! + +/mob/living/simple_animal/hostile/alien/maid/can_clean() + return TRUE + diff --git a/paradise.dme b/paradise.dme index 34b286d6e26..297b941f4bf 100644 --- a/paradise.dme +++ b/paradise.dme @@ -804,6 +804,7 @@ #include "code\game\mecha\working\ripley.dm" #include "code\game\mecha\working\working.dm" #include "code\game\objects\buckling.dm" +#include "code\game\objects\cleaning.dm" #include "code\game\objects\empulse.dm" #include "code\game\objects\explosion.dm" #include "code\game\objects\items.dm"