diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index cec707b8196..23ac017f1ec 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -5,6 +5,3 @@
#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in an inventory, ex: Defibrillator, Backpack, Space Suits
#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons
#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe
-
-#define TV_TRIP "trip"
-#define TV_SLIP "slip"
diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm
new file mode 100644
index 00000000000..0ea8e313378
--- /dev/null
+++ b/code/datums/components/slippery.dm
@@ -0,0 +1,54 @@
+/**
+ This is a component that can be applied to any movable atom (mob or obj).
+
+ While the atom has this component, any carbon mob that walks over it will slip.
+ Duration, tiles moved, and so on, depend on what variables are passed in when the component is added.
+*/
+/datum/component/slippery
+ /// Text that gets displayed in the slip proc, i.e. "user slips on [description]"
+ var/description
+ /// The amount of stun to apply after slip.
+ var/stun
+ /// The amount of weaken to apply after slip.
+ var/weaken
+ /// The chance that walking over the parent will slip you.
+ var/slip_chance
+ /// The amount of tiles someone will be moved after slip.
+ var/slip_tiles
+ /// TRUE If this slip can be avoided by walking.
+ var/walking_is_safe
+ /// TRUE if having no slip shoes makes you immune to this slip.
+ var/noslip_is_immune
+ /// The verb that players will see when someone slips on the parent. In the form of "You [slip_verb]ped on".
+ var/slip_verb
+
+/datum/component/slippery/Initialize(_description, _stun = 0, _weaken = 0, _slip_chance = 100, _slip_tiles = 0, \
+ _walking_is_safe = TRUE, _noslip_is_immune = TRUE, _slip_verb = "slip")
+ if(!ismovable(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ description = _description
+ stun = max(0, _stun)
+ weaken = max(0, _weaken)
+ slip_chance = max(0, _slip_chance)
+ slip_tiles = max(0, _slip_tiles)
+ walking_is_safe = _walking_is_safe
+ noslip_is_immune = _noslip_is_immune
+ slip_verb = _slip_verb
+
+/datum/component/slippery/RegisterWithParent()
+ RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
+
+/datum/component/slippery/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED))
+
+/**
+ Called whenever the parent recieves either the `MOVABLE_CROSSED` signal or the `ATOM_ENTERED` signal.
+
+ Calls the `victim`'s `slip()` proc with the component's variables as arguments.
+ Additionally calls the parent's `after_slip()` proc on the `victim`.
+*/
+/datum/component/slippery/proc/Slip(datum/source, mob/living/carbon/human/victim)
+ if(istype(victim) && prob(slip_chance) && victim.slip(description, stun, weaken, slip_tiles, walking_is_safe, noslip_is_immune, slip_verb))
+ var/atom/movable/owner = parent
+ owner.after_slip(victim)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ac77d3d4553..dff58d485f5 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -330,6 +330,16 @@
SSspacedrift.processing[src] = src
return 1
+/**
+ Base proc, intended to be overriden.
+
+ This should only be called from one place: inside the slippery component.
+ Called after a human mob slips on this atom.
+
+ If you want the person who slipped to have something special done to them, put it here.
+*/
+/atom/movable/proc/after_slip(mob/living/carbon/human/H)
+ return
//called when src is thrown into hit_atom
/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index fba55ba0557..ab6ebe6a0fe 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -98,15 +98,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc.
var/sprite_sheets_obj = null //Used to override hardcoded clothing inventory object dmis in human clothing proc.
- var/trip_verb = TV_TRIP
- var/trip_chance = 0
-
- var/trip_stun = 0
- var/trip_weaken = 0
- var/trip_any = FALSE
- var/trip_walksafe = TRUE
- var/trip_tiles = 0
-
//Tooltip vars
var/in_inventory = FALSE //is this item equipped into an inventory slot or hand of a mob?
var/tip_timer = 0
@@ -606,16 +597,6 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
/obj/item/proc/is_equivalent(obj/item/I)
return I == src
-/obj/item/Crossed(atom/movable/AM, oldloc)
- . = ..()
- if(prob(trip_chance) && ishuman(AM))
- var/mob/living/carbon/human/H = AM
- on_trip(H)
-
-/obj/item/proc/on_trip(mob/living/carbon/human/H)
- if(H.slip(src, trip_stun, trip_weaken, trip_tiles, trip_walksafe, trip_any, trip_verb))
- return TRUE
-
/obj/item/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
diff --git a/code/game/objects/items/weapons/grenades/clowngrenade.dm b/code/game/objects/items/weapons/grenades/clowngrenade.dm
index cfb2e1cad3d..1dcf250dfe4 100644
--- a/code/game/objects/items/weapons/grenades/clowngrenade.dm
+++ b/code/game/objects/items/weapons/grenades/clowngrenade.dm
@@ -13,22 +13,12 @@
/obj/item/grenade/clown_grenade/prime()
..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 25, -3)
- /*
- for(var/turf/simulated/floor/T in view(affected_area, src.loc))
- if(prob(75))
- banana(T)
- */
var/i = 0
var/number = 0
for(var/direction in GLOB.alldirs)
for(i = 0; i < 2; i++)
number++
var/obj/item/grown/bananapeel/traitorpeel/peel = new /obj/item/grown/bananapeel/traitorpeel(get_turf(src.loc))
- /* var/direction = pick(alldirs)
- var/spaces = pick(1;150, 2)
- var/a = 0
- for(a = 0; a < spaces; a++)
- step(peel,direction)*/
var/a = 1
if(number & 2)
for(a = 1; a <= 2; a++)
@@ -39,21 +29,17 @@
qdel(src)
return
-/obj/item/grown/bananapeel/traitorpeel
- trip_stun = 0
- trip_weaken = 7
- trip_tiles = 4
- trip_walksafe = FALSE
-
- trip_chance = 100
-
-
-/obj/item/grown/bananapeel/traitorpeel/on_trip(mob/living/carbon/human/H)
+/obj/item/grown/bananapeel/traitorpeel/New(newloc, obj/item/seeds/new_seed)
. = ..()
- if(.)
- to_chat(H, "Your feet feel like they're on fire!")
- H.take_overall_damage(0, rand(2,8))
- H.take_organ_damage(2) // Was 5 -- TLE
+ // The reason this AddComponent is here and not in ComponentInitialize() is because if it's put there, it will be ran before the parent New proc for /grown types.
+ // And then be overriden by the generic component placed onto it by the `/datum/plant_gene/trait/slip`.
+ AddComponent(/datum/component/slippery, src, 0, 7, 100, 4, FALSE)
+
+/obj/item/grown/bananapeel/traitorpeel/after_slip(mob/living/carbon/human/H)
+ to_chat(H, "Your feet feel like they're on fire!")
+ H.take_overall_damage(0, rand(2,8))
+ H.take_organ_damage(2)
+ return ..()
/obj/item/grown/bananapeel/traitorpeel/throw_impact(atom/hit_atom)
var/burned = rand(1,3)
diff --git a/code/game/objects/items/weapons/soap.dm b/code/game/objects/items/weapons/soap.dm
index 62f65b5a6cc..cb220ff9565 100644
--- a/code/game/objects/items/weapons/soap.dm
+++ b/code/game/objects/items/weapons/soap.dm
@@ -11,15 +11,11 @@
throw_speed = 4
throw_range = 20
discrete = 1
-
- trip_stun = 4
- trip_weaken = 2
- trip_chance = 100
- trip_walksafe = FALSE
- trip_verb = TV_SLIP
-
var/cleanspeed = 50 //slower than mop
+/obj/item/soap/ComponentInitialize()
+ AddComponent(/datum/component/slippery, src, 4, 2, 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.
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index d86f6f8f4c5..f4a6a18e417 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -160,11 +160,11 @@
T.on_cross(src, AM)
..()
-/obj/item/reagent_containers/food/snacks/grown/on_trip(mob/living/carbon/human/H)
- . = ..()
- if(. && seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_slip(src, H)
+/obj/item/reagent_containers/food/snacks/grown/after_slip(mob/living/carbon/human/H)
+ if(!seed)
+ return
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_slip(src, H)
// Glow gene procs
/obj/item/reagent_containers/food/snacks/grown/generate_trash(atom/location)
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index dc78ff71335..0552f78ee92 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -118,12 +118,10 @@
/obj/item/grown/bananapeel/specialpeel //used by /obj/item/clothing/shoes/clown_shoes/banana_shoes
name = "synthesized banana peel"
desc = "A synthetic banana peel."
- trip_stun = 2
- trip_weaken = 2
- trip_chance = 100
- trip_walksafe = FALSE
- trip_verb = TV_SLIP
-/obj/item/grown/bananapeel/specialpeel/on_trip(mob/living/carbon/human/H)
- if(..())
- qdel(src)
+/obj/item/grown/bananapeel/specialpeel/ComponentInitialize()
+ AddComponent(/datum/component/slippery, src, 2, 2, 100, 0, FALSE)
+
+/obj/item/grown/bananapeel/specialpeel/after_slip(mob/living/carbon/human/H)
+ . = ..()
+ qdel(src)
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 14a4b42ca5f..13263b4cc75 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -57,11 +57,11 @@
T.on_cross(src, AM)
..()
-/obj/item/grown/on_trip(mob/living/carbon/human/H)
- . = ..()
- if(. && seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_slip(src, H)
+/obj/item/grown/after_slip(mob/living/carbon/human/H)
+ if(!seed)
+ return
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_slip(src, H)
/obj/item/grown/throw_impact(atom/hit_atom)
if(!..()) //was it caught by a mob?
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index d20413d6331..19209a680ad 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -217,11 +217,7 @@
stun_len = min(stun_len, 7) // No fun allowed
- G.trip_stun = stun_len
- G.trip_weaken = stun_len
- G.trip_chance = 100
- G.trip_verb = TV_SLIP
- G.trip_walksafe = FALSE
+ G.AddComponent(/datum/component/slippery, G, stun_len, stun_len, 100, 0, FALSE)
/datum/plant_gene/trait/cell_charge
// Cell recharging trait. Charges all mob's power cells to (potency*rate)% mark when eaten.
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 74c5a71c94b..4b6d6c68603 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -977,25 +977,30 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
/mob/living/carbon/proc/slip(description, stun, weaken, tilesSlipped, walkSafely, slipAny, slipVerb = "slip")
if(flying || buckled || (walkSafely && m_intent == MOVE_INTENT_WALK))
- return 0
+ return FALSE
+
if((lying) && (!(tilesSlipped)))
- return 0
+ return FALSE
+
if(!(slipAny))
if(istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
if(isobj(H.shoes) && H.shoes.flags & NOSLIP)
- return 0
+ return FALSE
+
if(tilesSlipped)
- for(var/t = 0, t<=tilesSlipped, t++)
- spawn (t) step(src, src.dir)
+ for(var/i in 1 to tilesSlipped)
+ spawn(i)
+ step(src, dir)
+
stop_pulling()
to_chat(src, "You [slipVerb]ped on [description]!")
- playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3)
+ playsound(loc, 'sound/misc/slip.ogg', 50, 1, -3)
// Something something don't run with scissors
moving_diagonally = 0 //If this was part of diagonal move slipping will stop it.
Stun(stun)
Weaken(weaken)
- return 1
+ return TRUE
/mob/living/carbon/proc/can_eat(flags = 255)
return 1
diff --git a/code/modules/pda/pdas.dm b/code/modules/pda/pdas.dm
index 0e5c58f968a..f6f02e3457f 100644
--- a/code/modules/pda/pdas.dm
+++ b/code/modules/pda/pdas.dm
@@ -38,11 +38,8 @@
desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings."
ttone = "honk"
- trip_stun = 8
- trip_weaken = 5
- trip_chance = 100
- trip_walksafe = TRUE
- trip_verb = TV_SLIP
+/obj/item/pda/clown/ComponentInitialize()
+ AddComponent(/datum/component/slippery, src, 8, 5, 100)
/obj/item/pda/mime
default_cartridge = /obj/item/cartridge/mime
@@ -191,7 +188,7 @@
var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger)
if(M)
M.m_hidden = 1
-
+
//Some spare PDAs in a box
/obj/item/storage/box/PDAs
name = "spare PDAs"
diff --git a/paradise.dme b/paradise.dme
index c3dcfbd3c2d..a9165f49a76 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -300,6 +300,7 @@
#include "code\datums\components\label.dm"
#include "code\datums\components\material_container.dm"
#include "code\datums\components\paintable.dm"
+#include "code\datums\components\slippery.dm"
#include "code\datums\components\spawner.dm"
#include "code\datums\components\squeak.dm"
#include "code\datums\components\waddling.dm"