diff --git a/src/js/generateGenetics.js b/src/js/generateGenetics.js
index 6151aeca4ff49eda5a563b94a1779d3522b1fb96..1b3f544ec88a103ab17f6d1460154d9ecd415d7d 100644
--- a/src/js/generateGenetics.js
+++ b/src/js/generateGenetics.js
@@ -9,12 +9,8 @@ window.generateGenetics = (function() {
 	let activeFather;
 	let V;
 
-	// intelligence and face parameters are the same so we can use the intelligence distribution for face values
-	const fuzzy = (a, b, spread=20, min=-100, max=100) => Intelligence.random({
-		mean: (a+b)/2,
-		spread: spread,
-		limitIntelligence: [min, max]
-	});
+	// intelligence and face parameters are the same so we can use the same distribution for both values
+	const fuzzy = (a, b) => normalRandInt((a+b)/2, 20);
 
 	function generateGenetics(actor1, actor2, x) {
 		V = State.variables;
@@ -568,16 +564,19 @@ window.generateGenetics = (function() {
 		let smarts;
 		if (mother.ID === -1) {
 			if (actor2 === -6) {
-				smarts = jsRandom(90, 100);
+				smarts = normalRandInt(95, 2.5);
 			} else if (father !== 0) {
+				smarts = fuzzy(father.intelligence, mother.intelligence);
 				// player is considered "good stock"
-				smarts = fuzzy(father.intelligence, mother.intelligence, 20, 50, 100);
+				while (smarts < 50) fuzzy(father.intelligence, mother.intelligence);
 			} else {
-				smarts = jsRandom(50, 100);
+				smarts = normalRandInt(75, 12.5);
 			}
 		} else if (father !== 0) {
+			smarts = fuzzy(father.intelligence, mother.intelligence);
 			// elite slaves are also considered "good stock"
-			smarts = fuzzy(father.intelligence, mother.intelligence, 20, activeMother.breedingMark ? 50 : -100, 100);
+			while (activeMother.breedingMark && smarts < 50)
+				smarts = fuzzy(father.intelligence, mother.intelligence);
 		} else {
 			smarts = mother.intelligence;
 		}
@@ -614,16 +613,20 @@ window.generateGenetics = (function() {
 			face = -100;
 		} else if (mother.ID === -1) {
 			if (actor2 === -6) {
-				face = jsRandom(90, 100);
+				face = normalRandInt(95, 2.5);
 			} else if (father !== 0) {
-				// player is considered "good stock"
-				face = fuzzy(father.face, mother.face, 20, 50, 100);
+				face = fuzzy(father.face, mother.face);
+				// the player is considered "good stock"
+				while (face < 50)
+					face = fuzzy(father.face, mother.face);
 			} else {
-				face = jsRandom(20, 100);
+				face = normalRandInt(60, 20);
 			}
 		} else if (father !== 0) {
+			face = fuzzy(father.face, mother.face);
 			// elite slaves are also considered "good stock"
-			face = fuzzy(father.face, mother.face, 20, activeMother.breedingMark ? 50 : -100, 100);
+			while(activeMother.breedingMark && face < 50)
+				face = fuzzy(father.face, mother.face);
 		} else {
 			face = mother.face;
 		}
diff --git a/src/js/utilJS.js b/src/js/utilJS.js
index 4d882f6b04656b6e5f013bb6f631753d1d4ff196..62901c799400c15500e03ab011e6f3e418a3c827 100644
--- a/src/js/utilJS.js
+++ b/src/js/utilJS.js
@@ -893,6 +893,21 @@ window.gaussianPair = function() {
 	return [r * Math.cos(sigma), r * Math.sin(sigma)];
 };
 
+// generate a random number with a normal distribution
+// the mean is 0 and the variance is 1
+// NOTE: the result is NOT bounded!
+window.normalRandom = function() {
+	let u1 = 0;
+	let u2 = 0;
+	// range must be (0,1) instead of [0,1)
+	while(u1 === 0) u1 = Math.random();
+	while(u2 === 0) u2 = Math.random();
+	return Math.sqrt(-2.0*Math.log(u1)) * Math.cos(2.0*Math.PI*u2);
+};
+
+// generate a random integer with a normal distribution
+window.normalRandInt = (mean, scale) => Math.floor(mean + normalRandom() * scale);
+
 /*
 A categorizer is used to "slice" a value range into distinct categories in an efficient manner.
 
@@ -2433,7 +2448,7 @@ window.SkillIncrease = (function() {
 	 * @returns {string}
 	 */
 	function OralSkillIncrease(slave, skillIncrease = 1) {
-		const {He, his} = getPronouns(slave)
+		const {He, his} = getPronouns(slave);
 		let r = "";
 
 		if (slave.skill.oral <= 10) {