Files
Bubberstation/code/game/objects/effects/decals/cleanable.dm
T
MrMelbertandRoxy ec3f5acec0 [MDB Ignore] Damp Rag can now get dirty / Repaths damp rag (it's no longer a cup) (#90700)
- Damp rag is now no longer god's perfect cleaning tool. After blood,
the damp rag will collect it, and after cleaning a lot of blood, you can
no longer clean with the rag until you wash it in a sink (or with
cleaner or however you want)
- This means the rag will collect DNA in it as you clean, which gives
detectives an opportunity to investigate.
- It also means the DNA it collects will occasionally spread onto you,
meaning you will have to clean your gloves or hands.
- Cleaning vomit and such is (currently) unaffected (and does not dirty
the rag).
- Diseases are not currently transferred to the rag (but this would be
fun to add)

- Gauze now gets dirty when using it to wrap bleeding wounds. This is
just visual, though blood DNA gets transferred. It can be washed in a
sink.

- Removed gauze on sink / cloth on sink interaction.
   - Can't really wash gauze with it, plus it's redundant.

- Damp rag is no longer a cup.

Damp rag is just "soap without any downsides", which is kinda lame.
I thought about going a step further and making it require you wet it
first but then it just becomes "mop but small" which is also lame.

Instead, you're required to clean it, which gives janitors / crewmembers
an alternate cleaning method:
- Soap: Small, finite, limited. Can't be replenished.
- Cleaner: Small, finite, even more limited, ranged. Can be refilled
with chemistry's help.
- Mop: Large, infinite, limited. Needs a water bucket.
- Damp Rag: Small, infinite, limited. Need to clean it after a few goes.

🆑 Melbert
balance: Damp Rags can now get dirty when using them to clean blood,
passing blood DNA along.
add: Gauze now gets dirty when apply it to actively bleeding wounds.
Doesn't spread disease or anything, just passes blood DNA. It can be
cleaned in a sink.
del: Removed cloth on sink / gauze on sink interaction to make rags.
Just use the crafting menu
/🆑
2025-05-22 21:14:47 -04:00

161 lines
5.7 KiB
Plaintext

/obj/effect/decal/cleanable
gender = PLURAL
layer = CLEANABLE_FLOOR_OBJECT_LAYER
var/list/random_icon_states = null
///I'm sorry but cleanable/blood code is ass, and so is blood_DNA
var/blood_state = ""
///0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
var/bloodiness = 0
///When two of these are on a same tile or do we need to merge them into just one?
var/mergeable_decal = TRUE
var/beauty = 0
///The type of cleaning required to clean the decal. See __DEFINES/cleaning.dm for the options
var/clean_type = CLEAN_TYPE_LIGHT_DECAL
///The reagent this decal holds. Leave blank for none.
var/datum/reagent/decal_reagent
///The amount of reagent this decal holds, if decal_reagent is defined
var/reagent_amount = 0
/// If TRUE, gains TRAIT_MOPABLE on init - thus this cleanable will cleaned if its turf is cleaned
/// Set to FALSE for things that hang high on the walls or things which generally shouldn't be mopped up
var/is_mopped = TRUE
/// Creates a cleanable decal on a turf
/// Use this if your decal is one of one, and thus we should not spawn it if it's there already
/// Returns either the existing cleanable, the one we created, or null if we can't spawn on that turf
/turf/proc/spawn_unique_cleanable(obj/effect/decal/cleanable/cleanable_type)
var/turf/checkturf = src
while (isgroundlessturf(checkturf) && checkturf.zPassOut(DOWN))
var/turf/below = GET_TURF_BELOW(checkturf)
if (!below || !below.zPassIn(DOWN))
break
checkturf = below
// There is no need to spam unique cleanables, they don't stack and it just chews cpu
var/obj/effect/decal/cleanable/existing = locate(cleanable_type) in checkturf
if(existing)
return existing
return new cleanable_type(checkturf)
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
. = ..()
if (random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
icon_state = pick(random_icon_states)
create_reagents(300)
if(decal_reagent)
reagents.add_reagent(decal_reagent, reagent_amount)
if(loc && isturf(loc))
for(var/obj/effect/decal/cleanable/C in loc)
if(C != src && C.type == type && !QDELETED(C))
if (replace_decal(C))
handle_merge_decal(C)
return INITIALIZE_HINT_QDEL
if(is_mopped)
ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT)
if(LAZYLEN(diseases))
var/list/datum/disease/diseases_to_add = list()
for(var/datum/disease/D in diseases)
if(D.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)
diseases_to_add += D
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
AddElement(/datum/element/beauty, beauty)
var/turf/T = get_turf(src)
if(T && is_station_level(T.z))
SSblackbox.record_feedback("tally", "station_mess_created", 1, name)
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/effect/decal/cleanable/Destroy()
var/turf/T = get_turf(src)
if(T && is_station_level(T.z))
SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name)
return ..()
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
return TRUE
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, list/modifiers)
if((istype(W, /obj/item/reagent_containers/cup) && !istype(W, /obj/item/rag)) || istype(W, /obj/item/reagent_containers/cup/glass))
if(src.reagents && W.reagents)
. = 1 //so the containers don't splash their content on the src while scooping.
if(!src.reagents.total_volume)
to_chat(user, span_notice("[src] isn't thick enough to scoop up!"))
return
if(W.reagents.total_volume >= W.reagents.maximum_volume)
to_chat(user, span_notice("[W] is full!"))
return
to_chat(user, span_notice("You scoop up [src] into [W]!"))
reagents.trans_to(W, reagents.total_volume, transferred_by = user)
if(!reagents.total_volume) //scooped up all of it
qdel(src)
return
if(W.get_temperature()) //todo: make heating a reagent holder proc
if(istype(W, /obj/item/cigarette))
return
else
var/hotness = W.get_temperature()
reagents.expose_temperature(hotness)
to_chat(user, span_notice("You heat [name] with [W]!"))
else
return ..()
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
if(reagents)
reagents.expose_temperature(exposed_temperature)
..()
//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/proc/on_entered(datum/source, atom/movable/AM)
SIGNAL_HANDLER
if(iscarbon(AM) && blood_state && bloodiness >= 40)
SEND_SIGNAL(AM, COMSIG_STEP_ON_BLOOD, src)
update_appearance()
/obj/effect/decal/cleanable/wash(clean_types)
. = ..()
if (. || (clean_types & clean_type))
qdel(src)
return TRUE
return .
/**
* Checks if this decal is a valid decal that can be blood crawled in.
*/
/obj/effect/decal/cleanable/proc/can_bloodcrawl_in()
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
return bloodiness
return FALSE
/**
* Gets the color associated with the any blood present on this decal. If there is no blood, returns null.
*/
/obj/effect/decal/cleanable/proc/get_blood_color()
switch(blood_state)
if(BLOOD_STATE_HUMAN)
return rgb(149, 10, 10)
if(BLOOD_STATE_XENO)
return rgb(43, 186, 0)
if(BLOOD_STATE_OIL)
return rgb(22, 22, 22)
return null
/obj/effect/decal/cleanable/blood/get_blood_color()
return color || ..()
/obj/effect/decal/cleanable/proc/handle_merge_decal(obj/effect/decal/cleanable/merger)
if(!merger)
return
if(merger.reagents && reagents)
reagents.trans_to(merger, reagents.total_volume)