diff --git a/code/__DEFINES/~~bubber_defines/span.dm b/code/__DEFINES/~~bubber_defines/span.dm
index ae88cc47010..37a8e8fcf66 100644
--- a/code/__DEFINES/~~bubber_defines/span.dm
+++ b/code/__DEFINES/~~bubber_defines/span.dm
@@ -4,3 +4,4 @@
#define span_velvet(str) ("" + str + "")
#define vote_font(str) ("" + str + "")
+#define span_yellow_flashy(str) ("" + str + "")
diff --git a/code/controllers/subsystem/processing/quirks.dm b/code/controllers/subsystem/processing/quirks.dm
index f7d32d2bf72..13b41ad9586 100644
--- a/code/controllers/subsystem/processing/quirks.dm
+++ b/code/controllers/subsystem/processing/quirks.dm
@@ -46,6 +46,7 @@ GLOBAL_LIST_INIT_TYPED(quirk_blacklist, /list/datum/quirk, list(
list(/datum/quirk/featherweight, /datum/quirk/oversized),
list(/datum/quirk/overweight, /datum/quirk/obese),
list(/datum/quirk/dominant_aura, /datum/quirk/well_trained),
+ list(/datum/quirk/equipping/entombed, /datum/quirk/equipping/seamless_clothes),
list(/datum/quirk/equipping/entombed, /datum/quirk/badback),
//BUBBER EDIT ADDITION END
))
diff --git a/html/changelogs/AutoChangeLog-pr-3132.yml b/html/changelogs/AutoChangeLog-pr-3132.yml
deleted file mode 100644
index 44a38d61561..00000000000
--- a/html/changelogs/AutoChangeLog-pr-3132.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Alecksohs"
-delete-after: True
-changes:
- - code_imp: "Vendors are now aware of sprite refits and will inform you if any are available."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3167.yml b/html/changelogs/AutoChangeLog-pr-3167.yml
new file mode 100644
index 00000000000..1f2308b8e80
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3167.yml
@@ -0,0 +1,4 @@
+author: "TealSeer"
+delete-after: True
+changes:
+ - bugfix: "fixed the SAD deleting wounds"
\ No newline at end of file
diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml
index 99303d6734e..dd83b31d8ab 100644
--- a/html/changelogs/archive/2025-02.yml
+++ b/html/changelogs/archive/2025-02.yml
@@ -369,3 +369,21 @@
- rscadd: Nurse costume suit now in loadout and medical vendor
SpooksAnno:
- rscadd: The ability to grab parts and cells as a borg.
+2025-02-25:
+ ABoxFaux:
+ - code_imp: Teshari and Vox primalis can now use size collars in dorms/interlink
+ areas.
+ Alecksohs:
+ - code_imp: Vendors are now aware of sprite refits and will inform you if any are
+ available.
+ StrangeWeirdKitten:
+ - rscadd: Seamless heels quirk
+ - rscadd: Nameless Quirk
+ xPokee:
+ - rscadd: added the intern ghoul plushie to both in game and the loadouts
+2025-02-26:
+ StrangeWeirdKitten:
+ - rscadd: Hypnotic Quirk
+ nikothedude:
+ - rscadd: Quirk; venemous bite. Allows you to bite people and inject them with a
+ venom, or medicine, of your choosing.
diff --git a/modular_skyrat/master_files/code/datums/components/damage_tracker.dm b/modular_skyrat/master_files/code/datums/components/damage_tracker.dm
index fe0b1cac095..33b111926df 100644
--- a/modular_skyrat/master_files/code/datums/components/damage_tracker.dm
+++ b/modular_skyrat/master_files/code/datums/components/damage_tracker.dm
@@ -76,6 +76,9 @@
/// What brain traumas does the owner currently have?
var/list/trauma_list = list()
+ /// What wounds does the owner currently have?
+ var/list/wound_list = list()
+
/datum/component/damage_tracker/human/update_damage_values()
. = ..()
var/mob/living/carbon/human/human_parent = parent
@@ -86,7 +89,13 @@
if(length(current_trauma_list))
trauma_list = current_trauma_list.Copy()
- heart_damage = human_parent.check_organ_damage(/obj/item/organ/heart)
+ for(var/obj/item/bodypart/limb as anything in human_parent.get_wounded_bodyparts())
+ for(var/datum/wound/limb_wound as anything in limb.wounds)
+ if(!islist(wound_list[limb.type]))
+ wound_list[limb.type] = list()
+ wound_list[limb.type] |= limb_wound.type
+
+heart_damage = human_parent.check_organ_damage(/obj/item/organ/heart)
liver_damage = human_parent.check_organ_damage(/obj/item/organ/liver)
lung_damage = human_parent.check_organ_damage(/obj/item/organ/lungs)
stomach_damage = human_parent.check_organ_damage(/obj/item/organ/stomach)
@@ -121,6 +130,14 @@
human_brain.gain_trauma(trauma_to_add)
+ for(var/obj/item/bodypart/limb_type as anything in wound_list)
+ var/obj/item/bodypart/limb_instance = locate(limb_type) in human_parent.bodyparts
+ if(!limb_instance)
+ continue
+ for(var/datum/wound/wound_type as anything in wound_list[limb_type])
+ var/datum/wound/new_wound = new wound_type()
+ new_wound.apply_wound(limb_instance, TRUE)
+
return TRUE
/datum/component/damage_tracker/human/Initialize(...)
diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm
index 95bfa297c59..d50cf6342ff 100644
--- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm
+++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/size_items.dm
@@ -116,13 +116,20 @@
if(!human_parent || !size_to_apply || (human_parent.dna.features["body_size"] == size_to_apply))
return FALSE
+ if(isteshari(human_parent) || isvoxprimalis(human_parent)) // We check if the human_parent is a Vox Primalis or Teshari & temporarily disable the bodysize restriction
+ human_parent.dna.species.body_size_restricted = FALSE
+
human_parent.dna.features["body_size"] = size_to_apply
human_parent.maptext_height = 32 * human_parent.dna.features["body_size"]
human_parent.dna.update_body_size()
return TRUE
/datum/component/temporary_size/Destroy(force, silent)
+ var/mob/living/carbon/human/human_parent = parent
apply_size(original_size)
+
+ if(isteshari(human_parent) || isvoxprimalis(human_parent)) // We reapply it on destroy if they were
+ human_parent.dna.species.body_size_restricted = TRUE
UnregisterSignal(parent, COMSIG_ENTER_AREA)
return ..()
diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm
index caa19427537..d506bf1fef4 100644
--- a/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm
+++ b/modular_zubbers/code/datums/quirks/neutral_quirks/entombed.dm
@@ -175,7 +175,8 @@
return "Civilian"
/datum/preference/choiced/entombed_skin/is_accessible(datum/preferences/preferences)
- if (!..())
+ . = ..()
+ if(!.)
return FALSE
return "Entombed" in preferences.all_quirks
@@ -191,7 +192,8 @@
maximum_value_length = 48
/datum/preference/text/entombed_mod_name/is_accessible(datum/preferences/preferences)
- if (!..())
+ . = ..()
+ if(!.)
return FALSE
return "Entombed" in preferences.all_quirks
@@ -216,7 +218,8 @@
can_randomize = FALSE
/datum/preference/text/entombed_mod_desc/is_accessible(datum/preferences/preferences)
- if (!..())
+ . = ..()
+ if(!.)
return FALSE
return "Entombed" in preferences.all_quirks
@@ -242,7 +245,8 @@
maximum_value_length = 16
/datum/preference/text/entombed_mod_prefix/is_accessible(datum/preferences/preferences)
- if (!..())
+ . = ..()
+ if(!.)
return FALSE
return "Entombed" in preferences.all_quirks
diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm
new file mode 100644
index 00000000000..9a8ee52dfc3
--- /dev/null
+++ b/modular_zubbers/code/datums/quirks/neutral_quirks/hypnotic.dm
@@ -0,0 +1,99 @@
+/datum/quirk/hypnotic
+ name = "Hypnotic"
+ desc = "You are extremely captivating to people who might be suspectable to fall into a stupor"
+ icon = FA_ICON_FACE_GRIN_HEARTS
+ value = 0
+ quirk_flags = QUIRK_HUMAN_ONLY | QUIRK_HIDE_FROM_SCAN
+ gain_text = "Your presence grows richer."
+ lose_text = "Your potent presence dulls."
+ medical_record_text = "Patient shows signs of a far richer presence then normal."
+ erp_quirk = TRUE
+ var/hypnotic_text
+ var/hypnotic_color
+
+/datum/quirk/hypnotic/add(client/client_source)
+ RegisterSignal(quirk_holder, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+
+/datum/quirk/hypnotic/post_add()
+ hypnotic_text = quirk_holder.client.prefs.read_preference(/datum/preference/text/hypnotic_text)
+ hypnotic_color = quirk_holder.client.prefs.read_preference(/datum/preference/choiced/hypnotic_span)
+
+/datum/quirk/hypnotic/remove()
+ UnregisterSignal(quirk_holder, COMSIG_ATOM_EXAMINE)
+
+/datum/quirk/hypnotic/proc/on_examine(atom/source, mob/user, list/examine_list)
+ SIGNAL_HANDLER
+
+ var/mob/living/examinee = source
+ if(!istype(user))
+ return
+ if(!(examinee.client.prefs.read_preference(/datum/preference/toggle/erp/hypnosis)))
+ return
+ if(user.stat == DEAD)
+ return
+ if(isnull(hypnotic_color))
+ return
+ examine_list += pick_color()
+
+/datum/quirk/hypnotic/proc/pick_color()
+ var/choice
+ switch(hypnotic_color)
+ if("Hypnophrase")
+ choice = "hypnophrase"
+ if("Velvet")
+ choice = "velvet"
+ if("Yellow Flashy")
+ choice = "glossy"
+ if("Pink")
+ choice = "pink"
+ if("Cult")
+ choice = "cult"
+
+ return "[isnull(hypnotic_text) ? "Their eyes are enticing to stare at." : hypnotic_text]"
+
+/datum/quirk_constant_data/hypnotic
+ associated_typepath = /datum/quirk/hypnotic
+ customization_options = list(
+ /datum/preference/text/hypnotic_text,
+ /datum/preference/choiced/hypnotic_span,
+ )
+
+/datum/preference/text/hypnotic_text
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "hypnotic_quirk_text"
+ savefile_identifier = PREFERENCE_CHARACTER
+ can_randomize = FALSE
+ maximum_value_length = 100
+
+/datum/preference/text/hypnotic_text/serialize(input)
+ return htmlrendertext(input)
+
+/datum/preference/text/hypnotic_text/deserialize(input, datum/preferences/preferences)
+ return htmlrendertext(input)
+
+/datum/preference/choiced/hypnotic_span
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "flashy_text"
+ savefile_identifier = PREFERENCE_CHARACTER
+ can_randomize = FALSE
+
+/datum/preference/choiced/hypnotic_span/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
+ return
+
+/datum/preference/text/hypnotic_text/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
+ return
+
+/datum/preference/text/hypnotic_text/create_default_value()
+ return "Their eyes are inciticing to stare at."
+
+/datum/preference/choiced/hypnotic_span/create_default_value()
+ return "Hypnophrase"
+
+/datum/preference/choiced/hypnotic_span/init_possible_values()
+ return list(
+ "Hypnophrase",
+ "Velvet",
+ "Yellow Flashy",
+ "Pink",
+ "Cult",
+ )
diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm
new file mode 100644
index 00000000000..fc58e26b91d
--- /dev/null
+++ b/modular_zubbers/code/datums/quirks/neutral_quirks/nameless.dm
@@ -0,0 +1,63 @@
+/datum/quirk/nameless
+ name = "Nameless"
+ desc = "You don't have a name. You are known only as a number."
+ medical_record_text = "Subject lacks a name in records."
+ value = 0
+ icon = FA_ICON_USER_NINJA
+ gain_text = span_notice("You feel your name slip away.")
+ lose_text = span_notice("You spontaniously remember your full name!")
+ quirk_flags = QUIRK_HIDE_FROM_SCAN
+ var/character_name
+ var/new_name
+
+/datum/preference/text/nameless_quirk_option
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "nameless_quirk_name"
+ savefile_identifier = PREFERENCE_CHARACTER
+ can_randomize = FALSE
+ maximum_value_length = 20
+
+/// Some sanity to ensure you can't have " #1000" as your name.
+/datum/preference/text/nameless_quirk_option/is_valid(value)
+ if(isnull(value))
+ return TRUE
+ return !isnull(permissive_sanitize_name(value))
+
+/datum/preference/text/nameless_quirk_option/serialize(input)
+ return htmlrendertext(input)
+
+/datum/preference/text/nameless_quirk_option/deserialize(input, datum/preferences/preferences)
+ return htmlrendertext(input)
+
+/datum/preference/text/nameless_quirk_option/apply_to_human(mob/living/carbon/human/target, value)
+ return
+
+/datum/quirk_constant_data/nameless
+ associated_typepath = /datum/quirk/nameless
+ customization_options = list(
+ /datum/preference/text/nameless_quirk_option
+ )
+
+/datum/quirk/nameless/add(client/client_source)
+ character_name = client_source?.prefs.read_preference(/datum/preference/name/real_name)
+ new_name = generate_name()
+ quirk_holder.fully_replace_character_name(character_name, new_name)
+
+/datum/quirk/nameless/remove()
+ quirk_holder.fully_replace_character_name(new_name, character_name)
+
+/datum/quirk/nameless/proc/generate_name()
+
+ var/prefix = quirk_holder.client?.prefs.read_preference(/datum/preference/text/nameless_quirk_option)
+ var/job
+ var/number = pick(rand(1000, 9999))
+
+ if(prefix)
+ job = prefix
+ else
+ job = isnull(quirk_holder.job) ? pick("Alpha", "Beta", "Delta", "Echo", "Zulu", "Omega") : quirk_holder.job
+
+ return "[job] #[number]"
+
+
+
diff --git a/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm b/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm
new file mode 100644
index 00000000000..2ad7ecb7f19
--- /dev/null
+++ b/modular_zubbers/code/datums/quirks/neutral_quirks/seamless_clothes.dm
@@ -0,0 +1,53 @@
+/datum/quirk/equipping/seamless_clothes
+ name = "Seamless Heels"
+ desc = "You come with heels stuck on you. Whether it be a freak accident or part of your design, you can't take them off."
+ medical_record_text = "Subject appears to have clothing attire fused to their body."
+ value = 0
+ icon = FA_ICON_TSHIRT
+ gain_text = span_notice("You feel things stick to your body.")
+ lose_text = span_notice("You feel things loose their grip on your body.")
+ quirk_flags = QUIRK_HIDE_FROM_SCAN
+ forced_items = list(/obj/item/clothing/shoes/fancy_heels = list(ITEM_SLOT_FEET))
+ var/prefix = "seamless"
+ var/obj/item/clothing/shoes/shoes
+
+/datum/quirk/equipping/seamless_clothes/on_equip_item(obj/item/equipped, success)
+ shoes = equipped
+
+/datum/quirk/equipping/seamless_clothes/post_add() // Quirks init on round start ready up before client does.
+ if(!istype(shoes, /obj/item/clothing/shoes/fancy_heels))
+ CRASH("Type mismatch on [src] during on_equip_item. Tried to equip [shoes]")
+ shoes.name = "[prefix] [initial(shoes.name)]"
+ shoes.desc = "A pair of heels which refuse to come off your feet."
+ shoes.greyscale_colors = quirk_holder.client.prefs.read_preference(/datum/preference/color/seamless_shoe_color)
+ shoes.resistance_flags = ACID_PROOF | FIRE_PROOF
+ shoes.update_greyscale()
+ ADD_TRAIT(shoes, TRAIT_NODROP, CLOTHING_TRAIT)
+ RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(remove_quirk))
+
+/datum/quirk/equipping/seamless_clothes/remove()
+ if(isnull(shoes))
+ return
+ UnregisterSignal(shoes, COMSIG_ITEM_DROPPED)
+ QDEL_NULL(shoes)
+
+/datum/quirk/equipping/seamless_clothes/proc/remove_quirk()
+ SIGNAL_HANDLER
+ qdel(src)
+
+/datum/quirk_constant_data/seamless_clothes
+ associated_typepath = /datum/quirk/equipping/seamless_clothes
+ customization_options = list(
+ /datum/preference/color/seamless_shoe_color
+ )
+
+/datum/preference/color/seamless_shoe_color
+ savefile_key = "seamless_shoe_color"
+ savefile_identifier = PREFERENCE_CHARACTER
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+
+/datum/preference/color/seamless_shoe_color/create_default_value()
+ return "#e7e7e7"
+
+/datum/preference/color/seamless_shoe_color/apply_to_human(mob/living/carbon/human/target, value)
+ return
diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm
new file mode 100644
index 00000000000..8016ffc1a9b
--- /dev/null
+++ b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite.dm
@@ -0,0 +1,145 @@
+#define VENOMOUS_BITE_DAMAGE 5
+#define VENOMOUS_BITE_WOUND_CHANCE 20
+#define VENOMOUS_BITE_WOUND_BONUS 40
+
+/datum/action/cooldown/mob_cooldown/venomous_bite
+ name = "Inject Venom"
+ desc = "Sink your fangs into another and inject them with your venom. Ineffective against those wearing armor."
+
+ button_icon = 'modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi'
+ button_icon_state = "venom"
+
+ ranged_mousepointer = 'icons/effects/mouse_pointers/supplypod_pickturf.dmi'
+
+ check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_INCAPACITATED | AB_CHECK_HANDS_BLOCKED // cant use it if cuffed
+
+ /// The reagent we will inject.
+ var/datum/reagent/reagent_typepath
+ /// How much of [reagent_typepath] we will inject.
+ var/to_inject = 0
+
+/datum/action/cooldown/mob_cooldown/venomous_bite/New(Target, original, datum/reagent/our_reagent, quantity_override = null)
+ . = ..()
+
+ set_reagent(our_reagent, quantity_override)
+
+/datum/action/cooldown/mob_cooldown/venomous_bite/proc/set_reagent(datum/reagent/new_reagent, quantity_override = null, cooldown_override = null)
+ reagent_typepath = new_reagent
+
+ var/list/reagent_spec = /datum/preference/choiced/venomous_bite_venom::venomous_bite_choice_specs[new_reagent]
+ if (isnum(quantity_override))
+ to_inject = quantity_override
+ else
+ to_inject = reagent_spec[1]
+
+ if (isnum(cooldown_override))
+ cooldown_time = cooldown_override
+ else
+ cooldown_time = reagent_spec[2]
+
+/datum/action/cooldown/mob_cooldown/venomous_bite/set_click_ability(mob/on_who)
+ . = ..()
+ if (!.)
+ return
+
+ owner.visible_message("[owner] bares [owner.p_their()] fangs...", span_warning("You bare your fangs..."))
+
+/datum/action/cooldown/mob_cooldown/venomous_bite/Activate(atom/target_atom)
+ if (!isliving(target_atom))
+ return FALSE
+ if (iscarbon(owner))
+ var/mob/living/carbon/carbon_holder = owner
+ if (carbon_holder.is_mouth_covered())
+ owner.balloon_alert(owner, "mouth covered!")
+ return FALSE
+
+ if (!owner.Adjacent(target_atom))
+ owner.balloon_alert(owner, "too far!")
+ return FALSE
+
+ if (target_atom == owner)
+ owner.balloon_alert(owner, "can't bite yourself!")
+ return FALSE
+
+ owner.visible_message(span_warning("[owner] starts to bite [target_atom]!"), span_warning("You start to bite [target_atom]!"), ignored_mobs = target_atom)
+ to_chat(target_atom, span_userdanger("[owner] starts to bite you!"))
+ owner.balloon_alert_to_viewers("biting...")
+ var/result = do_after(owner, 0.5 SECONDS, target_atom, IGNORE_HELD_ITEM)
+ if (!result)
+ return FALSE
+
+ . = ..()
+
+ var/penetrated = try_bite(target_atom)
+ if (penetrated)
+ inject(target_atom)
+ return TRUE
+
+/// Does NOT inject reagents; represents the initial bite. Can end in your teeth being broken by armor. Dumbass.
+/datum/action/cooldown/mob_cooldown/venomous_bite/proc/try_bite(mob/living/target)
+ var/target_zone = check_zone(owner.zone_selected)
+ var/armor = target.run_armor_check(target_zone, MELEE)
+ var/obj/item/bodypart/part = target.get_bodypart(target_zone)
+
+ var/text = "[owner] sinks [owner.p_their()] teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"
+ var/self_message = "You sink your teeth into [target]'s [target.parse_zone_with_bodypart(target_zone)]!"
+ var/victim_message = "[owner] sinks [owner.p_their()] teeth into your [target.parse_zone_with_bodypart(target_zone)]!"
+
+ var/covered = FALSE
+ if (ishuman(target))
+ var/mob/living/carbon/human/human_target = target
+ for (var/obj/item/clothing/iter_clothing as anything in human_target.get_clothing_on_part(part))
+ if (iter_clothing.clothing_flags & THICKMATERIAL)
+ covered = TRUE
+
+ text = "[owner] tries to bite [target], but breaks [owner.p_their()] teeth on [target]'s clothing! Ouch!"
+ self_message = "You try to bite [target], but you break your teeth on [target.p_their()] clothing! Ouch!"
+ victim_message = "[owner] tries to bite you, but breaks [owner.p_their()] teeth on your clothing! Ouch!"
+
+ owner.emote("scream")
+ if (isliving(owner))
+ var/mob/living/living_owner = owner
+ living_owner.apply_damage(1, BRUTE, BODY_ZONE_HEAD)
+
+ break
+
+ owner.visible_message(span_warning(text), span_warning(self_message), ignored_mobs = list(target))
+ to_chat(target, span_userdanger(victim_message))
+
+ owner.do_attack_animation(target, ATTACK_EFFECT_BITE)
+ playsound(owner, 'sound/items/weapons/bite.ogg', 60, TRUE)
+ if (covered)
+ return FALSE
+ var/wound_bonus = 0
+ if (prob(VENOMOUS_BITE_WOUND_CHANCE))
+ wound_bonus = VENOMOUS_BITE_WOUND_BONUS
+ target.apply_damage(VENOMOUS_BITE_DAMAGE, BRUTE, target_zone, armor, wound_bonus = wound_bonus, sharpness = SHARP_POINTY)
+ if (iscarbon(owner))
+ var/mob/living/carbon/carbon_owner = owner
+ for (var/datum/disease/our_disease as anything in carbon_owner.diseases)
+ if (our_disease.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS || our_disease.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
+ target.ContactContractDisease(our_disease, target_zone)
+
+ if (iscarbon(target))
+ var/mob/living/carbon/carbon_target = target
+ for (var/datum/disease/their_disease as anything in carbon_target.diseases)
+ if (their_disease.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS || their_disease.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
+ carbon_owner.ContactContractDisease(their_disease, target_zone)
+
+ return TRUE
+
+/datum/action/cooldown/mob_cooldown/venomous_bite/proc/inject(mob/living/target)
+ var/target_zone = check_zone(owner.zone_selected)
+ if (!target.try_inject(owner, target_zone))
+ return FALSE
+ var/temp
+ if (ishuman(owner))
+ var/mob/living/carbon/human/human_holder = owner
+ temp = human_holder.coretemperature
+ target.reagents.add_reagent(reagent_typepath, to_inject, reagtemp = temp)
+
+ return TRUE
+
+#undef VENOMOUS_BITE_DAMAGE
+#undef VENOMOUS_BITE_WOUND_BONUS
+#undef VENOMOUS_BITE_WOUND_CHANCE
diff --git a/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm
new file mode 100644
index 00000000000..86d169e8ec4
--- /dev/null
+++ b/modular_zubbers/code/datums/quirks/positive_quirks/venemous_bite/venomous_bite_quirk.dm
@@ -0,0 +1,84 @@
+/datum/quirk/venomous_bite
+ name = "Venomous Bite"
+ desc = "You have a venom gland, and can bite people to inject them with a toxin of your choosing."
+ icon = FA_ICON_TEETH_OPEN
+ value = 8
+ gain_text = span_notice("You feel a venom gland in the back of your throat.")
+ lose_text = span_warning("Your venom gland vanishes.")
+ medical_record_text = "Patient possesses a venom gland."
+
+/datum/quirk/venomous_bite/add(client/client_source)
+ var/datum/reagent/reagent = text2path(client_source?.prefs?.read_preference(/datum/preference/choiced/venomous_bite_venom))
+
+ var/mob/living/carbon/human/human_holder = quirk_holder
+ var/datum/action/cooldown/mob_cooldown/venomous_bite/action = new /datum/action/cooldown/mob_cooldown/venomous_bite(human_holder, our_reagent = reagent)
+ action.Grant(human_holder)
+
+/datum/quirk/venomous_bite/remove()
+ var/datum/action/cooldown/mob_cooldown/venomous_bite/action = locate(/datum/action/cooldown/mob_cooldown/venomous_bite) in quirk_holder.actions
+ action.Remove()
+
+ return ..()
+
+/datum/quirk_constant_data/venomous_bite
+ associated_typepath = /datum/quirk/venomous_bite
+ customization_options = list(/datum/preference/choiced/venomous_bite_venom)
+
+/datum/preference/choiced/venomous_bite_venom
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_key = "venomous_bite_venom"
+ savefile_identifier = PREFERENCE_CHARACTER
+ /// Format: (reagent typepath -> list(amount to inject per bite, cooldown))
+ var/static/list/venomous_bite_choice_specs = list(
+ /datum/reagent/toxin = list(5, 80 SECONDS),
+ /datum/reagent/toxin/venom = list(5, 180 SECONDS),
+ /datum/reagent/toxin/carpotoxin = list(5, 60 SECONDS), // less powerful than toxin
+ // drugs
+ /datum/reagent/drug/space_drugs = list(5, 60 SECONDS),
+ /datum/reagent/toxin/mindbreaker = list(5, 60 SECONDS),
+ // erp stuff
+ /datum/reagent/drug/aphrodisiac/crocin = list(5, 2 SECONDS),
+ /datum/reagent/drug/aphrodisiac/crocin/hexacrocin = list(5, 5 SECONDS),
+ /datum/reagent/drug/aphrodisiac/succubus_milk = list(5, 2 SECONDS),
+ /datum/reagent/drug/aphrodisiac/incubus_draft = list(5, 2 SECONDS),
+)
+
+
+/datum/preference/choiced/venomous_bite_venom/init_possible_values()
+ var/list/choices = list()
+ for (var/entry in venomous_bite_choice_specs)
+ choices += "[entry]"
+
+ return choices
+
+/datum/preference/choiced/venomous_bite_venom/create_default_value()
+ return "/datum/reagent/toxin"
+
+/datum/preference/choiced/venomous_bite_venom/compile_constant_data()
+ var/list/data = ..()
+
+ var/list/titles = list()
+
+ for (var/datum/reagent/entry as anything in venomous_bite_choice_specs)
+ var/list/specs = venomous_bite_choice_specs[entry]
+
+ var/inject = specs[1]
+ var/cooldown = specs[2]
+
+ var/name = entry::name
+
+ titles["[entry]"] = "[name] ([inject]u, [cooldown / 10] second cooldown)"
+
+ data[CHOICED_PREFERENCE_DISPLAY_NAMES] = titles
+
+ return data
+
+/datum/preference/choiced/venomous_bite_venom/is_accessible(datum/preferences/preferences)
+ . = ..()
+ if (!.)
+ return FALSE
+
+ return "Venomous Bite" in preferences.all_quirks
+
+/datum/preference/choiced/venomous_bite_venom/apply_to_human(mob/living/carbon/human/target, value)
+ return
diff --git a/modular_zubbers/code/game/objects/items/plushes.dm b/modular_zubbers/code/game/objects/items/plushes.dm
index e0256dd6341..40cbf750995 100644
--- a/modular_zubbers/code/game/objects/items/plushes.dm
+++ b/modular_zubbers/code/game/objects/items/plushes.dm
@@ -244,3 +244,12 @@
gender = FEMALE
squeak_override = list('modular_zubbers/sound/emotes/arf.ogg' = 1)
+// xPokee's plush
+/obj/item/toy/plush/ghoul
+ name = "intern ghoul plushie"
+ desc = "Even the marketable plushie of this thing is utterly terrifying. At least it's cuddly..."
+ icon = 'modular_zubbers/icons/obj/toys/plushes.dmi'
+ icon_state = "johnghoul"
+ attack_verb_continuous = list("ghouls")
+ attack_verb_simple = list("ghoul")
+ squeak_override = list('modular_zubbers/code/modules/blooper/voice/bloopers/kazooie/ehh.ogg' = 1)
diff --git a/modular_zubbers/code/modules/loadout/categories/toys.dm b/modular_zubbers/code/modules/loadout/categories/toys.dm
index fb9246e6b23..a43073757fd 100644
--- a/modular_zubbers/code/modules/loadout/categories/toys.dm
+++ b/modular_zubbers/code/modules/loadout/categories/toys.dm
@@ -86,3 +86,7 @@
/datum/loadout_item/toys/androiddog
name = "Android Dog Plushie"
item_path = /obj/item/toy/plush/androiddog
+
+/datum/loadout_item/toys/ghoul
+ name = "Intern Ghoul Plushie"
+ item_path = /obj/item/toy/plush/ghoul
diff --git a/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi b/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi
new file mode 100644
index 00000000000..45761c4335f
Binary files /dev/null and b/modular_zubbers/icons/mob/actions/quirks/venomous_bite.dmi differ
diff --git a/modular_zubbers/icons/obj/toys/plushes.dmi b/modular_zubbers/icons/obj/toys/plushes.dmi
index 8a2679cd87d..d3b9e66e7bf 100644
Binary files a/modular_zubbers/icons/obj/toys/plushes.dmi and b/modular_zubbers/icons/obj/toys/plushes.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 76d2290b478..10b6b0f112e 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -8832,15 +8832,20 @@
#include "modular_zubbers\code\datums\quirks\neutral_quirks\food.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\hungry.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\hydrophilic.dm"
+#include "modular_zubbers\code\datums\quirks\neutral_quirks\hypnotic.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\lungs.dm"
+#include "modular_zubbers\code\datums\quirks\neutral_quirks\nameless.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\oversized_quirk.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\pet_owner.dm"
+#include "modular_zubbers\code\datums\quirks\neutral_quirks\seamless_clothes.dm"
#include "modular_zubbers\code\datums\quirks\neutral_quirks\waddle.dm"
#include "modular_zubbers\code\datums\quirks\positive_quirks\dominant_aura.dm"
#include "modular_zubbers\code\datums\quirks\positive_quirks\empath_override.dm"
#include "modular_zubbers\code\datums\quirks\positive_quirks\featherweight.dm"
#include "modular_zubbers\code\datums\quirks\positive_quirks\life_savings.dm"
#include "modular_zubbers\code\datums\quirks\positive_quirks\masquerade_food.dm"
+#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite.dm"
+#include "modular_zubbers\code\datums\quirks\positive_quirks\venemous_bite\venomous_bite_quirk.dm"
#include "modular_zubbers\code\datums\shuttle\arena.dm"
#include "modular_zubbers\code\datums\shuttles\emergency.dm"
#include "modular_zubbers\code\datums\station_traits\disabled_traits.dm"
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx
new file mode 100644
index 00000000000..05b48e9f2dd
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/hypnotic_quirk.tsx
@@ -0,0 +1,14 @@
+import { Feature, FeatureChoiced, FeatureShortTextInput } from '../../base';
+import { FeatureDropdownInput } from '../../dropdowns';
+
+export const hypnotic_quirk_text: Feature = {
+ name: 'Hypnotic Text Examine',
+ description:
+ 'The examine text portrayed from your character. Use third person (Their, He, She, etc)',
+ component: FeatureShortTextInput,
+};
+
+export const flashy_text: FeatureChoiced = {
+ name: 'Text Color Selection',
+ component: FeatureDropdownInput,
+};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx
new file mode 100644
index 00000000000..d8b519a14c1
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/nameless.tsx
@@ -0,0 +1,8 @@
+import { Feature, FeatureShortTextInput } from '../../base';
+
+export const nameless_quirk_name: Feature = {
+ name: 'Prefix Name',
+ description:
+ 'Example: (Prefix) #1334. Leave blank to default to job title. Minimum 3 characters.',
+ component: FeatureShortTextInput,
+};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx
new file mode 100644
index 00000000000..ac33c2a28a3
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/seamless_clothes.tsx
@@ -0,0 +1,6 @@
+import { Feature, FeatureColorInput } from '../../base';
+
+export const seamless_shoe_color: Feature = {
+ name: 'Shoe Color',
+ component: FeatureColorInput,
+};
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx
new file mode 100644
index 00000000000..ecbada22de9
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/bubbers/venomous_bite.tsx
@@ -0,0 +1,7 @@
+import { FeatureChoiced } from '../../base';
+import { FeatureDropdownInput } from '../../dropdowns';
+
+export const venomous_bite_venom: FeatureChoiced = {
+ name: 'Venom Type',
+ component: FeatureDropdownInput,
+};