About This File
For men: This mod adds 7 new traits that replace the game's body hair gene, each trait visually modifies the character with one of the six vanilla's body hair genes: sparse, average, dense, sparse (low stubble), average (low stubble), dense (low stubble), and a new smooth variation with no body hair. There's very little difference between the normal variations and the "low stubble" ones. Only male characters are affected and the NPCs are seeded with a random trait (if they don't have one already) after the age of 18.
For men and women: Since version 1.1.0, the dynamic pubic hair trait has been added with the 3 states: Hairy Pubes, Trimmed Pubes and Shaved Pubes. This trait, unlike the Body Hair, is not congenital and it's seeded by script, it also does not change the character portrait with any gene.
Since version 1.3.0, a new congenital "bad trait" has been added. With "Alopecia Universalis" character will have no hair on their body. (note: if you're adding it from the Ruler Designer, you have to manually remove hair and beard.)
For the court: The court position "Royal Shaver" will be available for county or greater titles. The employee rules will follow the martial rules of the realm. When employed, all courtiers and the liege will slowly increase the Hairy Pubes trait to the shaved state.
Feel free to report bugs and give suggestions, as this is a very clunky genetic mod. Special thanks to Luther Slade and Cheri, for the seeding traits structure is just a simplified version of the Carnalitas one.
⚠️Compatibility: The mod should be compatible with any other mod, but if they change the body hair gene, they should be loaded after this one to avoid errors. If using a total conversion mod, the log might throw errors during the initial play, yet these should not persist. If you found any conflicts, please share.
----
📃 Notes from the version 1.6.0 forwards
The update is a 'revamp' mostly edited by Claude AI and Github's Copilot. Things changed so there's less strain caused by the scripts. The traits are no longer distributed as a simple random list or as copy of a 'father' character. Some things like the decision to shave body have been removed, though shaving pubes is still present. Religions do get doctrines about pubic shaving, but I couldn't manage to make them appear on the UI. The new architecture is described by Claude as the following:
Hairiness is a number now
var:bh_hair_value, 0–100, stored on every character including women, so maternal inheritance works. It is built as:
- baseline 50, shifted by heritage (flavour pack only)
-
blended toward the mid-parent value at
bh_heritability_value(0.62) - plus noise of ±22
- plus a few points in the mid-twenties and again around thirty
then banded into the existing traits. Two consequences worth knowing: mixed dynasties now produce sensible intermediate children instead of copying the father's tier, and you tune the whole distribution from seven numbers in bh_script_values.txt instead of editing four random_list blocks.
The old father-only check has been replaced entirely. It also read scope:real_father in contexts where that scope did not exist, which is where most of your error log came from.
Total conversion support
The failure mode was never the logic — it was that faith:ashari resolves when the file loads, not when it runs, so no guard helps and a TC that lacks the faith gets a hard error. The fix is quarantine:
-
Faith attitudes are assigned by a heuristic over doctrines every faith is guaranteed to have (
doctrine_pluralism_fundamentalist, the adultery and deviancy crime doctrines). Any map, any custom faith, no named references. - The flavour pack then corrects the four cases where the heuristic is wrong, and it matches on religion rather than listing forty faith keys — so reformed, hybrid and custom faiths inherit the right attitude for free, and there are four references to break instead of forty.
- Assignment only ever touches a faith that has no attitude yet, so a faith that declares one itself is never overridden.
To run on a TC, copy optional/zz_bh_flavour_vanilla_TC.txt over common/scripted_effects/zz_bh_flavour_vanilla.txt. Do not delete it — the core calls both effects by name.
Distribution
Indo-Aryan and Iranian cultures move to the top tier (+22), where the anthropometry actually puts them; the old buckets had them mid. Turkic and Mongolic are separated from East Asian rather than sharing one bucket. Only heritage keys your 1.19 log proved valid are used. A comment in the flavour file lists the Sub-Saharan and All Under Heaven heritages worth adding once you have checked their keys against common/culture/pillars/ — until then those cultures sit at the neutral baseline, which is dull but errorless.
Religion
The -45 realm-wide opinion penalty is gone. Nobody can see this, so it is a secret now (secret_grooming_transgression), criminal under an illegal doctrine and shunned under the others, kept in sync by bh_refresh_secret_effect. bh_expose_grooming_effect is the hook for spouses, lovers, physicians and the Royal Shaver to discover it.
What stays public is what plausibly would be: piety drift and clergy opinion via faith_modifier on the trait.
Performance
Removed: ai_character_pulse, on_birthday, on_weight_changed, on_title_gain, and the every_living_character sweep at game start (which now means 20,000+ extra characters on the 1.18 map).
What remains is one yearly pulse gated on bh_is_relevant_trigger — player, any landed ruler, or anyone in a non-AI character's court — plus lazy seeding from the places that actually read the value. Most of the world is never touched.
The Royal Shaver runs from the employer on quarterly_playable_pulse, looping every_courtier: one scope per court, four times a year, instead of a trigger per character per pulse. That also kills the 89 "event queued twice with the same data" errors, which came from several on_actions firing the same event on the same character on the same day.
Decision intervals went from ai_check_interval = 3 to 24–60 with ai_check_interval_by_tier on top, and the ~20 repeated faith = { has_doctrine = ... } lookups per ai_will_do collapsed into one cached bh_faith_attitude_value.
----
Body Hair Trait - CK3 - Git
Edited by Winderig
What's New in Version 2.0.1
Released
2.0.1
- Replaced the partial heritage list in the flavour pack with full coverage of all 59 heritage pillars in 00_heritage.txt, checked directly against that file rather than assumed.
- Added Dravidian, Caucasian (highest tier); Syriac, Phoenician, Egyptian, Israelite, Ancient Greek, Tocharian (high tier); Albanian, Vlach (moderate tier); Baltic, Magyar, Gothic (middling tier); Akan, East African, Sahelian, Senegambian, Somalian, Bantu, West African, Central African, Yoruba, Volga Finnic (lower tier); Hunnic (steppe tier); Korean, Buyeo, Tai, Hmongic, Mon-Khmer, Viet, Japonic, Tungusic, Nivkh, Austronesian (lowest tier).
- Ainu given its own bracket rather than being grouped with neighbouring East Asian heritages, reflecting the population's documented higher body/facial hair density.
- Magyar placed with Central/Northern Europe rather than with the other Uralic-language heritages, reflecting post-conquest admixture rather than linguistic ancestry.
- Decision to Shave Body Hair removed.
2.0.0
- Rewrote the mod around a numeric hairiness model (var:bh_hair_value, 0-100) with two-parent inheritance, regression to a regional mean, individual variation and growth through the twenties, replacing the father-only random_list buckets.
- Total conversion support: all references to named vanilla cultures, religions and faiths are quarantined in a single flavour file, with a no-op replacement in optional/. Faith attitudes are otherwise assigned by a doctrine-based heuristic that works on any map.
- Faith overrides now match on religion instead of enumerating forty faith keys, so reformed, hybrid and custom faiths inherit the right attitude automatically.
- Corrected the regional distribution: Indo-Aryan and Iranian cultures move to the hairiest tier, and Turkic/Mongolic are separated from East Asian.
- Being out of step with your faith is now a secret rather than a realm-wide opinion penalty, discoverable by spouses, lovers, physicians and the Royal Shaver.
- Performance: dropped ai_character_pulse, on_birthday, on_weight_changed, on_title_gain and the every_living_character sweep at game start. One yearly pulse gated on relevance, plus lazy seeding.
- The Royal Shaver now runs once per court from the employer on a quarterly playable pulse instead of per character per pulse. This also fixes the duplicate event queueing errors.
- Decision AI intervals raised from 3 months to 24-60, with ai_check_interval_by_tier, and the repeated doctrine lookups in ai_will_do collapsed into one cached script value.
- All tuning consolidated into common/script_values/bh_script_values.txt.
- Doctrines restructured for the 1.19 split database.
1.6.0
- Update to version 1.19 "Scribe".
-
Fixed seeding throwing scope errors on every character: the heritage seeding effect read
scope:real_fathereven when it was called from a pulse where that scope does not exist. -
Merged the two on_action files into one. Both declared
on_16th_birthdayandon_game_start_after_lobby, so the later file silently replaced the earlier one and half the content never ran. -
Replaced the hand-maintained NOR fallback in the heritage seeding with a plain
else, so cultures added by new patches no longer fall through unhandled. -
Removed an
opinion_modifierline from inside afaith_modifierblock on the Pubes trait, which is not a valid key there. -
Removed a duplicate AI-personality block on
body_hair_ls_1. -
Removed the duplicate
alopeciaportrait modifier category; the trait portrait modifier now removes hair and beard at full strength. - Fixed three female eyelash decals that were using the male aging preset.
-
shaving_event.0003now checks the character actually has the Pubes trait before adding XP to it.