diff --git a/src/endWeek/saServeThePublic.js b/src/endWeek/saServeThePublic.js
index 31c680d7ee87c868648cf9f71726173da2951092..0374d5bf3e8ace382e3a2016fce06907fc9b9c5e 100644
--- a/src/endWeek/saServeThePublic.js
+++ b/src/endWeek/saServeThePublic.js
@@ -532,6 +532,10 @@ window.saServeThePublic = (function saServeThePublic() {
 					skillIncrease = (10 + Math.floor((slave.intelligence + slave.intelligenceImplant) / 32));
 					r += ` ${SkillIncrease.Entertain(slave, skillIncrease)}`;
 				}
+				if (slave.skill.entertainment > jsRandom(50, 99) && slave.skill.whore < 50) {
+					r += ` ${His} ability to entertain gave ${him} a better understanding of ${his} <span class="green">body's worth as a sexual object.</span>`;
+					slave.skill.whore += (2.5 + Math.floor((slave.intelligence + slave.intelligenceImplant) / 64));
+				}
 			}
 		}
 	}
diff --git a/src/endWeek/saWhore.js b/src/endWeek/saWhore.js
index c94e2d1f96cd3d84fee98f6b640e3a4edfb311cb..791cbf53f4458854a8447b4684da4b49081ca79d 100644
--- a/src/endWeek/saWhore.js
+++ b/src/endWeek/saWhore.js
@@ -245,7 +245,24 @@ window.saWhore = (function saWhore() {
 	 * @param {App.Entity.SlaveState} slave
 	 */
 	function usageCountDescriptions(slave) {
-		r += ` ${His} appearance attracted ${beauty} ${customers} members of the public (${Math.trunc(beauty / 7)} a day)`;
+		r += ` ${His} appearance`;
+		if (slave.maxWhoreClass > slave.effectiveWhoreClass) {
+			let customers2;
+			if (slave.maxWhoreClass === 4) {
+				customers2 = "extremely wealthy";
+			} else if (slave.maxWhoreClass === 3) {
+				customers2 = "upper class";
+			} else if (slave.maxWhoreClass === 2) {
+				customers2 = "middle class";
+			} else {
+				customers2 = "ERROR";
+			}
+			r += ` can attract the ${customers2}, but they already had plenty slaves to fuck so she `;
+		}
+		r += ` attracted ${beauty} ${customers} members of the public (${Math.trunc(beauty / 7)} a day)`;
+		if (slave.maxWhoreClass > slave.effectiveWhoreClass) {
+			` instead`;
+		}
 		if (beauty > 160) {
 			r += `, so many that `;
 			if (canDoVaginal(slave) && canDoAnal(slave)) {
@@ -511,6 +528,10 @@ window.saWhore = (function saWhore() {
 					r += `squeezing johns for every penny.`;
 				}
 			}
+			if (slave.skill.entertainment < 50 && slave.effectiveWhoreClass > 2) {
+				slave.skill.entertainment += Math.floor(2.5 + (slave.intelligence + slave.intelligenceImplant) / 64);
+				r += ` ${He} learns a little about how to better <span class="green">entertain</span> ${his} classy clients.`;
+			}
 		}
 
 		if (slave.aphrodisiacs > 1 || slave.inflationType === "aphrodisiac") {
@@ -569,14 +590,7 @@ window.saWhore = (function saWhore() {
 				} else {
 					r += ` pleasing the masses with ${his} chest,`;
 				}
-				r += ` ${he} works social gatherings and high society`;
-				if (slave.skill.entertainment < 50) {
-					r += `, where ${he} learns how to captivate ${his} audience.`;
-					skillIncrease = Math.floor(2.5 + (slave.intelligence + slave.intelligenceImplant) / 32);
-					r += ` ${SkillIncrease.Entertain(slave, skillIncrease)}`;
-				} else {
-					r += `.`;
-				}
+				r += ` ${he} works social gatherings and high society.`;
 			} else {
 				r += ` ${He} shows diligence, and ${his} <span class="green">sexual skills improve,</span> according to what the customers demand`;
 				if (!canDoVaginal(slave)) {
diff --git a/src/js/datatypeCleanupJS.js b/src/js/datatypeCleanupJS.js
index f85228f52b8e70c3725a5f50d34be999b9a8aece..6545021cee0979ab38bcf8ff3b992447b84d8ea8 100644
--- a/src/js/datatypeCleanupJS.js
+++ b/src/js/datatypeCleanupJS.js
@@ -1749,10 +1749,10 @@ window.EconomyDatatypeCleanup = function EconomyDatatypeCleanup() {
 	V.sexSupplyBarriers.middleClass = Math.clamp(+V.sexSupplyBarriers.middleClass, 0, 4) || 0;
 	V.sexSupplyBarriers.upperClass = Math.clamp(+V.sexSupplyBarriers.upperClass, 0, 4) || 0;
 	V.sexSupplyBarriers.topClass = Math.clamp(+V.sexSupplyBarriers.topClass, 0, 4) || 0;
-	V.NPCSexSupply.lowerClass = Math.max(+V.NPCSexSupply.lowerClass, 0) || 0;
-	V.NPCSexSupply.middleClass = Math.max(+V.NPCSexSupply.middleClass, 0) || 0;
-	V.NPCSexSupply.upperClass = Math.max(+V.NPCSexSupply.upperClass, 0) || 0;
-	V.NPCSexSupply.topClass = Math.max(+V.NPCSexSupply.topClass, 0) || 0;
+	V.NPCSexSupply.lowerClass = Math.max(+V.NPCSexSupply.lowerClass, 500) || 3000;
+	V.NPCSexSupply.middleClass = Math.max(+V.NPCSexSupply.middleClass, 500) || 3000;
+	V.NPCSexSupply.upperClass = Math.max(+V.NPCSexSupply.upperClass, 500) || 3000;
+	V.NPCSexSupply.topClass = Math.max(+V.NPCSexSupply.topClass, 500) || 3000;
 
 	V.rentDefaults.lowerClass = Math.max(+V.rentDefaults.lowerClass, 0) || 20; /* nowhere modified */
 	V.rentDefaults.middleClass = Math.max(+V.rentDefaults.middleClass, 0) || 50; /* nowhere modified */
@@ -1785,6 +1785,12 @@ window.EconomyDatatypeCleanup = function EconomyDatatypeCleanup() {
 	if (!V.NPCMarketShare) {
 		V.NPCMarketShare = {};
 	}
+
+	// fixing potential massive oversupply
+	if (V.NPCSexSupply.lowerClass > V.lowerClass * V.whoreBudget.lowerClass) {
+		V.NPCSexSupply.lowerClass = V.lowerClass * V.whoreBudget.lowerClass;
+	}
+
 	V.NPCMarketShare.lowerClass = Math.clamp(+V.NPCMarketShare.lowerClass, 0, 1000) || 0;
 	V.NPCMarketShare.middleClass = Math.clamp(+V.NPCMarketShare.middleClass, 0, 1000) || 0;
 	V.NPCMarketShare.upperClass = Math.clamp(+V.NPCMarketShare.upperClass, 0, 1000) || 0;
diff --git a/src/js/economyJS.js b/src/js/economyJS.js
index c215a4f6789ce586472f6b66b2b4b82f8c932132..4a707dceb4b9ce00938651141c3ff4c369ab7799 100644
--- a/src/js/economyJS.js
+++ b/src/js/economyJS.js
@@ -904,8 +904,8 @@ window.NPCSexSupply = function(lowerDemandLeft, lowerTotalDemand, middleDemandLe
 		} else {
 			NPCSexSupply.lowerClass = Math.trunc(NPCSexSupply.lowerClass * (1 + normalRandInt(0, 20) / 1000)); // Some random fluxuations whenever the NPC supply is roughly on target.
 		}
-	} else { // Increase NPC supply slightly if it drops below the standard minimum share of supply
-		NPCSexSupply.lowerClass = Math.trunc(NPCSexSupply.lowerClass * (1 + normalRandInt(30, 10) / 1000));
+	} else { // Increase NPC supply if it drops below the standard minimum share of supply
+		NPCSexSupply.lowerClass += Math.max(Math.trunc(NPCSexSupply.lowerClass * (normalRandInt(150, 10) / 1000)), 500);
 	}
 
 
@@ -922,7 +922,7 @@ window.NPCSexSupply = function(lowerDemandLeft, lowerTotalDemand, middleDemandLe
 			NPCSexSupply.middleClass = Math.trunc(NPCSexSupply.middleClass * (1 + normalRandInt(0, 20) / 1000));
 		}
 	} else {
-		NPCSexSupply.middleClass = Math.trunc(NPCSexSupply.middleClass * (1 + normalRandInt(30, 10) / 1000));
+		NPCSexSupply.middleClass += Math.max(Math.trunc(NPCSexSupply.middleClass * (normalRandInt(150, 10) / 1000)), 500);
 	}
 
 	// Upper class Calculations
@@ -938,7 +938,7 @@ window.NPCSexSupply = function(lowerDemandLeft, lowerTotalDemand, middleDemandLe
 			NPCSexSupply.upperClass = Math.trunc(NPCSexSupply.upperClass * (1 + normalRandInt(0, 20) / 1000));
 		}
 	} else {
-		NPCSexSupply.upperClass = Math.trunc(NPCSexSupply.upperClass * (1 + normalRandInt(30, 10) / 1000));
+		NPCSexSupply.upperClass += Math.max(Math.trunc(NPCSexSupply.upperClass * (normalRandInt(150, 10) / 1000)), 500);
 	}
 
 	// Top class calculations
@@ -954,14 +954,14 @@ window.NPCSexSupply = function(lowerDemandLeft, lowerTotalDemand, middleDemandLe
 			NPCSexSupply.topClass = Math.trunc(NPCSexSupply.topClass * (1 + normalRandInt(0, 20) / 1000));
 		}
 	} else {
-		NPCSexSupply.topClass = Math.trunc(NPCSexSupply.topClass * (1 + normalRandInt(30, 10) / 1000));
+		NPCSexSupply.topClass += Math.max(Math.trunc(NPCSexSupply.topClass * (normalRandInt(150, 10) / 1000)), 500);
 	}
 
 	return NPCSexSupply;
 };
 
 // The function for calculating and storing a slave's sexual interaction with citizens/'the outside'
-window.slaveJobValues = function() {
+window.slaveJobValues = function(lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef) {
 	const slaveJobValues = {
 		arcade: 0,
 		club: 0,
@@ -1198,6 +1198,11 @@ window.slaveJobValues = function() {
 		SJVClub(V.slaves[V.slaveIndices[ID]]);
 	});
 
+	// Saturation penalty for public servants. Even the most beautiful slaves lose some of their shine if they have too much competition.
+	if (slaveJobValues.club > 0) {
+		slaveJobValues.clubSP = (Math.pow(slaveJobValues.club / 1000, 0.95) * 1000) / slaveJobValues.club;
+	}
+
 	// Street whores adding to 'brothel'
 	V.JobIDArray["whore"].forEach(ID => {
 		SJVBrothel(V.slaves[V.slaveIndices[ID]]);
@@ -1205,7 +1210,7 @@ window.slaveJobValues = function() {
 
 	// Brothel whores adding to 'brothel'
 	V.BrothiIDs.forEach(ID => {
-		SJVBrothel(V.slaves[V.slaveIndices[ID]]);
+		SJVBrothel(V.slaves[V.slaveIndices[ID]], lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef);
 	});
 
 	function SJVClub(s) {
@@ -1400,7 +1405,7 @@ window.slaveJobValues = function() {
 		}
 	}
 
-	function SJVBrothel(s) {
+	function SJVBrothel(s, lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef) {
 		let toTheBrothel = 0;
 		let beautyMultiplier = 1;
 		s.minorInjury = 0;
@@ -1586,61 +1591,81 @@ window.slaveJobValues = function() {
 
 		// The whoreScore function finds the appropriate customer class and then calculates the whore income stats associated with that class and adds to the class supply.
 		// whoreClass is the MAXIMUM player set class the whore is allowed to service, if the whore is not eligable it will service the highest it is capable of servicing properly. A whoreClass of 0 means it is on auto (always service the highest possible class).
-		function whoreScore(s) {
+		function whoreScore(s, lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef) {
 			let income = s.sexAmount * s.sexQuality;
-			effectiveWhoreClass(s);
+			s.effectiveWhoreClass = effectiveWhoreClass(s);
+			s.maxWhoreClass = s.effectiveWhoreClass;
+
+			// Automatically changing effectiveWhoreClass
+			// what is the initial effective whore class? Are we providing more sex than overal demand? Is the ratio of supply/demand for this tier higher than the one below it?
+			// This also takes into consideration public sluts and ignores the NPC market and arcades
+			const topSDRatio = slaveJobValues.brothel.topClass / topClassSexDemandRef;
+			const upperSDRatio = slaveJobValues.brothel.upperClass / upperClassSexDemandRef;
+			const middleClubSupply = slaveJobValues.club * slaveJobValues.clubSP * (middleClassSexDemandRef / (lowerClassSexDemandRef + middleClassSexDemandRef));
+			const middleSupply = slaveJobValues.brothel.middleClass + middleClubSupply;
+			const middleSDRatio = middleSupply / middleClassSexDemandRef;
+			const lowerClubSupply = slaveJobValues.club * slaveJobValues.clubSP * (lowerClassSexDemandRef / (lowerClassSexDemandRef + middleClassSexDemandRef));
+			const lowerSupply = slaveJobValues.brothel.lowerClass + lowerClubSupply;
+			const lowerSDRatio = lowerSupply / lowerClassSexDemandRef;
+			if (s.effectiveWhoreClass === 4 && topSDRatio > 1 && topSDRatio > upperSDRatio) {
+				s.effectiveWhoreClass -= 1;
+			}
+			if (s.effectiveWhoreClass === 3 && upperSDRatio > 1 && upperSDRatio > middleSDRatio) {
+				s.effectiveWhoreClass -= 1;
+			}
+			if (s.effectiveWhoreClass === 2 && middleSDRatio > 1 && middleSDRatio > lowerSDRatio) {
+				s.effectiveWhoreClass -= 1;
+			}
 
 			// Calculate the stats
 			if (s.effectiveWhoreClass === 4) {
 				s.sexAmount = normalRandInt(50, 4); // Bringing sex amount into the desired range
 				s.sexQuality = Math.trunc(Math.min((income * 1.2) / s.sexAmount, V.whoreBudget.topClass * 0.2)); // Adjusting the price to the correct sex amount with 20% bonus for being of the highest tier
-				slaveJobValues.brothel.topClass += Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.topClass * 0.2); // Registering the job value in the right slot
+				slaveJobValues.brothel.topClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.topClass * 0.2)); // Registering the job value in the right slot
 			} else if (s.effectiveWhoreClass === 3) {
 				s.sexAmount = normalRandInt(60, 5);
 				s.sexQuality = Math.min(Math.trunc((income * 1.05) / s.sexAmount), V.whoreBudget.upperClass * 0.5); // The upper class will pay a maximum of 60% of their weekly budget per service
-				slaveJobValues.brothel.upperClass += Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.upperClass * 0.6);
+				slaveJobValues.brothel.upperClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.upperClass * 0.6));
 			} else if (s.effectiveWhoreClass === 2) {
 				s.sexAmount = normalRandInt(70, 6);
 				s.sexQuality = Math.min(Math.trunc((income * 0.9) / s.sexAmount), V.whoreBudget.middleClass); // The middle class will pay a maximum of 125% of their weekly budget per service
-				slaveJobValues.brothel.middleClass += Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.middleClass * 1.25);
+				slaveJobValues.brothel.middleClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.middleClass * 1.25));
 			} else {
 				s.sexAmount = normalRandInt(80, 7);
-				s.sexQuality = Math.clamp((income * 0.75) / s.sexAmount, 2, V.whoreBudget.lowerClass * 2); // The lower class will pay a maximum of 300% of their weekly budget per service and a minimum of 3
-				slaveJobValues.brothel.lowerClass += Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.lowerClass * 3);
+				s.sexQuality = Math.clamp((income * 0.75) / s.sexAmount, 2, V.whoreBudget.lowerClass * 2); // The lower class will pay a maximum of 300% of their weekly budget per service and a minimum of 2
+				slaveJobValues.brothel.lowerClass += Math.trunc(Math.min(s.sexAmount * s.sexQuality, s.sexAmount * V.whoreBudget.lowerClass * 3));
 			}
 		}
 
 		if (typeof s.whoreClass === 'undefined') {
 			s.whoreClass = 0;
 		}
-		whoreScore(s);
+		whoreScore(s, lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef);
 	}
 
-	// Saturation penalty for public servants. Even the most beautiful slaves lose some of their shine if they have too much competition.
-	if (slaveJobValues.club > 0) {
-		slaveJobValues.clubSP = (Math.pow(slaveJobValues.club / 1000, 0.95) * 1000) / slaveJobValues.club;
-	}
 	return slaveJobValues;
 };
 
 window.effectiveWhoreClass = function(s) {
 	let score = s.sexAmount * s.sexQuality;
+	let result;
 	if (typeof s.whoreClass === 'undefined' || s.whoreClass === 0) {
-		s.effectiveWhoreClass = 4;
+		result = 4;
 	} else {
-		s.effectiveWhoreClass = s.whoreClass;
+		result = s.whoreClass;
 	}
 	// Find maximum eligable class
 	// these could be refined further if needed.
-	if (s.effectiveWhoreClass === 4 && !(score > 5000 && s.skill.whoring > 80 && s.skill.entertainment > 50)) {
-		s.effectiveWhoreClass -= 1;
+	if (result === 4 && !(score > 5000 && s.skill.whoring > 80 && s.skill.entertainment > 50)) {
+		result -= 1;
 	}
-	if (s.effectiveWhoreClass === 3 && !(score > 2500 && s.skill.whoring > 50)) {
-		s.effectiveWhoreClass -= 1;
+	if (result === 3 && !(score > 2500 && s.skill.whoring > 50)) {
+		result -= 1;
 	}
-	if (s.effectiveWhoreClass === 2 && (score <= 1000)) {
-		s.effectiveWhoreClass -= 1;
+	if (result === 2 && (score <= 1000)) {
+		result -= 1;
 	}
+	return result;
 };
 
 window.getSlaveStatisticData = function(s, facility) {
diff --git a/src/uncategorized/slaveAssignmentsReport.tw b/src/uncategorized/slaveAssignmentsReport.tw
index fa248c9daefd32d259782c21181ee8f7961eddbc..b8ec2375276066a5439e1146aec0d51a0756593a 100644
--- a/src/uncategorized/slaveAssignmentsReport.tw
+++ b/src/uncategorized/slaveAssignmentsReport.tw
@@ -31,14 +31,14 @@ _topClassSexDemandRef = Math.max(_topClassSexDemand, 1),
 $whorePriceAdjustment = {lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0},
 $NPCMarketShare = {lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0},
 $sexDemandResult = {lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0},
-$slaveJobValues = slaveJobValues()>>
+$slaveJobValues = slaveJobValues(_lowerClassSexDemandRef, _middleClassSexDemandRef, _upperClassSexDemandRef, _topClassSexDemandRef)>>
 
 /*Supply of sexual services*/
 <<if ($cheatMode == 1) || ($debugMode == 1)>>
-	<br>Lower Class SD: <<print _lowerClassSexDemand>>
-	<br>Middle Class SD: <<print _middleClassSexDemand>>
-	<br>Upper Class SD: <<print _upperClassSexDemand>>
-	<br>Top Class SD: <<print _topClassSexDemand>>
+	<br>Lower Class SD: <<print _lowerClassSexDemandRef>>
+	<br>Middle Class SD: <<print _middleClassSexDemandRef>>
+	<br>Upper Class SD: <<print _upperClassSexDemandRef>>
+	<br>Top Class SD: <<print _topClassSexDemandRef>>
 	<br>Club SP: <<print Math.trunc($slaveJobValues.club * $slaveJobValues.clubSP)>>
 	<br>Arcade SP: <<print $slaveJobValues.arcade>>
 	<br>Brothel SP: <<print $slaveJobValues.brothel.lowerClass>>, <<print $slaveJobValues.brothel.middleClass>>, <<print $slaveJobValues.brothel.upperClass>>, <<print $slaveJobValues.brothel.topClass>>