/obj/effect/decal/cleanable gender = PLURAL layer = CLEANABLE_FLOOR_OBJECT_LAYER abstract_type = /obj/effect/decal/cleanable flags_1 = UNPAINTABLE_1 var/list/random_icon_states = null /// 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 /obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases) . = ..() if (LAZYLEN(random_icon_states)) icon_state = pick(random_icon_states) base_icon_state = icon_state if (isturf(loc)) for (var/obj/effect/decal/cleanable/other in loc) if (other != src && other.type == type && !QDELETED(other) && replace_decal(other)) handle_merge_decal(other) return INITIALIZE_HINT_QDEL if (is_mopped) ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT) if (LAZYLEN(diseases)) add_diseases(diseases) AddElement(/datum/element/beauty, beauty) var/turf/our_turf = get_turf(src) if (our_turf && is_station_level(our_turf.z)) SSblackbox.record_feedback("tally", "station_mess_created", 1, name) /obj/effect/decal/cleanable/Destroy() var/turf/our_turf = get_turf(src) if (our_turf && is_station_level(our_turf.z)) SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name) return ..() /obj/effect/decal/cleanable/proc/add_diseases(list/datum/disease/diseases) var/list/datum/disease/diseases_to_add = list() for (var/datum/disease/disease as anything in diseases) if (disease.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS) diseases_to_add += disease if (LAZYLEN(diseases_to_add)) AddComponent(/datum/component/infective, diseases_to_add) /// Check if we should give up in favor of the pre-existing decal /obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/other) if (mergeable_decal) return TRUE /obj/effect/decal/cleanable/wash(clean_types) . = ..() if (. || clean_types & clean_type) qdel(src) . |= COMPONENT_CLEANED|COMPONENT_CLEANED_GAIN_XP /obj/effect/decal/cleanable/proc/handle_merge_decal(obj/effect/decal/cleanable/merger) if (!reagents && !decal_reagent) return if (!reagents && !merger.reagents && (!merger.decal_reagent || merger.decal_reagent == decal_reagent)) merger.decal_reagent = decal_reagent merger.reagent_amount += reagent_amount else if (lazy_init_reagents() && merger.lazy_init_reagents()) merger.reagents.maximum_volume += reagents.total_volume reagents.trans_to(merger, reagents.total_volume) /// Returns reagents datum if it exists, or lazyloads one if it doesn't /obj/effect/decal/cleanable/proc/lazy_init_reagents() RETURN_TYPE(/datum/reagents) if (reagents) return reagents return init_reagents(decal_reagent, reagent_amount) /obj/effect/decal/cleanable/proc/init_reagents(reagent = null, amount = null) RETURN_TYPE(/datum/reagents) if (!reagent) return create_reagents(amount) reagents.add_reagent(reagent, amount) return reagents /obj/effect/decal/cleanable/item_interaction(mob/living/user, obj/item/tool, list/modifiers) // Why are rags cups??? if (!istype(tool, /obj/item/reagent_containers/cup) || istype(tool, /obj/item/rag)) return NONE if (!lazy_init_reagents()?.total_volume) to_chat(user, span_notice("[src] isn't thick enough to scoop up!")) return ITEM_INTERACT_BLOCKING if (!reagents.trans_to(tool, reagents.total_volume, transferred_by = user)) to_chat(user, span_warning("[tool] is full!")) return ITEM_INTERACT_BLOCKING to_chat(user, span_notice("You scoop up [reagents.total_volume > 0 ? "some of " : ""]\the [src] into \the [tool]!")) if (!reagents.total_volume) //scooped up all of it qdel(src) return ITEM_INTERACT_SUCCESS /// Checks if this decal can be bloodcrawled in /obj/effect/decal/cleanable/proc/can_bloodcrawl_in() if (decal_reagent == /datum/reagent/blood || reagents?.has_reagent(/datum/reagent/blood)) return TRUE var/list/blood_DNA = GET_ATOM_BLOOD_DECALS(src) for (var/blood_key in blood_DNA) var/datum/blood_type/blood_type = blood_DNA[blood_key] if (blood_type.reagent_type == /datum/reagent/blood) return 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) /turf/proc/spawn_glitter(glitter_colors) var/obj/effect/decal/cleanable/glitter/new_glitter = spawn_unique_cleanable(/obj/effect/decal/cleanable/glitter) new_glitter.color = pick_weight(glitter_colors)