diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 1d1dda6d99..b5d203a166 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -264,3 +264,6 @@
#define BODYPART_LIFE_UPDATE_HEALTH (1<<0)
#define HUMAN_FIRE_STACK_ICON_NUM 3
+
+#define PULL_PRONE_SLOWDOWN 1.5
+#define HUMAN_CARRY_SLOWDOWN 0.35
\ No newline at end of file
diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm
index c0aac36415..4336ad28f7 100644
--- a/code/__DEFINES/movespeed_modification.dm
+++ b/code/__DEFINES/movespeed_modification.dm
@@ -31,3 +31,6 @@
#define MOVESPEED_ID_PAI_SPACEWALK_SPEEDMOD "PAI_SPACEWALK_MODIFIER"
#define MOVESPEED_ID_SANITY "MOOD_SANITY"
+
+#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
+#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
\ No newline at end of file
diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm
index e6c9f20de6..e9c9597068 100644
--- a/code/datums/components/footstep.dm
+++ b/code/datums/components/footstep.dm
@@ -1,108 +1,104 @@
-/datum/component/footstep
- var/steps = 0
- var/volume
- var/e_range
-
-/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
- if(!isliving(parent))
- return COMPONENT_INCOMPATIBLE
- volume = volume_
- e_range = e_range_
- RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
-
-/datum/component/footstep/proc/play_footstep()
- var/turf/open/T = get_turf(parent)
- if(!istype(T))
- return
-
- var/mob/living/LM = parent
- var/v = volume
- var/e = e_range
- if(!T.footstep || LM.buckled || LM.lying || !LM.canmove || LM.resting || LM.buckled || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING))
- if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
- playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
- return
-
- if(HAS_TRAIT(LM, TRAIT_SILENT_STEP))
- return
-
- if(iscarbon(LM))
- var/mob/living/carbon/C = LM
- if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
- return
- if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
- v /= 2
- e -= 5
- steps++
-
- if(steps >= 3)
- steps = 0
-
- else
- return
-
- if(prob(80) && !LM.has_gravity(T)) // don't need to step as often when you hop around
- return
-
- //begin playsound shenanigans//
-
- //for barefooted non-clawed mobs like monkeys
- if(isbarefoot(LM))
- playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
- GLOB.barefootstep[T.barefootstep][2] * v,
- TRUE,
- GLOB.barefootstep[T.barefootstep][3] + e)
- return
-
- //for xenomorphs, dogs, and other clawed mobs
- if(isclawfoot(LM))
- if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
- v /= 3
- e -= 5
-
- playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
- GLOB.clawfootstep[T.clawfootstep][2] * v,
- TRUE,
- GLOB.clawfootstep[T.clawfootstep][3] + e)
- return
-
- //for megafauna and other large and imtimidating mobs such as the bloodminer
- if(isheavyfoot(LM))
- playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
- GLOB.heavyfootstep[T.heavyfootstep][2] * v,
- TRUE,
- GLOB.heavyfootstep[T.heavyfootstep][3] + e)
- return
-
- //for slimes
- if(isslime(LM))
- playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
- return
-
- //for (simple) humanoid mobs (clowns, russians, pirates, etc.)
- if(isshoefoot(LM))
- if(!ishuman(LM))
- playsound(T, pick(GLOB.footstep[T.footstep][1]),
- GLOB.footstep[T.footstep][2] * v,
- TRUE,
- GLOB.footstep[T.footstep][3] + e)
- return
- if(ishuman(LM)) //for proper humans, they're special
- var/mob/living/carbon/human/H = LM
- var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
-
- if (H.dna.features["taur"] == "Naga" || H.dna.features["taur"] == "Tentacle") //are we a naga or tentacle taur creature
- playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
- return
-
- if(H.shoes || feetCover) //are we wearing shoes
- playsound(T, pick(GLOB.footstep[T.footstep][1]),
- GLOB.footstep[T.footstep][2] * v,
- TRUE,
- GLOB.footstep[T.footstep][3] + e)
-
- if((!H.shoes && !feetCover)) //are we NOT wearing shoes
- playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
- GLOB.barefootstep[T.barefootstep][2] * v,
- TRUE,
- GLOB.barefootstep[T.barefootstep][3] + e)
\ No newline at end of file
+/datum/component/footstep
+ var/steps = 0
+ var/volume
+ var/e_range
+
+/datum/component/footstep/Initialize(volume_ = 0.5, e_range_ = -1)
+ if(!isliving(parent))
+ return COMPONENT_INCOMPATIBLE
+ volume = volume_
+ e_range = e_range_
+ RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED), .proc/play_footstep)
+
+/datum/component/footstep/proc/play_footstep()
+ var/turf/open/T = get_turf(parent)
+ if(!istype(T))
+ return
+
+ var/mob/living/LM = parent
+ var/v = volume
+ var/e = e_range
+ if(!T.footstep || LM.buckled || LM.lying || !CHECK_MULTIPLE_BITFIELDS(LM.mobility_flags, MOBILITY_STAND | MOBILITY_MOVE) || LM.throwing || LM.movement_type & (VENTCRAWLING | FLYING))
+ if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying
+ playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * v)
+ return
+
+ if(iscarbon(LM))
+ var/mob/living/carbon/C = LM
+ if(!C.get_bodypart(BODY_ZONE_L_LEG) && !C.get_bodypart(BODY_ZONE_R_LEG))
+ return
+ if(ishuman(C) && C.m_intent == MOVE_INTENT_WALK)
+ v /= 2
+ e -= 5
+ steps++
+
+ if(steps >= 6)
+ steps = 0
+
+ if(steps % 2)
+ return
+
+ if(!LM.has_gravity(T) && steps != 0) // don't need to step as often when you hop around
+ return
+
+ //begin playsound shenanigans//
+
+ //for barefooted non-clawed mobs like monkeys
+ if(isbarefoot(LM))
+ playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
+ GLOB.barefootstep[T.barefootstep][2] * v,
+ TRUE,
+ GLOB.barefootstep[T.barefootstep][3] + e)
+ return
+
+ //for xenomorphs, dogs, and other clawed mobs
+ if(isclawfoot(LM))
+ if(isalienadult(LM)) //xenos are stealthy and get quieter footsteps
+ v /= 3
+ e -= 5
+
+ playsound(T, pick(GLOB.clawfootstep[T.clawfootstep][1]),
+ GLOB.clawfootstep[T.clawfootstep][2] * v,
+ TRUE,
+ GLOB.clawfootstep[T.clawfootstep][3] + e)
+ return
+
+ //for megafauna and other large and imtimidating mobs such as the bloodminer
+ if(isheavyfoot(LM))
+ playsound(T, pick(GLOB.heavyfootstep[T.heavyfootstep][1]),
+ GLOB.heavyfootstep[T.heavyfootstep][2] * v,
+ TRUE,
+ GLOB.heavyfootstep[T.heavyfootstep][3] + e)
+ return
+
+ //for slimes
+ if(isslime(LM))
+ playsound(T, 'sound/effects/footstep/slime1.ogg', 15 * v)
+ return
+
+ //for (simple) humanoid mobs (clowns, russians, pirates, etc.)
+ if(isshoefoot(LM))
+ if(!ishuman(LM))
+ playsound(T, pick(GLOB.footstep[T.footstep][1]),
+ GLOB.footstep[T.footstep][2] * v,
+ TRUE,
+ GLOB.footstep[T.footstep][3] + e)
+ return
+ if(ishuman(LM)) //for proper humans, they're special
+ var/mob/living/carbon/human/H = LM
+ var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
+
+ if(H.shoes || feetCover) //are we wearing shoes
+ playsound(T, pick(GLOB.footstep[T.footstep][1]),
+ GLOB.footstep[T.footstep][2] * v,
+ TRUE,
+ GLOB.footstep[T.footstep][3] + e)
+
+ if((!H.shoes && !feetCover)) //are we NOT wearing shoes
+ if(H.dna.species.special_step_sounds)
+ playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE)
+ else
+ playsound(T, pick(GLOB.barefootstep[T.barefootstep][1]),
+ GLOB.barefootstep[T.barefootstep][2] * v,
+ TRUE,
+ GLOB.barefootstep[T.barefootstep][3] + e)
\ No newline at end of file
diff --git a/code/datums/components/riding.dm b/code/datums/components/riding.dm
index 7b80f87657..6fc58b9f5d 100644
--- a/code/datums/components/riding.dm
+++ b/code/datums/components/riding.dm
@@ -195,21 +195,47 @@
. = ..()
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
+/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
+ var/mob/living/carbon/human/H = parent
+ H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
+ . = ..()
+
+/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
+ . = ..()
+ var/mob/living/carbon/human/H = parent
+ H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN)
+
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
- var/mob/living/carbon/human/AM = parent
- if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
+ var/mob/living/carbon/human/H = parent
+ if(H.a_intent == INTENT_DISARM && (target in H.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
- if(AM.dir == SOUTH)
- AM.layer = ABOVE_MOB_LAYER
+ for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied
+ M.layer = MOB_LAYER
+ if(!AM.buckle_lying)
+ if(AM.dir == SOUTH)
+ AM.layer = ABOVE_MOB_LAYER
+ else
+ AM.layer = OBJ_LAYER
else
- AM.layer = OBJ_LAYER
+ if(AM.dir == NORTH)
+ AM.layer = OBJ_LAYER
+ else
+ AM.layer = ABOVE_MOB_LAYER
else
AM.layer = MOB_LAYER
+/datum/component/riding/human/get_offsets(pass_index)
+ var/mob/living/carbon/human/H = parent
+ if(H.buckle_lying)
+ return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
+ else
+ return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
+
+
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
@@ -273,12 +299,15 @@
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
-/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
+/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, riding_target_override = null)
var/atom/movable/AM = parent
var/amount_equipped = 0
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
- inhand.rider = user
+ if(!riding_target_override)
+ inhand.rider = user
+ else
+ inhand.rider = riding_target_override
inhand.parent = AM
if(user.put_in_hands(inhand, TRUE))
amount_equipped++
@@ -318,7 +347,7 @@
. = ..()
/obj/item/riding_offhand/equipped()
- if(loc != rider)
+ if(loc != rider && loc != parent)
selfdeleting = TRUE
qdel(src)
. = ..()
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 8c29c1b2c5..b02c10dc5e 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -115,6 +115,9 @@
log_combat(user, pushed_mob, "placed")
/obj/structure/table/proc/tablepush(mob/living/user, mob/living/pushed_mob)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "Throwing [pushed_mob] onto the table might hurt them!")
+ return
var/added_passtable = FALSE
if(!pushed_mob.pass_flags & PASSTABLE)
added_passtable = TRUE
@@ -125,9 +128,9 @@
if(pushed_mob.loc != loc) //Something prevented the tabling
return
pushed_mob.Knockdown(40)
- pushed_mob.visible_message("[user] pushes [pushed_mob] onto [src].", \
- "[user] pushes [pushed_mob] onto [src].")
- log_combat(user, pushed_mob, "pushed")
+ pushed_mob.visible_message("[user] slams [pushed_mob] onto [src]!", \
+ "[user] slams you onto [src]!")
+ log_combat(user, pushed_mob, "tabled", null, "onto [src]")
if(!ishuman(pushed_mob))
return
var/mob/living/carbon/human/H = pushed_mob
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 528b55c921..9e1adf4604 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -854,52 +854,83 @@
.["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]"
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
- //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
- if(user == target && can_piggyback(target) && pulling == target && (HAS_TRAIT(src, TRAIT_PACIFISM) || grab_state >= GRAB_AGGRESSIVE) && stat == CONSCIOUS)
- buckle_mob(target,TRUE,TRUE)
+ if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
+ //If they dragged themselves and we're currently aggressively grabbing them try to piggyback
+ if(user == target && can_piggyback(target))
+ piggyback(target)
+ return
+ //If you dragged them to you and you're aggressively grabbing try to fireman carry them
+ else if(user != target && can_be_firemanned(target))
+ fireman_carry(target)
+ return
. = ..()
-/mob/living/carbon/human/proc/piggyback_instant(mob/living/M)
- return buckle_mob(M, TRUE, TRUE, FALSE, TRUE)
+//src is the user that will be carrying, target is the mob to be carried
+/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
+ return (istype(target) && target.stat == CONSCIOUS)
-//Can C try to piggyback at all.
-/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/C)
- if(istype(C) && C.stat == CONSCIOUS)
- return TRUE
- return FALSE
+/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
+ return (ishuman(target) && !(target.mobility_flags & MOBILITY_STAND))
-/mob/living/carbon/human/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE, bypass_piggybacking = FALSE, no_delay = FALSE)
+/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
+ if(can_be_firemanned(target))
+ visible_message("[src] starts lifting [target] onto their back...",
+ "You start lifting [target] onto your back...")
+ if(do_after(src, 50, TRUE, target))
+ //Second check to make sure they're still valid to be carried
+ if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
+ buckle_mob(target, TRUE, TRUE, 90, 1, 0)
+ return
+ visible_message("[src] fails to fireman carry [target]!")
+ else
+ to_chat(src, "You can't fireman carry [target] while they're standing!")
+
+/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
+ if(can_piggyback(target))
+ visible_message("[target] starts to climb onto [src]...")
+ if(do_after(target, 15, target = src))
+ if(can_piggyback(target))
+ if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
+ target.visible_message("[target] can't hang onto [src]!")
+ return
+ buckle_mob(target, TRUE, TRUE, FALSE, 0, 2)
+ else
+ visible_message("[target] fails to climb onto [src]!")
+ else
+ to_chat(target, "You can't piggyback ride [src] right now!")
+
+/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0)
if(!force)//humans are only meant to be ridden through piggybacking and special cases
return
- if(bypass_piggybacking)
- return ..()
- if(!is_type_in_typecache(M, can_ride_typecache))
- M.visible_message("[M] really can't seem to mount [src]...")
+ if(!is_type_in_typecache(target, can_ride_typecache))
+ target.visible_message("[target] really can't seem to mount [src]...")
return
+ buckle_lying = lying_buckle
var/datum/component/riding/human/riding_datum = LoadComponent(/datum/component/riding/human)
- riding_datum.ride_check_rider_incapacitated = TRUE
- riding_datum.ride_check_rider_restrained = TRUE
- riding_datum.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4)))
- if(buckled_mobs && ((M in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled || (M.stat != CONSCIOUS))
+ if(target_hands_needed)
+ riding_datum.ride_check_rider_restrained = TRUE
+ if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
return
- if(can_piggyback(M))
- riding_datum.ride_check_ridden_incapacitated = TRUE
- visible_message("[M] starts to climb onto [src]...")
- if(no_delay || do_after(M, 15, target = src))
- if(can_piggyback(M))
- if(M.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
- M.visible_message("[M] can't hang onto [src]!")
- return
- if(!riding_datum.equip_buckle_inhands(M, 2)) //MAKE SURE THIS IS LAST!!
- M.visible_message("[M] can't climb onto [src]!")
- return
- . = ..(M, force, check_loc)
- stop_pulling()
- else
- visible_message("[M] fails to climb onto [src]!")
- else
- . = ..(M,force,check_loc)
- stop_pulling()
+ var/equipped_hands_self
+ var/equipped_hands_target
+ if(hands_needed)
+ equipped_hands_self = riding_datum.equip_buckle_inhands(src, hands_needed, target)
+ if(target_hands_needed)
+ equipped_hands_target = riding_datum.equip_buckle_inhands(target, target_hands_needed)
+
+ if(hands_needed || target_hands_needed)
+ if(hands_needed && !equipped_hands_self)
+ src.visible_message("[src] can't get a grip on [target] because their hands are full!",
+ "You can't get a grip on [target] because your hands are full!")
+ return
+ else if(target_hands_needed && !equipped_hands_target)
+ target.visible_message("[target] can't get a grip on [src] because their hands are full!",
+ "You can't get a grip on [src] because your hands are full!")
+ return
+
+ stop_pulling()
+ riding_datum.handle_vehicle_layer()
+ . = ..(target, force, check_loc)
/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 19f18f9973..2c48e56be4 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -286,6 +286,8 @@
var/mob/living/carbon/C = L
if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER))
C.grippedby(src)
+
+ update_pull_movespeed()
//mob verbs are a lot faster than object verbs
//for more info on why this is not atom/pull, see examinate() in mob.dm
@@ -300,6 +302,7 @@
/mob/living/stop_pulling()
..()
+ update_pull_movespeed()
update_pull_hud_icon()
/mob/living/verb/stop_pulling1()
@@ -520,6 +523,10 @@
var/old_direction = dir
var/turf/T = loc
+
+ if(pulling)
+ update_pull_movespeed()
+
. = ..()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move.
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index e434bc4e95..9d04f288cd 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -153,7 +153,7 @@
to_chat(user, "[src] can't be grabbed more aggressively!")
return FALSE
- if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ if(user.grab_state >= GRAB_AGGRESSIVE && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "You don't want to risk hurting [src]!")
return FALSE
@@ -184,11 +184,17 @@
user.grab_state++
switch(user.grab_state)
if(GRAB_AGGRESSIVE)
- log_combat(user, src, "grabbed", addition="aggressive grab")
- visible_message("[user] has grabbed [src] aggressively!", \
- "[user] has grabbed [src] aggressively!")
- drop_all_held_items()
+ var/add_log = ""
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ visible_message("[user] has firmly gripped [src]!",
+ "[user] has firmly gripped you!")
+ add_log = " (pacifist)"
+ else
+ visible_message("[user] has grabbed [src] aggressively!", \
+ "[user] has grabbed you aggressively!")
+ drop_all_held_items()
stop_pulling()
+ log_combat(user, src, "grabbed", addition="aggressive grab[add_log]")
if(GRAB_NECK)
log_combat(user, src, "grabbed", addition="neck grab")
visible_message("[user] has grabbed [src] by the neck!",\
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index c24e6ab108..d5fa479189 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -110,3 +110,5 @@
//List of active diseases
var/list/diseases = list() // list of all diseases in a mob
var/list/disease_resistances = list()
+
+ var/drag_slowdown = TRUE //Whether the mob is slowed down when dragging another prone mob
diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm
index 9566edc2ed..d8d7c40ee2 100644
--- a/code/modules/mob/living/living_movement.dm
+++ b/code/modules/mob/living/living_movement.dm
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
/mob/living/Moved()
. = ..()
update_turf_movespeed(loc)
@@ -25,3 +26,11 @@
add_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = T.slowdown)
else
remove_movespeed_modifier(MOVESPEED_ID_LIVING_TURF_SPEEDMOD)
+
+/mob/living/proc/update_pull_movespeed()
+ if(pulling && isliving(pulling))
+ var/mob/living/L = pulling
+ if(drag_slowdown && !(L.mobility_flags & MOBILITY_STAND) && !L.buckled && grab_state < GRAB_AGGRESSIVE)
+ add_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING, multiplicative_slowdown = PULL_PRONE_SLOWDOWN)
+ return
+ remove_movespeed_modifier(MOVESPEED_ID_PRONE_DRAGGING)
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 29fbd39e2c..94c0cad81c 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -1207,14 +1207,15 @@
return
if(incapacitated())
return
- if(M.incapacitated())
- return
if(module)
if(!module.allow_riding)
M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!")
return
- if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 1)))
- M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!")
+ if(iscarbon(M) && !M.incapacitated() && !riding_datum.equip_buckle_inhands(M, 1))
+ if(M.get_num_arms() <= 0)
+ M.visible_message("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!")
+ else
+ M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!")
return
. = ..(M, force, check_loc)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c64702f9ef..0b29b19aa5 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -524,7 +524,12 @@
return
if(isAI(M))
return
- show_inv(usr)
+
+/mob/MouseDrop_T(atom/dropping, atom/user)
+ . = ..()
+ if(ismob(dropping) && dropping != user)
+ var/mob/M = dropping
+ M.show_inv(user)
/mob/proc/is_muzzled()
return 0