diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index 83db83c329c..cec707b8196 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -4,4 +4,7 @@
#define WEIGHT_CLASS_NORMAL 3 //Standard backpacks can carry tiny, small & normal items, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets
#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
\ No newline at end of file
+#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/game/objects/items.dm b/code/game/objects/items.dm
index 9f92bfa87f7..a1a68ff5cf7 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -87,6 +87,15 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
var/sprite_sheets_obj = null //Used to override hardcoded clothing inventory object dmis in human clothing proc.
var/list/species_fit = null //This object has a different appearance when worn by these species
+ 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
+
/obj/item/New()
..()
for(var/path in actions_types)
@@ -530,3 +539,12 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
/obj/item/proc/is_equivalent(obj/item/I)
return I == src
+
+/obj/item/Crossed(atom/movable/AM)
+ 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
diff --git a/code/game/objects/items/weapons/clown_items.dm b/code/game/objects/items/weapons/clown_items.dm
index ad8a30bed07..841d8fa1cda 100644
--- a/code/game/objects/items/weapons/clown_items.dm
+++ b/code/game/objects/items/weapons/clown_items.dm
@@ -5,49 +5,6 @@
* Bike Horns
*/
-/*
- * Soap
- */
-/obj/item/weapon/soap/Crossed(AM as mob|obj) //EXACTLY the same as bananapeel for now, so it makes sense to put it in the same dm -- Urist
- if(istype(AM, /mob/living/carbon))
- var/mob/living/carbon/M = AM
- M.slip("soap", 4, 2)
-
-/obj/item/weapon/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))
- var/mob/living/carbon/human/muncher = user
- if(muncher && muncher.get_species() == "Drask")
- to_chat(user, "You take a bite of the [src.name]. Delicious!")
- playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0)
- user.nutrition += 2
- else if(istype(target,/obj/effect/decal/cleanable))
- user.visible_message("[user] begins to scrub \the [target.name] out with [src].")
- if(do_after(user, src.cleanspeed, target = target) && target)
- to_chat(user, "You scrub \the [target.name] out.")
- qdel(target)
- else
- user.visible_message("[user] begins to clean \the [target.name] with [src].")
- if(do_after(user, src.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()
- if(istype(target, /turf/simulated))
- var/turf/simulated/T = target
- T.dirt = 0
- return
-
-/obj/item/weapon/soap/attack(mob/target as mob, mob/user as mob)
- if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == "mouth" )
- user.visible_message("\the [user] washes \the [target]'s mouth out with [src.name]!")
- return
- ..()
-
/*
* Bike Horns
*/
diff --git a/code/game/objects/items/weapons/grenades/clowngrenade.dm b/code/game/objects/items/weapons/grenades/clowngrenade.dm
index c6ab7d376c1..a9d6c20011a 100644
--- a/code/game/objects/items/weapons/grenades/clowngrenade.dm
+++ b/code/game/objects/items/weapons/grenades/clowngrenade.dm
@@ -50,24 +50,20 @@
*/
/obj/item/weapon/grown/bananapeel/traitorpeel
+ trip_stun = 0
+ trip_weaken = 7
+ trip_tiles = 4
+ trip_walksafe = FALSE
+
+ trip_chance = 100
-/obj/item/weapon/grown/bananapeel/traitorpeel/Crossed(AM as mob|obj)
- var/burned = rand(2,5)
- if(istype(AM, /mob/living/carbon))
- var/mob/living/carbon/M = AM
- if(ishuman(M))
- if(isobj(M:shoes))
- if(M:shoes.flags & NOSLIP)
- return
- else
- to_chat(M, "Your feet feel like they're on fire!")
- M.take_overall_damage(0, max(0, (burned - 2)))
-
- if(!istype(M, /mob/living/carbon/slime) && !isrobot(M))
- M.slip("banana peel!", 0, 7, 4)
- M.take_organ_damage(2) // Was 5 -- TLE
- M.take_overall_damage(0, burned)
+/obj/item/weapon/grown/bananapeel/traitorpeel/on_trip(mob/living/carbon/human/H)
+ . = ..()
+ 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
/obj/item/weapon/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 85dfe4868d0..d7db1e64185 100644
--- a/code/game/objects/items/weapons/soap.dm
+++ b/code/game/objects/items/weapons/soap.dm
@@ -9,8 +9,51 @@
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/weapon/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))
+ var/mob/living/carbon/human/muncher = user
+ if(muncher && muncher.get_species() == "Drask")
+ to_chat(user, "You take a bite of the [src.name]. Delicious!")
+ playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0)
+ user.nutrition += 2
+ else if(istype(target,/obj/effect/decal/cleanable))
+ user.visible_message("[user] begins to scrub \the [target.name] out with [src].")
+ if(do_after(user, src.cleanspeed, target = target) && target)
+ to_chat(user, "You scrub \the [target.name] out.")
+ qdel(target)
+ else
+ user.visible_message("[user] begins to clean \the [target.name] with [src].")
+ if(do_after(user, src.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()
+ if(istype(target, /turf/simulated))
+ var/turf/simulated/T = target
+ T.dirt = 0
+
+/obj/item/weapon/soap/attack(mob/target as mob, mob/user as mob)
+ if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_sel &&user.zone_sel.selecting == "mouth" )
+ user.visible_message("\the [user] washes \the [target]'s mouth out with [src.name]!")
+ return
+ ..()
+
/obj/item/weapon/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 22ccbecfdf6..61f622c071f 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -69,16 +69,16 @@
switch(src.wet)
if(TURF_WET_WATER)
- if(!(M.slip("wet floor", 4, 2, 0, 1)))
+ if(!(M.slip("wet floor", 4, 2, tilesSlipped = 0, walkSafely = 1)))
M.inertia_dir = 0
return
if(TURF_WET_LUBE) //lube
- M.slip("floor", 0, 5, 3, 0, 1)
+ M.slip("floor", 0, 5, tilesSlipped = 3, walkSafely = 0, slipAny = 1)
if(TURF_WET_ICE) // Ice
- if(!(prob(30) && M.slip("icy floor", 4, 2, 1, 1)))
+ if(!(prob(30) && M.slip("icy floor", 4, 2, tilesSlipped = 1, walkSafely = 1)))
M.inertia_dir = 0
/turf/simulated/ChangeTurf(var/path)
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 130fc2730ac..82abda8e7d6 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -131,6 +131,11 @@
T.on_cross(src, AM)
..()
+/obj/item/weapon/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)
// Glow gene procs
/obj/item/weapon/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 8301b021cc4..9787edb59c3 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -113,9 +113,12 @@
/obj/item/weapon/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/weapon/grown/bananapeel/specialpeel/Crossed(AM)
- if(iscarbon(AM))
- var/mob/living/carbon/carbon = AM
- if(carbon.slip("[src]", 2, 2))
- qdel(src)
+/obj/item/weapon/grown/bananapeel/specialpeel/on_trip(mob/living/carbon/human/H)
+ if(..())
+ qdel(src)
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index c94706f00e5..1136ec4296b 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -57,8 +57,14 @@
T.on_cross(src, AM)
..()
+/obj/item/weapon/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/weapon/grown/throw_impact(atom/hit_atom)
if(!..()) //was it caught by a mob?
if(seed)
for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_throw_impact(src, hit_atom)
\ No newline at end of file
+ T.on_throw_impact(src, hit_atom)
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index cfda1499555..b9b1c8efcc6 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -204,24 +204,23 @@
rate = 0.1
examine_line = "It has a very slippery skin."
-/datum/plant_gene/trait/slip/on_cross(obj/item/weapon/reagent_containers/food/snacks/grown/G, atom/target)
- if(iscarbon(target))
- var/obj/item/seeds/seed = G.seed
- var/mob/living/carbon/M = target
+/datum/plant_gene/trait/slip/on_new(obj/item/weapon/reagent_containers/food/snacks/grown/G, newloc)
+ . = ..()
+ if(istype(G) && ispath(G.trash, /obj/item/weapon/grown))
+ return
- var/stun_len = seed.potency * rate * 0.8
- if(istype(G) && ispath(G.trash, /obj/item/weapon/grown))
- return
+ var/stun_len = G.seed.potency * rate * 0.8
- if(!istype(G, /obj/item/weapon/grown/bananapeel) && (!G.reagents || !G.reagents.has_reagent("lube")))
- stun_len /= 3
+ if(!istype(G, /obj/item/weapon/grown/bananapeel) && (!G.reagents || !G.reagents.has_reagent("lube")))
+ stun_len /= 3
- var/stun = min(stun_len, 7)
- var/weaken = min(stun_len, 7)
+ stun_len = min(stun_len, 7) // No fun allowed
- if(M.slip("[G]", stun, weaken))
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_slip(G, M)
+ G.trip_stun = stun_len
+ G.trip_weaken = stun_len
+ G.trip_chance = 100
+ G.trip_verb = TV_SLIP
+ G.trip_walksafe = 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 4de2dff6212..3175258c19e 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -930,7 +930,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
W.plane = initial(W.plane)
-/mob/living/carbon/proc/slip(var/description, var/stun, var/weaken, var/tilesSlipped, var/walkSafely, var/slipAny)
+/mob/living/carbon/proc/slip(description, stun, weaken, tilesSlipped, walkSafely, slipAny, slipVerb = "slip")
if(flying || buckled || (walkSafely && m_intent == MOVE_INTENT_WALK))
return 0
if((lying) && (!(tilesSlipped)))
@@ -944,10 +944,10 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
for(var/t = 0, t<=tilesSlipped, t++)
spawn (t) step(src, src.dir)
stop_pulling()
- to_chat(src, "You slipped on [description]!")
+ to_chat(src, "You [slipVerb]ped on [description]!")
playsound(src.loc, 'sound/misc/slip.ogg', 50, 1, -3)
- if(stun)
- Stun(stun)
+ // Something something don't run with scissors
+ Stun(stun)
Weaken(weaken)
return 1
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 30fe030bdcb..b8d432d5609 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -330,6 +330,8 @@
SetParalysis(max(paralysis, amount), updating, force)
/mob/living/SetParalysis(amount, updating = 1, force = 0)
+ if((!!amount) == (!!paralysis)) // We're not changing from + to 0 or vice versa
+ updating = FALSE
if(status_flags & CANPARALYSE || force)
paralysis = max(amount, 0)
if(updating)
@@ -358,9 +360,11 @@
SetSleeping(max(sleeping, amount), updating, no_alert)
/mob/living/SetSleeping(amount, updating = 1, no_alert = FALSE)
+ if((!!amount) == (!!sleeping)) // We're not changing from + to 0 or vice versa
+ updating = FALSE
sleeping = max(amount, 0)
- update_sleeping_effects(no_alert)
if(updating)
+ update_sleeping_effects(no_alert)
update_stat()
update_canmove()
@@ -410,6 +414,8 @@
SetStunned(max(stunned, amount), updating, force)
/mob/living/SetStunned(amount, updating = 1, force = 0) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
+ if((!!amount) == (!!stunned)) // We're not changing from + to 0 or vice versa
+ updating = FALSE
if(status_flags & CANSTUN || force)
stunned = max(amount, 0)
if(updating)
@@ -440,6 +446,8 @@
SetWeakened(max(weakened, amount), updating, force)
/mob/living/SetWeakened(amount, updating = 1, force = 0)
+ if((!!amount) == (!!weakened)) // We're not changing from + to 0 or vice versa
+ updating = FALSE
if(status_flags & CANWEAKEN || force)
weakened = max(amount, 0)
if(updating)
diff --git a/code/modules/pda/pdas.dm b/code/modules/pda/pdas.dm
index db7d68fdf37..8fdffded4df 100644
--- a/code/modules/pda/pdas.dm
+++ b/code/modules/pda/pdas.dm
@@ -38,10 +38,11 @@
desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings."
ttone = "honk"
-/obj/item/device/pda/clown/Crossed(AM as mob|obj) //Clown PDA is slippery.
- if(istype(AM, /mob/living/carbon))
- var/mob/living/carbon/M = AM
- M.slip("pda", 8, 5, 0, 1)
+ trip_stun = 8
+ trip_weaken = 5
+ trip_chance = 100
+ trip_walksafe = TRUE
+ trip_verb = TV_SLIP
/obj/item/device/pda/mime
default_cartridge = /obj/item/weapon/cartridge/mime
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 4bb0f2846c7..915dd67d6af 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -435,7 +435,7 @@ var/static/regex/multispin_words = regex("like a record baby")
playsound(get_turf(owner), 'sound/items/bikehorn.ogg', 300, 1)
if(owner.mind && owner.mind.assigned_role == "Clown")
for(var/mob/living/carbon/C in listeners)
- C.slip(0,7 * power_multiplier)
+ C.slip("your feet", 0, 7 * power_multiplier)
next_command = world.time + cooldown_stun
else
next_command = world.time + cooldown_meme