diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 4b42595b48..1d1dda6d99 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -54,6 +54,10 @@
#define BODYPART_ORGANIC 1
#define BODYPART_ROBOTIC 2
+#define BODYPART_NOT_DISABLED 0
+#define BODYPART_DISABLED_DAMAGE 1
+#define BODYPART_DISABLED_PARALYSIS 2
+
#define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi'
#define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi'
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index b2caf614b3..c0e3e141c7 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -50,7 +50,13 @@
#define TRAIT_NOHARDCRIT "nohardcrit"
#define TRAIT_NOSOFTCRIT "nosoftcrit"
#define TRAIT_MINDSHIELD "mindshield"
+#define TRAIT_PARALYSIS_L_ARM "para-l-arm" //These are used for brain-based paralysis, where replacing the limb won't fix it
+#define TRAIT_PARALYSIS_R_ARM "para-r-arm"
+#define TRAIT_PARALYSIS_L_LEG "para-l-leg"
+#define TRAIT_PARALYSIS_R_LEG "para-r-leg"
+ //non-mob traits
+#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_AGEUSIA "ageusia"
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index a8adbfbce8..8e13522a02 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -60,18 +60,63 @@
/datum/brain_trauma/severe/paralysis
name = "Paralysis"
- desc = "Patient's brain can no longer control its motor functions."
+ desc = "Patient's brain can no longer control part of its motor functions."
scan_desc = "cerebral paralysis"
- gain_text = "You can't feel your body anymore!"
- lose_text = "You can feel your limbs again!"
+ gain_text = ""
+ lose_text = ""
+ var/paralysis_type
+ var/list/paralysis_traits = list()
+ //for descriptions
-/datum/brain_trauma/severe/paralysis/on_life()
- owner.Knockdown(200, ignore_canknockdown = TRUE)
+/datum/brain_trauma/severe/paralysis/New(specific_type)
+ paralysis_type = specific_type
+ if(!paralysis_type)
+ paralysis_type = pick("full","left","right","arms","legs","r_arm","l_arm","r_leg","l_leg")
+ var/subject
+ switch(paralysis_type)
+ if("full")
+ subject = "your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)
+ if("left")
+ subject = "the left side of your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_L_LEG)
+ if("right")
+ subject = "the right side of your body"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_ARM, TRAIT_PARALYSIS_R_LEG)
+ if("arms")
+ subject = "your arms"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM, TRAIT_PARALYSIS_R_ARM)
+ if("legs")
+ subject = "your legs"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_LEG, TRAIT_PARALYSIS_R_LEG)
+ if("r_arm")
+ subject = "your right arm"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_ARM)
+ if("l_arm")
+ subject = "your left arm"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_ARM)
+ if("r_leg")
+ subject = "your right leg"
+ paralysis_traits = list(TRAIT_PARALYSIS_R_LEG)
+ if("l_leg")
+ subject = "your left leg"
+ paralysis_traits = list(TRAIT_PARALYSIS_L_LEG)
+
+ gain_text = "You can't feel [subject] anymore!"
+ lose_text = "You can feel [subject] again!"
+
+/datum/brain_trauma/severe/paralysis/on_gain()
..()
+ for(var/X in paralysis_traits)
+ owner.add_trait(X, "trauma_paralysis")
+ owner.update_disabled_bodyparts()
/datum/brain_trauma/severe/paralysis/on_lose()
- owner.SetKnockdown(0)
..()
+ for(var/X in paralysis_traits)
+ owner.remove_trait(X, "trauma_paralysis")
+ owner.update_disabled_bodyparts()
+
/datum/brain_trauma/severe/narcolepsy
name = "Narcolepsy"
@@ -203,4 +248,4 @@
/datum/brain_trauma/severe/pacifism/on_lose()
owner.remove_trait(TRAIT_PACIFISM, TRAUMA_TRAIT)
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 614cc65cbb..ed5ac0b49b 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -187,6 +187,40 @@
to_chat(quirk_holder, "Your antagonistic nature has caused you to renounce your pacifism.")
qdel(src)
+/datum/quirk/paraplegic
+ name = "Paraplegic"
+ desc = "Your legs do not function. Nothing will ever fix this. But hey, free wheelchair!"
+ value = -3
+ human_only = TRUE
+ gain_text = null // Handled by trauma.
+ lose_text = null
+ medical_record_text = "Patient has an untreatable impairment in motor function in the lower extremities."
+
+ /datum/quirk/paraplegic/add()
+ var/datum/brain_trauma/severe/paralysis/paraplegic/T = new()
+ var/mob/living/carbon/human/H = quirk_holder
+ H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE)
+
+ /datum/quirk/paraplegic/on_spawn()
+ if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs.
+ quirk_holder.buckled.unbuckle_mob(quirk_holder)
+
+ var/turf/T = get_turf(quirk_holder)
+ var/obj/structure/chair/spawn_chair = locate() in T
+
+ var/obj/vehicle/ridden/wheelchair/wheels = new(T)
+ if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking
+ wheels.setDir(spawn_chair.dir)
+
+ wheels.buckle_mob(quirk_holder)
+
+ // During the spawning process, they may have dropped what they were holding, due to the paralysis
+ // So put the things back in their hands.
+
+ for(var/obj/item/I in T)
+ if(I.fingerprintslast == quirk_holder.ckey)
+ quirk_holder.put_in_hands(I)
+
/datum/quirk/poor_aim
name = "Poor Aim"
desc = "You're terrible with guns and can't line up a straight shot to save your life. Dual-wielding is right out."
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index ea13255dfe..23267b88c6 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -895,6 +895,11 @@
var/obj/item/organ/I = X
I.Insert(src)
+/mob/living/carbon/proc/update_disabled_bodyparts()
+ for(var/B in bodyparts)
+ var/obj/item/bodypart/BP = B
+ BP.update_disabled()
+
/mob/living/carbon/vv_get_dropdown()
. = ..()
. += "---"
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 71b659b73f..db032aaa4a 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -21,7 +21,7 @@
var/held_index = 0 //are we a hand? if so, which one!
var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws
- var/disabled = FALSE //If TRUE, limb is as good as missing
+ var/disabled = BODYPART_NOT_DISABLED //If disabled, limb is as good as missing
var/body_damage_coeff = 1 //Multiplier of the limb's damage that gets applied to the mob
var/stam_damage_coeff = 0.5
var/brutestate = 0
@@ -189,7 +189,7 @@
if(stamina > DAMAGE_PRECISION)
owner.update_stamina()
consider_processing()
- check_disabled()
+ update_disabled()
return update_bodypart_damage_state()
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
@@ -209,7 +209,7 @@
if(owner && updating_health)
owner.updatehealth()
consider_processing()
- check_disabled()
+ update_disabled()
return update_bodypart_damage_state()
//Returns total damage.
@@ -220,15 +220,23 @@
return total
//Checks disabled status thresholds
-/obj/item/bodypart/proc/check_disabled()
- if(!can_dismember() || owner.has_trait(TRAIT_NODISMEMBER))
- return
- if(!disabled && (get_damage(TRUE) >= max_damage))
- set_disabled(TRUE)
- else if(disabled && (get_damage(TRUE) <= (max_damage * 0.5)))
- set_disabled(FALSE)
+//Checks disabled status thresholds
+/obj/item/bodypart/proc/update_disabled()
+ set_disabled(is_disabled())
-/obj/item/bodypart/proc/set_disabled(new_disabled = TRUE)
+/obj/item/bodypart/proc/is_disabled()
+ if(has_trait(TRAIT_PARALYSIS))
+ return BODYPART_DISABLED_PARALYSIS
+ if(can_dismember() && !owner.has_trait(TRAIT_NODISMEMBER))
+ . = disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled
+ if((get_damage(TRUE) >= max_damage))
+ return BODYPART_DISABLED_DAMAGE
+ if(disabled && (get_damage(TRUE) <= (max_damage * 0.5)))
+ return BODYPART_NOT_DISABLED
+ else
+ return BODYPART_NOT_DISABLED
+
+/obj/item/bodypart/proc/set_disabled(new_disabled)
if(disabled == new_disabled)
return
disabled = new_disabled
@@ -598,13 +606,27 @@
px_y = 0
stam_heal_tick = 2
-/obj/item/bodypart/l_arm/set_disabled(new_disabled = TRUE)
- ..()
- if(disabled)
- to_chat(owner, "Your [name] is too damaged to function!")
- owner.emote("scream")
+/obj/item/bodypart/l_arm/is_disabled()
+ if(owner.has_trait(TRAIT_PARALYSIS_L_ARM))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/l_arm/set_disabled(new_disabled)
+ . = ..()
+ if(disabled == new_disabled)
+ return
+ if(disabled == BODYPART_DISABLED_DAMAGE)
+ if(owner.stat > UNCONSCIOUS)
+ owner.emote("scream")
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "Your [name] is too damaged to function!")
if(held_index)
owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ else if(disabled == BODYPART_DISABLED_PARALYSIS)
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "You can't feel your [name]!")
+ if(held_index)
+ owner.dropItemToGround(owner.get_item_for_held_index(held_index))
if(owner.hud_used)
var/obj/screen/inventory/hand/L = owner.hud_used.hand_slots["[held_index]"]
if(L)
@@ -649,18 +671,33 @@
stam_heal_tick = 2
max_stamina_damage = 50
-/obj/item/bodypart/r_arm/set_disabled(new_disabled = TRUE)
- ..()
- if(disabled)
- to_chat(owner, "Your [name] is too damaged to function!")
- owner.emote("scream")
+/obj/item/bodypart/r_arm/is_disabled()
+ if(owner.has_trait(TRAIT_PARALYSIS_R_ARM))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/r_arm/set_disabled(new_disabled)
+ . = ..()
+ if(disabled == new_disabled)
+ return
+ if(disabled == BODYPART_DISABLED_DAMAGE)
+ if(owner.stat > UNCONSCIOUS)
+ owner.emote("scream")
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "Your [name] is too damaged to function!")
if(held_index)
owner.dropItemToGround(owner.get_item_for_held_index(held_index))
+ else if(disabled == BODYPART_DISABLED_PARALYSIS)
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "You can't feel your [name]!")
+ if(held_index)
+ owner.dropItemToGround(owner.get_item_for_held_index(held_index))
if(owner.hud_used)
var/obj/screen/inventory/hand/R = owner.hud_used.hand_slots["[held_index]"]
if(R)
R.update_icon()
+
/obj/item/bodypart/r_arm/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_r_arm"
@@ -697,11 +734,24 @@
stam_heal_tick = 2
max_stamina_damage = 50
-/obj/item/bodypart/l_leg/set_disabled(new_disabled = TRUE)
- ..()
- if(disabled)
- to_chat(owner, "Your [name] is too damaged to function!")
- owner.emote("scream")
+/obj/item/bodypart/l_leg/is_disabled()
+ if(owner.has_trait(TRAIT_PARALYSIS_L_LEG))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/l_leg/set_disabled(new_disabled)
+ . = ..()
+ if(disabled == new_disabled)
+ return
+ if(disabled == BODYPART_DISABLED_DAMAGE)
+ if(owner.stat > UNCONSCIOUS)
+ owner.emote("scream")
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "Your [name] is too damaged to function!")
+ else if(disabled == BODYPART_DISABLED_PARALYSIS)
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "You can't feel your [name]!")
+
/obj/item/bodypart/l_leg/digitigrade
name = "left digitigrade leg"
@@ -744,11 +794,23 @@
max_stamina_damage = 50
stam_heal_tick = 2
-/obj/item/bodypart/r_leg/set_disabled(new_disabled = TRUE)
- ..()
- if(disabled)
- to_chat(owner, "Your [name] is too damaged to function!")
- owner.emote("scream")
+/obj/item/bodypart/r_leg/is_disabled()
+ if(owner.has_trait(TRAIT_PARALYSIS_R_LEG))
+ return BODYPART_DISABLED_PARALYSIS
+ return ..()
+
+/obj/item/bodypart/r_leg/set_disabled(new_disabled)
+ . = ..()
+ if(disabled == new_disabled)
+ return
+ if(disabled == BODYPART_DISABLED_DAMAGE)
+ if(owner.stat > UNCONSCIOUS)
+ owner.emote("scream")
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "Your [name] is too damaged to function!")
+ else if(disabled == BODYPART_DISABLED_PARALYSIS)
+ if(. && (owner.stat > DEAD))
+ to_chat(owner, "You can't feel your [name]!")
/obj/item/bodypart/r_leg/digitigrade
name = "right digitigrade leg"