diff --git a/.gitignore b/.gitignore
index 2db28904a7f6875834614b3f000015f2a1659a88..0ea52ffc09be35e3a67aa3da71d84cf88658c5d2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ src/002-config/start.tw
 node_modules
 package-lock.json
 yarn.lock
+pnpm-lock.yaml
 
 # Visual Studio Code
 .vscode/settings.json
diff --git a/src/endWeek/economics/neighborsDevelopment.js b/src/endWeek/economics/neighborsDevelopment.js
index 56f7de056e53bb2f36c1348ce77ff69045c81ea8..17a76c44d0c96b5b86bd7078507afcb6bee5e44c 100644
--- a/src/endWeek/economics/neighborsDevelopment.js
+++ b/src/endWeek/economics/neighborsDevelopment.js
@@ -295,34 +295,15 @@ App.EndWeek.neighborsDevelopment = function() {
 				r.push(`This week, you made <span class="yellowgreen">${cashFormat(rents)}</span> from your holdings in this arcology.`);
 			}
 
+			let cyberWarfareCatchChance = Math.max(5, Math.floor((((V.PC.skill.hacking + 100) / 200) ** 0.9) * 100));
 			/* CYBER ECONOMIC WARFARE */
 			if (arc.direction === V.arcologies[0].CyberEconomicTarget) {
-				let catchChance;
-				if (V.PC.skill.hacking === -100) {
-					catchChance = 10;
-				} else if (V.PC.skill.hacking <= -75) {
-					catchChance = 30;
-				} else if (V.PC.skill.hacking <= -50) {
-					catchChance = 40;
-				} else if (V.PC.skill.hacking <= -25) {
-					catchChance = 45;
-				} else if (V.PC.skill.hacking === 0) {
-					catchChance = 50;
-				} else if (V.PC.skill.hacking <= 25) {
-					catchChance = 60;
-				} else if (V.PC.skill.hacking <= 50) {
-					catchChance = 70;
-				} else if (V.PC.skill.hacking <= 75) {
-					catchChance = 85;
-				} else if (V.PC.skill.hacking >= 100) {
-					catchChance = 100;
-				}
 				const weekModifier = Math.max(1, (100 - (V.week * 2)));
 				arc.prosperity -= V.arcologies[0].CyberEconomic * 2;
 				const warSpoils = Math.ceil(10 + Math.max(((100 / weekModifier) * arc.prosperity * V.arcologies[0].CyberEconomic), 0));
 				arc.prosperity = Math.clamp(arc.prosperity, 1, 300);
 				let redHanded = 0;
-				if (random(0, 100) >= catchChance - (10 * V.arcologies[0].CyberEconomic)) {
+				if (random(0, 100) >= cyberWarfareCatchChance - (10 * V.arcologies[0].CyberEconomic)) {
 					V.arcologies[0].prosperity -= V.arcologies[0].CyberEconomic * 3;
 					redHanded = 1;
 					repX(forceNeg(random(100, 200)), "war");
@@ -342,26 +323,6 @@ App.EndWeek.neighborsDevelopment = function() {
 				}
 			} else if (arc.direction === V.arcologies[0].CyberReputationTarget) {
 				/* REPUTATION WARFARE */
-				let catchChance;
-				if (V.PC.skill.hacking === -100) {
-					catchChance = 10;
-				} else if (V.PC.skill.hacking <= -75) {
-					catchChance = 30;
-				} else if (V.PC.skill.hacking <= -50) {
-					catchChance = 40;
-				} else if (V.PC.skill.hacking <= -25) {
-					catchChance = 45;
-				} else if (V.PC.skill.hacking === 0) {
-					catchChance = 50;
-				} else if (V.PC.skill.hacking <= 25) {
-					catchChance = 60;
-				} else if (V.PC.skill.hacking <= 50) {
-					catchChance = 70;
-				} else if (V.PC.skill.hacking <= 75) {
-					catchChance = 85;
-				} else if (V.PC.skill.hacking >= 100) {
-					catchChance = 100;
-				}
 				arc.prosperity -= V.arcologies[0].CyberReputation;
 				if (arc.rival !== 1) {
 					arc.ownership -= V.arcologies[0].CyberReputation;
@@ -369,7 +330,7 @@ App.EndWeek.neighborsDevelopment = function() {
 				arc.prosperity = Math.clamp(arc.prosperity, 1, 300);
 				arc.ownership = Math.clamp(arc.ownership, 0, 100);
 				let redHanded = 0;
-				if (random(0, 100) >= catchChance - (10 * V.arcologies[0].CyberReputation)) {
+				if (random(0, 100) >= cyberWarfareCatchChance - (10 * V.arcologies[0].CyberReputation)) {
 					V.arcologies[0].prosperity -= V.arcologies[0].CyberReputation * 3;
 					redHanded = 1;
 					repX(forceNeg(random(100, 200)), "war");
diff --git a/src/endWeek/economics/persBusiness.js b/src/endWeek/economics/persBusiness.js
index a1161fb2bb9265da3d4432f831c51cb2d80a8e6b..2b775cbc4470afcbb35f398c110889f8f05ca3e8 100644
--- a/src/endWeek/economics/persBusiness.js
+++ b/src/endWeek/economics/persBusiness.js
@@ -10,7 +10,6 @@ App.EndWeek.personalBusiness = function() {
 	let cal;
 	let X;
 	let windfall;
-	let catchTChance;
 	let upgradeCount;
 	let dataGain;
 	let hindranceMod = isHinderedDegree(V.PC);
@@ -95,7 +94,7 @@ App.EndWeek.personalBusiness = function() {
 			r.push(`You focus on getting ready to give birth this week; when it happens, you want to be prepared.`);
 		} else if (isInduced(V.PC)) {
 			r.push(`This week, you focus on your labor and the impending birth of your ${V.PC.pregType > 1 ? "children" : "child"}.`);
-		} else if (PC.geneMods.rapidCellGrowth !== 1 && PC.bellyPreg >= 100000 && PC.belly > (PC.pregAdaptation * 3200) && (PC.bellyPreg >= 500000 || PC.wombImplant !== "restraint")) {
+		} else if (V.PC.geneMods.rapidCellGrowth !== 1 && V.PC.bellyPreg >= 100000 && V.PC.belly > (V.PC.pregAdaptation * 3200) && (V.PC.bellyPreg >= 500000 || V.PC.wombImplant !== "restraint")) {
 			r.push(`You're stuck in bed waiting to pop. Hopefully this means giving birth, and not the alternative.`);
 		}
 	} else if (V.personalAttention.task === PersonalAttention.WHORING) {
@@ -136,25 +135,7 @@ App.EndWeek.personalBusiness = function() {
 	} else if (V.personalAttention.task === PersonalAttention.TECH) {
 		windfall = Math.trunc((150 * V.PC.skill.hacking) + random(100, 2500));
 		X = 0;
-		if (V.PC.skill.hacking === -100) {
-			catchTChance = 10;
-		} else if (V.PC.skill.hacking <= -75) {
-			catchTChance = 30;
-		} else if (V.PC.skill.hacking <= -50) {
-			catchTChance = 40;
-		} else if (V.PC.skill.hacking <= -25) {
-			catchTChance = 45;
-		} else if (V.PC.skill.hacking === 0) {
-			catchTChance = 50;
-		} else if (V.PC.skill.hacking <= 25) {
-			catchTChance = 60;
-		} else if (V.PC.skill.hacking <= 50) {
-			catchTChance = 70;
-		} else if (V.PC.skill.hacking <= 75) {
-			catchTChance = 85;
-		} else if (V.PC.skill.hacking >= 100) {
-			catchTChance = 100;
-		}
+		let catchTChance = Math.max(5, Math.floor((((V.PC.skill.hacking + 100) / 200) ** 0.9) * 100));
 		r.push(`This week your services to the highest bidder earned you <span class="yellowgreen">${cashFormat(windfall)}.</span>`);
 		if (random(0, 100) >= catchTChance) {
 			r.push(`However, since the source of the attack was traced back to your arcology, your`);
diff --git a/src/events/nonRandom/daughters/pUndergroundRailroad.js b/src/events/nonRandom/daughters/pUndergroundRailroad.js
index 1636009b2dd0cc9d2f8c236b91bf2f42ccfd362f..c6b524d636c32c47d81c64f1e969ba23ef4c4085 100644
--- a/src/events/nonRandom/daughters/pUndergroundRailroad.js
+++ b/src/events/nonRandom/daughters/pUndergroundRailroad.js
@@ -31,6 +31,15 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 			V.traitorType = "standard";
 		}
 
+		/** Determines whether slave actually cares about potential freedom
+		 * @param {FC.SlaveState} slave
+		 * @returns {boolean}
+		 */
+		function desiresFreedom(slave) {
+			return !isMindbroken(slave) &&
+				(slave.devotion < jsRandom(50, 95) || slave.trust < 50);
+		}
+
 		r.push(`One fine day, as normal as any day surrounded by your slaves can be, you're sitting at your desk when`);
 		if (V.traitorType === "agent") {
 			// TODO: canMove canWalk variants.
@@ -348,7 +357,7 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 			let r = [];
 			unlock();
 			r.push(`${traitor.slaveName} nods ${his} head in acceptance. There is too much at stake to take such a risk. All attempts to use your monitoring systems to find the citizens who contacted ${him} fail; it seems their ability to corrupt your systems is considerable. ${He} keeps ${his} lips shut tight in an effort to prevent rumors from spreading, but <span class="devotion dec">whispers of freedom</span> still manage to run through your chattel.`);
-			V.slaves.forEach(function(s) { s.devotion -= 5; });
+			V.slaves.filter(desiresFreedom).forEach(s => s.devotion -= 5);
 			App.Events.addParagraph(frag, r);
 			return frag;
 		}
@@ -379,7 +388,7 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 				r.push(`${traitor.slaveName} almost <span class="devotion dec">faints with relief</span> when it becomes apparent you aren't going to punish ${him} for speaking of freedom.`);
 			}
 			r.push(`All attempts to use your monitoring systems to find the citizens who contacted ${him} fail; it seems their ability to corrupt your systems is considerable. <span class="devotion dec">Whispers of freedom</span> run like wildfire amongst your slaves.`);
-			V.slaves.forEach(function(s) { s.devotion -= 10; });
+			V.slaves.filter(desiresFreedom).forEach(s => s.devotion -= 10);
 			traitor.devotion -= 15;
 			App.Events.addParagraph(frag, r);
 			return frag;
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index 45e0681696ce01b6a724d4545ffc957796123928..c37ed827c9d5920ff2dfa50a6d18ffff538089e1 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -1198,3 +1198,11 @@ globalThis.isHorny = function(actor) {
 		(actor.inflationType === "aphrodisiac") ||
 		(actor.drugs === "priapism agents"));
 };
+
+/**
+ * @param {FC.HumanState} slave
+ * @returns {boolean}
+ */
+globalThis.isMindbroken = function(slave) {
+	return slave.fetish === Fetish.MINDBROKEN;
+};