diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 6f8b67f0bbd..c45b41afa84 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -55,6 +55,7 @@
#define TRAIT_PARALYSIS_R_ARM "para-r-arm"
#define TRAIT_PARALYSIS_L_LEG "para-l-leg"
#define TRAIT_PARALYSIS_R_LEG "para-r-leg"
+#define TRAIT_NOMOBSWAP "no-mob-swap"
#define TRAIT_XRAY_VISION "xray_vision"
//non-mob traits
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index e09ebcb10c4..bb849746d38 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -81,3 +81,21 @@ GLOBAL_VAR_INIT(cmp_field, "name")
/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B)
return A.totalResistance() - B.totalResistance()
+
+/proc/cmp_quirk_asc(datum/quirk/A, datum/quirk/B)
+ var/a_sign = num2sign(initial(A.value) * -1)
+ var/b_sign = num2sign(initial(B.value) * -1)
+
+ // Neutral traits go last.
+ if(a_sign == 0)
+ a_sign = 2
+ if(b_sign == 0)
+ b_sign = 2
+
+ var/a_name = initial(A.name)
+ var/b_name = initial(B.name)
+
+ if(a_sign != b_sign)
+ return a_sign - b_sign
+ else
+ return sorttext(b_name, a_name)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 27b7eb75a94..4b371819e1f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1558,3 +1558,11 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
if(channels_to_use.len)
world.TgsChatBroadcast()
+
+/proc/num2sign(numeric)
+ if(numeric > 0)
+ return 1
+ else if(numeric < 0)
+ return -1
+ else
+ return 0
diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm
index 7f0ee25e7cc..631a2921123 100644
--- a/code/controllers/subsystem/processing/quirks.dm
+++ b/code/controllers/subsystem/processing/quirks.dm
@@ -20,7 +20,10 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
return ..()
/datum/controller/subsystem/processing/quirks/proc/SetupQuirks()
- for(var/V in subtypesof(/datum/quirk))
+ // Sort by Positive, Negative, Neutral; and then by name
+ var/list/quirk_list = sortList(subtypesof(/datum/quirk), /proc/cmp_quirk_asc)
+
+ for(var/V in quirk_list)
var/datum/quirk/T = V
quirks[initial(T.name)] = T
quirk_points[initial(T.name)] = initial(T.value)
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index e6eb94eca28..2f8b425d259 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -307,6 +307,14 @@
to_chat(quirk_holder, "Please note that your dissociation syndrome does NOT give you the right to attack people or otherwise cause any interference to \
the round. You are not an antagonist, and the rules will treat you the same as other crewmembers.")
+/datum/quirk/obstructive
+ name = "Physically Obstructive"
+ desc = "You somehow manage to always be in the way. You can't swap places with other people."
+ value = -1
+ mob_trait = TRAIT_NOMOBSWAP
+ gain_text = "You feel like you're in the way."
+ lose_text = "You feel less like you're in the way."
+
/datum/quirk/social_anxiety
name = "Social Anxiety"
desc = "Talking to people is very difficult for you, and you often stutter or even lock up."
@@ -332,3 +340,4 @@
dumb_thing = FALSE //only once per life
if(prob(1))
new/obj/item/reagent_containers/food/snacks/spaghetti/pastatomato(get_turf(H)) //now that's what I call spaghetti code
+
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index e4b716fd2be..8570b15af43 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1,9 +1,5 @@
-
-
GLOBAL_LIST_EMPTY(preferences_datums)
-
-
/datum/preferences
var/client/parent
//doohickeys for savefiles
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index afed282a2f0..c6e465888a0 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -105,13 +105,15 @@
return 1
if(!M.buckled && !M.has_buckled_mobs())
- var/mob_swap
+ var/mob_swap = FALSE
//the puller can always swap with its victim if on grab intent
if(M.pulledby == src && a_intent == INTENT_GRAB)
- mob_swap = 1
+ mob_swap = TRUE
+ else if(M.has_trait(TRAIT_NOMOBSWAP) || has_trait(TRAIT_NOMOBSWAP))
+ mob_swap = FALSE
//restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
- mob_swap = 1
+ mob_swap = TRUE
if(mob_swap)
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
@@ -1209,4 +1211,4 @@
if("resize")
update_transform()
if("lighting_alpha")
- sync_lighting_plane_alpha()
\ No newline at end of file
+ sync_lighting_plane_alpha()