diff --git a/code/__DEFINES/quirks.dm b/code/__DEFINES/quirks.dm
new file mode 100644
index 00000000000..290fed93c95
--- /dev/null
+++ b/code/__DEFINES/quirks.dm
@@ -0,0 +1,14 @@
+//Medical Categories for quirks
+#define CAT_QUIRK_ALL 0
+#define CAT_QUIRK_NOTES 1
+#define CAT_QUIRK_MINOR_DISABILITY 2
+#define CAT_QUIRK_MAJOR_DISABILITY 3
+
+/// This quirk can only be applied to humans
+#define QUIRK_HUMAN_ONLY (1<<0)
+/// This quirk processes on SSquirks (and should implement quirk process)
+#define QUIRK_PROCESSES (1<<1)
+/// This quirk is has a visual aspect in that it changes how the player looks. Used in generating dummies.
+#define QUIRK_CHANGES_APPEARANCE (1<<2)
+/// The only thing this quirk effects is mood so it should be disabled if mood is
+#define QUIRK_MOODLET_BASED (1<<3)
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 1fa4f4909ff..7e1c8a7d862 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -692,12 +692,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Echolocation has a higher range.
#define TRAIT_ECHOLOCATION_EXTRA_RANGE "echolocation_extra_range"
-//Medical Categories for quirks
-#define CAT_QUIRK_ALL 0
-#define CAT_QUIRK_NOTES 1
-#define CAT_QUIRK_MINOR_DISABILITY 2
-#define CAT_QUIRK_MAJOR_DISABILITY 3
-
// common trait sources
#define TRAIT_GENERIC "generic"
#define UNCONSCIOUS_TRAIT "unconscious"
diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm
index cd75412aec5..d5bb0effa59 100644
--- a/code/controllers/subsystem/processing/quirks.dm
+++ b/code/controllers/subsystem/processing/quirks.dm
@@ -76,19 +76,19 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
continue
hardcore_quirks[quirk_type] += hardcore_value
-/datum/controller/subsystem/processing/quirks/proc/AssignQuirks(mob/living/user, client/cli)
+/datum/controller/subsystem/processing/quirks/proc/AssignQuirks(mob/living/user, client/applied_client)
var/badquirk = FALSE
- for(var/quirk_name in cli.prefs.all_quirks)
- var/datum/quirk/Q = quirks[quirk_name]
- if(Q)
- if(user.add_quirk(Q))
+ for(var/quirk_name in applied_client.prefs.all_quirks)
+ var/datum/quirk/quirk_type = quirks[quirk_name]
+ if(ispath(quirk_type))
+ if(user.add_quirk(quirk_type, override_client = applied_client))
SSblackbox.record_feedback("nested tally", "quirks_taken", 1, list("[quirk_name]"))
else
- stack_trace("Invalid quirk \"[quirk_name]\" in client [cli.ckey] preferences")
- cli.prefs.all_quirks -= quirk_name
+ stack_trace("Invalid quirk \"[quirk_name]\" in client [applied_client.ckey] preferences")
+ applied_client.prefs.all_quirks -= quirk_name
badquirk = TRUE
if(badquirk)
- cli.prefs.save_character()
+ applied_client.prefs.save_character()
/*
*Randomises the quirks for a specified mob
@@ -169,7 +169,7 @@ PROCESSING_SUBSYSTEM_DEF(quirks)
if (isnull(quirk))
continue
- if (initial(quirk.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
+ if ((initial(quirk.quirk_flags) & QUIRK_MOODLET_BASED) && CONFIG_GET(flag/disable_human_mood))
continue
var/blacklisted = FALSE
diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm
index 1f24e1e3034..85885e62127 100644
--- a/code/datums/quirks/_quirk.dm
+++ b/code/datums/quirks/_quirk.dm
@@ -1,20 +1,29 @@
//every quirk in this folder should be coded around being applied on spawn
//these are NOT "mob quirks" like GOTTAGOFAST, but exist as a medium to apply them and other different effects
/datum/quirk
+ /// The name of the quirk
var/name = "Test Quirk"
+ /// The description of the quirk
var/desc = "This is a test quirk."
+ /// What the quirk is worth in preferences, zero = neutral / free
var/value = 0
- var/human_only = TRUE
- var/gain_text
- var/lose_text
- var/medical_record_text //This text will appear on medical records for the trait. Not yet implemented
- var/mood_quirk = FALSE //if true, this quirk affects mood and is unavailable if moodlets are disabled
- var/mob_trait //if applicable, apply and remove this mob trait
- /// Amount of points this trait is worth towards the hardcore character mode; minus points implies a positive quirk, positive means its hard. This is used to pick the quirks assigned to a hardcore character. 0 means its not available to hardcore draws.
- var/hardcore_value = 0
+ /// Flags related to this quirk.
+ var/quirk_flags = QUIRK_HUMAN_ONLY
+ /// Reference to the mob currently tied to this quirk datum. Quirks are not singletons.
var/mob/living/quirk_holder
- /// This quirk should START_PROCESSING when added and STOP_PROCESSING when removed.
- var/processing_quirk = FALSE
+ /// Text displayed when this quirk is assigned to a mob (and not transferred)
+ var/gain_text
+ /// Text displayed when this quirk is removed from a mob (and not transferred)
+ var/lose_text
+ ///This text will appear on medical records for the trait.
+ var/medical_record_text
+ /// if applicable, apply and remove this mob trait
+ var/mob_trait
+ /// Amount of points this trait is worth towards the hardcore character mode.
+ /// Minus points implies a positive quirk, positive means its hard.
+ /// This is used to pick the quirks assigned to a hardcore character.
+ //// 0 means its not available to hardcore draws.
+ var/hardcore_value = 0
/// When making an abstract quirk (in OOP terms), don't forget to set this var to the type path for that abstract quirk.
var/abstract_parent_type = /datum/quirk
/// The icon to show in the preferences menu.
@@ -45,11 +54,11 @@
* * new_holder - The mob to add this quirk to.
* * quirk_transfer - If this is being added to the holder as part of a quirk transfer. Quirks can use this to decide not to spawn new items or apply any other one-time effects.
*/
-/datum/quirk/proc/add_to_holder(mob/living/new_holder, quirk_transfer = FALSE)
+/datum/quirk/proc/add_to_holder(mob/living/new_holder, quirk_transfer = FALSE, client/client_source)
if(!new_holder)
CRASH("Quirk attempted to be added to null mob.")
- if(human_only && !ishuman(new_holder))
+ if((quirk_flags & QUIRK_HUMAN_ONLY) && !ishuman(new_holder))
CRASH("Human only quirk attempted to be added to non-human mob.")
if(new_holder.has_quirk(type))
@@ -60,19 +69,21 @@
quirk_holder = new_holder
quirk_holder.quirks += src
+ // If we weren't passed a client source try to use a present one
+ client_source ||= quirk_holder.client
if(mob_trait)
ADD_TRAIT(quirk_holder, mob_trait, QUIRK_TRAIT)
- add()
+ add(client_source)
- if(processing_quirk)
+ if(quirk_flags & QUIRK_PROCESSES)
START_PROCESSING(SSquirks, src)
if(!quirk_transfer)
if(gain_text)
to_chat(quirk_holder, gain_text)
- add_unique()
+ add_unique(client_source)
if(quirk_holder.client)
post_add()
@@ -98,7 +109,7 @@
if(mob_trait)
REMOVE_TRAIT(quirk_holder, mob_trait, QUIRK_TRAIT)
- if(processing_quirk)
+ if(quirk_flags & QUIRK_PROCESSES)
STOP_PROCESSING(SSquirks, src)
remove()
@@ -119,13 +130,23 @@
post_add()
/// Any effect that should be applied every single time the quirk is added to any mob, even when transferred.
-/datum/quirk/proc/add()
-/// Any effects from the proc that should not be done multiple times if the quirk is transferred between mobs. Put stuff like spawning items in here.
-/datum/quirk/proc/add_unique()
+/datum/quirk/proc/add(client/client_source)
+ return
+
+/// Any effects from the proc that should not be done multiple times if the quirk is transferred between mobs.
+/// Put stuff like spawning items in here.
+/datum/quirk/proc/add_unique(client/client_source)
+ return
+
/// Removal of any reversible effects added by the quirk.
/datum/quirk/proc/remove()
-/// Any special effects or chat messages which should be applied. This proc is guaranteed to run if the mob has a client when the quirk is added. Otherwise, it runs once on the next COMSIG_MOB_LOGIN.
+ return
+
+/// Any special effects or chat messages which should be applied.
+/// This proc is guaranteed to run if the mob has a client when the quirk is added.
+/// Otherwise, it runs once on the next COMSIG_MOB_LOGIN.
/datum/quirk/proc/post_add()
+ return
/// Subtype quirk that has some bonus logic to spawn items for the player.
/datum/quirk/item_quirk
@@ -219,12 +240,13 @@
return medical ? "No issues have been declared." : "None"
return medical ? dat.Join("
") : dat.Join(", ")
-/mob/living/proc/cleanse_trait_datums() //removes all trait datums
- for(var/V in quirks)
- var/datum/quirk/T = V
- qdel(T)
+/mob/living/proc/cleanse_quirk_datums() //removes all trait datums
+ QDEL_LIST(quirks)
+
+/mob/living/proc/transfer_quirk_datums(mob/living/to_mob)
+ // We could be done before the client was moved or after the client was moved
+ var/datum/preferences/to_pass = client || to_mob.client
-/mob/living/proc/transfer_trait_datums(mob/living/to_mob)
for(var/datum/quirk/quirk as anything in quirks)
quirk.remove_from_current_holder(quirk_transfer = TRUE)
- quirk.add_to_holder(to_mob, quirk_transfer = TRUE)
+ quirk.add_to_holder(to_mob, quirk_transfer = TRUE, client_source = to_pass)
diff --git a/code/datums/quirks/negative_quirks.dm b/code/datums/quirks/negative_quirks.dm
index f51bb7bfff2..2ea1b41004d 100644
--- a/code/datums/quirks/negative_quirks.dm
+++ b/code/datums/quirks/negative_quirks.dm
@@ -5,7 +5,7 @@
desc = "Thanks to your poor posture, backpacks and other bags never sit right on your back. More evenly weighted objects are fine, though."
icon = "hiking"
value = -8
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
gain_text = "Your back REALLY hurts!"
lose_text = "Your back feels better."
medical_record_text = "Patient scans indicate severe and chronic back pain."
@@ -13,7 +13,7 @@
mail_goodies = list(/obj/item/cane)
var/datum/weakref/backpack
-/datum/quirk/badback/add()
+/datum/quirk/badback/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/storage/backpack/equipped_backpack = human_holder.back
if(istype(equipped_backpack))
@@ -60,7 +60,7 @@
lose_text = "You feel vigorous again."
medical_record_text = "Patient requires regular treatment for blood loss due to low production of blood."
hardcore_value = 8
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/item/reagent_containers/blood/o_minus) // universal blood type that is safe for all
var/min_blood = BLOOD_VOLUME_SAFE - 25 // just barely survivable without treatment
var/drain_rate = 0.275
@@ -87,12 +87,13 @@
lose_text = "You miraculously gain back your vision."
medical_record_text = "Patient has permanent blindness."
hardcore_value = 15
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
mail_goodies = list(/obj/item/clothing/glasses/sunglasses, /obj/item/cane/white)
-/datum/quirk/item_quirk/blindness/add_unique()
+/datum/quirk/item_quirk/blindness/add_unique(client/client_source)
give_item_to_holder(/obj/item/clothing/glasses/blindfold/white, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
-/datum/quirk/item_quirk/blindness/add()
+/datum/quirk/item_quirk/blindness/add(client/client_source)
quirk_holder.become_blind(QUIRK_TRAIT)
/datum/quirk/item_quirk/blindness/remove()
@@ -112,10 +113,10 @@
lose_text = "You feel wrinkled again."
medical_record_text = "Patient has a tumor in their brain that is slowly driving them to brain death."
hardcore_value = 12
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/item/storage/pill_bottle/mannitol/braintumor)
-/datum/quirk/item_quirk/brainproblems/add_unique()
+/datum/quirk/item_quirk/brainproblems/add_unique(client/client_source)
give_item_to_holder(
/obj/item/storage/pill_bottle/mannitol/braintumor,
list(
@@ -148,7 +149,7 @@
hardcore_value = 12
mail_goodies = list(/obj/item/clothing/mask/whistle)
-/datum/quirk/item_quirk/deafness/add_unique()
+/datum/quirk/item_quirk/deafness/add_unique(client/client_source)
give_item_to_holder(/obj/item/clothing/accessory/deaf_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
/datum/quirk/depression
@@ -160,7 +161,7 @@
gain_text = "You start feeling depressed."
lose_text = "You no longer feel depressed." //if only it were that easy!
medical_record_text = "Patient has a mild mood disorder causing them to experience acute episodes of depression."
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
hardcore_value = 2
mail_goodies = list(/obj/item/storage/pill_bottle/happinesspsych)
@@ -169,15 +170,14 @@
desc = "You are the current owner of an heirloom, passed down for generations. You have to keep it safe!"
icon = "toolbox"
value = -2
- mood_quirk = TRUE
medical_record_text = "Patient demonstrates an unnatural attachment to a family heirloom."
hardcore_value = 1
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES|QUIRK_MOODLET_BASED
/// A weak reference to our heirloom.
var/datum/weakref/heirloom
mail_goodies = list(/obj/item/storage/secure/briefcase)
-/datum/quirk/item_quirk/family_heirloom/add_unique()
+/datum/quirk/item_quirk/family_heirloom/add_unique(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/heirloom_type
@@ -266,7 +266,7 @@
/obj/item/clothing/mask/luchador/tecnicos,
)
-/datum/quirk/glass_jaw/add()
+/datum/quirk/glass_jaw/add(client/client_source)
RegisterSignal(quirk_holder, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(punch_out))
/datum/quirk/glass_jaw/remove()
@@ -332,7 +332,7 @@
hardcore_value = 3
mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie_delux)
-/datum/quirk/hypersensitive/add()
+/datum/quirk/hypersensitive/add(client/client_source)
if (quirk_holder.mob_mood)
quirk_holder.mob_mood.mood_modifier += 0.5
@@ -361,26 +361,29 @@
lose_text = "You start seeing faraway things normally again."
medical_record_text = "Patient requires prescription glasses in order to counteract nearsightedness."
hardcore_value = 5
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
mail_goodies = list(/obj/item/clothing/glasses/regular) // extra pair if orginal one gets broken by somebody mean
- var/glasses
-/datum/quirk/item_quirk/nearsighted/add_unique()
- glasses = glasses || quirk_holder.client?.prefs?.read_preference(/datum/preference/choiced/glasses)
- switch(glasses)
+/datum/quirk/item_quirk/nearsighted/add_unique(client/client_source)
+ var/glasses_name = client_source?.prefs.read_preference(/datum/preference/choiced/glasses) || "Regular"
+ var/obj/item/clothing/glasses/glasses_type
+ switch(glasses_name)
if ("Thin")
- glasses = /obj/item/clothing/glasses/regular/thin
+ glasses_type = /obj/item/clothing/glasses/regular/thin
if ("Circle")
- glasses = /obj/item/clothing/glasses/regular/circle
+ glasses_type = /obj/item/clothing/glasses/regular/circle
if ("Hipster")
- glasses = /obj/item/clothing/glasses/regular/hipster
- if ("Modern")
- glasses = /obj/item/clothing/glasses/betterunshit
+ glasses_type = /obj/item/clothing/glasses/regular/hipster
else
- glasses = /obj/item/clothing/glasses/regular
+ glasses_type = /obj/item/clothing/glasses/regular
- give_item_to_holder(glasses, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
+ give_item_to_holder(glasses_type, list(
+ LOCATION_EYES = ITEM_SLOT_EYES,
+ LOCATION_BACKPACK = ITEM_SLOT_BACKPACK,
+ LOCATION_HANDS = ITEM_SLOT_HANDS,
+ ))
-/datum/quirk/item_quirk/nearsighted/add()
+/datum/quirk/item_quirk/nearsighted/add(client/client_source)
quirk_holder.become_nearsighted(QUIRK_TRAIT)
/datum/quirk/item_quirk/nearsighted/remove()
@@ -395,7 +398,7 @@
hardcore_value = 5
mail_goodies = list(/obj/effect/spawner/random/engineering/flashlight)
-/datum/quirk/nyctophobia/add()
+/datum/quirk/nyctophobia/add(client/client_source)
RegisterSignal(quirk_holder, COMSIG_MOVABLE_MOVED, PROC_REF(on_holder_moved))
/datum/quirk/nyctophobia/remove()
@@ -450,14 +453,13 @@
desc = "Your legs do not function. Nothing will ever fix this. But hey, free wheelchair!"
icon = "wheelchair"
value = -12
- 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."
hardcore_value = 15
mail_goodies = list(/obj/vehicle/ridden/wheelchair/motorized) //yes a fullsized unfolded motorized wheelchair does fit
-/datum/quirk/paraplegic/add_unique()
+/datum/quirk/paraplegic/add_unique(client/client_source)
if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs.
quirk_holder.buckled.unbuckle_mob(quirk_holder)
@@ -465,7 +467,7 @@
var/obj/structure/chair/spawn_chair = locate() in holder_turf
var/obj/vehicle/ridden/wheelchair/wheels
- if(quirk_holder.client?.get_award_status(/datum/award/score/hardcore_random) >= 5000) //More than 5k score? you unlock the gamer wheelchair.
+ if(client_source?.get_award_status(/datum/award/score/hardcore_random) >= 5000) //More than 5k score? you unlock the gamer wheelchair.
wheels = new /obj/vehicle/ridden/wheelchair/gold(holder_turf)
else
wheels = new(holder_turf)
@@ -480,7 +482,7 @@
if(dropped_item.fingerprintslast == quirk_holder.ckey)
quirk_holder.put_in_hands(dropped_item)
-/datum/quirk/paraplegic/add()
+/datum/quirk/paraplegic/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic, TRAUMA_RESILIENCE_ABSOLUTE)
@@ -516,9 +518,10 @@
var/slot_string = "limb"
medical_record_text = "During physical examination, patient was found to have a prosthetic limb."
hardcore_value = 3
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
mail_goodies = list(/obj/item/weldingtool/mini, /obj/item/stack/cable_coil/five)
-/datum/quirk/prosthetic_limb/add_unique()
+/datum/quirk/prosthetic_limb/add_unique(client/client_source)
var/limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/bodypart/prosthetic
@@ -548,8 +551,9 @@
value = -6
medical_record_text = "During physical examination, patient was found to have all prosthetic limbs."
hardcore_value = 6
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
-/datum/quirk/quadruple_amputee/add_unique()
+/datum/quirk/quadruple_amputee/add_unique(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/left/robot/surplus)
human_holder.del_and_replace_bodypart(new /obj/item/bodypart/arm/right/robot/surplus)
@@ -587,7 +591,7 @@
/// Weakref to the trauma we give out
var/datum/weakref/added_trama_ref
-/datum/quirk/insanity/add()
+/datum/quirk/insanity/add(client/client_source)
if(!iscarbon(quirk_holder))
return
var/mob/living/carbon/carbon_quirk_holder = quirk_holder
@@ -630,7 +634,7 @@
mail_goodies = list(/obj/item/storage/pill_bottle/psicodine)
var/dumb_thing = TRUE
-/datum/quirk/social_anxiety/add()
+/datum/quirk/social_anxiety/add(client/client_source)
RegisterSignal(quirk_holder, COMSIG_MOB_EYECONTACT, PROC_REF(eye_contact))
RegisterSignal(quirk_holder, COMSIG_MOB_EXAMINATE, PROC_REF(looks_at_floor))
RegisterSignal(quirk_holder, COMSIG_MOB_SAY, PROC_REF(handle_speech))
@@ -740,7 +744,7 @@
gain_text = "You suddenly feel the craving for drugs."
medical_record_text = "Patient has a history of hard drugs."
hardcore_value = 4
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/effect/spawner/random/contraband/narcotics)
var/drug_list = list(/datum/reagent/drug/blastoff, /datum/reagent/drug/krokodil, /datum/reagent/medicine/morphine, /datum/reagent/drug/happiness, /datum/reagent/drug/methamphetamine) //List of possible IDs
var/datum/reagent/reagent_type //!If this is defined, reagent_id will be unused and the defined reagent type will be instead.
@@ -753,7 +757,7 @@
var/next_process = 0 //! ticker for processing
var/drug_flavour_text = "Better hope you don't run out..."
-/datum/quirk/item_quirk/junkie/add_unique()
+/datum/quirk/item_quirk/junkie/add_unique(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
if(!reagent_type)
@@ -893,13 +897,13 @@
lose_text = "You feel your immune system phase back into perfect shape."
medical_record_text = "Patient's immune system responds violently to certain chemicals."
hardcore_value = 3
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/item/reagent_containers/hypospray/medipen) // epinephrine medipen stops allergic reactions
var/list/allergies = list()
var/list/blacklist = list(/datum/reagent/medicine/c2,/datum/reagent/medicine/epinephrine,/datum/reagent/medicine/adminordrazine,/datum/reagent/medicine/omnizine/godblood,/datum/reagent/medicine/cordiolis_hepatico,/datum/reagent/medicine/synaphydramine,/datum/reagent/medicine/diphenhydramine)
var/allergy_string
-/datum/quirk/item_quirk/allergic/add_unique()
+/datum/quirk/item_quirk/allergic/add_unique(client/client_source)
var/list/chem_list = subtypesof(/datum/reagent/medicine) - blacklist
var/list/allergy_chem_names = list()
for(var/i in 0 to 5)
@@ -956,11 +960,11 @@
gain_text = "You just want people to leave you alone."
lose_text = "You could use a big hug."
medical_record_text = "Patient has disdain for being touched. Potentially has undiagnosed haphephobia."
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
hardcore_value = 1
mail_goodies = list(/obj/item/reagent_containers/spray/pepper) // show me on the doll where the bad man touched you
-/datum/quirk/bad_touch/add()
+/datum/quirk/bad_touch/add(client/client_source)
RegisterSignals(quirk_holder, list(COMSIG_LIVING_GET_PULLED, COMSIG_CARBON_HELP_ACT), PROC_REF(uncomfortable_touch))
/datum/quirk/bad_touch/remove()
@@ -986,7 +990,7 @@
value = -4
medical_record_text = "Patient demonstrates a fear of tight spaces."
hardcore_value = 5
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/item/reagent_containers/syringe/convermol) // to help breathing
/datum/quirk/claustrophobia/remove()
@@ -1044,12 +1048,24 @@
hardcore_value = 8
mail_goodies = list(/obj/item/pai_card) // can read things for you
+
+/datum/quirk/mute
+ name = "Mute"
+ desc = "For some reason you are completely unable to speak."
+ icon = "volume-xmark"
+ value = -4
+ mob_trait = TRAIT_MUTE
+ gain_text = span_danger("You find yourself unable to speak!")
+ lose_text = span_notice("You feel a growing strength in your vocal chords.")
+ medical_record_text = "The patient is unable to use their voice in any capacity."
+ hardcore_value = 4
+
/datum/quirk/body_purist
name = "Body Purist"
desc = "You believe your body is a temple and its natural form is an embodiment of perfection. Accordingly, you despise the idea of ever augmenting it with unnatural parts, cybernetic, prosthetic, or anything like it."
icon = "person-rays"
value = -2
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
gain_text = "You now begin to hate the idea of having cybernetic implants."
lose_text = "Maybe cybernetics aren't so bad. You now feel okay with augmentations and prosthetics."
medical_record_text = "This patient has disclosed an extreme hatred for unnatural bodyparts and augmentations."
@@ -1057,7 +1073,7 @@
mail_goodies = list(/obj/item/paper/pamphlet/cybernetics)
var/cybernetics_level = 0
-/datum/quirk/body_purist/add()
+/datum/quirk/body_purist/add(client/client_source)
check_cybernetics()
RegisterSignal(quirk_holder, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain))
RegisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(on_organ_lose))
@@ -1116,14 +1132,3 @@
if(!IS_ORGANIC_LIMB(old_limb))
cybernetics_level--
update_mood()
-
-/datum/quirk/mute
- name = "Mute"
- desc = "For some reason you are completely unable to speak."
- icon = "volume-xmark"
- value = -4
- mob_trait = TRAIT_MUTE
- gain_text = span_danger("You find yourself unable to speak!")
- lose_text = span_notice("You feel a growing strength in your vocal chords.")
- medical_record_text = "The patient is unable to use their voice in any capacity."
- hardcore_value = 4
diff --git a/code/datums/quirks/neutral_quirks.dm b/code/datums/quirks/neutral_quirks.dm
index f8e944577e3..da9b0d307b6 100644
--- a/code/datums/quirks/neutral_quirks.dm
+++ b/code/datums/quirks/neutral_quirks.dm
@@ -44,7 +44,7 @@
medical_record_text = "Patient does not speak Galactic Common and may require an interpreter."
mail_goodies = list(/obj/item/taperecorder) // for translation
-/datum/quirk/foreigner/add()
+/datum/quirk/foreigner/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.add_blocked_language(/datum/language/common)
if(ishumanbasic(human_holder))
@@ -66,7 +66,7 @@
medical_record_text = "Patient reports a vegetarian diet."
mail_goodies = list(/obj/effect/spawner/random/food_or_drink/salad)
-/datum/quirk/vegetarian/add()
+/datum/quirk/vegetarian/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/datum/species/species = human_holder.dna.species
species.liked_food &= ~MEAT
@@ -109,7 +109,7 @@
medical_record_text = "Patient demonstrates a pathological love of pineapple."
mail_goodies = list(/obj/item/food/pizzaslice/pineapple)
-/datum/quirk/pineapple_liker/add()
+/datum/quirk/pineapple_liker/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/datum/species/species = human_holder.dna.species
species.liked_food |= PINEAPPLE
@@ -141,7 +141,7 @@
/obj/item/food/pizzaslice/sassysage,
)
-/datum/quirk/pineapple_hater/add()
+/datum/quirk/pineapple_hater/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/datum/species/species = human_holder.dna.species
species.disliked_food |= PINEAPPLE
@@ -167,7 +167,7 @@
medical_record_text = "Patient demonstrates irregular nutrition preferences."
mail_goodies = list(/obj/item/food/urinalcake, /obj/item/food/badrecipe) // Mhhhmmm yummy
-/datum/quirk/deviant_tastes/add()
+/datum/quirk/deviant_tastes/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/datum/species/species = human_holder.dna.species
var/liked = species.liked_food
@@ -192,36 +192,27 @@
name = "Heterochromatic"
desc = "One of your eyes is a different color than the other!"
icon = "eye-low-vision" // Ignore the icon name, its actually a fairly good representation of different color eyes
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
value = 0
mail_goodies = list(/obj/item/clothing/glasses/eyepatch)
- var/color
-/datum/quirk/heterochromatic/add()
- color = color || quirk_holder.client?.prefs?.read_preference(/datum/preference/color/heterochromatic)
+// Only your first eyes are heterochromatic
+// If someone comes and says "well mr coder you can have DNA bound heterochromia so it's not unrealistic
+// to allow all inserted replacement eyes to become heterochromatic or for it to transfer between mobs"
+// Then just change this to [proc/add] I really don't care
+/datum/quirk/heterochromatic/add_unique(client/client_source)
+ var/color = client_source?.prefs.read_preference(/datum/preference/color/heterochromatic)
if(!color)
return
- link_to_holder()
+ apply_heterochromatic_eyes(color)
-/datum/quirk/heterochromatic/post_add()
- if(color)
- return
-
- color = quirk_holder.client?.prefs?.read_preference(/datum/preference/color/heterochromatic)
- if(!color)
- return
-
- link_to_holder()
-
-/datum/quirk/heterochromatic/remove()
- UnregisterSignal(quirk_holder, COMSIG_CARBON_LOSE_ORGAN)
-
-/datum/quirk/heterochromatic/proc/link_to_holder()
+/// Applies the passed color to this mob's eyes
+/datum/quirk/heterochromatic/proc/apply_heterochromatic_eyes(color)
var/mob/living/carbon/human/human_holder = quirk_holder
+ var/was_not_hetero = !human_holder.eye_color_heterochromatic
human_holder.eye_color_heterochromatic = TRUE
human_holder.eye_color_right = color
- // We set override to TRUE as link to holder will be called whenever the preference is applied, given this quirk exists on the mob
- RegisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_eye_removal), override=TRUE)
var/obj/item/organ/internal/eyes/eyes_of_the_holder = quirk_holder.getorgan(/obj/item/organ/internal/eyes)
if(!eyes_of_the_holder)
@@ -231,6 +222,15 @@
eyes_of_the_holder.old_eye_color_right = color
eyes_of_the_holder.refresh()
+ if(was_not_hetero)
+ RegisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN, PROC_REF(check_eye_removal))
+
+/datum/quirk/heterochromatic/remove()
+ var/mob/living/carbon/human/human_holder = quirk_holder
+ human_holder.eye_color_heterochromatic = FALSE
+ human_holder.eye_color_right = human_holder.eye_color_left
+ UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN)
+
/datum/quirk/heterochromatic/proc/check_eye_removal(datum/source, obj/item/organ/internal/eyes/removed)
SIGNAL_HANDLER
@@ -240,7 +240,7 @@
// Eyes were removed, remove heterochromia from the human holder and bid them adieu
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.eye_color_heterochromatic = FALSE
- human_holder.eye_color_right = initial(human_holder.eye_color_right)
+ human_holder.eye_color_right = human_holder.eye_color_left
UnregisterSignal(human_holder, COMSIG_CARBON_LOSE_ORGAN)
/datum/quirk/monochromatic
@@ -256,7 +256,7 @@
/obj/item/clothing/head/fedora/white,
)
-/datum/quirk/monochromatic/add()
+/datum/quirk/monochromatic/add(client/client_source)
quirk_holder.add_client_colour(/datum/client_colour/monochrome)
/datum/quirk/monochromatic/post_add()
@@ -273,21 +273,16 @@
icon = "spider"
value = 0
medical_record_text = "Patient has an irrational fear of something."
- var/phobia
mail_goodies = list(/obj/item/clothing/glasses/blindfold, /obj/item/storage/pill_bottle/psicodine)
-/datum/quirk/phobia/add()
- phobia = phobia || quirk_holder.client?.prefs?.read_preference(/datum/preference/choiced/phobia)
-
- if(phobia)
- var/mob/living/carbon/human/human_holder = quirk_holder
- human_holder.gain_trauma(new /datum/brain_trauma/mild/phobia(phobia), TRAUMA_RESILIENCE_ABSOLUTE)
-
-/datum/quirk/phobia/post_add()
+// Phobia will follow you between transfers
+/datum/quirk/phobia/add(client/client_source)
+ var/phobia = client_source?.prefs.read_preference(/datum/preference/choiced/phobia)
if(!phobia)
- var/mob/living/carbon/human/human_holder = quirk_holder
- phobia = human_holder.client.prefs.read_preference(/datum/preference/choiced/phobia)
- human_holder.gain_trauma(new /datum/brain_trauma/mild/phobia(phobia), TRAUMA_RESILIENCE_ABSOLUTE)
+ return
+
+ var/mob/living/carbon/human/human_holder = quirk_holder
+ human_holder.gain_trauma(new /datum/brain_trauma/mild/phobia(phobia), TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/phobia/remove()
var/mob/living/carbon/human/human_holder = quirk_holder
@@ -315,7 +310,7 @@
/// The user's starting hairstyle
var/old_hair
-/datum/quirk/item_quirk/bald/add()
+/datum/quirk/item_quirk/bald/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
old_hair = human_holder.hairstyle
human_holder.hairstyle = "Bald"
@@ -323,7 +318,7 @@
RegisterSignal(human_holder, COMSIG_CARBON_EQUIP_HAT, PROC_REF(equip_hat))
RegisterSignal(human_holder, COMSIG_CARBON_UNEQUIP_HAT, PROC_REF(unequip_hat))
-/datum/quirk/item_quirk/bald/add_unique()
+/datum/quirk/item_quirk/bald/add_unique(client/client_source)
var/obj/item/clothing/head/wig/natural/baldie_wig = new(get_turf(quirk_holder))
if (old_hair == "Bald")
@@ -369,7 +364,7 @@
medical_record_text = "Patient mentions photography as a stress-relieving hobby."
mail_goodies = list(/obj/item/camera_film)
-/datum/quirk/item_quirk/photographer/add_unique()
+/datum/quirk/item_quirk/photographer/add_unique(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/storage/photo_album/personal/photo_album = new(get_turf(human_holder))
photo_album.persistence_id = "personal_[human_holder.last_mind?.key]" // this is a persistent album, the ID is tied to the account's key to avoid tampering
@@ -397,7 +392,7 @@
medical_record_text = "Patient enjoys dyeing their hair with pretty colors."
mail_goodies = list(/obj/item/dyespray)
-/datum/quirk/item_quirk/colorist/add_unique()
+/datum/quirk/item_quirk/colorist/add_unique(client/client_source)
give_item_to_holder(/obj/item/dyespray, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
*/
@@ -415,7 +410,7 @@
/// Timer for gaming withdrawal to kick in
var/gaming_withdrawal_timer = TIMER_ID_NULL
-/datum/quirk/gamer/add()
+/datum/quirk/gamer/add(client/client_source)
// Gamer diet
var/mob/living/carbon/human/human_holder = quirk_holder
var/datum/species/species = human_holder.dna.species
@@ -438,7 +433,7 @@
UnregisterSignal(human_holder, COMSIG_MOB_LOST_VIDEOGAME)
UnregisterSignal(human_holder, COMSIG_MOB_PLAYED_VIDEOGAME)
-/datum/quirk/gamer/add_unique()
+/datum/quirk/gamer/add_unique(client/client_source)
// The gamer starts off quelled
gaming_withdrawal_timer = addtimer(CALLBACK(src, PROC_REF(enter_withdrawal)), GAMING_WITHDRAWAL_TIME, TIMER_STOPPABLE)
diff --git a/code/datums/quirks/positive_quirks.dm b/code/datums/quirks/positive_quirks.dm
index 7e43c0e35b3..a0e29e32d97 100644
--- a/code/datums/quirks/positive_quirks.dm
+++ b/code/datums/quirks/positive_quirks.dm
@@ -17,17 +17,15 @@
desc = "You just don't care as much as other people. That's nice to have in a place like this, I guess."
icon = "meh"
value = 4
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
medical_record_text = "Patient was administered the Apathy Evaluation Scale but did not bother to complete it."
mail_goodies = list(/obj/item/hourglass)
-/datum/quirk/apathetic/add()
- if (quirk_holder.mob_mood)
- quirk_holder.mob_mood.mood_modifier -= 0.2
+/datum/quirk/apathetic/add(client/client_source)
+ quirk_holder.mob_mood?.mood_modifier -= 0.2
/datum/quirk/apathetic/remove()
- if (quirk_holder.mob_mood)
- quirk_holder.mob_mood.mood_modifier += 0.2
+ quirk_holder.mob_mood?.mood_modifier += 0.2
/datum/quirk/drunkhealing
name = "Drunken Resilience"
@@ -37,7 +35,7 @@
gain_text = "You feel like a drink would do you good."
lose_text = "You no longer feel like drinking would ease your pain."
medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages."
- processing_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
mail_goodies = list(/obj/effect/spawner/random/food_or_drink/booze)
/datum/quirk/drunkhealing/process(delta_time)
@@ -85,10 +83,10 @@
/obj/item/toy/figure/clown,
)
-/datum/quirk/item_quirk/clown_enjoyer/add_unique()
+/datum/quirk/item_quirk/clown_enjoyer/add_unique(client/client_source)
give_item_to_holder(/obj/item/clothing/accessory/clown_enjoyer_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
-/datum/quirk/item_quirk/clown_enjoyer/add()
+/datum/quirk/item_quirk/clown_enjoyer/add(client/client_source)
var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN]
fan.show_to(quirk_holder)
@@ -115,10 +113,10 @@
/obj/item/toy/crayon/spraycan/mimecan,
)
-/datum/quirk/item_quirk/mime_fan/add_unique()
+/datum/quirk/item_quirk/mime_fan/add_unique(client/client_source)
give_item_to_holder(/obj/item/clothing/accessory/mime_fan_pin, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
-/datum/quirk/item_quirk/mime_fan/add()
+/datum/quirk/item_quirk/mime_fan/add(client/client_source)
var/datum/atom_hud/fan = GLOB.huds[DATA_HUD_FAN]
fan.show_to(quirk_holder)
@@ -141,7 +139,7 @@
mob_trait = TRAIT_FRIENDLY
gain_text = "You want to hug someone."
lose_text = "You no longer feel compelled to hug others."
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
medical_record_text = "Patient demonstrates low-inhibitions for physical contact and well-developed arms. Requesting another doctor take over this case."
mail_goodies = list(/obj/item/storage/box/hug)
@@ -151,7 +149,7 @@
icon = "grin"
value = 4
mob_trait = TRAIT_JOLLY
- mood_quirk = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_MOODLET_BASED
medical_record_text = "Patient demonstrates constant euthymia irregular for environment. It's a bit much, to be honest."
mail_goodies = list(/obj/item/clothing/mask/joy)
@@ -177,7 +175,7 @@
medical_record_text = "Patient brain scans show a highly-developed auditory pathway."
mail_goodies = list(/obj/effect/spawner/random/entertainment/musical_instrument, /obj/item/instrument/piano_synth/headphones)
-/datum/quirk/item_quirk/musician/add_unique()
+/datum/quirk/item_quirk/musician/add_unique(client/client_source)
give_item_to_holder(/obj/item/choice_beacon/music, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
/datum/quirk/night_vision
@@ -195,7 +193,7 @@
/obj/item/skillchip/light_remover,
)
-/datum/quirk/night_vision/add()
+/datum/quirk/night_vision/add(client/client_source)
refresh_quirk_holder_eyes()
/datum/quirk/night_vision/remove()
@@ -244,7 +242,7 @@
/obj/item/storage/fancy/candle_box,
)
-/datum/quirk/item_quirk/spiritual/add_unique()
+/datum/quirk/item_quirk/spiritual/add_unique(client/client_source)
give_item_to_holder(/obj/item/storage/fancy/candle_box, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
give_item_to_holder(/obj/item/storage/box/matches, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
@@ -264,7 +262,7 @@
/obj/item/canvas/twentythree_twentythree
)
-/datum/quirk/item_quirk/tagger/add_unique()
+/datum/quirk/item_quirk/tagger/add_unique(client/client_source)
give_item_to_holder(/obj/item/toy/crayon/spraycan, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
/datum/quirk/voracious
@@ -282,9 +280,10 @@
desc = "You possess excellent communication skills in sign language."
icon = "hands"
value = 4
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
mail_goodies = list(/obj/item/clothing/gloves/radio)
-/datum/quirk/item_quirk/signer/add_unique()
+/datum/quirk/item_quirk/signer/add_unique(client/client_source)
quirk_holder.AddComponent(/datum/component/sign_language)
var/obj/item/clothing/gloves/gloves_type = /obj/item/clothing/gloves/radio
if(isplasmaman(quirk_holder))
diff --git a/code/modules/client/preferences/heterochromatic.dm b/code/modules/client/preferences/heterochromatic.dm
index 03753a290f5..38d0d646089 100644
--- a/code/modules/client/preferences/heterochromatic.dm
+++ b/code/modules/client/preferences/heterochromatic.dm
@@ -10,6 +10,5 @@
return "Heterochromatic" in preferences.all_quirks
/datum/preference/color/heterochromatic/apply_to_human(mob/living/carbon/human/target, value)
- for(var/datum/quirk/heterochromatic/hetero_quirk in target.quirks)
- hetero_quirk.color = value
- hetero_quirk.link_to_holder()
+ var/datum/quirk/heterochromatic/hetero_quirk = locate() in target.quirks
+ hetero_quirk?.apply_heterochromatic_eyes(value)
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index 55c7b4fd0dc..a16daec0b31 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -67,7 +67,7 @@
available_hardcore_quirks -= picked_quirk
continue
- if(initial(picked_quirk.mood_quirk) && CONFIG_GET(flag/disable_human_mood)) //check for moodlet quirks
+ if((initial(picked_quirk.quirk_flags) & QUIRK_MOODLET_BASED) && CONFIG_GET(flag/disable_human_mood)) //check for moodlet quirks
available_hardcore_quirks -= picked_quirk
continue
@@ -106,5 +106,16 @@
mannequin.job = preview_job.title
mannequin.dress_up_as_job(preview_job, TRUE)
+ // Apply visual quirks
+ // Yes we do it every time because it needs to be done after job gear
+ if(SSquirks?.initialized)
+ // And yes we need to clean all the quirk datums every time
+ mannequin.cleanse_quirk_datums()
+ for(var/quirk_name as anything in all_quirks)
+ var/datum/quirk/quirk_type = SSquirks.quirks[quirk_name]
+ if(!(initial(quirk_type.quirk_flags) & QUIRK_CHANGES_APPEARANCE))
+ continue
+ mannequin.add_quirk(quirk_type, parent)
+
return mannequin.appearance
*/
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 6d5f65a414e..1522b357421 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -297,7 +297,7 @@
var/datum/species/jelly/slime/spare_datum = spare.dna.species
spare_datum.bodies = origin_datum.bodies
- H.transfer_trait_datums(spare)
+ H.transfer_quirk_datums(spare)
H.mind.transfer_to(spare)
spare.visible_message("[H] distorts as a new body \
\"steps out\" of [H.p_them()].",
@@ -443,7 +443,7 @@
span_notice("You stop moving this body..."))
else
to_chat(M.current, span_notice("You abandon this body..."))
- M.current.transfer_trait_datums(dupe)
+ M.current.transfer_quirk_datums(dupe)
M.transfer_to(dupe)
dupe.visible_message("[dupe] blinks and looks \
around.",
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index c5af051f4ce..216bba9f836 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -483,15 +483,24 @@
priority_absorb_key["stuns_absorbed"] += amount
return TRUE
-/mob/living/proc/add_quirk(quirktype) //separate proc due to the way these ones are handled
- if(HAS_TRAIT(src, quirktype))
- return
- var/datum/quirk/quirk = quirktype
- var/qname = initial(quirk.name)
+/**
+ * Adds the passed quirk to the mob
+ *
+ * Arguments
+ * * quirktype - Quirk typepath to add to the mob
+ * * override_client - optional, allows a client to be passed to the quirks on add procs.
+ * If not passed, defaults to this mob's client.
+ *
+ * Returns TRUE on success, FALSE on failure (already has the quirk, etc)
+ */
+/mob/living/proc/add_quirk(datum/quirk/quirktype, client/override_client)
+ if(has_quirk(quirktype))
+ return FALSE
+ var/qname = initial(quirktype.name)
if(!SSquirks || !SSquirks.quirks[qname])
- return
- quirk = new quirktype()
- if(quirk.add_to_holder(src))
+ return FALSE
+ var/datum/quirk/quirk = new quirktype()
+ if(quirk.add_to_holder(new_holder = src, client_source = override_client))
return TRUE
qdel(quirk)
return FALSE
diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
index 64d0280558e..7f703ac88fd 100644
--- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
@@ -89,7 +89,7 @@
H.visible_message(span_notice("A faint light leaves [H], moving to [src] and animating it!"),span_notice("You leave your old body behind, and transfer into [src]!"))
show_flavor = FALSE
var/mob/living/carbon/human/newgolem = create(newname = H.real_name)
- H.transfer_trait_datums(newgolem)
+ H.transfer_quirk_datums(newgolem)
H.mind.transfer_to(newgolem)
H.death()
return
diff --git a/modular_skyrat/master_files/code/datums/quirks/negative.dm b/modular_skyrat/master_files/code/datums/quirks/negative.dm
index 6f1cdc11ae9..08599ea2875 100644
--- a/modular_skyrat/master_files/code/datums/quirks/negative.dm
+++ b/modular_skyrat/master_files/code/datums/quirks/negative.dm
@@ -42,17 +42,18 @@
// If brainproblems is added to a synth, this detours to the brainproblems/synth quirk.
// TODO: Add more brain-specific detours when PR #16105 is merged
-/datum/quirk/item_quirk/brainproblems/add_to_holder(mob/living/new_holder, quirk_transfer)
- if(!(issynthetic(new_holder) && (src.type == /datum/quirk/item_quirk/brainproblems)))
+/datum/quirk/item_quirk/brainproblems/add_to_holder(mob/living/new_holder, quirk_transfer, client/client_source)
+ if(!issynthetic(new_holder) || type != /datum/quirk/item_quirk/brainproblems)
// Defer to TG brainproblems if the character isn't robotic.
return ..()
+
// TODO: Check brain type and detour to appropriate brainproblems quirk
var/datum/quirk/item_quirk/brainproblems/synth/bp_synth = new
qdel(src)
- return bp_synth.add_to_holder(new_holder, quirk_transfer)
+ return bp_synth.add_to_holder(new_holder, quirk_transfer, client_source)
// Synthetics get liquid_solder with Brain Tumor instead of mannitol.
-/datum/quirk/item_quirk/brainproblems/synth/add_unique()
+/datum/quirk/item_quirk/brainproblems/synth/add_unique(client/client_source)
give_item_to_holder(
/obj/item/storage/pill_bottle/liquid_solder/braintumor,
list(
@@ -76,10 +77,11 @@
hidden_quirk = TRUE
// If blooddeficiency is added to a synth, this detours to the blooddeficiency/synth quirk.
-/datum/quirk/blooddeficiency/add_to_holder(mob/living/new_holder, quirk_transfer)
- if(!(issynthetic(new_holder) && (src.type == /datum/quirk/blooddeficiency)))
+/datum/quirk/blooddeficiency/add_to_holder(mob/living/new_holder, quirk_transfer, client/client_source)
+ if(!issynthetic(new_holder) || type != /datum/quirk/blooddeficiency)
// Defer to TG blooddeficiency if the character isn't robotic.
return ..()
+
var/datum/quirk/blooddeficiency/synth/bd_synth = new
qdel(src)
return bd_synth.add_to_holder(new_holder, quirk_transfer)
diff --git a/modular_skyrat/master_files/code/datums/quirks/neutral.dm b/modular_skyrat/master_files/code/datums/quirks/neutral.dm
index efb84d5e292..ff7f149fa88 100644
--- a/modular_skyrat/master_files/code/datums/quirks/neutral.dm
+++ b/modular_skyrat/master_files/code/datums/quirks/neutral.dm
@@ -1,11 +1,12 @@
/datum/quirk/equipping
abstract_parent_type = /datum/quirk/equipping
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
/// the items that will be equipped, formatted in the way of [item_path = list of slots it can be equipped to], will not equip over nodrop items
var/list/items = list()
/// the items that will be forcefully equipped, formatted in the way of [item_path = list of slots it can be equipped to], will equip over nodrop items
var/list/forced_items = list()
-/datum/quirk/equipping/add_unique()
+/datum/quirk/equipping/add_unique(client/client_source)
var/mob/living/carbon/carbon_holder = quirk_holder
if (!items || !carbon_holder)
return
@@ -56,7 +57,7 @@
items = list(/obj/item/clothing/accessory/breathing = list(ITEM_SLOT_BACKPACK))
var/breath_type = "oxygen"
-/datum/quirk/equipping/lungs/add()
+/datum/quirk/equipping/lungs/add(client/client_source)
var/mob/living/carbon/human/carbon_holder = quirk_holder
if (!istype(carbon_holder) || !lungs_typepath)
return
diff --git a/modular_skyrat/master_files/code/datums/traits/neutral.dm b/modular_skyrat/master_files/code/datums/traits/neutral.dm
index d5571e0b129..2810450f34f 100644
--- a/modular_skyrat/master_files/code/datums/traits/neutral.dm
+++ b/modular_skyrat/master_files/code/datums/traits/neutral.dm
@@ -36,14 +36,27 @@
name = "Pseudobulbar Affect"
desc = "At random intervals, you suffer uncontrollable bursts of laughter."
value = 0
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_PROCESSES
medical_record_text = "Patient suffers with sudden and uncontrollable bursts of laughter."
var/pcooldown = 0
var/pcooldown_time = 60 SECONDS
icon = "grin-squint-tears"
-/datum/quirk/item_quirk/joker/add_unique()
+/datum/quirk/item_quirk/joker/add_unique(client/client_source)
give_item_to_holder(/obj/item/paper/joker, list(LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS))
+/datum/quirk/item_quirk/joker/process()
+ if(pcooldown > world.time)
+ return
+ pcooldown = world.time + pcooldown_time
+ var/mob/living/carbon/human/user = quirk_holder
+ if(user && istype(user))
+ if(user.stat == CONSCIOUS)
+ if(prob(20))
+ user.emote("laugh")
+ addtimer(CALLBACK(user, /mob/proc/emote, "laugh"), 5 SECONDS)
+ addtimer(CALLBACK(user, /mob/proc/emote, "laugh"), 10 SECONDS)
+
/obj/item/paper/joker
name = "disability card"
icon = 'modular_skyrat/master_files/icons/obj/card.dmi'
@@ -153,18 +166,6 @@
balloon_alert(user, "card flipped")
-/datum/quirk/item_quirk/joker/process()
- if(pcooldown > world.time)
- return
- pcooldown = world.time + pcooldown_time
- var/mob/living/carbon/human/user = quirk_holder
- if(user && istype(user))
- if(user.stat == CONSCIOUS)
- if(prob(20))
- user.emote("laugh")
- addtimer(CALLBACK(user, /mob/proc/emote, "laugh"), 5 SECONDS)
- addtimer(CALLBACK(user, /mob/proc/emote, "laugh"), 10 SECONDS)
-
/datum/quirk/feline_aspect
name = "Feline Traits"
desc = "You happen to act like a feline, for whatever reason."
@@ -181,7 +182,7 @@
value = 0
medical_record_text = "Patient was seen digging through the trash can. Keep an eye on them."
-/datum/quirk/item_quirk/canine/add_unique()
+/datum/quirk/item_quirk/canine/add_unique(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/organ/internal/tongue/old_tongue = human_holder.getorganslot(ORGAN_SLOT_TONGUE)
old_tongue.Remove(human_holder)
diff --git a/modular_skyrat/modules/hydra/code/neutral.dm b/modular_skyrat/modules/hydra/code/neutral.dm
index 6da99e20ecb..7187c550fec 100644
--- a/modular_skyrat/modules/hydra/code/neutral.dm
+++ b/modular_skyrat/modules/hydra/code/neutral.dm
@@ -8,7 +8,7 @@
medical_record_text = "There are multiple heads and personalities affixed to one body."
icon = "horse-head"
-/datum/quirk/hydra/add()
+/datum/quirk/hydra/add(client/client_source)
var/mob/living/carbon/human/hydra = quirk_holder
var/datum/action/innate/hydra/spell = new
var/datum/action/innate/hydrareset/resetspell = new
diff --git a/modular_skyrat/modules/oversized/code/oversized_quirk.dm b/modular_skyrat/modules/oversized/code/oversized_quirk.dm
index 195b5c0222f..cf1dc995c39 100644
--- a/modular_skyrat/modules/oversized/code/oversized_quirk.dm
+++ b/modular_skyrat/modules/oversized/code/oversized_quirk.dm
@@ -13,8 +13,9 @@
mob_trait = TRAIT_OVERSIZED
icon = "expand-arrows-alt"
veteran_only = TRUE
+ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE
-/datum/quirk/oversized/add()
+/datum/quirk/oversized/add(client/client_source)
var/mob/living/carbon/human/human_holder = quirk_holder
human_holder.dna.features["body_size"] = 2
human_holder.maptext_height = 32 * human_holder.dna.features["body_size"] //Adjust runechat height
diff --git a/tgstation.dme b/tgstation.dme
index 30b368280f6..b9767fd0f49 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -157,6 +157,7 @@
#include "code\__DEFINES\profile.dm"
#include "code\__DEFINES\projectiles.dm"
#include "code\__DEFINES\qdel.dm"
+#include "code\__DEFINES\quirks.dm"
#include "code\__DEFINES\radiation.dm"
#include "code\__DEFINES\radio.dm"
#include "code\__DEFINES\reactions.dm"