diff --git a/code/__DEFINES/cleaning.dm b/code/__DEFINES/cleaning.dm
new file mode 100644
index 0000000000..9f32992eb0
--- /dev/null
+++ b/code/__DEFINES/cleaning.dm
@@ -0,0 +1,7 @@
+//Cleaning tool strength
+#define CLEAN_VERY_WEAK 1 // What are you scrubbing the ground with a toothpick?
+#define CLEAN_WEAK 2
+#define CLEAN_MEDIUM 3 // Acceptable tools
+#define CLEAN_STRONG 4 // Industrial strength
+#define CLEAN_IMPRESSIVE 5 // Cleaning strong enough your granny would be proud
+#define CLEAN_GOD 6 // Cleans things spotless down to the atomic structure
\ No newline at end of file
diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 804ec2dc78..ddfa9942e6 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -18,6 +18,8 @@
#define COMSIG_COMPONENT_REMOVING "component_removing" //before a component is removed from a datum because of RemoveComponent: (/datum/component)
#define COMSIG_PARENT_QDELETED "parent_qdeleted" //before a datum's Destroy() is called: ()
+#define COMSIG_COMPONENT_CLEAN_ACT "clean_act" //called on an object to clean it of cleanables. Usualy with soap: (num/strength)
+
// /atom signals
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
diff --git a/code/datums/components/thermite.dm b/code/datums/components/thermite.dm
new file mode 100644
index 0000000000..7418e5d7b4
--- /dev/null
+++ b/code/datums/components/thermite.dm
@@ -0,0 +1,64 @@
+/datum/component/thermite
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ var/amount
+ var/overlay
+
+ var/static/list/blacklist = typecacheof(/turf/closed/wall/mineral/diamond)
+ var/static/list/resistlist = typecacheof(/turf/closed/wall/r_wall)
+
+/datum/component/thermite/Initialize(_amount)
+ if(!istype(parent, /turf))
+ return COMPONENT_INCOMPATIBLE
+ if(blacklist[parent.type])
+ _amount*=0 //Yeah the overlay can still go on it and be cleaned but you arent burning down a diamond wall
+ if(resistlist[parent.type])
+ _amount*=0.25
+
+ amount = _amount*10
+
+ var/turf/master = parent
+ overlay = mutable_appearance('icons/effects/effects.dmi', "thermite")
+ master.add_overlay(overlay)
+
+ RegisterSignal(COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
+ RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/attackby_react)
+ RegisterSignal(COMSIG_ATOM_FIRE_ACT, .proc/flame_react)
+
+/datum/component/thermite/Destroy()
+ var/turf/master = parent
+ master.cut_overlay(overlay)
+ return ..()
+
+/datum/component/thermite/InheritComponent(datum/component/thermite/newC, i_am_original)
+ if(!i_am_original)
+ return
+ amount += newC.amount
+
+/datum/component/thermite/proc/thermite_melt(mob/user)
+ var/turf/master = parent
+ master.cut_overlay(overlay)
+ var/obj/effect/overlay/thermite/fakefire = new(master)
+
+ playsound(master, 'sound/items/welder.ogg', 100, 1)
+
+ if(amount >= 50)
+ var/burning_time = max(100, 100-amount)
+ master = master.ChangeTurf(master.baseturf)
+ master.burn_tile()
+ if(user)
+ master.add_hiddenprint(user)
+ QDEL_IN(fakefire, burning_time)
+ else
+ QDEL_IN(fakefire, 50)
+
+/datum/component/thermite/proc/clean_react(strength)
+ //Thermite is just some loose powder, you could probably clean it with your hands. << todo?
+ qdel(src)
+
+/datum/component/thermite/proc/flame_react(exposed_temperature, exposed_volume)
+ if(exposed_temperature > 1922) // This is roughly the real life requirement to ignite thermite
+ thermite_melt()
+
+/datum/component/thermite/proc/attackby_react(obj/item/thing, mob/user, params)
+ if(thing.is_hot())
+ thermite_melt(user)
\ No newline at end of file
diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm
index f8ca514995..cadee92161 100644
--- a/code/game/objects/effects/misc.dm
+++ b/code/game/objects/effects/misc.dm
@@ -1,52 +1,61 @@
-//The effect when you wrap a dead body in gift wrap
-/obj/effect/spresent
- name = "strange present"
- desc = "It's a ... present?"
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "strangepresent"
+//The effect when you wrap a dead body in gift wrap
+/obj/effect/spresent
+ name = "strange present"
+ desc = "It's a ... present?"
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "strangepresent"
density = TRUE
anchored = FALSE
-
-/obj/effect/beam
- name = "beam"
- var/def_zone
- pass_flags = PASSTABLE
-
-/obj/effect/spawner
- name = "object spawner"
-
-/obj/effect/list_container
- name = "list container"
-
-/obj/effect/list_container/mobl
- name = "mobl"
- var/master = null
-
- var/list/container = list( )
-
-//Makes a tile fully lit no matter what
-/obj/effect/fullbright
- icon = 'icons/effects/alphacolors.dmi'
- icon_state = "white"
- plane = LIGHTING_PLANE
- layer = LIGHTING_LAYER
- blend_mode = BLEND_ADD
-
-/obj/effect/abstract/marker
- name = "marker"
- icon = 'icons/effects/effects.dmi'
- anchored = TRUE
- icon_state = "wave3"
- layer = RIPPLE_LAYER
-
-/obj/effect/abstract/marker/Initialize(mapload)
- . = ..()
- GLOB.all_abstract_markers += src
-
-/obj/effect/abstract/marker/Destroy()
- GLOB.all_abstract_markers -= src
- . = ..()
-
-/obj/effect/abstract/marker/at
- name = "active turf marker"
-
+
+/obj/effect/beam
+ name = "beam"
+ var/def_zone
+ pass_flags = PASSTABLE
+
+/obj/effect/spawner
+ name = "object spawner"
+
+/obj/effect/list_container
+ name = "list container"
+
+/obj/effect/list_container/mobl
+ name = "mobl"
+ var/master = null
+
+ var/list/container = list( )
+
+/obj/effect/overlay/thermite
+ name = "thermite"
+ desc = "Looks hot."
+ icon = 'icons/effects/fire.dmi'
+ icon_state = "2" //what?
+ anchored = TRUE
+ opacity = TRUE
+ density = TRUE
+ layer = FLY_LAYER
+
+//Makes a tile fully lit no matter what
+/obj/effect/fullbright
+ icon = 'icons/effects/alphacolors.dmi'
+ icon_state = "white"
+ plane = LIGHTING_PLANE
+ layer = LIGHTING_LAYER
+ blend_mode = BLEND_ADD
+
+/obj/effect/abstract/marker
+ name = "marker"
+ icon = 'icons/effects/effects.dmi'
+ anchored = TRUE
+ icon_state = "wave3"
+ layer = RIPPLE_LAYER
+
+/obj/effect/abstract/marker/Initialize(mapload)
+ . = ..()
+ GLOB.all_abstract_markers += src
+
+/obj/effect/abstract/marker/Destroy()
+ GLOB.all_abstract_markers -= src
+ . = ..()
+
+/obj/effect/abstract/marker/at
+ name = "active turf marker"
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index 09b8c35544..c9468cb79f 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -58,7 +58,8 @@
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))
+ target.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
+ if(user.client && ((target in user.client.screen) && !user.is_holding(target)))
to_chat(user, "You need to take that [target.name] off before cleaning it!")
else if(istype(target, /obj/effect/decal/cleanable))
user.visible_message("[user] begins to scrub \the [target.name] out with [src].", "You begin to scrub \the [target.name] out with [src]...")
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 7695eb86c6..f9be38a2fe 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -24,12 +24,10 @@
/obj/item/mop/proc/clean(turf/A)
if(reagents.has_reagent("water", 1) || reagents.has_reagent("holywater", 1) || reagents.has_reagent("vodka", 1) || reagents.has_reagent("cleaner", 1))
A.clean_blood()
+ A.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
for(var/obj/effect/O in A)
if(is_cleanable(O))
qdel(O)
- if(isclosedturf(A))
- var/turf/closed/C = A
- C.thermite = 0
reagents.reaction(A, TOUCH, 10) //Needed for proper floor wetting.
reagents.remove_any(1) //reaction() doesn't use up the reagents
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index e22d75f9aa..0cb6451116 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -226,6 +226,7 @@
soundloop.start()
wash_turf()
for(var/atom/movable/G in loc)
+ G.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
if(isliving(G))
var/mob/living/L = G
wash_mob(L)
@@ -295,6 +296,7 @@
/obj/machinery/shower/proc/wash_obj(obj/O)
+ O.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
. = O.clean_blood()
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
if(isitem(O))
@@ -306,6 +308,7 @@
/obj/machinery/shower/proc/wash_turf()
if(isturf(loc))
var/turf/tile = loc
+ tile.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
tile.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
tile.clean_blood()
for(var/obj/effect/E in tile)
@@ -314,6 +317,7 @@
/obj/machinery/shower/proc/wash_mob(mob/living/L)
+ L.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
L.wash_cream()
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm
index 029bb5b212..9f52c3e035 100644
--- a/code/game/turfs/closed.dm
+++ b/code/game/turfs/closed.dm
@@ -1,5 +1,4 @@
/turf/closed
- var/thermite = 0
layer = CLOSED_TURF_LAYER
opacity = 1
density = TRUE
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index 5595009778..0578861074 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -38,9 +38,6 @@
explosion_block = 3
canSmoothWith = list(/turf/closed/wall/mineral/diamond, /obj/structure/falsewall/diamond)
-/turf/closed/wall/mineral/diamond/thermitemelt(mob/user)
- return
-
/turf/closed/wall/mineral/clown
name = "bananium wall"
desc = "A wall with bananium plating. Honk!"
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 57037de446..d3edd42cec 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -161,12 +161,6 @@
add_fingerprint(user)
- //THERMITE related stuff. Calls src.thermitemelt() which handles melting simulated walls and the relevant effects
- if( thermite )
- if(W.is_hot())
- thermitemelt(user)
- return
-
var/turf/T = user.loc //get user's location for delay checks
//the istype cascade has been spread among various procs for easy overriding
@@ -239,31 +233,6 @@
return TRUE
return FALSE
-
-/turf/closed/wall/proc/thermitemelt(mob/user)
- cut_overlays()
- var/obj/effect/overlay/O = new/obj/effect/overlay( src )
- O.name = "thermite"
- O.desc = "Looks hot."
- O.icon = 'icons/effects/fire.dmi'
- O.icon_state = "2"
- O.anchored = TRUE
- O.opacity = 1
- O.density = TRUE
- O.layer = FLY_LAYER
-
- playsound(src, 'sound/items/welder.ogg', 100, 1)
-
- if(thermite >= 50)
- var/burning_time = max(100,300 - thermite)
- var/turf/open/floor/F = ChangeTurf(/turf/open/floor/plating)
- F.burn_tile()
- F.add_hiddenprint(user)
- QDEL_IN(O, burning_time)
- else
- thermite = 0
- QDEL_IN(O, 50)
-
/turf/closed/wall/singularity_pull(S, current_size)
..()
if(current_size >= STAGE_FIVE)
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index bec3df0bdd..b41d61be84 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -8,14 +8,8 @@
taste_description = "sweet tasting metal"
/datum/reagent/thermite/reaction_turf(turf/T, reac_volume)
- if(reac_volume >= 1 && iswallturf(T))
- var/turf/closed/wall/Wall = T
- if(istype(Wall, /turf/closed/wall/r_wall))
- Wall.thermite = Wall.thermite+(reac_volume*2.5)
- else
- Wall.thermite = Wall.thermite+(reac_volume*10)
- Wall.overlays = list()
- Wall.add_overlay(mutable_appearance('icons/effects/effects.dmi', "thermite"))
+ if(reac_volume >= 1)
+ T.AddComponent(/datum/component/thermite, reac_volume)
/datum/reagent/thermite/on_mob_life(mob/living/M)
M.adjustFireLoss(1, 0)
diff --git a/tgstation.dme b/tgstation.dme
index 0d0cf33d6b..18ddedb85f 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -30,6 +30,7 @@
#include "code\__DEFINES\callbacks.dm"
#include "code\__DEFINES\cinematics.dm"
#include "code\__DEFINES\citadel_defines.dm"
+#include "code\__DEFINES\cleaning.dm"
#include "code\__DEFINES\clockcult.dm"
#include "code\__DEFINES\combat.dm"
#include "code\__DEFINES\components.dm"
@@ -321,6 +322,7 @@
#include "code\datums\components\radioactive.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\squeek.dm"
+#include "code\datums\components\thermite.dm"
#include "code\datums\diseases\_disease.dm"
#include "code\datums\diseases\_MobProcs.dm"
#include "code\datums\diseases\anxiety.dm"