diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 7d87462b3a2..9b09432298b 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -6022,7 +6022,7 @@
/turf/open/floor/plating,
/area/station/engineering/atmos)
"cwg" = (
-/mob/living/simple_animal/hostile/asteroid/lobstrosity,
+/mob/living/basic/mining/lobstrosity,
/turf/open/misc/asteroid/airless,
/area/station/engineering/supermatter/room)
"cwp" = (
diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm
index d83963fb3b2..c2ace1e7441 100644
--- a/_maps/templates/lazy_templates/nukie_base.dmm
+++ b/_maps/templates/lazy_templates/nukie_base.dmm
@@ -3556,7 +3556,7 @@
/area/centcom/syndicate_mothership/control)
"Qh" = (
/obj/structure/window/reinforced/survival_pod/spawner/directional/south{
- name = "Frosted Window";
+ name = "Frosted Window"
},
/obj/item/soap/syndie,
/obj/structure/sign/poster/contraband/got_wood/directional/east,
diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm
index 43dee41e98a..428f4856ca1 100644
--- a/code/__DEFINES/ai.dm
+++ b/code/__DEFINES/ai.dm
@@ -231,6 +231,9 @@
///Blackboard key for a whitelist typecache of "things we can target while trying to move"
#define BB_OBSTACLE_TARGETTING_WHITELIST "BB_targetting_whitelist"
+/// Generic key for if we only have one action so we don't need to make a million subtypes with different keys
+#define BB_TARGETTED_ACTION "BB_targetted_action"
+
///Targetting keys for something to run away from, if you need to store this separately from current target
#define BB_BASIC_MOB_FLEE_TARGET "BB_basic_flee_target"
#define BB_BASIC_MOB_FLEE_TARGET_HIDING_LOCATION "BB_basic_flee_target_hiding_location"
@@ -343,3 +346,10 @@
#define BB_FOUND_HONEY "BB_found_honey"
///the tree that we will climb
#define BB_CLIMBED_TREE "BB_climbed_tree"
+
+/// Lobstrosities will only attack people with one of these traits
+#define BB_LOBSTROSITY_EXPLOIT_TRAITS "BB_lobstrosity_exploit_traits"
+/// Key where we store some tasty fingers
+#define BB_LOBSTROSITY_TARGET_LIMB "BB_lobstrosity_target_limb"
+/// We increment this counter every time we try to move while dragging an arm and if we go too long we'll give up trying to get out of line of sight and just eat the fingers
+#define BB_LOBSTROSITY_FINGER_LUST "BB_lobstrosity_finger_lust"
diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm
index 722bd78e384..2ae576f5e61 100644
--- a/code/datums/actions/mobs/charge.dm
+++ b/code/datums/actions/mobs/charge.dm
@@ -175,6 +175,10 @@
var/shake_duration = 1 SECONDS
/// Intensity of shaking animation
var/shake_pixel_shift = 2
+ /// Amount of time to stun self upon impact
+ var/recoil_duration = 0.6 SECONDS
+ /// Amount of time to knock over an impacted target
+ var/knockdown_duration = 0.6 SECONDS
/datum/action/cooldown/mob_cooldown/charge/basic_charge/do_charge_indicator(atom/charger, atom/charge_target)
charger.Shake(shake_pixel_shift, shake_pixel_shift, shake_duration)
@@ -190,18 +194,32 @@
source.visible_message(span_danger("[source] smashes into [target]!"))
if(!living_source)
return
- living_source.Stun(6, ignore_canstun = TRUE)
+ living_source.Stun(recoil_duration, ignore_canstun = TRUE)
return
var/mob/living/living_target = target
if(ishuman(living_target))
var/mob/living/carbon/human/human_target = living_target
if(human_target.check_shields(source, 0, "the [source.name]", attack_type = LEAP_ATTACK) && living_source)
- living_source.Stun(6, ignore_canstun = TRUE)
+ living_source.Stun(recoil_duration, ignore_canstun = TRUE)
return
living_target.visible_message(span_danger("[source] charges on [living_target]!"), span_userdanger("[source] charges into you!"))
- living_target.Knockdown(6)
+ living_target.Knockdown(knockdown_duration)
+
+
+/datum/status_effect/tired_post_charge
+ id = "tired_post_charge"
+ duration = 1 SECONDS
+ alert_type = null
+
+/datum/status_effect/tired_post_charge/on_apply()
+ . = ..()
+ owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/tired_post_charge)
+
+/datum/status_effect/tired_post_charge/on_remove()
+ . = ..()
+ owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/tired_post_charge)
/datum/action/cooldown/mob_cooldown/charge/triple_charge
name = "Triple Charge"
diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm
index b00f3ee2766..fca9e7bd732 100644
--- a/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm
+++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/run_away_from_target.dm
@@ -5,6 +5,8 @@
behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_MOVE_AND_PERFORM | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/// How far do we try to run? Further makes for smoother running, but potentially weirder pathfinding
var/run_distance = 9
+ /// Clear target if we finish the action unsuccessfully
+ var/clear_failed_targets = TRUE
/datum/ai_behavior/run_away_from_target/setup(datum/ai_controller/controller, target_key, hiding_location_key)
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
@@ -16,6 +18,8 @@
/datum/ai_behavior/run_away_from_target/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
. = ..()
+ if (!controller.blackboard[BB_BASIC_MOB_FLEEING])
+ return
var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key]
var/escaped = QDELETED(target) || !can_see(controller.pawn, target, run_distance) // If we can't see it we got away
if (escaped)
@@ -42,4 +46,5 @@
/datum/ai_behavior/run_away_from_target/finish_action(datum/ai_controller/controller, succeeded, target_key, hiding_location_key)
. = ..()
- controller.clear_blackboard_key(target_key)
+ if (clear_failed_targets)
+ controller.clear_blackboard_key(target_key)
diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm
index b737a8bcdd2..f3f18f94355 100644
--- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm
+++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeted_mob_ability.dm
@@ -46,3 +46,17 @@
/datum/ai_behavior/targeted_mob_ability/and_clear_target/finish_action(datum/ai_controller/controller, succeeded, ability_key, target_key)
. = ..()
controller.clear_blackboard_key(target_key)
+
+/**
+ * Attempts to move into the provided range and then use a mob's cooldown ability on a target
+ */
+/datum/ai_behavior/targeted_mob_ability/min_range
+ required_distance = 6
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT
+
+/datum/ai_behavior/targeted_mob_ability/min_range/setup(datum/ai_controller/controller, ability_key, target_key)
+ . = ..()
+ var/atom/target = controller.blackboard[target_key]
+ if(QDELETED(target))
+ return FALSE
+ set_movement_target(controller, target)
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm
index 0f53d53b618..b6b4d286df1 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/targeted_mob_ability.dm
@@ -1,7 +1,7 @@
/// Attempts to use a mob ability on a target
/datum/ai_planning_subtree/targeted_mob_ability
/// Blackboard key for the ability
- var/ability_key
+ var/ability_key = BB_TARGETTED_ACTION
/// Blackboard key for where the target ref is stored
var/target_key = BB_BASIC_MOB_CURRENT_TARGET
/// Behaviour to perform using ability
diff --git a/code/datums/elements/amputating_limbs.dm b/code/datums/elements/amputating_limbs.dm
new file mode 100644
index 00000000000..c2fe7c454a9
--- /dev/null
+++ b/code/datums/elements/amputating_limbs.dm
@@ -0,0 +1,66 @@
+/// This component will intercept bare-handed attacks by the owner on critically injured carbons and amputate random limbs instead
+/datum/element/amputating_limbs
+ element_flags = ELEMENT_BESPOKE
+ argument_hash_start_idx = 2
+ /// How long does it take?
+ var/surgery_time
+ /// What is the means by which we describe the act of amputation?
+ var/surgery_verb
+ /// The types of limb we can remove
+ var/list/target_zones
+
+/datum/element/amputating_limbs/Attach(
+ datum/target,
+ surgery_time = 5 SECONDS,
+ surgery_verb = "prying",
+ list/target_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG),
+)
+ . = ..()
+ if (!isliving(target))
+ return ELEMENT_INCOMPATIBLE
+ if (!length(target_zones))
+ CRASH("[src] for [target] was not provided a valid list of body zones to target.")
+
+ src.surgery_time = surgery_time
+ src.surgery_verb = surgery_verb
+ src.target_zones = target_zones
+ RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_amputate))
+
+/datum/element/amputating_limbs/Detach(datum/source)
+ UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET))
+ return ..()
+
+/// Called when you click on literally anything with your hands, see if it is an injured carbon and then try to cut it up
+/datum/element/amputating_limbs/proc/try_amputate(mob/living/surgeon, atom/victim)
+ SIGNAL_HANDLER
+ if (!iscarbon(victim) || HAS_TRAIT(victim, TRAIT_NODISMEMBER))
+ return
+
+ var/mob/living/carbon/limbed_victim = victim
+ if (limbed_victim.stat == CONSCIOUS)
+ return
+
+ if (DOING_INTERACTION_WITH_TARGET(surgeon, victim))
+ surgeon.balloon_alert(surgeon, "already busy!")
+ return COMPONENT_CANCEL_ATTACK_CHAIN
+
+ var/list/valid_targets = list()
+ for (var/obj/item/bodypart/possible_target as anything in limbed_victim.bodyparts)
+ if (possible_target.bodypart_flags & BODYPART_UNREMOVABLE)
+ continue
+ if (!(possible_target.body_zone in target_zones))
+ continue
+ valid_targets += possible_target
+
+ if (!length(valid_targets))
+ return
+
+ INVOKE_ASYNC(src, PROC_REF(amputate), surgeon, victim, pick(valid_targets))
+ return COMPONENT_CANCEL_ATTACK_CHAIN
+
+/// Chop one off
+/datum/element/amputating_limbs/proc/amputate(mob/living/surgeon, mob/living/carbon/victim, obj/item/bodypart/to_remove)
+ surgeon.visible_message(span_warning("[surgeon] begins [surgery_verb] [to_remove] off of [victim]!"))
+ if (!do_after(surgeon, delay = surgery_time, target = victim))
+ return
+ to_remove.dismember()
diff --git a/code/datums/mapgen/Cavegens/IcemoonCaves.dm b/code/datums/mapgen/Cavegens/IcemoonCaves.dm
index 486844af948..8e94c9563bd 100644
--- a/code/datums/mapgen/Cavegens/IcemoonCaves.dm
+++ b/code/datums/mapgen/Cavegens/IcemoonCaves.dm
@@ -3,19 +3,30 @@
weighted_closed_turf_types = list(/turf/closed/mineral/random/snow = 1)
- weighted_mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/wolf = 50, /obj/structure/spawner/ice_moon = 3, \
- /mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon/polarbear = 3, \
- /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10, \
- /mob/living/simple_animal/hostile/asteroid/lobstrosity = 15)
+ weighted_mob_spawn_list = list(
+ /mob/living/basic/mining/lobstrosity = 15,
+ /mob/living/simple_animal/hostile/asteroid/goldgrub = 10,
+ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50,
+ /mob/living/simple_animal/hostile/asteroid/polarbear = 30,
+ /mob/living/simple_animal/hostile/asteroid/wolf = 50,
+ /obj/structure/spawner/ice_moon = 3,
+ /obj/structure/spawner/ice_moon/polarbear = 3,
+ )
weighted_flora_spawn_list = list(
- /obj/structure/flora/tree/pine/style_random = 2,
+ /obj/structure/flora/ash/chilly = 2,
+ /obj/structure/flora/grass/both/style_random = 6,
/obj/structure/flora/rock/icy/style_random = 2,
/obj/structure/flora/rock/pile/icy/style_random = 2,
- /obj/structure/flora/grass/both/style_random = 6,
- /obj/structure/flora/ash/chilly = 2,
+ /obj/structure/flora/tree/pine/style_random = 2,
)
///Note that this spawn list is also in the lavaland generator
- weighted_feature_spawn_list = list(/obj/structure/geyser/wittel = 10, /obj/structure/geyser/random = 2, /obj/structure/geyser/plasma_oxide = 10, /obj/structure/geyser/protozine = 10, /obj/structure/geyser/hollowwater = 10)
+ weighted_feature_spawn_list = list(
+ /obj/structure/geyser/hollowwater = 10,
+ /obj/structure/geyser/plasma_oxide = 10,
+ /obj/structure/geyser/protozine = 10,
+ /obj/structure/geyser/random = 2,
+ /obj/structure/geyser/wittel = 10,
+ )
/datum/map_generator/cave_generator/icemoon/surface
flora_spawn_chance = 4
@@ -49,10 +60,15 @@
/datum/map_generator/cave_generator/icemoon/deep
weighted_closed_turf_types = list(/turf/closed/mineral/random/snow/underground = 1)
- weighted_mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/ice_demon = 100, /obj/structure/spawner/ice_moon/demonic_portal = 6, \
- /mob/living/simple_animal/hostile/asteroid/ice_whelp = 60, /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 6, \
- /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 100, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6, \
- SPAWN_MEGAFAUNA = 1)
+ weighted_mob_spawn_list = list(
+ SPAWN_MEGAFAUNA = 1,
+ /mob/living/simple_animal/hostile/asteroid/ice_demon = 100,
+ /mob/living/simple_animal/hostile/asteroid/ice_whelp = 60,
+ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 100,
+ /obj/structure/spawner/ice_moon/demonic_portal = 6,
+ /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 6,
+ /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 6,
+ )
weighted_megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/colossus = 1)
weighted_flora_spawn_list = list(
/obj/structure/flora/rock/icy/style_random = 6,
diff --git a/code/datums/mapgen/Cavegens/LavalandGenerator.dm b/code/datums/mapgen/Cavegens/LavalandGenerator.dm
index 3539dc29afc..ea440d2cf21 100644
--- a/code/datums/mapgen/Cavegens/LavalandGenerator.dm
+++ b/code/datums/mapgen/Cavegens/LavalandGenerator.dm
@@ -3,36 +3,36 @@
weighted_closed_turf_types = list(/turf/closed/mineral/random/volcanic = 1)
weighted_mob_spawn_list = list(
+ SPAWN_MEGAFAUNA = 2,
+ /mob/living/basic/mining/bileworm = 20,
/mob/living/basic/mining/goliath/random = 50,
- /obj/structure/spawner/lavaland/goliath = 3,
+ /mob/living/basic/mining/lobstrosity/lava = 20,
+ /mob/living/simple_animal/hostile/asteroid/brimdemon = 20,
+ /mob/living/simple_animal/hostile/asteroid/goldgrub = 10,
+ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30,
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40,
/obj/structure/spawner/lavaland = 2,
- /mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30,
+ /obj/structure/spawner/lavaland/goliath = 3,
/obj/structure/spawner/lavaland/legion = 3,
- SPAWN_MEGAFAUNA = 2,
- /mob/living/simple_animal/hostile/asteroid/goldgrub = 10,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity/lava = 20,
- /mob/living/simple_animal/hostile/asteroid/brimdemon = 20,
- /mob/living/basic/mining/bileworm = 20,
)
weighted_flora_spawn_list = list(
- /obj/structure/flora/ash/leaf_shroom = 2,
- /obj/structure/flora/ash/cap_shroom = 2,
- /obj/structure/flora/ash/stem_shroom = 2,
/obj/structure/flora/ash/cacti = 1,
- /obj/structure/flora/ash/tall_shroom = 2,
- /obj/structure/flora/ash/seraka = 2,
+ /obj/structure/flora/ash/cap_shroom = 2,
/obj/structure/flora/ash/fireblossom = 2,
+ /obj/structure/flora/ash/leaf_shroom = 2,
+ /obj/structure/flora/ash/seraka = 2,
+ /obj/structure/flora/ash/stem_shroom = 2,
+ /obj/structure/flora/ash/tall_shroom = 2,
)
///Note that this spawn list is also in the icemoon generator
weighted_feature_spawn_list = list(
- /obj/structure/geyser/wittel = 10,
- /obj/structure/geyser/random = 2,
+ /obj/structure/geyser/hollowwater = 10,
/obj/structure/geyser/plasma_oxide = 10,
/obj/structure/geyser/protozine = 10,
- /obj/structure/geyser/hollowwater = 10,
+ /obj/structure/geyser/random = 2,
+ /obj/structure/geyser/wittel = 10,
)
initial_closed_chance = 45
diff --git a/code/modules/fishing/fish/chasm_detritus.dm b/code/modules/fishing/fish/chasm_detritus.dm
index a5102b97f64..3f7139ffd4d 100644
--- a/code/modules/fishing/fish/chasm_detritus.dm
+++ b/code/modules/fishing/fish/chasm_detritus.dm
@@ -19,19 +19,19 @@
/// Stuff which you can always fish up even if nothing fell into a hole. Associative by type.
var/static/list/default_contents = list(
NORMAL_CONTENTS = list(
- /obj/item/stack/ore/slag = 2,
/obj/item/stack/sheet/bone = 3,
+ /obj/item/stack/ore/slag = 2,
+ /mob/living/basic/mining/lobstrosity/lava = 1,
/obj/effect/mob_spawn/corpse/human/skeleton = 1,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity/lava = 1,
),
BODIES_ONLY = list(
/obj/effect/mob_spawn/corpse/human/skeleton = 3,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity/lava = 1,
+ /mob/living/basic/mining/lobstrosity/lava = 1,
),
NO_CORPSES = list(
- /obj/item/stack/ore/slag = 10,
/obj/item/stack/sheet/bone = 14,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity/lava = 1,
+ /obj/item/stack/ore/slag = 10,
+ /mob/living/basic/mining/lobstrosity/lava = 1,
),
)
diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm
index 7d82a5d4b46..35de16343e2 100644
--- a/code/modules/fishing/sources/source_types.dm
+++ b/code/modules/fishing/sources/source_types.dm
@@ -71,10 +71,10 @@
fish_table = list(
FISHING_DUD = 5,
/obj/item/fish/chasm_crab/ice = 15,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity = 1,
- /obj/effect/decal/remains/plasma = 1,
- /obj/item/stack/ore/plasma = 3,
/obj/item/coin/plasma = 3,
+ /obj/item/stack/ore/plasma = 3,
+ /mob/living/basic/mining/lobstrosity = 1,
+ /obj/effect/decal/remains/plasma = 1,
)
fish_counts = list(
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 45d97e5c7de..a1edd69ba3e 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -254,26 +254,6 @@
/obj/item/crusher_trophy/proc/on_mark_application(mob/living/target, datum/status_effect/crusher_mark/mark, had_mark) //the target, the mark applied, and if the target had a mark before
/obj/item/crusher_trophy/proc/on_mark_detonation(mob/living/target, mob/living/user) //the target and the user
-//goliath
-/obj/item/crusher_trophy/goliath_tentacle
- name = "goliath tentacle"
- desc = "A sliced-off goliath tentacle. Suitable as a trophy for a kinetic crusher."
- icon_state = "goliath_tentacle"
- denied_type = /obj/item/crusher_trophy/goliath_tentacle
- bonus_value = 2
- var/missing_health_ratio = 0.1
- var/missing_health_desc = 10
-
-/obj/item/crusher_trophy/goliath_tentacle/effect_desc()
- return "mark detonation to do [bonus_value] more damage for every [missing_health_desc] health you are missing"
-
-/obj/item/crusher_trophy/goliath_tentacle/on_mark_detonation(mob/living/target, mob/living/user)
- var/missing_health = user.maxHealth - user.health
- missing_health *= missing_health_ratio //bonus is active at all times, even if you're above 90 health
- missing_health *= bonus_value //multiply the remaining amount by bonus_value
- if(missing_health > 0)
- target.adjustBruteLoss(missing_health) //and do that much damage
-
//watcher
/obj/item/crusher_trophy/watcher_wing
name = "watcher wing"
diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_trophy.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_trophy.dm
new file mode 100644
index 00000000000..a4801569cea
--- /dev/null
+++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_trophy.dm
@@ -0,0 +1,25 @@
+/// Mining crusher trophy from a goliath. Increases damage as your health decreases.
+/obj/item/crusher_trophy/goliath_tentacle
+ name = "goliath tentacle"
+ desc = "A sliced-off goliath tentacle. Suitable as a trophy for a kinetic crusher."
+ icon_state = "goliath_tentacle"
+ denied_type = /obj/item/crusher_trophy/goliath_tentacle
+ bonus_value = 2
+ /// Your missing health is multiplied by this value to find the bonus damage
+ var/missing_health_ratio = 0.1
+ /// Amount of health you must lose to gain damage, according to the examine text. Cached so we don't recalculate it every examine.
+ var/missing_health_desc
+
+/obj/item/crusher_trophy/goliath_tentacle/Initialize(mapload)
+ . = ..()
+ missing_health_desc = 1 / missing_health_ratio / bonus_value
+
+/obj/item/crusher_trophy/goliath_tentacle/effect_desc()
+ return "mark detonation to do [bonus_value] more damage for every [missing_health_desc] health you are missing"
+
+/obj/item/crusher_trophy/goliath_tentacle/on_mark_detonation(mob/living/target, mob/living/user)
+ var/missing_health = user.maxHealth - user.health
+ missing_health *= missing_health_ratio //bonus is active at all times, even if you're above 90 health
+ missing_health *= bonus_value //multiply the remaining amount by bonus_value
+ if(missing_health > 0)
+ target.adjustBruteLoss(missing_health) //and do that much damage
diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
new file mode 100644
index 00000000000..b0dfa60e49c
--- /dev/null
+++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
@@ -0,0 +1,85 @@
+/// Cowardly mob with a charging attack
+/mob/living/basic/mining/lobstrosity
+ name = "arctic lobstrosity"
+ desc = "These hairy crustaceans creep and multiply in underground lakes deep below the ice. They have a particular taste for fingers."
+ icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
+ icon_state = "arctic_lobstrosity"
+ icon_living = "arctic_lobstrosity"
+ icon_dead = "arctic_lobstrosity_dead"
+ mob_biotypes = MOB_ORGANIC|MOB_BEAST
+ friendly_verb_continuous = "chitters at"
+ friendly_verb_simple = "chitters at"
+ speak_emote = list("chitters")
+ maxHealth = 150
+ health = 150
+ obj_damage = 15
+ melee_damage_lower = 15
+ melee_damage_upper = 19
+ attack_verb_continuous = "snips"
+ attack_verb_simple = "snip"
+ attack_sound = 'sound/weapons/bite.ogg'
+ attack_vis_effect = ATTACK_EFFECT_BITE // Closer than a scratch to a crustacean pinching effect
+ butcher_results = list(
+ /obj/item/food/meat/crab = 2,
+ /obj/item/stack/sheet/bone = 2,
+ /obj/item/organ/internal/monster_core/rush_gland = 1,
+ )
+ crusher_loot = /obj/item/crusher_trophy/lobster_claw
+ ai_controller = /datum/ai_controller/basic_controller/lobstrosity
+ /// Charging ability
+ var/datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/charge
+ /// Limbs we will cut off an unconscious man
+ var/static/list/target_limbs = list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
+ /// Things we will eat if we see them (arms, chiefly)
+ var/static/list/target_foods = list(/obj/item/bodypart/arm)
+
+/mob/living/basic/mining/lobstrosity/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_SNOWSTORM_IMMUNE, INNATE_TRAIT)
+ AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
+ AddElement(/datum/element/basic_eating, food_types = target_foods)
+ AddElement(\
+ /datum/element/amputating_limbs,\
+ surgery_verb = "snipping",\
+ target_zones = target_limbs,\
+ )
+ charge = new(src)
+ charge.Grant(src)
+ ai_controller.set_blackboard_key(BB_TARGETTED_ACTION, charge)
+
+/mob/living/basic/mining/lobstrosity/Destroy()
+ QDEL_NULL(charge)
+ return ..()
+
+/mob/living/basic/mining/lobstrosity/ranged_secondary_attack(atom/atom_target, modifiers)
+ charge.Trigger(target = atom_target)
+
+/// Lavaland lobster variant, it basically just looks different
+/mob/living/basic/mining/lobstrosity/lava
+ name = "chasm lobstrosity"
+ desc = "Twitching crustaceans boiled red by the sulfurous fumes of the chasms in which they lurk. They have a particular taste for fingers."
+ icon_state = "lobstrosity"
+ icon_living = "lobstrosity"
+ icon_dead = "lobstrosity_dead"
+
+/// Charge a long way, knock down for longer, and perform an instant melee attack
+/datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster
+ charge_distance = 8
+ knockdown_duration = 2.5 SECONDS
+
+/datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/hit_target(atom/movable/source, atom/target, damage_dealt)
+ . = ..()
+ if(!isliving(target) || !isbasicmob(source))
+ return
+ var/mob/living/basic/basic_source = source
+ var/mob/living/living_target = target
+ basic_source.melee_attack(living_target)
+ basic_source.ai_controller?.set_blackboard_key(BB_BASIC_MOB_FLEEING, FALSE)
+ basic_source.start_pulling(living_target)
+
+/datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/do_charge(atom/movable/charger, atom/target_atom, delay, past)
+ . = ..()
+ if(!isliving(charger))
+ return
+ var/mob/living/living_charger = charger
+ living_charger.apply_status_effect(/datum/status_effect/tired_post_charge)
diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm
new file mode 100644
index 00000000000..7ec1bbab7c7
--- /dev/null
+++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_ai.dm
@@ -0,0 +1,211 @@
+/datum/ai_controller/basic_controller/lobstrosity
+ blackboard = list(
+ BB_TARGETTING_DATUM = new /datum/targetting_datum/basic/lobster,
+ BB_LOBSTROSITY_EXPLOIT_TRAITS = list(TRAIT_INCAPACITATED, TRAIT_FLOORED, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT),
+ BB_BASIC_MOB_FLEEING = TRUE,
+ BB_LOBSTROSITY_FINGER_LUST = 0
+ )
+
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/insect,
+ /datum/ai_planning_subtree/hoard_fingers,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/targeted_mob_ability/lobster,
+ /datum/ai_planning_subtree/flee_target/lobster,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree/lobster,
+ /datum/ai_planning_subtree/find_fingers,
+ )
+
+/datum/targetting_datum/basic/lobster
+ stat_attack = HARD_CRIT
+
+/datum/ai_planning_subtree/basic_melee_attack_subtree/lobster
+ melee_attack_behavior = /datum/ai_behavior/basic_melee_attack/lobster
+
+/datum/ai_planning_subtree/basic_melee_attack_subtree/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ if (controller.blackboard[BB_BASIC_MOB_FLEEING])
+ return
+ if (!isnull(controller.blackboard[BB_LOBSTROSITY_TARGET_LIMB]))
+ return
+ var/mob/living/living_pawn = controller.pawn
+ if (DOING_INTERACTION_WITH_TARGET(living_pawn, controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]))
+ return
+ return ..()
+
+/datum/ai_behavior/basic_melee_attack/lobster
+ action_cooldown = 1 SECONDS
+
+/datum/ai_behavior/basic_melee_attack/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targetting_datum_key, hiding_location_key)
+ var/mob/living/target = controller.blackboard[target_key]
+ if (isnull(target))
+ return ..()
+ var/is_vulnerable = FALSE
+ for (var/trait in controller.blackboard[BB_LOBSTROSITY_EXPLOIT_TRAITS])
+ if (!HAS_TRAIT(target, trait))
+ continue
+ is_vulnerable = TRUE
+ break
+ if (!is_vulnerable)
+ controller.set_blackboard_key(BB_BASIC_MOB_FLEEING, TRUE)
+ if (controller.blackboard[BB_BASIC_MOB_FLEEING])
+ finish_action(controller = controller, succeeded = TRUE, target_key = target_key) // We don't want to clear our target
+ return
+ var/mob/living/living_pawn = controller.pawn
+ if (target.stat != CONSCIOUS)
+ living_pawn.start_pulling(target) // No crawling away
+ return ..()
+
+/datum/ai_planning_subtree/flee_target/lobster
+ flee_behaviour = /datum/ai_behavior/run_away_from_target/lobster
+
+/datum/ai_behavior/run_away_from_target/lobster
+ clear_failed_targets = FALSE
+
+/datum/ai_behavior/run_away_from_target/lobster/perform(seconds_per_tick, datum/ai_controller/controller, target_key, hiding_location_key)
+ var/atom/target = controller.blackboard[target_key]
+ for (var/trait in controller.blackboard[BB_LOBSTROSITY_EXPLOIT_TRAITS])
+ if (!HAS_TRAIT(target, trait))
+ continue
+ controller.set_blackboard_key(BB_BASIC_MOB_FLEEING, FALSE)
+ finish_action(controller, succeeded = FALSE)
+ return
+
+ return ..()
+
+/// Don't use charge ability on an adjacent target, and make sure you're visible before you start
+/datum/ai_planning_subtree/targeted_mob_ability/lobster
+ use_ability_behaviour = /datum/ai_behavior/targeted_mob_ability/min_range
+
+/datum/ai_planning_subtree/targeted_mob_ability/lobster/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ var/atom/target = controller.blackboard[target_key]
+ if(QDELETED(target) || in_range(controller.pawn, target))
+ return FALSE
+ return ..()
+
+/// Look for loose arms lying around
+/datum/ai_planning_subtree/find_fingers
+ /// Where do we store target limb data?
+ var/target_key = BB_LOBSTROSITY_TARGET_LIMB
+ /// What are we actually looking for?
+ var/desired_type = /obj/item/bodypart/arm
+
+/datum/ai_planning_subtree/find_fingers/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ . = ..()
+ controller.queue_behavior(/datum/ai_behavior/find_and_set, target_key, desired_type)
+
+/// If you see an arm, grab it and run
+/datum/ai_planning_subtree/hoard_fingers
+ /// Where do we store target limb data?
+ var/target_key = BB_LOBSTROSITY_TARGET_LIMB
+
+/datum/ai_planning_subtree/hoard_fingers/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
+ . = ..()
+ var/atom/current_target = controller.blackboard[target_key]
+ if (QDELETED(current_target))
+ return
+
+ var/mob/living/living_pawn = controller.pawn
+ if (living_pawn.pulling != current_target)
+ controller.queue_behavior(/datum/ai_behavior/grab_fingers, target_key)
+ else
+ controller.queue_behavior(/datum/ai_behavior/hoard_fingers, target_key)
+ return SUBTREE_RETURN_FINISH_PLANNING
+
+/// If our target is an arm then move over and drag it
+/datum/ai_behavior/grab_fingers
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
+
+/datum/ai_behavior/grab_fingers/setup(datum/ai_controller/controller, target_key)
+ . = ..()
+ var/atom/current_target = controller.blackboard[target_key]
+ if (QDELETED(current_target))
+ return FALSE
+ set_movement_target(controller, current_target)
+
+/datum/ai_behavior/grab_fingers/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
+ . = ..()
+
+ var/atom/current_target = controller.blackboard[target_key]
+ if (QDELETED(current_target))
+ return
+ var/mob/living/living_pawn = controller.pawn
+ living_pawn.start_pulling(current_target)
+ finish_action(controller, succeeded = TRUE)
+
+/// How far we'll try to go before eating an arm
+#define FLEE_TO_RANGE 9
+/// How many times we'll attempt to move before giving up
+#define MAX_LOBSTROSITY_PATIENCE 15
+
+/// If we are dragging an arm then run away until we are out of range and feast
+/datum/ai_behavior/hoard_fingers
+ required_distance = 0
+ behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT | AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
+ /// We store a counter at this key we increment on every movement until we are overwhelmed with hunger
+ var/patience_key = BB_LOBSTROSITY_FINGER_LUST
+
+/datum/ai_behavior/hoard_fingers/setup(datum/ai_controller/controller, target_key)
+ . = ..()
+ var/atom/current_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
+ if (QDELETED(current_target))
+ set_movement_target(controller, get_turf(controller.pawn))
+ return
+ target_step_away(controller, current_target, target_key)
+
+/// Find the next step to take away from the current target
+/datum/ai_behavior/hoard_fingers/proc/target_step_away(datum/ai_controller/controller, atom/current_target, target_key)
+ var/turf/next_step = get_step_away(controller.pawn, current_target)
+ if (!isnull(next_step) && !next_step.is_blocked_turf(exclude_mobs = TRUE))
+ set_movement_target(controller, next_step)
+ return
+ var/list/all_dirs = GLOB.alldirs.Copy()
+ all_dirs -= get_dir(controller.pawn, next_step)
+ all_dirs -= get_dir(controller.pawn, current_target)
+ shuffle_inplace(all_dirs)
+ for (var/dir in all_dirs)
+ next_step = get_step(controller.pawn, dir)
+ if (!isnull(next_step) && !next_step.is_blocked_turf(exclude_mobs = TRUE))
+ set_movement_target(controller, next_step)
+ return
+ finish_action(controller, succeeded = FALSE, target_key = target_key)
+ return
+
+/datum/ai_behavior/hoard_fingers/perform(seconds_per_tick, datum/ai_controller/controller, target_key)
+ . = ..()
+ var/current_patience = controller.blackboard[patience_key] + 1
+ if (current_patience >= MAX_LOBSTROSITY_PATIENCE)
+ eat_fingers(controller, target_key)
+ return
+ controller.set_blackboard_key(patience_key, current_patience)
+ var/mob/living/living_pawn = controller.pawn
+ if (isnull(living_pawn.pulling))
+ finish_action(controller, succeeded = FALSE, target_key = target_key)
+ return
+
+ var/atom/current_target = controller.blackboard[BB_BASIC_MOB_CURRENT_TARGET]
+ if (QDELETED(current_target) || !can_see(controller.pawn, current_target, FLEE_TO_RANGE))
+ eat_fingers(controller, target_key)
+ return
+ target_step_away(controller, current_target, target_key)
+
+/// Finally consume those delicious digits
+/datum/ai_behavior/hoard_fingers/proc/eat_fingers(datum/ai_controller/controller, target_key)
+ var/mob/living/basic/living_pawn = controller.pawn
+ var/atom/fingers = controller.blackboard[target_key]
+ if (QDELETED(fingers) || living_pawn.pulling != fingers)
+ finish_action(controller, succeeded = FALSE, target_key = target_key)
+ return
+ living_pawn.melee_attack(fingers)
+ finish_action(controller, succeeded = TRUE, target_key = target_key)
+
+/datum/ai_behavior/hoard_fingers/finish_action(datum/ai_controller/controller, succeeded, target_key)
+ . = ..()
+ controller.set_blackboard_key(patience_key, 0)
+ controller.clear_blackboard_key(target_key)
+ controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET)
+
+#undef FLEE_TO_RANGE
+#undef MAX_LOBSTROSITY_PATIENCE
diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_trophy.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_trophy.dm
new file mode 100644
index 00000000000..c018795b20b
--- /dev/null
+++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity_trophy.dm
@@ -0,0 +1,13 @@
+/// Lobstrosity crusher trophy. Staggers targets, increasing their click cooldown.
+/obj/item/crusher_trophy/lobster_claw
+ name = "lobster claw"
+ icon_state = "lobster_claw"
+ desc = "A lobster claw."
+ denied_type = /obj/item/crusher_trophy/lobster_claw
+ bonus_value = 1
+
+/obj/item/crusher_trophy/lobster_claw/effect_desc()
+ return "mark detonation to briefly stagger the target for [bonus_value] seconds"
+
+/obj/item/crusher_trophy/lobster_claw/on_mark_detonation(mob/living/target, mob/living/user)
+ target.apply_status_effect(/datum/status_effect/stagger, bonus_value SECONDS)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobstrosity.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobstrosity.dm
deleted file mode 100644
index 483f0fa2b2b..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/lobstrosity.dm
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Lobstrosities, the poster boy of charging AI mobs. Drops crab meat and bones.
- * Outside of charging, it's intended behavior is that it is generally slow moving, but makes up for that with a knockdown attack to score additional hits.
- */
-/mob/living/simple_animal/hostile/asteroid/lobstrosity
- name = "arctic lobstrosity"
- desc = "A marvel of evolution gone wrong, the frosty ice produces underground lakes where these ill tempered seafood gather. Beware its charge."
- icon = 'icons/mob/simple/icemoon/icemoon_monsters.dmi'
- icon_state = "arctic_lobstrosity"
- icon_living = "arctic_lobstrosity"
- icon_dead = "arctic_lobstrosity_dead"
- mob_biotypes = MOB_ORGANIC|MOB_BEAST
- mouse_opacity = MOUSE_OPACITY_ICON
- friendly_verb_continuous = "chitters at"
- friendly_verb_simple = "chits at"
- speak_emote = list("chitters")
- ranged = TRUE
- speed = 3
- move_to_delay = 20
- maxHealth = 150
- health = 150
- obj_damage = 15
- melee_damage_lower = 15
- melee_damage_upper = 19
- attack_verb_continuous = "snips"
- attack_verb_simple = "snip"
- attack_sound = 'sound/weapons/bite.ogg'
- attack_vis_effect = ATTACK_EFFECT_BITE //the closest we have to a crustacean pinching attack effect rn.
- weather_immunities = list(TRAIT_SNOWSTORM_IMMUNE)
- vision_range = 5
- aggro_vision_range = 7
- butcher_results = list(
- /obj/item/food/meat/crab = 2,
- /obj/item/stack/sheet/bone = 2,
- /obj/item/organ/internal/monster_core/rush_gland = 1,
- )
- robust_searching = TRUE
- footstep_type = FOOTSTEP_MOB_CLAW
- crusher_loot = /obj/item/crusher_trophy/lobster_claw
- /// Charging ability
- var/datum/action/cooldown/mob_cooldown/charge/basic_charge/charge
-
-/mob/living/simple_animal/hostile/asteroid/lobstrosity/Initialize(mapload)
- . = ..()
- charge = new /datum/action/cooldown/mob_cooldown/charge/basic_charge()
- charge.Grant(src)
-
-/mob/living/simple_animal/hostile/asteroid/lobstrosity/Destroy()
- QDEL_NULL(charge)
- return ..()
-
-/mob/living/simple_animal/hostile/asteroid/lobstrosity/OpenFire()
- if(client)
- return
- charge.Trigger(target = target)
-
-/mob/living/simple_animal/hostile/asteroid/lobstrosity/lava
- name = "tropical lobstrosity"
- desc = "A marvel of evolution gone wrong, the sulfur lakes of lavaland have given them a vibrant, red hued shell. Beware its charge."
- icon_state = "lobstrosity"
- icon_living = "lobstrosity"
- icon_dead = "lobstrosity_dead"
- weather_immunities = list(TRAIT_LAVA_IMMUNE,TRAIT_ASHSTORM_IMMUNE)
-
-/obj/item/crusher_trophy/lobster_claw
- name = "lobster claw"
- icon_state = "lobster_claw"
- desc = "A lobster claw."
- denied_type = /obj/item/crusher_trophy/lobster_claw
- bonus_value = 1
-
-/obj/item/crusher_trophy/lobster_claw/effect_desc()
- return "mark detonation to briefly stagger the target for [bonus_value] seconds"
-
-/obj/item/crusher_trophy/lobster_claw/on_mark_detonation(mob/living/target, mob/living/user)
- target.apply_status_effect(/datum/status_effect/stagger, bonus_value SECONDS)
diff --git a/code/modules/movespeed/modifiers/status_effects.dm b/code/modules/movespeed/modifiers/status_effects.dm
index 734a45b95cd..e8aad88c50d 100644
--- a/code/modules/movespeed/modifiers/status_effects.dm
+++ b/code/modules/movespeed/modifiers/status_effects.dm
@@ -34,3 +34,6 @@
/datum/movespeed_modifier/status_effect/light_speed
multiplicative_slowdown = -0.2 // lighting is pretty slow in BYOND
+
+/datum/movespeed_modifier/status_effect/tired_post_charge
+ multiplicative_slowdown = 3
diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm
index 403eb39bba7..a4f2a5811c3 100644
--- a/code/modules/unit_tests/simple_animal_freeze.dm
+++ b/code/modules/unit_tests/simple_animal_freeze.dm
@@ -85,8 +85,6 @@
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/snow,
/mob/living/simple_animal/hostile/asteroid/ice_demon,
/mob/living/simple_animal/hostile/asteroid/ice_whelp,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity,
- /mob/living/simple_animal/hostile/asteroid/lobstrosity/lava,
/mob/living/simple_animal/hostile/asteroid/polarbear,
/mob/living/simple_animal/hostile/asteroid/polarbear/lesser,
/mob/living/simple_animal/hostile/asteroid/wolf,
diff --git a/icons/mob/simple/icemoon/icemoon_monsters.dmi b/icons/mob/simple/icemoon/icemoon_monsters.dmi
index 9240b9bca44..6b05cf64580 100644
Binary files a/icons/mob/simple/icemoon/icemoon_monsters.dmi and b/icons/mob/simple/icemoon/icemoon_monsters.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index bb527c7ac44..287d60fb3cb 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1194,6 +1194,7 @@
#include "code\datums\elements\ai_held_item.dm"
#include "code\datums\elements\ai_retaliate.dm"
#include "code\datums\elements\ai_target_damagesource.dm"
+#include "code\datums\elements\amputating_limbs.dm"
#include "code\datums\elements\animal_variety.dm"
#include "code\datums\elements\art.dm"
#include "code\datums\elements\atmos_requirements.dm"
@@ -4093,7 +4094,11 @@
#include "code\modules\mob\living\basic\lavaland\goliath\goliath.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_actions.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\goliath_ai.dm"
+#include "code\modules\mob\living\basic\lavaland\goliath\goliath_trophy.dm"
#include "code\modules\mob\living\basic\lavaland\goliath\tentacle.dm"
+#include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity.dm"
+#include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity_ai.dm"
+#include "code\modules\mob\living\basic\lavaland\lobstrosity\lobstrosity_trophy.dm"
#include "code\modules\mob\living\basic\pets\fox.dm"
#include "code\modules\mob\living\basic\pets\penguin.dm"
#include "code\modules\mob\living\basic\pets\pet.dm"
@@ -4410,7 +4415,6 @@
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\hivelord.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\ice_demon.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\ice_whelp.dm"
-#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\lobstrosity.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\mining_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\polarbear.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\wolf.dm"
diff --git a/tools/UpdatePaths/Scripts/77253_simple_to_basic_lobstrosity.txt b/tools/UpdatePaths/Scripts/77253_simple_to_basic_lobstrosity.txt
new file mode 100644
index 00000000000..8053730ec24
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/77253_simple_to_basic_lobstrosity.txt
@@ -0,0 +1 @@
+/mob/living/simple_animal/hostile/asteroid/lobstrosity/@SUBTYPES : /mob/living/basic/mining/lobstrosity/@SUBTYPES{@OLD}