diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm
index e0b8def1581..3784a079ce0 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm
@@ -11,6 +11,8 @@
#define COMSIG_ATOM_NO_LONGER_PULLING "movable_no_longer_pulling"
///called for each movable in a turf contents on /turf/zImpact(): (atom/movable/A, levels)
#define COMSIG_ATOM_INTERCEPT_Z_FALL "movable_intercept_z_impact"
+///signal sent out by an atom upon onZImpact : (turf/impacted_turf, levels)
+#define COMSIG_ATOM_ON_Z_IMPACT "movable_on_z_impact"
///called on a movable (NOT living) when it starts pulling (atom/movable/pulled, state, force)
#define COMSIG_ATOM_START_PULL "movable_start_pull"
///called on /living when someone starts pulling (atom/movable/pulled, state, force)
diff --git a/code/datums/elements/falling_hazard.dm b/code/datums/elements/falling_hazard.dm
new file mode 100644
index 00000000000..cfa9285e7f8
--- /dev/null
+++ b/code/datums/elements/falling_hazard.dm
@@ -0,0 +1,80 @@
+/// An element that will make a target thing do damage to any mob that it falls on from a z-level above
+/datum/element/falling_hazard
+ element_flags = ELEMENT_BESPOKE
+ id_arg_index = 2
+
+ /// The amount of damage to do when the target falls onto a mob
+ var/fall_damage = 5
+ /// The wound bonus to give damage dealt against mobs we fall on
+ var/fall_wound_bonus = 0
+ /// Does we take into consideration if the target has head protection (hardhat, or a strong enough helmet)
+ var/obeys_hardhats = TRUE
+ /// Does the target crush and flatten whoever it falls on
+ var/crushes_people = FALSE
+ /// What sound is played when the target falls onto a mob
+ var/impact_sound = 'sound/magic/clockwork/fellowship_armory.ogg' //CLANG
+
+/datum/element/falling_hazard/Attach(datum/target, damage, wound_bonus, hardhat_safety, crushes, impact_sound)
+ . = ..()
+ if(!isatom(target))
+ return ELEMENT_INCOMPATIBLE
+
+ src.fall_damage = damage
+ src.fall_wound_bonus = wound_bonus
+ src.obeys_hardhats = hardhat_safety
+ src.crushes_people = crushes
+ src.impact_sound = impact_sound
+
+ RegisterSignal(target, COMSIG_ATOM_ON_Z_IMPACT, PROC_REF(fall_onto_stuff))
+
+/datum/element/falling_hazard/Detach(datum/target)
+ . = ..()
+ UnregisterSignal(target, COMSIG_ATOM_ON_Z_IMPACT)
+
+/// Gathers every mob in the turf the target falls on, and does damage/crushes them/makes a message about the target falling on them
+/datum/element/falling_hazard/proc/fall_onto_stuff(datum/source, turf/impacted_turf, levels)
+ SIGNAL_HANDLER
+
+ var/mob/living/poor_target = locate(/mob/living) in impacted_turf
+
+ if(!poor_target)
+ return
+
+ var/target_head_armor = poor_target.run_armor_check(BODY_ZONE_HEAD, MELEE, silent = TRUE)
+
+ if(obeys_hardhats && target_head_armor >= 15) // 15 melee armor is enough that most head items dont have this, but anything above a hardhat should protect you
+ poor_target.visible_message(
+ span_warning("[source] falls on [poor_target], thankfully [poor_target.p_they()] had a helmet on!"),
+ span_userdanger("You are hit on the head by [source], good thing you had a helmet on!"),
+ span_hear("You hear a [crushes_people ? "crash" : "bonk"]!"),
+ )
+
+ if(crushes_people)
+ poor_target.Knockdown(0.25 SECONDS * fall_damage) // For a piano, that would be 15 seconds
+
+ playsound(poor_target, 'sound/weapons/parry.ogg', 50, TRUE) // You PARRIED the falling object with your EPIC hardhat
+ return
+
+ var/obj/item/bodypart/target_head = poor_target.get_bodypart(BODY_ZONE_HEAD)
+
+ // This does more damage the more levels the falling object has fallen
+ if(!crushes_people && target_head)
+ poor_target.apply_damage(fall_damage * levels, def_zone = BODY_ZONE_HEAD, forced = TRUE, wound_bonus = fall_wound_bonus)
+ else
+ poor_target.apply_damage(fall_damage * levels, forced = TRUE, spread_damage = TRUE, wound_bonus = fall_wound_bonus)
+
+ poor_target.visible_message(
+ span_userdanger("[source] falls on [poor_target], [crushes_people ? "crushing [poor_target.p_them()]" : "hitting [poor_target.p_them()]"] [target_head ? "on the head!" : "!"]"),
+ span_userdanger("You are [crushes_people ? "crushed" : "hit"] by [source]!"),
+ span_hear("You hear a [crushes_people ? "crash" : "bonk"]!"),
+ )
+
+ playsound(poor_target, impact_sound, 50, TRUE)
+
+ if(!crushes_people)
+ return
+
+ poor_target.AddElement(/datum/element/squish, 30 SECONDS)
+ poor_target.Paralyze(0.5 SECONDS * fall_damage) // For a piano, that would be 30 seconds
+
+ add_memory_in_range(poor_target, 7, MEMORY_VENDING_CRUSHED, list(DETAIL_PROTAGONIST = poor_target, DETAIL_WHAT_BY = src), story_value = STORY_VALUE_AMAZING, memory_flags = MEMORY_CHECK_BLINDNESS, protagonist_memory_flags = MEMORY_SKIP_UNCONSCIOUS)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 769cd233734..98a91e610aa 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -223,6 +223,7 @@
. += emissive_block
/atom/movable/proc/onZImpact(turf/impacted_turf, levels, message = TRUE)
+ SHOULD_CALL_PARENT(TRUE)
if(message)
visible_message(span_danger("[src] crashes into [impacted_turf]!"))
var/atom/highest = impacted_turf
@@ -233,6 +234,7 @@
if(hurt_atom.layer > highest.layer)
highest = hurt_atom
INVOKE_ASYNC(src, PROC_REF(SpinAnimation), 5, 2)
+ SEND_SIGNAL(src, COMSIG_ATOM_ON_Z_IMPACT, impacted_turf, levels)
return TRUE
/*
diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm
index f83dae18c8b..c8fe4db5bfe 100644
--- a/code/game/objects/items/paint.dm
+++ b/code/game/objects/items/paint.dm
@@ -16,6 +16,10 @@
/// How many uses are left
var/paintleft = 10
+/obj/item/paint/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/falling_hazard, damage = 20, wound_bonus = 5, hardhat_safety = TRUE, crushes = FALSE) // You ever watched home alone?
+
/obj/item/paint/red
name = "red paint"
paint_color = COLOR_RED
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 1c88ab8a16d..cd4c77401b5 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -33,6 +33,8 @@
latches = "triple_latch"
update_appearance()
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
+
/obj/item/storage/toolbox/update_overlays()
. = ..()
if(has_latches)
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index e6cc1c23793..5c8672efd0c 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -24,6 +24,10 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 50, ACID = 30)
var/force_opens = FALSE
+/obj/item/crowbar/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
+
/obj/item/crowbar/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1)
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index 01300df0512..bb769f1a0ba 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -54,6 +54,7 @@
set_greyscale(colors=list(screwdriver_colors[our_color]))
. = ..()
AddElement(/datum/element/eyestab)
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
/obj/item/screwdriver/abductor
name = "alien screwdriver"
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 59dcbaaf2ea..d93e6e931dd 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -53,6 +53,8 @@
. = ..()
AddElement(/datum/element/update_icon_updates_onmob, ITEM_SLOT_HANDS)
AddElement(/datum/element/tool_flash, light_range)
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
+
create_reagents(max_fuel)
reagents.add_reagent(/datum/reagent/fuel, max_fuel)
update_appearance()
diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm
index 0d850600aef..10e603594f5 100644
--- a/code/game/objects/items/tools/wirecutters.dm
+++ b/code/game/objects/items/tools/wirecutters.dm
@@ -46,6 +46,9 @@
if(random_color)
var/our_color = pick(wirecutter_colors)
set_greyscale(colors=list(wirecutter_colors[our_color]))
+
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
+
return ..()
/obj/item/wirecutters/attack(mob/living/carbon/attacked_carbon, mob/user)
diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm
index f969d1e00f7..ea43940dc05 100644
--- a/code/game/objects/items/tools/wrench.dm
+++ b/code/game/objects/items/tools/wrench.dm
@@ -24,6 +24,10 @@
toolspeed = 1
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 50, ACID = 30)
+/obj/item/wrench/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/falling_hazard, damage = force, wound_bonus = wound_bonus, hardhat_safety = TRUE, crushes = FALSE, impact_sound = hitsound)
+
/obj/item/wrench/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1)
diff --git a/code/modules/instruments/stationary.dm b/code/modules/instruments/stationary.dm
index 1b726e823ff..a1cc70dace2 100644
--- a/code/modules/instruments/stationary.dm
+++ b/code/modules/instruments/stationary.dm
@@ -41,6 +41,10 @@
density = TRUE
var/broken_icon_state = "pianobroken"
+/obj/structure/musician/piano/Initialize(mapload)
+ . = ..()
+ AddElement(/datum/element/falling_hazard, damage = 60, wound_bonus = 10, hardhat_safety = FALSE, crushes = TRUE, impact_sound = 'sound/effects/piano_hit.ogg')
+
/obj/structure/musician/piano/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm
index e1d58a155d2..22358fe20e4 100644
--- a/code/modules/library/book.dm
+++ b/code/modules/library/book.dm
@@ -110,6 +110,8 @@
. = ..()
book_data = new(starting_title, starting_author, starting_content)
+ AddElement(/datum/element/falling_hazard, damage = 5, wound_bonus = 0, hardhat_safety = TRUE, crushes = FALSE, impact_sound = drop_sound)
+
/obj/item/book/proc/on_read(mob/living/user)
if(book_data?.content)
user << browse("Penned by [book_data.author].
" + "[book_data.content]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index 1438503b54f..b835eb2f55e 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -258,6 +258,8 @@
thing.attach(src, FALSE)
equip_by_category[key] -= path
+ AddElement(/datum/element/falling_hazard, damage = 80, wound_bonus = 10, hardhat_safety = FALSE, crushes = TRUE)
+
/obj/vehicle/sealed/mecha/Destroy()
for(var/ejectee in occupants)
mob_exit(ejectee, silent = TRUE)
diff --git a/modular_skyrat/modules/primitive_fun/code/big_mortar.dm b/modular_skyrat/modules/primitive_fun/code/big_mortar.dm
index a957abf57d9..bfb0a47fef3 100644
--- a/modular_skyrat/modules/primitive_fun/code/big_mortar.dm
+++ b/modular_skyrat/modules/primitive_fun/code/big_mortar.dm
@@ -18,6 +18,8 @@
. = ..()
create_reagents(200, OPENCONTAINER)
+ AddElement(/datum/element/falling_hazard, damage = 20, wound_bonus = 5, hardhat_safety = TRUE, crushes = FALSE)
+
/obj/structure/large_mortar/examine(mob/user)
. = ..()
. += span_notice("It currently contains [length(contents)]/[maximum_contained_items] items.")
diff --git a/modular_skyrat/modules/reagent_forging/code/anvil.dm b/modular_skyrat/modules/reagent_forging/code/anvil.dm
index 9979556ec33..5d3f4a757b9 100644
--- a/modular_skyrat/modules/reagent_forging/code/anvil.dm
+++ b/modular_skyrat/modules/reagent_forging/code/anvil.dm
@@ -10,6 +10,8 @@
/obj/structure/reagent_anvil/Initialize(mapload)
. = ..()
+ AddElement(/datum/element/falling_hazard, damage = 40, wound_bonus = 10, hardhat_safety = FALSE, crushes = TRUE)
+
/obj/structure/reagent_anvil/update_appearance()
. = ..()
cut_overlays()
diff --git a/tgstation.dme b/tgstation.dme
index 95865ebb100..c772c17c56a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1113,6 +1113,7 @@
#include "code\datums\elements\embed.dm"
#include "code\datums\elements\empprotection.dm"
#include "code\datums\elements\eyestab.dm"
+#include "code\datums\elements\falling_hazard.dm"
#include "code\datums\elements\firestacker.dm"
#include "code\datums\elements\footstep.dm"
#include "code\datums\elements\forced_gravity.dm"