diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 35a85794fe5..e5d5bb723c1 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -54,7 +54,7 @@
//#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage
-//#define STATUS_EFFECT_SAWBLEED /datum/status_effect/saw_bleed //if the bleed builds up enough, takes a ton of damage
+#define STATUS_EFFECT_SAWBLEED /datum/status_effect/saw_bleed //if the bleed builds up enough, takes a ton of damage
//#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse
//#define CURSE_BLINDING 1 //makes the edges of the target's screen obscured
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index f05ac4ce96d..9b26bba67af 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -587,13 +587,14 @@ proc/GaussRandRound(var/sigma,var/roundto)
return 1
-/proc/is_blocked_turf(var/turf/T)
- var/cant_pass = 0
- if(T.density) cant_pass = 1
- for(var/atom/A in T)
- if(A.density)//&&A.anchored
- cant_pass = 1
- return cant_pass
+proc/is_blocked_turf(turf/T, exclude_mobs)
+ if(T.density)
+ return 1
+ for(var/i in T)
+ var/atom/A = i
+ if(A.density && (!exclude_mobs || !ismob(A)))
+ return 1
+ return 0
/proc/get_step_towards2(var/atom/ref , var/atom/trg)
var/base_dir = get_dir(ref, get_step_towards(ref,trg))
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index cfafa912b64..6e809b32606 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -7,4 +7,76 @@
/datum/status_effect/cultghost/tick()
if(owner.reagents)
- owner.reagents.del_reagent("holywater") //can't be deconverted
\ No newline at end of file
+ owner.reagents.del_reagent("holywater") //can't be deconverted
+
+/datum/status_effect/saw_bleed
+ id = "saw_bleed"
+ duration = -1 //removed under specific conditions
+ tick_interval = 6
+ alert_type = null
+ var/mutable_appearance/bleed_overlay
+ var/mutable_appearance/bleed_underlay
+ var/bleed_amount = 3
+ var/bleed_buildup = 3
+ var/delay_before_decay = 5
+ var/bleed_damage = 200
+ var/needs_to_bleed = FALSE
+
+/datum/status_effect/saw_bleed/Destroy()
+ if(owner)
+ owner.cut_overlay(bleed_overlay)
+ owner.underlays -= bleed_underlay
+ QDEL_NULL(bleed_overlay)
+ return ..()
+
+/datum/status_effect/saw_bleed/on_apply()
+ if(owner.stat == DEAD)
+ return FALSE
+ bleed_overlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
+ bleed_underlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
+ var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
+ var/icon_height = I.Height()
+ bleed_overlay.pixel_x = -owner.pixel_x
+ bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
+ bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
+ bleed_underlay.pixel_x = -owner.pixel_x
+ bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
+ bleed_underlay.alpha = 40
+ owner.add_overlay(bleed_overlay)
+ owner.underlays += bleed_underlay
+ return ..()
+
+/datum/status_effect/saw_bleed/tick()
+ if(owner.stat == DEAD)
+ qdel(src)
+ else
+ add_bleed(-1)
+
+/datum/status_effect/saw_bleed/proc/add_bleed(amount)
+ owner.cut_overlay(bleed_overlay)
+ owner.underlays -= bleed_underlay
+ bleed_amount += amount
+ if(bleed_amount)
+ if(bleed_amount >= 10)
+ needs_to_bleed = TRUE
+ qdel(src)
+ else
+ if(amount > 0)
+ tick_interval += delay_before_decay
+ bleed_overlay.icon_state = "bleed[bleed_amount]"
+ bleed_underlay.icon_state = "bleed[bleed_amount]"
+ owner.add_overlay(bleed_overlay)
+ owner.underlays += bleed_underlay
+ else
+ qdel(src)
+
+/datum/status_effect/saw_bleed/on_remove()
+ if(needs_to_bleed)
+ var/turf/T = get_turf(owner)
+ new /obj/effect/temp_visual/bleed/explode(T)
+ for(var/d in alldirs)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
+ playsound(T, "desceration", 200, 1, -1)
+ owner.adjustBruteLoss(bleed_damage)
+ else
+ new /obj/effect/temp_visual/bleed(get_turf(owner))
\ No newline at end of file
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 880043c8be6..dda9d18c77f 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -228,4 +228,65 @@
randomdir = FALSE
pixel_y = -16
pixel_x = -16
- duration = 20
\ No newline at end of file
+ duration = 20
+
+/obj/effect/temp_visual/bleed
+ name = "bleed"
+ icon = 'icons/effects/bleed.dmi'
+ icon_state = "bleed0"
+ duration = 10
+ var/shrink = TRUE
+
+/obj/effect/temp_visual/bleed/Initialize(mapload, atom/size_calc_target)
+ . = ..()
+ var/size_matrix = matrix()
+ if(size_calc_target)
+ layer = size_calc_target.layer + 0.01
+ var/icon/I = icon(size_calc_target.icon, size_calc_target.icon_state, size_calc_target.dir)
+ size_matrix = matrix() * (I.Height()/world.icon_size)
+ transform = size_matrix //scale the bleed overlay's size based on the target's icon size
+ var/matrix/M = transform
+ if(shrink)
+ M = size_matrix*0.1
+ else
+ M = size_matrix*2
+ animate(src, alpha = 20, transform = M, time = duration, flags = ANIMATION_PARALLEL)
+
+/obj/effect/temp_visual/bleed/explode
+ icon_state = "bleed10"
+ duration = 12
+ shrink = FALSE
+
+/obj/effect/temp_visual/small_smoke
+ icon_state = "smoke"
+ duration = 50
+
+/obj/effect/temp_visual/small_smoke/halfsecond
+ duration = 5
+
+/obj/effect/temp_visual/dir_setting/firing_effect
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "firing_effect"
+ duration = 2
+
+/obj/effect/temp_visual/dir_setting/firing_effect/setDir(newdir)
+ switch(newdir)
+ if(NORTH)
+ layer = BELOW_MOB_LAYER
+ pixel_x = rand(-3,3)
+ pixel_y = rand(4,6)
+ if(SOUTH)
+ pixel_x = rand(-3,3)
+ pixel_y = rand(-1,1)
+ else
+ pixel_x = rand(-1,1)
+ pixel_y = rand(-1,1)
+ ..()
+
+/obj/effect/temp_visual/dir_setting/firing_effect/energy
+ icon_state = "firing_effect_energy"
+ duration = 3
+
+/obj/effect/temp_visual/dir_setting/firing_effect/magic
+ icon_state = "shieldsparkles"
+ duration = 3
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm
index 0d85245d58f..12d4f95d964 100644
--- a/code/game/objects/items/weapons/melee/energy.dm
+++ b/code/game/objects/items/weapons/melee/energy.dm
@@ -2,6 +2,8 @@
var/active = 0
var/force_on = 30 //force when active
var/throwforce_on = 20
+ var/faction_bonus_force = 0 //Bonus force dealt against certain factions
+ var/list/nemesis_factions //Any mob with a faction that exists in this list will take bonus damage/effects
w_class = WEIGHT_CLASS_SMALL
var/w_class_on = WEIGHT_CLASS_BULKY
var/icon_state_on = "axe1"
@@ -13,6 +15,19 @@
var/brightness_on = 2
var/colormap = list(red=LIGHT_COLOR_RED, blue=LIGHT_COLOR_LIGHTBLUE, green=LIGHT_COLOR_GREEN, purple=LIGHT_COLOR_PURPLE, rainbow=LIGHT_COLOR_WHITE)
+/obj/item/melee/energy/attack(mob/living/target, mob/living/carbon/human/user)
+ var/nemesis_faction = FALSE
+ if(LAZYLEN(nemesis_factions))
+ for(var/F in target.faction)
+ if(F in nemesis_factions)
+ nemesis_faction = TRUE
+ force += faction_bonus_force
+ nemesis_effects(user, target)
+ break
+ . = ..()
+ if(nemesis_faction)
+ force -= faction_bonus_force
+
/obj/item/melee/energy/suicide_act(mob/user)
user.visible_message(pick("[user] is slitting [user.p_their()] stomach open with the [name]! It looks like [user.p_theyre()] trying to commit seppuku.", \
"[user] is falling on the [name]! It looks like [user.p_theyre()] trying to commit suicide."))
@@ -225,3 +240,125 @@
desc = "An extremely sharp blade made out of hard light. Packs quite a punch."
icon_state = "lightblade"
item_state = "lightblade"
+
+/obj/item/melee/energy/proc/nemesis_effects(mob/living/user, mob/living/target)
+ return
+
+/obj/item/melee/energy/cleaving_saw
+ name = "cleaving saw"
+ desc = "This saw, effective at drawing the blood of beasts, transforms into a long cleaver that makes use of centrifugal force."
+ force = 12
+ force_on = 20 //force when active
+ throwforce = 20
+ throwforce_on = 20
+ icon = 'icons/obj/lavaland/artefacts.dmi'
+ lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
+ inhand_x_dimension = 64
+ inhand_y_dimension = 64
+ icon_state = "cleaving_saw"
+ icon_state_on = "cleaving_saw_open"
+ slot_flags = SLOT_BELT
+ var/attack_verb_off = list("attacked", "sawed", "sliced", "torn", "ripped", "diced", "cut")
+ attack_verb_on = list("cleaved", "swiped", "slashed", "chopped")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ w_class = WEIGHT_CLASS_BULKY
+ sharp = 1
+ faction_bonus_force = 30
+ nemesis_factions = list("mining", "boss")
+ var/transform_cooldown
+ var/swiping = FALSE
+
+/obj/item/melee/energy/cleaving_saw/nemesis_effects(mob/living/user, mob/living/target)
+ var/datum/status_effect/saw_bleed/B = target.has_status_effect(STATUS_EFFECT_SAWBLEED)
+ if(!B)
+ if(!active) //This isn't in the above if-check so that the else doesn't care about active
+ target.apply_status_effect(STATUS_EFFECT_SAWBLEED)
+ else
+ B.add_bleed(B.bleed_buildup)
+
+/obj/item/melee/energy/cleaving_saw/attack_self(mob/living/carbon/user)
+ transform_weapon(user)
+
+/obj/item/melee/energy/cleaving_saw/proc/transform_weapon(mob/living/user, supress_message_text)
+ if(transform_cooldown > world.time)
+ return FALSE
+
+ transform_cooldown = world.time + (CLICK_CD_MELEE * 0.5)
+ user.changeNext_move(CLICK_CD_MELEE * 0.25)
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.disabilities & CLUMSY && prob(50))
+ to_chat(H, "You accidentally cut yourself with [src], like a doofus!")
+ H.take_organ_damage(10,10)
+ active = !active
+ if(active)
+ force = force_on
+ throwforce = throwforce_on
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ throw_speed = 4
+ if(attack_verb_on.len)
+ attack_verb = attack_verb_on
+ if(!item_color)
+ icon_state = icon_state_on
+ set_light(brightness_on)
+ else
+ icon_state = "sword[item_color]"
+ set_light(brightness_on, l_color=colormap[item_color])
+ w_class = w_class_on
+ playsound(user, 'sound/magic/fellowship_armory.ogg', 35, TRUE, frequency = 90000 - (active * 30000))
+ to_chat(user, "You open [src]. It will now cleave enemies in a wide arc and deal additional damage to fauna.")
+ else
+ force = initial(force)
+ throwforce = initial(throwforce)
+ hitsound = initial(hitsound)
+ throw_speed = initial(throw_speed)
+ if(attack_verb_on.len)
+ attack_verb = list()
+ icon_state = initial(icon_state)
+ w_class = initial(w_class)
+ playsound(user, 'sound/magic/fellowship_armory.ogg', 35, 1) //changed it from 50% volume to 35% because deafness
+ set_light(0)
+ to_chat(user, "You close [src]. It will now attack rapidly and cause fauna to bleed.")
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
+ add_fingerprint(user)
+
+/obj/item/melee/energy/cleaving_saw/examine(mob/user)
+ ..()
+ to_chat(user, "It is [active ? "open, will cleave enemies in a wide arc and deal additional damage to fauna":"closed, and can be used for rapid consecutive attacks that cause fauna to bleed"].
\
+ Both modes will build up existing bleed effects, doing a burst of high damage if the bleed is built up high enough.
\
+ Transforming it immediately after an attack causes the next attack to come out faster.")
+
+/obj/item/melee/energy/cleaving_saw/suicide_act(mob/user)
+ user.visible_message("[user] is [active ? "closing [src] on [user.p_their()] neck" : "opening [src] into [user.p_their()] chest"]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/melee/energy/cleaving_saw/melee_attack_chain(mob/user, atom/target, params)
+ ..()
+ if(!active)
+ user.changeNext_move(CLICK_CD_MELEE * 0.5) //when closed, it attacks very rapidly
+
+/obj/item/melee/energy/cleaving_saw/attack(mob/living/target, mob/living/carbon/human/user)
+ if(!active || swiping || !target.density || get_turf(target) == get_turf(user))
+ if(!active)
+ faction_bonus_force = 0
+ ..()
+ if(!active)
+ faction_bonus_force = initial(faction_bonus_force)
+ else
+ var/turf/user_turf = get_turf(user)
+ var/dir_to_target = get_dir(user_turf, get_turf(target))
+ swiping = TRUE
+ var/static/list/cleaving_saw_cleave_angles = list(0, -45, 45) //so that the animation animates towards the target clicked and not towards a side target
+ for(var/i in cleaving_saw_cleave_angles)
+ var/turf/T = get_step(user_turf, turn(dir_to_target, i))
+ for(var/mob/living/L in T)
+ if(user.Adjacent(L) && L.density)
+ melee_attack_chain(user, L)
+ swiping = FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 6e12748911b..873e47ae1a5 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -68,3 +68,5 @@
var/list/status_effects //a list of all status effects the mob has
var/deathgasp_on_death = FALSE
+
+ var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
new file mode 100644
index 00000000000..5fd5b4e9231
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -0,0 +1,265 @@
+#define MINER_DASH_RANGE 4
+
+/*
+
+BLOOD-DRUNK MINER
+
+Effectively a highly aggressive miner, the blood-drunk miner has very few attacks but compensates by being highly aggressive.
+
+The blood-drunk miner's attacks are as follows
+- If not in KA range, it will rapidly dash at its target
+- If in KA range, it will fire its kinetic accelerator
+- If in melee range, will rapidly attack, akin to an actual player
+- After any of these attacks, may transform its cleaving saw:
+ Untransformed, it attacks very rapidly for smaller amounts of damage
+ Transformed, it attacks at normal speed for higher damage and cleaves enemies hit
+
+When the blood-drunk miner dies, it leaves behind the cleaving saw it was using and its kinetic accelerator.
+
+Difficulty: Medium
+
+*/
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner
+ name = "blood-drunk miner"
+ desc = "A miner destined to wander forever, engaged in an endless hunt."
+ health = 900
+ maxHealth = 900
+ icon_state = "miner"
+ icon_living = "miner"
+ icon = 'icons/mob/alienqueen.dmi'
+ light_color = "#E4C7C5"
+ speak_emote = list("roars")
+ speed = 1
+ move_to_delay = 3
+ projectiletype = /obj/item/projectile/kinetic/miner
+ projectilesound = 'sound/weapons/kenetic_accel.ogg'
+ ranged = 1
+ ranged_cooldown_time = 16
+ pixel_x = -16
+ loot = list(/obj/item/melee/energy/cleaving_saw, /obj/item/gun/energy/kinetic_accelerator)
+ wander = FALSE
+ del_on_death = TRUE
+ blood_volume = BLOOD_VOLUME_NORMAL
+ var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
+ var/time_until_next_transform = 0
+ var/dashing = FALSE
+ var/dash_cooldown = 15
+ var/guidance = FALSE
+ deathmessage = "falls to the ground, decaying into glowing particles."
+ death_sound = "bodyfall"
+
+/obj/item/gps/internal/miner
+ icon_state = null
+ gpstag = "Resonant Signal"
+ desc = "The sweet blood, oh, it sings to me."
+ invisibility = 100
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/guidance
+ guidance = TRUE
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
+ . = ..()
+ if(. && prob(12))
+ INVOKE_ASYNC(src, .proc/dash)
+
+/obj/item/melee/energy/cleaving_saw/miner //nerfed saw because it is very murdery
+ force = 6
+ force_on = 10
+
+/obj/item/melee/energy/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
+ target.add_stun_absorption("miner", 10, INFINITY)
+ ..()
+ target.stun_absorption -= "miner"
+
+/obj/item/projectile/kinetic/miner
+ damage = 20
+ speed = 0.9
+ icon_state = "ka_tracer"
+ range = MINER_DASH_RANGE
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize()
+ . = ..()
+ miner_saw = new(src)
+ internal_gps = new/obj/item/gps/internal/miner(src)
+
+ // Add a zone selection UI; otherwise the mob can't melee attack properly.
+ zone_sel = new /obj/screen/zone_sel()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
+ var/adjustment_amount = amount * 0.1
+ if(world.time + adjustment_amount > next_move)
+ changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
+ . = ..()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
+ if(health > 0)
+ return
+ new /obj/effect/temp_visual/dir_setting/miner_death(loc, dir)
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Move(atom/newloc)
+ if(dashing || (newloc && newloc.z == z && (islava(newloc) || ischasm(newloc)))) //we're not stupid!
+ return FALSE
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/ex_act(severity, target)
+ if(dash())
+ return
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/AttackingTarget()
+ if(QDELETED(target))
+ return
+ if(next_move > world.time || !Adjacent(target)) //some cheating
+ INVOKE_ASYNC(src, .proc/quick_attack_loop)
+ return
+ face_atom(target)
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ visible_message("[src] butchers [L]!",
+ "You butcher [L], restoring your health!")
+ if(!is_station_level(z) || client) //NPC monsters won't heal while on station
+ if(guidance)
+ adjustHealth(-L.maxHealth)
+ else
+ adjustHealth(-(L.maxHealth * 0.5))
+ L.gib()
+ return TRUE
+ changeNext_move(CLICK_CD_MELEE)
+ miner_saw.melee_attack_chain(src, target)
+ if(guidance)
+ adjustHealth(-2)
+ transform_weapon()
+ INVOKE_ASYNC(src, .proc/quick_attack_loop)
+ return TRUE
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
+ if(!used_item && !isturf(A))
+ used_item = miner_saw
+ ..()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/GiveTarget(new_target)
+ var/targets_the_same = (new_target == target)
+ . = ..()
+ if(. && target && !targets_the_same)
+ wander = TRUE
+ transform_weapon()
+ INVOKE_ASYNC(src, .proc/quick_attack_loop)
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/OpenFire()
+ Goto(target, move_to_delay, minimum_distance)
+ if(get_dist(src, target) > MINER_DASH_RANGE && dash_cooldown <= world.time)
+ INVOKE_ASYNC(src, .proc/dash, target)
+ else
+ shoot_ka()
+ transform_weapon()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/shoot_ka()
+ if(ranged_cooldown <= world.time && get_dist(src, target) <= MINER_DASH_RANGE && !Adjacent(target))
+ ranged_cooldown = world.time + ranged_cooldown_time
+ visible_message("[src] fires the proto-kinetic accelerator!")
+ face_atom(target)
+ new /obj/effect/temp_visual/dir_setting/firing_effect(loc, dir)
+ Shoot(target)
+ changeNext_move(CLICK_CD_RANGE)
+
+//I'm still of the belief that this entire proc needs to be wiped from existence.
+// do not take my touching of it to be endorsement of it. ~mso
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/quick_attack_loop()
+ while(!QDELETED(target) && next_move <= world.time) //this is done this way because next_move can change to be sooner while we sleep.
+ stoplag(1)
+ sleep((next_move - world.time) * 1.5) //but don't ask me what the fuck this is about
+ if(QDELETED(target))
+ return
+ if(dashing || next_move > world.time || !Adjacent(target))
+ if(dashing && next_move <= world.time)
+ next_move = world.time + 1
+ INVOKE_ASYNC(src, .proc/quick_attack_loop) //lets try that again.
+ return
+ AttackingTarget()
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash(atom/dash_target)
+ if(world.time < dash_cooldown)
+ return
+ var/list/accessable_turfs = list()
+ var/self_dist_to_target = 0
+ var/turf/own_turf = get_turf(src)
+ if(!QDELETED(dash_target))
+ self_dist_to_target += get_dist(dash_target, own_turf)
+ for(var/turf/simulated/O in RANGE_TURFS(MINER_DASH_RANGE, own_turf))
+ var/turf_dist_to_target = 0
+ if(!QDELETED(dash_target))
+ turf_dist_to_target += get_dist(dash_target, O)
+ if(get_dist(src, O) >= MINER_DASH_RANGE && turf_dist_to_target <= self_dist_to_target && !islava(O) && !ischasm(O))
+ var/valid = TRUE
+ for(var/turf/T in getline(own_turf, O))
+ if(is_blocked_turf(T, TRUE))
+ valid = FALSE
+ continue
+ if(valid)
+ accessable_turfs[O] = turf_dist_to_target
+ var/turf/target_turf
+ if(!QDELETED(dash_target))
+ var/closest_dist = MINER_DASH_RANGE
+ for(var/t in accessable_turfs)
+ if(accessable_turfs[t] < closest_dist)
+ closest_dist = accessable_turfs[t]
+ for(var/t in accessable_turfs)
+ if(accessable_turfs[t] != closest_dist)
+ accessable_turfs -= t
+ if(!LAZYLEN(accessable_turfs))
+ return
+ dash_cooldown = world.time + initial(dash_cooldown)
+ target_turf = pick(accessable_turfs)
+ var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
+ var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
+ new /obj/effect/temp_visual/small_smoke/halfsecond(step_back_turf)
+ new /obj/effect/temp_visual/small_smoke/halfsecond(step_forward_turf)
+ var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc, src)
+ animate(D, alpha = 0, time = 5)
+ forceMove(step_back_turf)
+ playsound(own_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
+ dashing = TRUE
+ alpha = 0
+ animate(src, alpha = 255, time = 5)
+ sleep(2)
+ D.forceMove(step_forward_turf)
+ forceMove(target_turf)
+ playsound(target_turf, 'sound/weapons/punchmiss.ogg', 40, 1, -1)
+ sleep(1)
+ dashing = FALSE
+ shoot_ka()
+ return TRUE
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/transform_weapon()
+ if(time_until_next_transform <= world.time)
+ miner_saw.transform_cooldown = 0
+ miner_saw.transform_weapon(src, TRUE)
+ icon_state = "miner[miner_saw.active ? "_transformed":""]"
+ icon_living = "miner[miner_saw.active ? "_transformed":""]"
+ time_until_next_transform = world.time + rand(50, 100)
+
+/obj/effect/temp_visual/dir_setting/miner_death
+ icon_state = "miner_death"
+ duration = 15
+
+/obj/effect/temp_visual/dir_setting/miner_death/Initialize(mapload, set_dir)
+ . = ..()
+ INVOKE_ASYNC(src, .proc/fade_out)
+
+/obj/effect/temp_visual/dir_setting/miner_death/proc/fade_out()
+ var/matrix/M = new
+ M.Turn(pick(90, 270))
+ var/final_dir = dir
+ if(dir & (EAST|WEST)) //Facing east or west
+ final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass
+
+ animate(src, transform = M, pixel_y = -6, dir = final_dir, time = 2, easing = EASE_IN|EASE_OUT)
+ sleep(5)
+ animate(src, color = list("#A7A19E", "#A7A19E", "#A7A19E", list(0, 0, 0)), time = 10, easing = EASE_IN, flags = ANIMATION_PARALLEL)
+ sleep(4)
+ animate(src, alpha = 0, time = 6, easing = EASE_OUT, flags = ANIMATION_PARALLEL)
+
+#undef MINER_DASH_RANGE
\ No newline at end of file
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 2eea5755293..d4406a386b5 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -548,3 +548,37 @@
dna.SetSEState(block, 0, 1) //Fix the gene
genemutcheck(src, block,null, MUTCHK_FORCED)
dna.UpdateSE()
+
+///////////////////////////////////// STUN ABSORPTION /////////////////////////////////////
+
+/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message)
+//adds a stun absorption with a key, a duration in deciseconds, its priority, and the messages it makes when you're stun/examined, if any
+ if(!islist(stun_absorption))
+ stun_absorption = list()
+ if(stun_absorption[key])
+ stun_absorption[key]["end_time"] = world.time + duration
+ stun_absorption[key]["priority"] = priority
+ stun_absorption[key]["stuns_absorbed"] = 0
+ else
+ stun_absorption[key] = list("end_time" = world.time + duration, "priority" = priority, "stuns_absorbed" = 0, \
+ "visible_message" = message, "self_message" = self_message, "examine_message" = examine_message)
+
+/mob/living/proc/absorb_stun(amount, ignoring_flag_presence)
+ if(!amount || amount <= 0 || stat || ignoring_flag_presence || !islist(stun_absorption))
+ return FALSE
+ var/priority_absorb_key
+ var/highest_priority
+ for(var/i in stun_absorption)
+ if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority))
+ priority_absorb_key = stun_absorption[i]
+ highest_priority = priority_absorb_key["priority"]
+ if(priority_absorb_key)
+ if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
+ if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
+ else if(priority_absorb_key["visible_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]")
+ else if(priority_absorb_key["self_message"])
+ to_chat(src, "[priority_absorb_key["self_message"]]")
+ priority_absorb_key["stuns_absorbed"] += amount
+ return TRUE
\ No newline at end of file
diff --git a/icons/effects/bleed.dmi b/icons/effects/bleed.dmi
new file mode 100644
index 00000000000..d563334f632
Binary files /dev/null and b/icons/effects/bleed.dmi differ
diff --git a/icons/mob/alienqueen.dmi b/icons/mob/alienqueen.dmi
index b01af7e71b4..5d09aad2480 100644
Binary files a/icons/mob/alienqueen.dmi and b/icons/mob/alienqueen.dmi differ
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
new file mode 100644
index 00000000000..69b9922f140
Binary files /dev/null and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
new file mode 100644
index 00000000000..09cef64e2b0
Binary files /dev/null and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi
index 45927256e35..a0486389b74 100644
Binary files a/icons/obj/lavaland/artefacts.dmi and b/icons/obj/lavaland/artefacts.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 2cbae757457..09323624471 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1926,6 +1926,7 @@
#include "code\modules\mob\living\simple_animal\hostile\tree.dm"
#include "code\modules\mob\living\simple_animal\hostile\venus_human_trap.dm"
#include "code\modules\mob\living\simple_animal\hostile\winter_mobs.dm"
+#include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\colossus.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\drake.dm"
diff --git a/sound/magic/fellowship_armory.ogg b/sound/magic/fellowship_armory.ogg
new file mode 100644
index 00000000000..c108d4621c6
Binary files /dev/null and b/sound/magic/fellowship_armory.ogg differ