Reworks and fixes blood drunk miner megafauna (#96286)

## About The Pull Request

Blood-drunk miner has been reworked to change it from a DPS race into a
more dynamic fight

- Buffed health from 900 to 1300 (45% increase), slightly increased
speed (3 -> 2.5), increased saw damage (6/10 -> 8/12) to compensate for
other changes below
- Slightly reduced PKA shot damage (20 -> 18)
- Saw attacks now have a slightly longer delay inbetween hits
(especially in unfolded form), ***no longer are guaranteed to hit no
matter what*** (was a bug which forced players to eat 50 damage to the
face) and slow down the miner during the combo
- Singular PKA shot has been replaced with a telegraphed barrage of 3
projectiles, during which the miner cannot move, letting players gain
some distance
- Dash is no longer a teleport but a proper charge akin to that of
lobstrocities with a very short chargeup that deals no damage or
knockdown, but allows the miner to travel further
- Miner's attacks no longer give the target stun immunity for a brief
moment (why?)
- Default PKA it drops has been replaced with an infernal version, which
comes with a cheaper (30% vs 50% of the default one) in-built rapid
repeater (that also has a less punishing miss delay)

<img width="169" height="143" alt="Aseprite_UfXRbgVuqB"
src="https://github.com/user-attachments/assets/3ac257a4-5443-4c7f-a891-4e69f8188cb4"
/>

---

Full fight with a single basic pen and 2 legion cores, no PKC trophies:
(fumbled a bit midway though, pre-PKA projectile damage nerf)


https://github.com/user-attachments/assets/40c8af0d-035c-49da-861b-5e74ca7d7551

## Why It's Good For The Game

Current blood-drunk miner is a hard DPS check with unavoidable damage
(both due to the bug and instant dashes/PKA hits) that simply requires
you to facetank the damage using heals and kill it first before it kills
you.
This should make the fight a bit longer, more engaging and fairer than
it is right now.

## Changelog
🆑
add: Blood-drunk miner now drops an infernal PKA with an in-built
improved rapid repeater modification
balance: Blood-drunk miner has been reworked with new attacks and
patterns
fix: Blood-drunk miner's combos are no longer guaranteed to land even if
you move away from it
/🆑
This commit is contained in:
SmArtKar
2026-06-05 18:03:12 +02:00
committed by GitHub
parent 802e3053af
commit 9b110eb64e
19 changed files with 226 additions and 84 deletions
@@ -12,16 +12,17 @@ Difficulty: Medium
/mob/living/basic/boss/blood_drunk_miner
name = "blood-drunk miner"
desc = "A miner destined to wander forever, engaged in an endless hunt."
health = 900
maxHealth = 900
health = 1300
maxHealth = 1300
icon_state = "miner"
icon_living = "miner"
base_icon_state = "miner"
icon = 'icons/mob/simple/broadMobs.dmi'
health_doll_icon = "miner"
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_SPECIAL|MOB_MINING
light_color = COLOR_LIGHT_GRAYISH_RED
speak_emote = list("roars")
speed = 3
speed = 2.5
pixel_x = -16
base_pixel_x = -16
basic_mob_flags = DEL_ON_DEATH
@@ -43,7 +44,7 @@ Difficulty: Medium
victor_memory_type = /datum/memory/megafauna_slayer
crusher_loot = list(/obj/item/crusher_trophy/miner_eye, /obj/item/knife/hunting/wildhunter)
regular_loot = list(/obj/item/melee/cleaving_saw, /obj/item/gun/energy/recharge/kinetic_accelerator)
regular_loot = list(/obj/item/melee/cleaving_saw, /obj/item/gun/energy/recharge/kinetic_accelerator/bdm)
/// Their little saw
var/obj/item/melee/cleaving_saw/miner/miner_saw
@@ -87,9 +88,9 @@ Difficulty: Medium
/// Returns a list of innate actions for the blood-drunk miner.
/mob/living/basic/boss/blood_drunk_miner/proc/get_innate_actions()
var/static/list/innate_abilities = list(
/datum/action/cooldown/mob_cooldown/dash = BB_BDM_DASH_ABILITY,
/datum/action/cooldown/mob_cooldown/projectile_attack/kinetic_accelerator = BB_BDM_KINETIC_ACCELERATOR_ABILITY,
var/list/innate_abilities = list(
/datum/action/cooldown/mob_cooldown/charge/basic_charge/blood_drunk_miner = BB_BDM_DASH_ABILITY,
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator = BB_BDM_KINETIC_ACCELERATOR_ABILITY,
/datum/action/cooldown/mob_cooldown/dash_attack = BB_BDM_DASH_ATTACK_ABILITY,
/datum/action/cooldown/mob_cooldown/transform_weapon = BB_BDM_TRANSFORM_WEAPON_ABILITY,
)
@@ -101,6 +102,13 @@ Difficulty: Medium
INVOKE_ASYNC(ai_controller.blackboard[BB_BDM_TRANSFORM_WEAPON_ABILITY], TYPE_PROC_REF(/datum/action, Trigger), src, NONE)
/mob/living/basic/boss/blood_drunk_miner/proc/transform_saw()
miner_saw.attack_self(src)
var/saw_open = HAS_TRAIT(miner_saw, TRAIT_TRANSFORM_ACTIVE)
rapid_melee_hits = saw_open ? 3 : 5
icon_state = "[base_icon_state][saw_open ? "_transformed":""]"
icon_living = "[base_icon_state][saw_open ? "_transformed":""]"
/mob/living/basic/boss/blood_drunk_miner/ex_act(severity, target)
var/datum/action/cooldown/mob_cooldown/dash_ability = ai_controller.blackboard[BB_BDM_DASH_ABILITY]
if(dash_ability.Trigger(target = target))
@@ -145,28 +153,58 @@ Difficulty: Medium
/// Namely, we just use the miner saw to rapidly hit the target multiple times
/mob/living/basic/boss/blood_drunk_miner/proc/attack_override(mob/living/source, atom/target, proximity, modifiers)
SIGNAL_HANDLER
if(!istype(target, /mob/living))
if(!isliving(target))
return
var/mob/living/victim = target
if(should_devour(target))
devour(target)
if(should_devour(victim))
devour(victim)
return COMPONENT_HOSTILE_NO_ATTACK
do_chain_attack(victim, modifiers)
return COMPONENT_HOSTILE_NO_ATTACK
/mob/living/basic/boss/blood_drunk_miner/proc/do_chain_attack(mob/living/victim, modifiers, sequence_hit = 1)
if (!Adjacent(victim))
post_attack_effects(victim, modifiers)
return
changeNext_move(CLICK_CD_MELEE)
victim.visible_message(
span_danger("[src] slashes at [victim] with [p_their()] cleaving saw!"),
span_userdanger("You are slashed at by [src]'s cleaving saw!"),
)
var/datum/callback/melee_callback = CALLBACK(miner_saw, TYPE_PROC_REF(/obj/item/melee/cleaving_saw/miner, melee_attack_chain), src, victim, modifiers)
var/delay = 0.2 SECONDS
for(var/i in 1 to rapid_melee_hits)
addtimer(melee_callback, (i - 1) * delay)
var/delay = HAS_TRAIT(miner_saw, TRAIT_TRANSFORM_ACTIVE) ? 0.5 SECONDS : 0.3 SECONDS
apply_status_effect(/datum/status_effect/saw_slashes_slowdown, delay)
INVOKE_ASYNC(miner_saw, TYPE_PROC_REF(/obj/item/melee/cleaving_saw/miner, melee_attack_chain), src, victim, modifiers)
post_attack_effects(victim, modifiers)
if (sequence_hit >= rapid_melee_hits)
post_attack_effects(victim, modifiers)
return
return COMPONENT_HOSTILE_NO_ATTACK
addtimer(CALLBACK(src, PROC_REF(do_chain_attack), victim, modifiers, sequence_hit + 1), delay)
/datum/status_effect/saw_slashes_slowdown
id = "saw_slashes_slowdown"
alert_type = null
status_type = STATUS_EFFECT_REFRESH
/datum/status_effect/saw_slashes_slowdown/on_creation(mob/living/new_owner, new_duration)
duration = new_duration
return ..()
/datum/status_effect/saw_slashes_slowdown/refresh(effect, new_duration)
duration = new_duration
/datum/status_effect/saw_slashes_slowdown/on_apply()
. = ..()
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/saw_slashes_slowdown)
/datum/status_effect/saw_slashes_slowdown/on_remove()
. = ..()
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/saw_slashes_slowdown)
/// Hook for potential additional behaviors after attacking
/mob/living/basic/boss/blood_drunk_miner/proc/post_attack_effects(mob/living/victim, list/modifiers)
@@ -0,0 +1,82 @@
/datum/action/cooldown/mob_cooldown/charge/basic_charge/blood_drunk_miner
cooldown_time = 1.5 SECONDS
charge_delay = 0.1 SECONDS
shake_duration = 0.2 SECONDS // A bit longer so he shakes during the dash too
charge_distance = 6
// Don't stun ourselves or the target
recoil_duration = -1
knockdown_duration = -1
destroy_objects = FALSE
charge_damage = 0
charge_speed = 0.3
/datum/action/cooldown/mob_cooldown/charge/basic_charge/blood_drunk_miner/hit_target(atom/movable/source, atom/target, damage_dealt)
. = ..()
if(!isbasicmob(source) || !isliving(target))
return
var/mob/living/basic/basic_source = source
basic_source.melee_attack(target, ignore_cooldown = TRUE)
/datum/action/cooldown/mob_cooldown/transform_weapon
name = "Transform Weapon"
button_icon = 'icons/obj/mining_zones/artefacts.dmi'
button_icon_state = "cleaving_saw"
desc = "Transform weapon into a different state."
cooldown_time = 5 SECONDS
shared_cooldown = MOB_SHARED_COOLDOWN_2
/// The max possible cooldown, cooldown is random between the default cooldown time and this
var/max_cooldown_time = 10 SECONDS
/datum/action/cooldown/mob_cooldown/transform_weapon/Activate(atom/target_atom)
disable_cooldown_actions()
do_transform()
StartCooldown(rand(cooldown_time, max_cooldown_time), 0)
enable_cooldown_actions()
return TRUE
/datum/action/cooldown/mob_cooldown/transform_weapon/proc/do_transform()
if(!istype(owner, /mob/living/basic/boss/blood_drunk_miner))
return
var/mob/living/basic/boss/blood_drunk_miner/blood_drunk_miner = owner
blood_drunk_miner.transform_saw()
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator
name = "Fire Kinetic Accelerator"
desc = "Fires a kinetic accelerator projectile at the target."
button_icon = 'icons/obj/weapons/guns/energy.dmi'
button_icon_state = "kineticgun"
cooldown_time = 1.5 SECONDS
projectile_type = /obj/projectile/kinetic/miner
projectile_sound = 'sound/items/weapons/kinetic_accel.ogg'
shot_count = 3
shot_delay = 0.15 SECONDS
default_projectile_spread = 10
can_move = FALSE
/// Delay for the alert
var/alert_delay = 0.5 SECONDS
/// Delay before we start shooting during which we cannot move
var/prefire_delay = 0.2 SECONDS
/// Delay before the user can move or act again after firing
var/reload_delay = 0.1 SECONDS
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator/Activate(atom/target_atom)
owner.visible_message(span_danger("[owner] fires the proto-kinetic accelerator!"))
owner.face_atom(target_atom)
owner.do_alert_animation(alert_delay + (shot_count - 1) * shot_delay)
disable_cooldown_actions()
if (alert_delay > prefire_delay) // As to delay movement blocking
SLEEP_CHECK_DEATH(alert_delay - prefire_delay, owner)
return ..()
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator/attack_sequence(mob/living/firer, atom/target)
SLEEP_CHECK_DEATH(prefire_delay, firer)
. = ..()
sleep(reload_delay)
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator/shoot_projectile(atom/origin, atom/target, set_angle, mob/firer, projectile_spread, speed_multiplier, override_projectile_type, override_homing)
. = ..()
new /obj/effect/temp_visual/dir_setting/firing_effect(get_turf(firer), firer.dir)
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator/long_burst
shot_count = 5
shot_delay = 0.1 SECONDS
@@ -12,7 +12,7 @@
BB_BDM_RANGED_ATTACK_COOLDOWN = 0,
)
movement_delay = 0.3 SECONDS
movement_delay = 0.25 SECONDS
ai_movement = /datum/ai_movement/basic_avoidance
idle_behavior = /datum/idle_behavior/idle_random_walk
planning_subtrees = list(
@@ -63,4 +63,4 @@
return TRUE
/datum/ai_controller/blood_drunk_miner/doom
movement_delay = 0.8 SECONDS
movement_delay = 0.5 SECONDS
@@ -1,15 +1,10 @@
/// A slightly nerfed saw as the normal one is much too murdery.
/obj/item/melee/cleaving_saw/miner
force = 6
open_force = 10
/obj/item/melee/cleaving_saw/miner/attack(mob/living/target, mob/living/carbon/human/user)
target.add_stun_absorption(source = "miner", duration = 1 SECONDS, priority = INFINITY)
return ..()
force = 8
open_force = 12
/obj/projectile/kinetic/miner
damage = 20
speed = 1.1
damage = 18
icon_state = "ka_tracer"
range = 4
@@ -1,6 +1,6 @@
#define HUNTER_DASH_PROBABILITY 12
/// heals slightly on melee hits
/// Heals slightly on melee hits
/mob/living/basic/boss/blood_drunk_miner/guidance
/mob/living/basic/boss/blood_drunk_miner/guidance/attack_override(mob/living/source, atom/target, proximity, modifiers)
@@ -19,10 +19,11 @@
if(!isnull(dash_attack))
INVOKE_ASYNC(dash_attack, TYPE_PROC_REF(/datum/action, Trigger), src, NONE, victim)
/// Slow but constantly dashes and has longer barrages
/mob/living/basic/boss/blood_drunk_miner/doom
name = "hostile-environment miner"
desc = "A miner destined to hop across dimensions for all eternity, hunting anomalous creatures."
speed = 8
speed = 5
ranged_attack_cooldown_duration = 0.8 SECONDS
ai_controller = /datum/ai_controller/blood_drunk_miner/doom
@@ -32,4 +33,17 @@
if(!isnull(dash_ability))
dash_ability.cooldown_time = 0.8 SECONDS
var/datum/action/cooldown/dash_attack = ai_controller.blackboard[BB_BDM_DASH_ATTACK_ABILITY]
if(!isnull(dash_attack))
dash_attack.cooldown_time = 4 SECONDS
/mob/living/basic/boss/blood_drunk_miner/doom/get_innate_actions()
var/list/innate_abilities = list(
/datum/action/cooldown/mob_cooldown/charge/basic_charge/blood_drunk_miner = BB_BDM_DASH_ABILITY,
/datum/action/cooldown/mob_cooldown/projectile_attack/rapid_fire/kinetic_accelerator/long_burst = BB_BDM_KINETIC_ACCELERATOR_ABILITY,
/datum/action/cooldown/mob_cooldown/dash_attack = BB_BDM_DASH_ATTACK_ABILITY,
/datum/action/cooldown/mob_cooldown/transform_weapon = BB_BDM_TRANSFORM_WEAPON_ABILITY,
)
return innate_abilities
#undef HUNTER_DASH_PROBABILITY