diff --git a/code/game/objects/effects/temporary_visuals/misc_visuals.dm b/code/game/objects/effects/temporary_visuals/misc_visuals.dm
index 84e7966820c..20df3bdf7e9 100644
--- a/code/game/objects/effects/temporary_visuals/misc_visuals.dm
+++ b/code/game/objects/effects/temporary_visuals/misc_visuals.dm
@@ -523,6 +523,16 @@
animate(get_filter("ray"), offset = 10, time = 10 SECONDS, loop = -1)
animate(offset = 0, time = 10 SECONDS)
+/obj/effect/temp_visual/electrocution
+ name = "electrocution"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "electrocution"
+ duration = 1 SECONDS
+
+/obj/effect/temp_visual/electrocution/Initialize(mapload, set_duration)
+ duration = set_duration
+ . = ..()
+
/obj/effect/temp_visual/warning
name = "warning"
icon = 'icons/effects/96x96.dmi'
diff --git a/code/modules/mob/living/carbon/_defines.dm b/code/modules/mob/living/carbon/_defines.dm
index 871b140a503..2a62d6611a6 100644
--- a/code/modules/mob/living/carbon/_defines.dm
+++ b/code/modules/mob/living/carbon/_defines.dm
@@ -17,3 +17,9 @@
#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point
#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point
#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point
+
+/// Shock defines
+#define SHOCK_MINOR 1 // Minimum amount of damage for something to be considered a minor shock
+#define SHOCK_MODERATE 26 // Minimum amount of damage for something to be considered a moderate shock
+#define SHOCK_MAJOR 51 // Minimum amount of damage for something to be considered a major shock
+#define SHOCK_FLASH 201 // Minimum amount of damage to arc flash
diff --git a/code/modules/mob/living/carbon/carbon_procs.dm b/code/modules/mob/living/carbon/carbon_procs.dm
index b27e3f0bb7b..7026304b167 100644
--- a/code/modules/mob/living/carbon/carbon_procs.dm
+++ b/code/modules/mob/living/carbon/carbon_procs.dm
@@ -172,21 +172,52 @@
for(var/victim in shocking_queue)
var/mob/living/carbon/C = victim
C.electrocute_act(shock_damage * 0.75, src, 1, flags)
- //Stun
- var/should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)
- if(should_stun)
- Stun(1 SECONDS)
- //Jitter and other fluff.
- AdjustJitter(2000 SECONDS)
- AdjustStuttering(4 SECONDS)
- addtimer(CALLBACK(src, PROC_REF(secondary_shock), should_stun), 1 SECONDS)
+
+ // Minor shock - Jitters and Stutters
+ var/jitter_amount = 0
+ if(shock_damage >= SHOCK_MINOR)
+ jitter_amount = shock_damage
+ AdjustStuttering(4 SECONDS)
+
+ // Moderate shock - Stun, knockdown, funny effect
+ var/should_stun = FALSE
+ var/stun_dur = 0 SECONDS
+ if(shock_damage >= SHOCK_MODERATE)
+ should_stun = (!(flags & SHOCK_TESLA) || siemens_coeff > 0.5) && !(flags & SHOCK_NOSTUN)
+ if(should_stun)
+ stun_dur = max((shock_damage / 50) * 1 SECONDS, 4 SECONDS)
+ Stun(stun_dur)
+ if(shock_damage >= SHOCK_FLASH) // Arc flash explosion is instant, don't wait for the secondary shock and bypass the effect
+ stun_dur = 0
+ else
+ var/obj/effect/temp_visual/electrocution/shock_effect = new /obj/effect/temp_visual/electrocution(loc, stun_dur)
+ shock_effect.setDir(dir)
+ emote("scream")
+ AdjustStuttering(4 SECONDS)
+
+ // Major Shock - YEET
+ var/throw_distance = 0
+ var/throw_dir = null
+ if(shock_damage >= SHOCK_MAJOR)
+ do_sparks(3, TRUE, src)
+ AdjustStuttering(4 SECONDS)
+ if(isatom(source))
+ var/atom/shock_source = source
+ throw_dir = get_dir(shock_source.loc, src)
+ throw_distance = round(shock_damage / 10)
+
+ addtimer(CALLBACK(src, PROC_REF(secondary_shock), jitter_amount, should_stun, throw_dir, throw_distance), stun_dur)
return shock_damage
-///Called slightly after electrocute act to reduce jittering and apply a secondary knockdown.
-/mob/living/carbon/proc/secondary_shock(should_stun)
- AdjustJitter(-2000 SECONDS, bound_lower = 20 SECONDS) //Still jittery, but vastly less
+/// Called after electrocute_act to apply secondary effects
+/mob/living/carbon/proc/secondary_shock(jitter_amount, should_stun, throw_dir, throw_distance)
+ if(jitter_amount)
+ AdjustJitter(jitter_amount)
if(should_stun)
KnockDown(6 SECONDS)
+ if(throw_dir && throw_distance && !HAS_TRAIT(src, TRAIT_MAGPULSE)) // Don't yeet if they're wearing magboots
+ var/turf/general_direction = get_edge_target_turf(src, throw_dir)
+ src.throw_at(general_direction, throw_distance, throw_distance)
/mob/living/carbon/swap_hand()
if(SEND_SIGNAL(src, COMSIG_MOB_SWAPPING_HANDS, get_active_hand()) == COMPONENT_BLOCK_SWAP)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f1566e0a230..dc91c2b6dc5 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -97,7 +97,7 @@
"\The [source] arc flashes and electrocutes you!",
"You hear a lightning-like crack!")
playsound(loc, 'sound/effects/eleczap.ogg', 50, TRUE, -1)
- explosion(loc, -1, 0, 2, 2, cause = "Extreme Electrocution from [source]")
+ explosion(loc, -1, 1, 3, 3, cause = "Extreme Electrocution from [source]")
else
apply_damage(shock_damage, STAMINA)
visible_message(
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 87807830244..725c60a9c2d 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ