From 10fe99bdd538b33e4f6f04cf670bb85b89eb899b Mon Sep 17 00:00:00 2001
From: Jones <Jones>
Date: Thu, 5 Dec 2019 16:00:54 +0100
Subject: [PATCH] health changes

part 1 of conversion
---
 src/cheats/mod_EditChildCheatNew.tw           |  15 ++-
 src/cheats/mod_EditInfantCheatNew.tw          |  15 ++-
 src/cheats/mod_EditSlaveCheat.tw              |  13 +-
 src/cheats/mod_editSlaveCheatNew.tw           |  13 +-
 src/endWeek/illness.js                        |  51 ++++----
 src/endWeek/saNanny.js                        |   6 +-
 src/endWeek/saRest.js                         |  13 +-
 src/endWeek/saRules.js                        |  43 ++++++-
 src/endWeek/saServant.js                      |   2 +-
 src/endWeek/saServeThePublic.js               |  11 +-
 src/endWeek/saStayConfined.js                 |   2 +-
 src/endWeek/saWhore.js                        |  17 +--
 src/endWeek/saWorkAGloryHole.js               |  16 +--
 src/endWeek/saWorkTheFarm.js                  |  15 +--
 src/facilities/clinic/clinicFramework.js      |   2 +-
 src/facilities/farmyard/farmyardReport.tw     |  32 ++---
 src/facilities/nursery/childInteract.tw       |   2 +-
 .../nursery/nurseryDatatypeCleanup.js         |  22 +++-
 src/facilities/nursery/nurseryWidgets.js      | 116 +++++++++++-------
 src/facilities/spa/spaFramework.js            |   2 +-
 src/init/storyInit.tw                         |   3 +-
 src/js/DefaultRules.js                        |  32 ++---
 src/js/assayJS.js                             |   4 +-
 src/js/datatypeCleanupJS.js                   |  22 +++-
 src/js/descriptionWidgets.js                  |  20 +--
 src/uncategorized/BackwardsCompatibility.tw   |   3 +
 src/uncategorized/slaveAssignmentsReport.tw   |   9 ++
 27 files changed, 323 insertions(+), 178 deletions(-)

diff --git a/src/cheats/mod_EditChildCheatNew.tw b/src/cheats/mod_EditChildCheatNew.tw
index 2f1c32b9088..dc5ed2d194b 100644
--- a/src/cheats/mod_EditChildCheatNew.tw
+++ b/src/cheats/mod_EditChildCheatNew.tw
@@ -776,8 +776,17 @@
 	''Birth week:''
 	<<textbox "$tempSlave.birthWeek" $tempSlave.birthWeek>>
 	<br><br>
-	''Health (-99 to 100, -100 is death):''
-	<<textbox "$tempSlave.health" $tempSlave.health>>
+	''Condition (-99 to 100, -100 is death. Condition minus short and long of -100 is also death):''
+	<<textbox "$tempSlave.health.condition" $tempSlave.health.condition>>
+	<br>
+	''Damage - Short Term:''
+	<<textbox "$tempSlave.health.shortDamage" $tempSlave.health.shortDamage>>
+	<br>
+	''Damage - Long Term:''
+	<<textbox "$tempSlave.health.longDamage" $tempSlave.health.longDamage>>
+	<br>
+	''Illness (0 to 5):''
+	<<textbox "$tempSlave.health.illness" $tempSlave.health.illness>>
 	<br>
 	''DNA Errors (0 to 990):''
 	<<textbox "$tempSlave.chem" $tempSlave.chem>>
@@ -3463,7 +3472,7 @@
 <br><<print "@@.yellow;Refresh through selecting a new or the same passage again for Changes to be seen@@" >><br>
 <span id="spot"></span><br>
 /* ------------------------------------------------------------------------- Used Variables: ------------------------------------------------------------------------------------------------*/
-/*.visualAge .ageImplant .birthWeek .health .chem .addict .devotion .oldDevotion .trust .oldTrust .face .faceShape .faceImplant .markings .bald .hLength .hStyle .hColor .origHColor*/
+/*.visualAge .ageImplant .birthWeek .health.condition .health.shortDamage .health.longDamage .health.illness .chem .addict .devotion .oldDevotion .trust .oldTrust .face .faceShape .faceImplant .markings .bald .hLength .hStyle .hColor .origHColor*/
 /*.eyebrowHColor .pubicHColor .pubicHStyle .underArmHColor .underArmHStyle .eyeColor .origEye .eyes .hears .lips .lipsImplant .teeth .voiceImplant .voice .accent .genes .amp .fuckdoll .muscles .weight*/
 /*.waist .height .heightImplant .shoulders .shouldersImplant .hips .hipsImplant .bellyImplant .bellySag .burst .boobs .boobsImplant .boobsImplantType .lactation .boobShape .nipples .areolae*/
 /*.butt .buttImplant .anus .mpreg .vagina .vaginaLube .clit .labia .pubertyXX .pubertyAgeXX .crevixImplant .breedingMark .ovaries .preg .pregType .pregSource .dick .foreskin .balls*/
diff --git a/src/cheats/mod_EditInfantCheatNew.tw b/src/cheats/mod_EditInfantCheatNew.tw
index fe2cf6c010f..c9aeaa5d92a 100644
--- a/src/cheats/mod_EditInfantCheatNew.tw
+++ b/src/cheats/mod_EditInfantCheatNew.tw
@@ -778,8 +778,17 @@
 	''Birth week:''
 	<<textbox "$tempSlave.birthWeek" $tempSlave.birthWeek>>
 	<br><br>
-	''Health (-99 to 100, -100 is death):''
-	<<textbox "$tempSlave.health" $tempSlave.health>>
+	''Condition (-99 to 100, -100 is death. Condition minus short and long of -100 is also death):''
+	<<textbox "$tempSlave.health.condition" $tempSlave.health.condition>>
+	<br>
+	''Damage - Short Term:''
+	<<textbox "$tempSlave.health.shortDamage" $tempSlave.health.shortDamage>>
+	<br>
+	''Damage - Long Term:''
+	<<textbox "$tempSlave.health.longDamage" $tempSlave.health.longDamage>>
+	<br>
+	''Illness (0 to 5):''
+	<<textbox "$tempSlave.health.illness" $tempSlave.health.illness>>
 	<br>
 	''DNA Errors (0 to 990):''
 	<<textbox "$tempSlave.chem" $tempSlave.chem>>
@@ -3465,7 +3474,7 @@
 <br><<print "@@.yellow;Refresh through selecting a new or the same passage again for Changes to be seen@@" >><br>
 <span id="spot"></span><br>
 /* ------------------------------------------------------------------------- Used Variables: ------------------------------------------------------------------------------------------------*/
-/*.visualAge .ageImplant .birthWeek .health .chem .addict .devotion .oldDevotion .trust .oldTrust .face .faceShape .faceImplant .markings .bald .hLength .hStyle .hColor .origHColor*/
+/*.visualAge .ageImplant .birthWeek .health.condition .health.shortDamage .health.longDamage .health.illness .chem .addict .devotion .oldDevotion .trust .oldTrust .face .faceShape .faceImplant .markings .bald .hLength .hStyle .hColor .origHColor*/
 /*.eyebrowHColor .pubicHColor .pubicHStyle .underArmHColor .underArmHStyle .eyeColor .origEye .eyes .hears .lips .lipsImplant .teeth .voiceImplant .voice .accent .genes .amp .fuckdoll .muscles .weight*/
 /*.waist .height .heightImplant .shoulders .shouldersImplant .hips .hipsImplant .bellyImplant .bellySag .burst .boobs .boobsImplant .boobsImplantType .lactation .boobShape .nipples .areolae*/
 /*.butt .buttImplant .anus .mpreg .vagina .vaginaLube .clit .labia .pubertyXX .pubertyAgeXX .crevixImplant .breedingMark .ovaries .preg .pregType .pregSource .dick .foreskin .balls*/
diff --git a/src/cheats/mod_EditSlaveCheat.tw b/src/cheats/mod_EditSlaveCheat.tw
index 23bcd8588c8..962dd8ae0be 100644
--- a/src/cheats/mod_EditSlaveCheat.tw
+++ b/src/cheats/mod_EditSlaveCheat.tw
@@ -227,8 +227,17 @@
 ''Age Implant (0 or 1):''
 <<textbox "$tempSlave.ageImplant" $tempSlave.ageImplant>>
 <br>
-''Health (-99 to 100, -100 is death):''
-<<textbox "$tempSlave.health" $tempSlave.health>>
+''Condition (-99 to 100, -100 is death. Condition minus short and long of -100 is also death):''
+<<textbox "$tempSlave.health.condition" $tempSlave.health.condition>>
+<br>
+''Damage - Short Term:''
+<<textbox "$tempSlave.health.shortDamage" $tempSlave.health.shortDamage>>
+<br>
+''Damage - Long Term:''
+<<textbox "$tempSlave.health.longDamage" $tempSlave.health.longDamage>>
+<br>
+''Illness (0 to 5):''
+<<textbox "$tempSlave.health.illness" $tempSlave.health.illness>>
 <br>
 ''Addiction:''
 <<textbox "$tempSlave.addict" $tempSlave.addict>>
diff --git a/src/cheats/mod_editSlaveCheatNew.tw b/src/cheats/mod_editSlaveCheatNew.tw
index 6ddf809ca6f..0aa50348369 100644
--- a/src/cheats/mod_editSlaveCheatNew.tw
+++ b/src/cheats/mod_editSlaveCheatNew.tw
@@ -1524,8 +1524,17 @@
 	''Birth week:''
 	<<textbox "$tempSlave.birthWeek" $tempSlave.birthWeek>>
 	<br><br>
-	''Health (-99 to 100, -100 is death):''
-	<<textbox "$tempSlave.health" $tempSlave.health>>
+	''Condition (-99 to 100, -100 is death. Condition minus short and long of -100 is also death):''
+	<<textbox "$tempSlave.health.condition" $tempSlave.health.condition>>
+	<br>
+	''Damage - Short Term:''
+	<<textbox "$tempSlave.health.shortDamage" $tempSlave.health.shortDamage>>
+	<br>
+	''Damage - Long Term:''
+	<<textbox "$tempSlave.health.longDamage" $tempSlave.health.longDamage>>
+	<br>
+	''Illness (0 to 5):''
+	<<textbox "$tempSlave.health.illness" $tempSlave.health.illness>>
 	<br>
 	''DNA Errors (0 to 990):''
 	<<textbox "$tempSlave.chem" $tempSlave.chem>>
diff --git a/src/endWeek/illness.js b/src/endWeek/illness.js
index c0b39520675..de4287d9e04 100644
--- a/src/endWeek/illness.js
+++ b/src/endWeek/illness.js
@@ -116,6 +116,11 @@ window.healthDamage = function healthDamage(slave, damage) { // All things hurti
     slave.health.health = slave.health.condition - slave.health.longDamage - slave.health.shortDamage;
 };
 
+window.improveCondition = function improveCondition(slave, condition) { // All things improving a slave's condition go through this to update condition and slave health
+    slave.health.condition += this.Math.min(slave.health.condition + condition, 100);
+    slave.health.health = slave.health.condition - slave.health.longDamage - slave.health.shortDamage;
+}
+
 window.endWeekHealthDamage = function endWeekHealthDamage(slave) { // Run at the end of the week to take care of health changes
     let chemToShort = 0;
     let shortToCondition = 0;
@@ -144,9 +149,9 @@ window.endWeekHealthDamage = function endWeekHealthDamage(slave) { // Run at the
 
     // recovering and transfering short term damage to condition and long term
     if (slave.health.shortDamage > 0) {
-        shortToCondition += Math.max(Math.trunc(slave.health.shortDamage * 0.25), 1); /* 25% of short term damage gets transfered */
+        shortToCondition += Math.max(Math.trunc(slave.health.shortDamage * 0.25), 1); // 25% of short term damage gets transfered
         slave.health.shortDamage -= shortToCondition;
-        if (slave.curatives > 0) { /* transferred damage is half if on preventatives/curatives */
+        if (slave.curatives > 0) { // transferred damage is half if on preventatives/curatives
             shortToCondition = Math.trunc(shortToCondition * 0.5);
         }
         slave.health.condition -= shortToCondition;
@@ -168,6 +173,13 @@ window.endWeekHealthDamage = function endWeekHealthDamage(slave) { // Run at the
     if (slave.birthWeek === 0 && slave.age > 29) {
         slave.health.longDamage += Math.trunc((slave.age - 25 + jsrandom(1, 15)) / 20);
     }
+
+    // Making sure condition doesn't get too high
+    if (slave.health.condition > 100) {
+        slave.health.condition -= Math.trunc(Math.pow(slave.health.condition - 100, 0.5));
+    }
+
+    slave.health.health = slave.health.condition - slave.health.longDamage - slave.health.shortDamage;
 };
 
 
@@ -205,7 +217,6 @@ window.tired = function tired(slave) {
     let V = State.variables;
     let livingRules = 0;
     let assignment = 0;
-    let reward;
     let muscles;
     let health;
     let tiredChange;
@@ -218,8 +229,10 @@ window.tired = function tired(slave) {
     }
 
     // Assignment
-    if (slave.assignment === "rest" || slave.assignment === "get treatment in the clinic" || slave.assignment === "serve in the master suite" || slave.assignment === "please you") {
-        assignment -= normalRandInt(20, 2); // Reduces tired by an average of 15 points while on a relaxing assignment
+    if (slave.assignment === "rest" || slave.assignment === "get treatment in the clinic") {
+        assignment -= normalRandInt(15, 2); // Reduces tired by an average of 15 points while on a relaxing assignment
+    } else if (slave.assignment === "serve in the master suite" || slave.assignment === "please you") {
+        assignment -= normalRandInt(5); // Reduces tired by an average of 5 points while on a relatively easy assignment
     } else if (slave.assignment === "rest in the spa") {
         assignment -= Math.trunc(normalRandInt(40, 3) / (2 - V.spaUpgrade)); // Reduces tired by an average of 20 points while in the spa, 40 points with the upgraded spa
         if (V.Attendant !== 0) {
@@ -229,35 +242,17 @@ window.tired = function tired(slave) {
         assignment = normalRandInt(20, 2); // Increases tired by an average of 20 points while on a demanding assignment
     }
 
-    // Rewards
-    if (slave.devotion < -20 || (slave.standardReward !== "situational" && slave.standardReward !== "relaxation")) {
-        reward = 0; // The selected reward does not reduce tiredness
-    } else {
-        reward = 1 * normalRandInt(0, 5) / 100;
-        if (V.spa) {
-            reward *= 1 + Math.min((V.spa - V.spaiIDs.length) / (Math.max(V.slaves.length - V.spaiIDs.length, 1) / 10), 1); // Checking if the spa has enough room to provide relaxation for everyone or otherwise reduce the benefit. I would check exactly how much use the spa gets from all the slaves, but to do a loop through all slaves for it seems silly
-        }
-        if (slave.devotion >= 50) { // Gets rewarded often
-            reward *= 3;
-        } else if (slave.devotion >= 20) { // Gets rewarded quite a bit
-            reward *= 2;
-        }
-        if (slave.standardReward === "relaxation") { // Is set specifically to relaxation
-            rewardMultiplier *= 2;
-        }
-        reward = Math.trunc(reward);
-    }
-
     // Muscles
     if (slave.muscles < 50) {
-        muscles = -Math.trunc((slave.muscles / 10) * normalRandInt(0, 5) / 100); // Being weak increases tiredness, building muscles eventually reduces tiredness
+        muscles = -Math.trunc((slave.muscles / 10) * (1 + normalRandInt(0, 5) / 100)); // Being weak increases tiredness, building muscles eventually reduces tiredness
     } else {
-        muscles = -Math.trunc(5 * normalRandInt(0, 5) / 100); // Muscle benefits max out at 50
+        muscles = -Math.trunc(5 * (1 + normalRandInt(0, 5) / 100)); // Muscle benefits max out at 50
     }
 
     // Health
-    health = Math.trunc((slave.health.condition / 20 - slave.health.shortDamage / 2) * normalRandInt(0, 5) / 100); // Current condition reduces tiredness, health damage increases tiredness
+    health = Math.trunc((slave.health.condition / 20 - slave.health.shortDamage / 2) * (1 + normalRandInt(0, 5) / 100)); // Current condition reduces tiredness, health damage increases tiredness
 
-    tiredChange = livingRules + assignment + reward + muscles + health;
+    tiredChange = livingRules + assignment + muscles + health;
     slave.health.tired += tiredChange;
+    slave.health.tired = Math.clamp(slave.health.tired, 0, 100);
 };
diff --git a/src/endWeek/saNanny.js b/src/endWeek/saNanny.js
index 5cc9cdf0e41..b50312b1373 100644
--- a/src/endWeek/saNanny.js
+++ b/src/endWeek/saNanny.js
@@ -135,7 +135,7 @@ window.saNanny = function saNanny(slave) {
 			} else {
 				t += `an incident without lasting effect.`;
 			}
-			slave.health += (2 * vignette.effect);
+			improveCondition(slave, 2 * vignette.effect);
 		} else {
 			let modifier = FResult(slave);
 			if (vignette.effect > 0) {
@@ -167,8 +167,8 @@ window.saNanny = function saNanny(slave) {
 			if (slave.devotion < V.FarmerTrustThreshold) {
 				slave.trust += V.FarmerTrustBonus;
 			}
-			if (slave.health < 100) {
-				slave.health += V.FarmerHealthBonus;
+			if (slave.condition < 100) {
+				improveCondition(slave, V.FarmerHealthBonus);
 			}*/
 	}
 
diff --git a/src/endWeek/saRest.js b/src/endWeek/saRest.js
index 0b449f83928..d292d68635a 100644
--- a/src/endWeek/saRest.js
+++ b/src/endWeek/saRest.js
@@ -22,17 +22,17 @@ window.saRest = function saRest(slave) {
 		t += `in place.`;
 	}
 
-	if (slave.health > 90) {
+	if (slave.health.condition > 90) {
 		t += ` ${His} health is so outstanding that rest does not improve it.`;
-	} else if (slave.health > -100) {
+	} else if (slave.health.condition > -100) {
 		t += ` ${His} <span class="green">health recovers</span> with rest.`;
-		slave.health += 10;
+		improveCondition(slave, 10);
 		if (!(canHear(slave))) {
 			t += ` Since ${he} is deaf, the hustle and bustle of daily life in the penthouse <span class="green">didn't bother ${him} at all.</span>`;
-			slave.health += 3;
+			improveCondition(slave, 3);
 		} else if ((slave.hears === -1 && slave.earwear !== "hearing aids") || (slave.hears === 0 && slave.earwear === "muffling ear plugs")) {
 			t += ` Since ${he} is hard of hearing, the hustle and bustle of daily life in the penthouse <span class="green">didn't disturb ${his} rest as much.</span>`;
-			slave.health += 1;
+			improveCondition(slave, 1);
 		}
 	}
 
@@ -117,12 +117,13 @@ window.saRest = function saRest(slave) {
 		} else if (_vignette.type === "health") {
 			if (_vignette.effect > 0) {
 				t += `<span class="green">improving ${his} health.</span>`;
+				improveCondition(slave, 2 * _vignette.effect);
 			} else if (_vignette.effect < 0) {
 				t += `<span class="red">affecting ${his} health.</span>`;
+				healthDamage(slave, 2 * _vignette.effect);
 			} else {
 				t += `an incident without lasting effect.`;
 			}
-			slave.health += (2 * _vignette.effect);
 		} else {
 			if (_vignette.effect > 0) {
 				t += `<span class="green">gaining you a bit of reputation.</span>`;
diff --git a/src/endWeek/saRules.js b/src/endWeek/saRules.js
index 9161aae9959..97d593c939b 100644
--- a/src/endWeek/saRules.js
+++ b/src/endWeek/saRules.js
@@ -357,22 +357,39 @@ $(function() {
 							switch (slave.standardReward) {
 								case "relaxation":
 									r += `${He}'s given free time, which ${he}`;
-									if (V.spa) {
+									if (V.spa && V.spaSpots > 0) {
 										r += `usually spends in ${V.spaName}${V.Attendant ? ` enjoying ${Attendant.slaveName}'s care` : ``}. `;
+										improveCondition(slave, rewards * 2);
+										slave.health.tired -= Math.ceil(Math.max(normalRandInt(rewards * 3), 1) * (1 + V.spaUpgrade / 2));
+										V.spaSpots -= rewards * 2;
+									} else if (V.spa) {
+										r += 'mostly spends relaxing in the penthouse slave quarters because the spa was too busy. ';
+										improveCondition(slave, rewards);
+										slave.health.tired -= Math.max(normalRandInt(rewards * 2), 1);
 									} else {
 										r += `usually spends relaxing in the penthouse slave quarters. `;
+										improveCondition(slave, rewards);
+										slave.health.tired -= Math.max(normalRandInt(rewards * 2), 1);
 									}
 
 									if (slave.relationship) {
 										r += `${He} often asks to save these breaks so ${he} can spend them with ${his} ${slave.relationship === 1 ? `friend` : slave.relationship === 2 ? `best friend` : slave.relationship === 3 ? `friend with benefits` : slave.relationship === 4 ? `sweetheart` : `wife`}. `;
 									}
 									r += `These breaks are <span class="green">good for ${him}. </span>`;
-									slave.health += rewards;
 									break;
 								case "drugs":
 									r += `${He}'s <span class="hotpink">rewarded</span> with hits of mild recreational drugs, which <span class="red">isn't healthy,</span> but helps bind ${him} to you strongly. `;
-									slave.health -= rewards;
+									healthDamage(slave, rewards * 2);
 									slave.devotion += rewards * 2;
+									if (V.spa) {
+										if (V.spaSpots > 0) {
+											r += `${He} is also allowed to make use of the spa and <span class="green">relax a little. </span>`;
+											slave.health.tired -= Math.max(normalRandInt(rewards), 1);
+											V.spaSpots -= rewards;
+										} else {
+											r += `${He} can't relax in the spa, because it is full. `;
+										}
+									}
 									break;
 								case "orgasm":
 									r += `${He}'s <span class="hotpink">rewarded</span> with`;
@@ -389,6 +406,15 @@ $(function() {
 									}
 									slave.need -= rewards * 10;
 									slave.devotion += rewards;
+									if (V.spa) {
+										if (V.spaSpots > 0) {
+											r += `${He} is also allowed to make use of the spa and <span class="green">relax a little. </span>`;
+											slave.health.tired -= Math.max(normalRandInt(rewards), 1);
+											V.spaSpots -= rewards;
+										} else {
+											r += `${He} can't relax in the spa, because it is full. `;
+										}
+									}
 									break;
 								default:
 									r += `${He}'s <span class="hotpink">rewarded</span> `;
@@ -397,6 +423,15 @@ $(function() {
 									}
 									r += `situationally, letting ${him} develop normally. `;
 									slave.devotion += rewards;
+									if (V.spa) {
+										if (V.spaSpots > 0) {
+											r += `${He} is also allowed to make use of the spa and <span class="green">relax a little. </span>`;
+											slave.health.tired -= Math.max(normalRandInt(rewards), 1);
+											V.spaSpots -= rewards;
+										} else {
+											r += `${He} can't relax in the spa, because it is full. `;
+										}
+									}
 									break;
 							}
 						}
@@ -414,7 +449,7 @@ $(function() {
 									break;
 								case "whipping":
 									r += `When ${he} disobeys, ${he}'s <span class="gold">whipped,</span> not hard enough to mark ${him}, but hard enough to <span class="red">hurt,</span> breaking ${him} quickly. `;
-									slave.health -= punishments;
+									healthDamage(slave, punishments);
 									slave.trust -= 2 * punishments;
 									break;
 								case "chastity":
diff --git a/src/endWeek/saServant.js b/src/endWeek/saServant.js
index d403f24a8d4..603098fd8e4 100644
--- a/src/endWeek/saServant.js
+++ b/src/endWeek/saServant.js
@@ -183,7 +183,7 @@ window.saServant = function saServant(slave) {
 			} else {
 				t += `an incident without lasting effect.`;
 			}
-			slave.health += (2 * vignette.effect);
+			improveCondition(slave, 2 * vignette.effect);
 		} else {
 			let modifier = FResult(slave);
 			if (vignette.effect > 0) {
diff --git a/src/endWeek/saServeThePublic.js b/src/endWeek/saServeThePublic.js
index 279e166e739..6e6d38ebfd6 100644
--- a/src/endWeek/saServeThePublic.js
+++ b/src/endWeek/saServeThePublic.js
@@ -320,10 +320,10 @@ window.saServeThePublic = (function saServeThePublic() {
 					r += `${he}'s on`;
 				}
 				r += ` protect ${him} from the wear of being a slut.`;
-			} else if (slave.health < -50) {
-				r += ` The stress of being a slut while ill is <span class="red">very hard on ${him}.</span>`;
-			} else if (slave.health < -20 && jsRandom(1, 100) > 50) {
-				r += ` The stress of being a slut while ill is <span class="red">hard on ${him}.</span>`;
+			} else if (slave.health.condition < -50) {
+				r += ` The stress of being a slut while in terrible condition is <span class="red">very hard on ${him}.</span>`;
+			} else if (slave.health.condition < -20 && jsRandom(1, 100) > 50) {
+				r += ` The stress of being a slut while in poor condition is <span class="red">hard on ${him}.</span>`;
 			} else if (slave.vagina < 0) {
 				if (slave.minorInjury === 0) {
 					r += ` ${He}'s such an expert public servant that ${he} copes with the stress of being a ${SlaveTitle(slave)} slut.`;
@@ -1568,12 +1568,13 @@ window.saServeThePublic = (function saServeThePublic() {
 			} else if (vignette.type === "health") {
 				if (vignette.effect > 0) {
 					r += `<span class="green">improving ${his} health.</span>`;
+					improveCondition(slave, 2 * vignette.effect);
 				} else if (vignette.effect < 0) {
 					r += `<span class="red">affecting ${his} health.</span>`;
+					healthDamage(slave, 2 * vignette.effect);
 				} else {
 					r += `an incident without lasting effect.`;
 				}
-				slave.health += (2 * vignette.effect);
 			} else {
 				if (vignette.effect > 0) {
 					r += `<span class="green">gaining you a bit of reputation.</span>`;
diff --git a/src/endWeek/saStayConfined.js b/src/endWeek/saStayConfined.js
index 878fd6222c3..ff221a978af 100644
--- a/src/endWeek/saStayConfined.js
+++ b/src/endWeek/saStayConfined.js
@@ -46,7 +46,7 @@ window.saStayConfined = function saStayConfined(slave) {
 		}
 
 		t += ` The stress of confinement <span class="red">damages ${his} health.</span>`;
-		slave.health -= 10;
+		healthDamage(slave, 10);
 	} else {
 		t += `is oblivious to ${his} confinement.`;
 	}
diff --git a/src/endWeek/saWhore.js b/src/endWeek/saWhore.js
index e9f2ce3b42a..d87aecdf960 100644
--- a/src/endWeek/saWhore.js
+++ b/src/endWeek/saWhore.js
@@ -469,13 +469,13 @@ window.saWhore = (function saWhore() {
 					r += `${he}'s on`;
 				}
 				r += ` protect ${him} from the wear of whoring.`;
-			} else if (slave.health < -50) {
-				r += ` The stress of whoring while ill is <span class="red">very hard on ${him}.</span>`;
-				slave.health -= 13;
+			} else if (slave.health.condition < -50) {
+				r += ` The stress of whoring while in terrible condition is <span class="red">very hard on ${him}.</span>`;
+				healthDamage(slave, 13);
 				injury = 1;
-			} else if (slave.health < -20 && jsRandom(1, 100) > 50) {
-				r += ` The stress of whoring while ill is <span class="red">hard on ${him}.</span>`;
-				slave.health -= 10;
+			} else if (slave.health.condition < -20 && jsRandom(1, 100) > 50) {
+				r += ` The stress of whoring while in poor condition is <span class="red">hard on ${him}.</span>`;
+				healthDamage(slave, 10);
 				injury = 1;
 			} else {
 				let canA = canDoAnal(slave);
@@ -484,7 +484,7 @@ window.saWhore = (function saWhore() {
 				// Complicated, I know - but it should automatically account for what acts are possible to scale the injury risk smoothly between 90% when totally unskilled
 				// and 0% when perfectly skilled in the relevant method or methods.
 				if (jsRandom(1, 100) > skilltarget) {
-					slave.health -= 10 - 7*canA*canV;		// Any limitations means an injury inflicts the harsher 10 instead of 3
+					healthDamage(slave, 10 - 7 * canA * canV);		// Any limitations means an injury inflicts the harsher 10 instead of 3
 					injury = 1;
 				}
 
@@ -1759,12 +1759,13 @@ window.saWhore = (function saWhore() {
 		} else if (vignette.type === "health") {
 			if (vignette.effect > 0) {
 				r += `<span class="green">improving ${his} health.</span>`;
+				improveCondition(slave, 2 * vignette.effect);
 			} else if (vignette.effect < 0) {
 				r += `<span class="red">affecting ${his} health.</span>`;
+				healthDamage(slave, 2 * vignette.effect);
 			} else {
 				r += `an incident without lasting effect.`;
 			}
-			slave.health += (2 * vignette.effect);
 		} else {
 			if (vignette.effect > 0) {
 				r += `<span class="green">gaining you a bit of reputation.</span>`;
diff --git a/src/endWeek/saWorkAGloryHole.js b/src/endWeek/saWorkAGloryHole.js
index 2a2f510f60c..8733ee46247 100644
--- a/src/endWeek/saWorkAGloryHole.js
+++ b/src/endWeek/saWorkAGloryHole.js
@@ -105,27 +105,27 @@ window.saWorkAGloryHole = (function saWorkAGloryHole() {
 				r += `on`;
 			}
 			r += ` protect ${his} health from the stress of being used as a sexual appliance.`;
-		} else if (slave.health < -50) {
-			r += ` The stress of being used while very ill <span class="red">damaged ${his} health.</span>`;
-			slave.health -= Math.max(Math.trunc((slave.sexAmount - 100) / 25) + jsRandom(-2, 2), 1);
-		} else if (slave.health < -10) {
+		} else if (slave.health.condition < -50) {
+			r += ` The stress of being used while very in terrible condition <span class="red">damaged ${his} health.</span>`;
+			damageHealth(slave, Math.max(Math.trunc((slave.sexAmount - 400) / 25) + jsRandom(-2, 2), 1));
+		} else if (slave.health.condition < -10) {
 			if (jsRandom(1, 100) < 10) {
 				r += ` The stress of being used while weak has <span class="red">damaged ${his} health.</span>`;
-				slave.health -= Math.max(Math.trunc((slave.sexAmount - 100) / 25) + jsRandom(-2, 2), 1);
+				damageHealth(slave, Math.max(Math.trunc((slave.sexAmount - 400) / 25) + jsRandom(-2, 2), 1));
 			}
 		} else if (!canDoVaginal(slave) && !canDoAnal(slave)) {
 			if (jsRandom(1, 100) < 75) {
 				r += ` The stress of being used repeatedly in only one hole has <span class="red">damaged ${his} health.</span>`;
-				slave.health -= Math.max(Math.trunc((slave.sexAmount - 100) / 25) + jsRandom(-2, 2), 1);
+				damageHealth(slave, Math.max(Math.trunc((slave.sexAmount - 400) / 25) + jsRandom(-2, 2), 1));
 			}
 		} else if (!canDoVaginal(slave)) {
 			if (jsRandom(1, 100) < 50) {
 				r += ` The stress of being used in only two holes has <span class="red">damaged ${his} health.</span>`;
-				slave.health -= Math.max(Math.trunc((slave.sexAmount - 100) / 25) + jsRandom(-2, 2), 1);
+				damageHealth(slave, Math.max(Math.trunc((slave.sexAmount - 400) / 25) + jsRandom(-2, 2), 1));
 			}
 		} else if (jsRandom(1, 100) < 25) {
 			r += ` The stress of being used has <span class="red">damaged ${his} health.</span>`;
-			slave.health -= Math.max(Math.trunc((slave.sexAmount - 100) / 25) + jsRandom(-2, 2), 1);
+			damageHealth(slave, Math.max(Math.trunc((slave.sexAmount - 400) / 25) + jsRandom(-2, 2), 1));
 		}
 
 		if (slave.vagina === 0 && canDoVaginal(slave)) {
diff --git a/src/endWeek/saWorkTheFarm.js b/src/endWeek/saWorkTheFarm.js
index 1a124602369..5347d8ee854 100644
--- a/src/endWeek/saWorkTheFarm.js
+++ b/src/endWeek/saWorkTheFarm.js
@@ -31,8 +31,8 @@ window.saWorkTheFarm = function saWorkTheFarm(slave) {
 		if (slave.devotion < V.FarmerTrustThreshold) {
 			slave.trust += V.FarmerTrustBonus;
 		}
-		if (slave.health < 100) {
-			slave.health += V.FarmerHealthBonus;
+		if (slave.health.condition < 100) {
+			improveCondition(slave, V.FarmerHealthBonus);
 		}
 	}
 
@@ -54,9 +54,9 @@ window.saWorkTheFarm = function saWorkTheFarm(slave) {
 	} else if (slave.devotion < -50) {
 		t += `${He}'s so resistant that ${he} doesn't work as hard, and thus produces less food.`;
 	}
-	if (slave.health > 50) {
+	if (slave.health.condition > 50) {
 		t += `${His} shining health helps ${him} really work hard. `;
-	} else if (slave.health < -50) {
+	} else if (slave.health.condition < -50) {
 		t += `${His} poor health impedes ${his} ability to work efficiently. `;
 	}
 	if (slave.muscles > 50) {
@@ -296,9 +296,9 @@ window.saWorkTheFarm = function saWorkTheFarm(slave) {
 		} else if (slave.pornPrestige === 3) {
 			t += `${He} earns a lot more because ${he} is so famous from porn. `;
 		}
-		if (slave.health > 20) {
+		if (slave.health.condition > 20) {
 			t += `${He} is in such excellent health that ${he} is able to put on longer and more energetic shows, earning you more. `;
-		} else if (slave.health < -20) {
+		} else if (slave.health.condition < -20) {
 			t += `${His} poor health negatively affects ${his} ability to put on good shows, cutting into your profits. `;
 		}
 		if (slave.face > 40) {
@@ -492,12 +492,13 @@ window.saWorkTheFarm = function saWorkTheFarm(slave) {
 		} else if (vignette.type === "health") {
 			if (vignette.effect > 0) {
 				t += ` <span class="green">improving ${his} health.</span> `;
+				improveCondition(slave, 2 * vignette.effect);
 			} else if (vignette.effect < 0) {
 				t += ` <span class="red">affecting ${his} health.</span> `;
+				damageHealth(slave, 2 * vignette.effect);
 			} else {
 				t += ` an incident without lasting effect. `;
 			}
-			slave.health += 2 * vignette.effect;
 		} else {
 			FResult(slave);
 			if (vignette.effect > 0) {
diff --git a/src/facilities/clinic/clinicFramework.js b/src/facilities/clinic/clinicFramework.js
index 3bfc107d785..e3e21d31e14 100644
--- a/src/facilities/clinic/clinicFramework.js
+++ b/src/facilities/clinic/clinicFramework.js
@@ -36,7 +36,7 @@ App.Entity.Facilities.ClinicPatientJob = class extends App.Entity.Facilities.Fac
 	checkRequirements(slave) {
 		let r = super.checkRequirements(slave);
 
-		if ((slave.health >= 20) &&
+		if ((slave.health.condition >= 20) &&
 			(V.Nurse === 0 || ((slave.chem <= 15 || this.facility.upgrade("Filters") !== 1) &&
 				(V.bellyImplants !== 1 || slave.bellyImplant <= -1) &&
 				(slave.pregKnown !== 1 || (this.facility.option("SpeedGestation") <= 0 && slave.pregControl !== "speed up")) && (slave.pregAdaptation * 1000 >= slave.bellyPreg && slave.preg <= slave.pregData.normalBirth / 1.33)))) {
diff --git a/src/facilities/farmyard/farmyardReport.tw b/src/facilities/farmyard/farmyardReport.tw
index 346cf6d6589..7b3e676c920 100644
--- a/src/facilities/farmyard/farmyardReport.tw
+++ b/src/facilities/farmyard/farmyardReport.tw
@@ -14,14 +14,14 @@
 <<if ($Farmer != 0)>>
 	<<set _FLs = $slaveIndices[$Farmer.ID]>>
 
-	<<if ($slaves[_FLs].health < -80)>>
-		<<set $slaves[_FLs].health += 20>>
-	<<elseif $slaves[_FLs].health < -40>>
-		<<set $slaves[_FLs].health += 15>>
-	<<elseif $slaves[_FLs].health < 0>>
-		<<set $slaves[_FLs].health += 10>>
-	<<elseif $slaves[_FLs].health < 90>>
-		<<set $slaves[_FLs].health += 7>>
+	<<if ($slaves[_FLs].health.condition < -80)>>
+		<<run improveCondition($slaves[_FLs], 20)>>
+	<<elseif $slaves[_FLs].health.condition < -40>>
+		<<run improveCondition($slaves[_FLs], 15)>>
+	<<elseif $slaves[_FLs].health.condition < 0>>
+		<<run improveCondition($slaves[_FLs], 10)>>
+	<<elseif $slaves[_FLs].health.condition < 90>>
+		<<run improveCondition($slaves[_FLs], 7)>>
 	<</if>>
 	<<if $slaves[_FLs].devotion <= 45>>
 		<<set $slaves[_FLs].devotion += 5>>
@@ -213,14 +213,14 @@
 			<<set $slaves[$i].livingRules = "normal">>
 		<</switch>>
 		/* TODO: should FS with "spare" living rules cause some minor health damage and devotion / trust loss? */
-		<<if ($slaves[$i].health < -80)>>
-			<<set $slaves[$i].health += 20>>
-		<<elseif $slaves[$i].health < -40>>
-			<<set $slaves[$i].health += 15>>
-		<<elseif $slaves[$i].health < 0>>
-			<<set $slaves[$i].health += 10>>
-		<<elseif $slaves[$i].health < 90>>
-			<<set $slaves[$i].health += 7>>
+		<<if ($slaves[$i].health.condition < -80)>>
+			<<run improveCondition($slaves[_FLs], 20)>>
+		<<elseif $slaves[$i].health.condition < -40>>
+			<<run improveCondition($slaves[_FLs], 15)>>
+		<<elseif $slaves[$i].health.condition < 0>>
+			<<run improveCondition($slaves[_FLs], 10)>>
+		<<elseif $slaves[$i].health.condition < 90>>
+			<<run improveCondition($slaves[_FLs], 7)>>
 		<</if>>
 		<<if ($slaves[$i].devotion <= 20) && ($slaves[$i].trust >= -20)>>
 			<<set $slaves[$i].devotion -= 5, $slaves[$i].trust -= 5>>
diff --git a/src/facilities/nursery/childInteract.tw b/src/facilities/nursery/childInteract.tw
index 57eea67cf3e..4fbefab52b2 100644
--- a/src/facilities/nursery/childInteract.tw
+++ b/src/facilities/nursery/childInteract.tw
@@ -1419,7 +1419,7 @@ Hormones: <b><span id="hormones">$activeChild.hormones</span>.</b>
 	<<set $activeChild.diet = "healthy">>
 	<<replace "#diet">>$activeChild.diet<</replace>>
 <</link>>
-<<if ($activeChild.health < 90) && ($activeChild.chem >= 10) && ($dietCleanse)>>
+<<if ($activeChild.health.condition < 90) && ($activeChild.chem >= 10) && ($dietCleanse)>>
 |	<<link "Cleanse">>
 		<<set $activeChild.diet = "cleansing">>
 		<<replace "#diet">>$activeChild.diet<</replace>>
diff --git a/src/facilities/nursery/nurseryDatatypeCleanup.js b/src/facilities/nursery/nurseryDatatypeCleanup.js
index 2eac8e034c3..deb56bc9a5f 100644
--- a/src/facilities/nursery/nurseryDatatypeCleanup.js
+++ b/src/facilities/nursery/nurseryDatatypeCleanup.js
@@ -58,7 +58,16 @@ App.Facilities.Nursery.ChildDatatypeCleanup = function(child) {
 		if (typeof child.minorInjury !== "string") {
 			child.minorInjury = 0;
 		}
-		child.health = Math.clamp(+child.health, -100, 100) || 0;
+		if (typeof child.health === "number") {
+			const condition = child.health;
+			child.health = {};
+			child.health.condition = condition;
+		}
+		child.health.condition = Math.clamp(+child.health.condition, -100, 100) || 0;
+		child.health.shortDamage = Math.max(+child.health.shortDamage, 0) || 0;
+		child.health.longDamage = Math.max(+child.health.longDamage, 0) || 0;
+		child.health.illness = Math.max(+child.health.illness, 0) || 0;
+		child.health.tired = Math.clamp(+child.health.tired, 0, 100) || 0;
 		child.muscles = Math.clamp(+child.muscles, -100, 100) || 0;
 		child.weight = Math.clamp(+child.weight, -100, 200) || 0;
 		child.waist = Math.clamp(+child.waist, -100, 100) || 0;
@@ -556,7 +565,16 @@ App.Facilities.Nursery.InfantDatatypeCleanup = function(child) {
 		if (typeof child.skin !== "string") {
 			child.skin = "light";
 		}
-		child.health = Math.clamp(+child.health, -100, 100) || 0;
+		if (typeof child.health === "number") {
+			const condition = child.health;
+			child.health = {};
+			child.health.condition = condition;
+		}
+		child.health.condition = Math.clamp(+child.health.condition, -100, 100) || 0;
+		child.health.shortDamage = Math.max(+child.health.shortDamage, 0) || 0;
+		child.health.longDamage = Math.max(+child.health.longDamage, 0) || 0;
+		child.health.illness = Math.max(+child.health.illness, 0) || 0;
+		child.health.tired = Math.clamp(+child.health.tired, 0, 100) || 0;
 		child.weight = Math.clamp(+child.weight, -100, 200) || 0;
 	}
 
diff --git a/src/facilities/nursery/nurseryWidgets.js b/src/facilities/nursery/nurseryWidgets.js
index 0e1e991f32d..06ebd9730d1 100644
--- a/src/facilities/nursery/nurseryWidgets.js
+++ b/src/facilities/nursery/nurseryWidgets.js
@@ -117,12 +117,12 @@ App.Facilities.Nursery.InfantSummary = function(child) {
 	//  * @param {App.Entity.SlaveState} child
 	//  */
 	// function shortHealth(child) {
-	// 	if (child.health < -20) {
-	// 		r += `<strong><span class="red">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
-	// 	} else if (child.health <= 20) {
-	// 		r += `<strong><span class="yellow">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
-	// 	} else if (child.health > 20) {
-	// 		r += `<strong><span class="green">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
+	// 	if (child.health.condition < -20) {
+	// 		r += `<strong><span class="red">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
+	// 	} else if (child.health.condition <= 20) {
+	// 		r += `<strong><span class="yellow">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
+	// 	} else if (child.health.condition > 20) {
+	// 		r += `<strong><span class="green">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
 	// 	}
 	// 	r += " ";
 	// }
@@ -131,20 +131,20 @@ App.Facilities.Nursery.InfantSummary = function(child) {
 	//  * @param {App.Entity.SlaveState} child
 	//  */
 	// function longHealth(child) {
-	// 	if (child.health < -90) {
-	// 		r += `<span class="red">On the edge of death ${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-	// 	} else if (child.health < -50) {
-	// 		r += `<span class="red">Extremely unhealthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-	// 	} else if (child.health < -20) {
-	// 		r += `<span class="red">Unhealthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-	// 	} else if (child.health <= 20) {
-	// 		r += `<span class="yellow">Healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-	// 	} else if (child.health <= 50) {
-	// 		r += `<span class="green">Very healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-	// 	} else if (child.health <= 90) {
-	// 		r += `<span class="green">Extremely healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
+	// 	if (child.health.condition < -90) {
+	// 		r += `<span class="red">On the edge of death ${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+	// 	} else if (child.health.condition < -50) {
+	// 		r += `<span class="red">Extremely unhealthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+	// 	} else if (child.health.condition < -20) {
+	// 		r += `<span class="red">Unhealthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+	// 	} else if (child.health.condition <= 20) {
+	// 		r += `<span class="yellow">Healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+	// 	} else if (child.health.condition <= 50) {
+	// 		r += `<span class="green">Very healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+	// 	} else if (child.health.condition <= 90) {
+	// 		r += `<span class="green">Extremely healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
 	// 	} else {
-	// 		r += `<span class="green">Unnaturally healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
+	// 		r += `<span class="green">Unnaturally healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
 	// 	}
 	// 	r += " ";
 	// }
@@ -3136,12 +3136,12 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 	 * @param {App.Entity.SlaveState} child
 	 */
 	function shortHealth(child) {
-		if (child.health < -20) {
-			r += `<strong><span class="red">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
-		} else if (child.health <= 20) {
-			r += `<strong><span class="yellow">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
-		} else if (child.health > 20) {
-			r += `<strong><span class="green">H ${V.summaryStats ? `[${child.health}]` : ''}</span></strong> `;
+		if (child.health.condition < -20) {
+			r += `<strong><span class="red">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
+		} else if (child.health.condition <= 20) {
+			r += `<strong><span class="yellow">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
+		} else if (child.health.condition > 20) {
+			r += `<strong><span class="green">H ${V.summaryStats ? `[${child.health.condition}]` : ''}</span></strong> `;
 		}
 	}
 
@@ -3149,20 +3149,20 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 	 * @param {App.Entity.SlaveState} child
 	 */
 	function longHealth(child) {
-		if (child.health < -90) {
-			r += `<span class="red">On the edge of death ${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-		} else if (child.health < -50) {
-			r += `<span class="red">Extremely unhealthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-		} else if (child.health < -20) {
-			r += `<span class="red">Unhealthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-		} else if (child.health <= 20) {
-			r += `<span class="yellow">Healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-		} else if (child.health <= 50) {
-			r += `<span class="green">Very healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
-		} else if (child.health <= 90) {
-			r += `<span class="green">Extremely healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
+		if (child.health.condition < -90) {
+			r += `<span class="red">On the edge of death ${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+		} else if (child.health.condition < -50) {
+			r += `<span class="red">Extremely unhealthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+		} else if (child.health.condition < -20) {
+			r += `<span class="red">Unhealthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+		} else if (child.health.condition <= 20) {
+			r += `<span class="yellow">Healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+		} else if (child.health.condition <= 50) {
+			r += `<span class="green">Very healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
+		} else if (child.health.condition <= 90) {
+			r += `<span class="green">Extremely healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
 		} else {
-			r += `<span class="green">Unnaturally healthy${V.summaryStats ? `[${child.health}]` : ''}.</span> `;
+			r += `<span class="green">Unnaturally healthy${V.summaryStats ? `[${child.health.condition}]` : ''}.</span> `;
 		}
 	}
 
@@ -15685,7 +15685,11 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.hStyle = "long",
 	child.haircuts = 0,
 	child.headAccessory = "none",
-	child.health = jsRandom(80, 100),
+	child.health.condition = jsRandom(80, 100),
+	child.health.shortDamage = 0,
+	child.health.longDamage = 0,
+	child.health.illness = 0,
+	child.health.tired = 0,
 	child.hears = 0,
 	child.heels = 0,
 	child.height = jsRandom(85, 105),
@@ -16791,7 +16795,28 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		* * 50  -  90: Extremely healthy
 		* * 90  -  : Unnaturally healthy
 		*/
-		this.health = 0;
+		this.health.condition = 0;
+		/** Child's short term health damage */
+		this.health.shortDamage = 0;
+		/** Child's long term health damage */
+		this.health.longDamage = 0;
+		/**
+		* Child's current illness status
+		* * 0 : Not ill
+		* * 1 : A little under the weather
+		* * 2 : Minor illness
+		* * 3 : Ill
+		* * 4 : serious illness
+		* * 5 : dangerous illness
+		*/
+		this.health.illness = 0;
+		/**
+		* Child's current level of exhaustion
+		* * 0  - 50 : Perfectly fine
+		* * 50 - 80 : tired
+		* * 80 - 100 : exhausted
+		*/
+		this.health.tired = 0;
 		/**
 		* slave has a minor injury ("black eye", "bruise", "split lip")
 		* @type {number | string}
@@ -19093,8 +19118,8 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 				he, him, his, himself, He, His
 			} = getPronouns(Matron);
 
-		if (Matron.health < 100) {
-			Matron.health += 20;
+		if (Matron.health.condition < 100) {
+			improveCondition(Matron, 20);
 		}
 		if (Matron.devotion <= 60) {
 			Matron.devotion++;
@@ -19240,7 +19265,8 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 
 		V.i = App.Utils.slaveIndexForId(slave.ID);
 
-		slave.devotion += devBonus, slave.trust += trustBonus, slave.health += healthBonus;
+		slave.devotion += devBonus, slave.trust += trustBonus;
+		improveCondition(slave, healthBonus);
 
 		// TODO: rework these
 		if (slave.devotion < 60 && slave.trust < 60) {
@@ -19252,8 +19278,8 @@ App.Facilities.Nursery.nurseryReport = function nurseryReport() {
 		}
 
 		// TODO: rework this
-		if (V.nurseryUpgrade === 1 && slave.health < 20) {
-			slave.health += 3;
+		if (V.nurseryUpgrade === 1 && slave.health.condition < 20) {
+			improveCondition(slave, 3);
 		}
 
 		// TODO:
diff --git a/src/facilities/spa/spaFramework.js b/src/facilities/spa/spaFramework.js
index bc17f8ae2c2..967ec8c42b5 100644
--- a/src/facilities/spa/spaFramework.js
+++ b/src/facilities/spa/spaFramework.js
@@ -36,7 +36,7 @@ App.Entity.Facilities.SpaAssigneeJob = class extends App.Entity.Facilities.Facil
 	checkRequirements(slave) {
 		let r = super.checkRequirements(slave);
 
-		if (((slave.devotion < -20 && slave.fetish !== "mindbroken") || (slave.health >= 20 && slave.trust > 60 && slave.devotion > 60 && slave.fetish !== "mindbroken" && slave.sexualFlaw === "none" && slave.behavioralFlaw === "none"))) {
+		if (((slave.devotion < -20 && slave.fetish !== "mindbroken") || (slave.health.condition >= 20 && slave.trust > 60 && slave.devotion > 60 && slave.fetish !== "mindbroken" && slave.sexualFlaw === "none" && slave.behavioralFlaw === "none"))) {
 			r.push(`${slave.slaveName} will not benefit from time at ${this.facility.name}.`);
 		}
 
diff --git a/src/init/storyInit.tw b/src/init/storyInit.tw
index e481f7ad4ef..6248c97ec36 100644
--- a/src/init/storyInit.tw
+++ b/src/init/storyInit.tw
@@ -552,6 +552,7 @@ You should have received a copy of the GNU General Public License along with thi
 <<set $schoolroomNameCaps = "The Schoolroom">>
 <<set $spaDecoration = "standard">>
 <<set $spa = 0>>
+<<set $spaSpots = 0>>
 <<set $spaUpgrade = 0>>
 <<set $spaFix = 0>>
 <<set $spaName = "the Spa">>
@@ -1368,7 +1369,7 @@ You should have received a copy of the GNU General Public License along with thi
 <<set $weatherToday = $niceWeather.random()>>
 
 <<set $customSlaveOrdered = 0>>
-<<set $customSlave = {age: 19, health: 0, muscles: 0, lips: 15, heightMod: "normal", weight: 0, face: 0, race: "white", skin: "left natural", boobs: 500, butt: 3, sex: 1, virgin: 0, dick: 2, balls: 2, clit: 0, labia: 0, vaginaLube: 1, analVirgin: 0, skills: 15, skill: {whore: 15, combat: 0}, intelligence: 0, intelligenceImplant: 0, nationality: "Stateless", leg: {left: new App.Entity.LimbState(), right: new App.Entity.LimbState()}, arm: {left: new App.Entity.LimbState(), right: new App.Entity.LimbState()}, eyes: 1, hears: 0}>>
+<<set $customSlave = {age: 19, health: {health: 0, condition: 0, shortDamage: 0, longDamage: 0, illness: 0}, muscles: 0, lips: 15, heightMod: "normal", weight: 0, face: 0, race: "white", skin: "left natural", boobs: 500, butt: 3, sex: 1, virgin: 0, dick: 2, balls: 2, clit: 0, labia: 0, vaginaLube: 1, analVirgin: 0, skills: 15, skill: {whore: 15, combat: 0}, intelligence: 0, intelligenceImplant: 0, nationality: "Stateless", leg: {left: new App.Entity.LimbState(), right: new App.Entity.LimbState()}, arm: {left: new App.Entity.LimbState(), right: new App.Entity.LimbState()}, eyes: 1, hears: 0}>>
 
 <<set $huskSlaveOrdered = 0>>
 <<set $huskSlave = {age: 18, nationality: "Stateless", race: "white", sex: 1, virgin: 0}>>
diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js
index f078255943e..2e4c5ede60b 100644
--- a/src/js/DefaultRules.js
+++ b/src/js/DefaultRules.js
@@ -938,9 +938,9 @@ window.DefaultRules = (function() {
 		// silent calls to surgery degradation have been replaced with a js function, which is less hacky
 		if ((rule.bellyImplantVol !== undefined) && slave.bellyImplant >= 0 && rule.bellyImplantVol >= 0) {
 			r += "<br>";
-			if (slave.health > -10) {
+			if (slave.health.condition > -10) {
 				let diff = rule.bellyImplantVol - slave.bellyImplant;
-				if (diff >= 5000 && slave.bellyPain === 0 && slave.health > 50) {
+				if (diff >= 5000 && slave.bellyPain === 0 && slave.health.condition > 50) {
 					r += `${slave.slaveName}'s belly is way too small, so ${he} has been directed to have intensive belly implant filling procedures throughout this week.`;
 					slave.bellyImplant += 1000;
 					slave.bellyPain += 2;
@@ -1187,7 +1187,7 @@ window.DefaultRules = (function() {
 			if (slave.balls > 0) {
 				growDrugs.balls = "hyper testicle enhancement";
 			}
-		} else if (rule.growth.intensity && slave.indentureRestrictions < 2 && slave.health > 0) {
+		} else if (rule.growth.intensity && slave.indentureRestrictions < 2 && slave.health.condition > 0) {
 			growDrugs.boobs = "intensive breast injections";
 			growDrugs.butt = "intensive butt injections";
 			if (slave.dick > 0) {
@@ -1471,7 +1471,7 @@ window.DefaultRules = (function() {
 	function ProcessEnema(slave, rule) {
 		if ((rule.inflationType !== undefined) && (rule.inflationType !== null)) {
 			if (slave.inflationType !== rule.inflationType) {
-				if ((slave.inflationType === "curative" && slave.health > 90) || (slave.inflationType === "tightener" && slave.anus <= 1 && slave.vagina <= 1)) {
+				if ((slave.inflationType === "curative" && slave.health.condition > 90) || (slave.inflationType === "tightener" && slave.anus <= 1 && slave.vagina <= 1)) {
 					r += `<br>${slave.slaveName} cannot benefit from ${his} assigned enema and has been defaulted to none.`;
 					slave.inflation = 0;
 					slave.inflationType = "none";
@@ -1479,7 +1479,7 @@ window.DefaultRules = (function() {
 					slave.milkSource = 0;
 					slave.cumSource = 0;
 					SetBellySize(slave);
-				} else if ((rule.inflationType === "curative" && slave.health > 90) || (rule.inflationType === "tightener" && slave.anus <= 1 && slave.vagina <= 1)) {
+				} else if ((rule.inflationType === "curative" && slave.health.condition > 90) || (rule.inflationType === "tightener" && slave.anus <= 1 && slave.vagina <= 1)) {
 					// empty block
 				} else {
 					r += `<br>${slave.slaveName}'s current enema regimen has been set to ${rule.inflationType}.`;
@@ -1491,7 +1491,7 @@ window.DefaultRules = (function() {
 					SetBellySize(slave);
 				}
 			}
-			if (slave.inflationType !== "none" && slave.inflation > 1 && slave.health < -50) {
+			if (slave.inflationType !== "none" && slave.inflation > 1 && slave.health.condition < -50) {
 				r += `<br>${slave.slaveName}'s current enema regimen risks death, so it has been reduced to a less threatening level.`;
 				slave.inflation = 1;
 				SetBellySize(slave);
@@ -1627,7 +1627,7 @@ window.DefaultRules = (function() {
 						}
 					}
 				} else if ((rule.diet === "cleansing")) {
-					if ((slave.diet !== "cleansing") && (slave.health < 90 || slave.chem >= 10)) {
+					if ((slave.diet !== "cleansing") && (slave.health.condition < 90 || slave.chem >= 10)) {
 						slave.diet = "cleansing";
 						r += `<br>${slave.slaveName} has been put on a diet of cleansers.`;
 					}
@@ -1698,7 +1698,7 @@ window.DefaultRules = (function() {
 		if ((rule.curatives !== undefined) && (rule.curatives !== null)) {
 			if (slave.curatives !== rule.curatives) {
 				if (rule.curatives === 2) {
-					if (slave.health > 100) {
+					if (slave.health.condition > 100) {
 						if ((slave.curatives !== 1)) {
 							r += `<br>${slave.slaveName} has been put on preventatives, since curatives cannot improve ${his} health further.`;
 							slave.curatives = 1;
@@ -1798,21 +1798,21 @@ window.DefaultRules = (function() {
 			if (rule.pregSpeed === "slow" && slave.preg < slave.pregData.minLiveBirth) {
 				slave.pregControl = "slow gestation";
 				r += `<br>${slave.slaveName} is pregnant, so ${he} has been put on the gestation slowing agents.`;
-			} else if (rule.pregSpeed === "fast" && slave.preg < slave.pregData.minLiveBirth && slave.health > -50) {
+			} else if (rule.pregSpeed === "fast" && slave.preg < slave.pregData.minLiveBirth && slave.health.condition > -50) {
 				slave.pregControl = "speed up";
 				r += `<br>${slave.slaveName} is pregnant, so ${he} has been put on rapid gestation agents. CAUTION! Can be dangerous. Clinic supervision is recommended.`;
-			} else if (rule.pregSpeed === "suppress" && slave.preg >= slave.pregData.minLiveBirth && slave.health > -50) {
+			} else if (rule.pregSpeed === "suppress" && slave.preg >= slave.pregData.minLiveBirth && slave.health.condition > -50) {
 				slave.pregControl = "labor suppressors";
 				r += `<br>${slave.slaveName} is ready to birth, so ${he} has been put on labor suppressing agents.`;
-			} else if (rule.pregSpeed === "stimulate" && slave.preg > slave.pregData.minLiveBirth && slave.health > -50) {
+			} else if (rule.pregSpeed === "stimulate" && slave.preg > slave.pregData.minLiveBirth && slave.health.condition > -50) {
 				slave.labor = 1;
 				slave.induce = 1;
 				V.birthee = 1;
 				r += `<br>${slave.slaveName} is ready to birth, so ${his} labor has been stimulated.`;
-			} else if (rule.pregSpeed === "fast" && slave.pregControl === "speed up" && slave.health <= -50) {
+			} else if (rule.pregSpeed === "fast" && slave.pregControl === "speed up" && slave.health.condition <= -50) {
 				slave.pregControl = "none";
 				r += `<br>${slave.slaveName} is on rapid gestation agents and dangerously unhealthy, so ${his} agent regimen has been stopped.`;
-			} else if (rule.pregSpeed === "suppress" && slave.pregControl === "labor suppressors" && slave.health <= -50) {
+			} else if (rule.pregSpeed === "suppress" && slave.pregControl === "labor suppressors" && slave.health.condition <= -50) {
 				slave.pregControl = "none";
 				r += `<br>${slave.slaveName} is on labor suppression agents and unhealthy, so ${his} agent regimen has been stopped.`;
 			}
@@ -2714,7 +2714,7 @@ window.DefaultRules = (function() {
 			}
 		}
 		if ((rule.autoBrand === 1)) {
-			if ((slave.health > -20)) {
+			if ((slave.health.condition > -20)) {
 				let brandPlace = "";
 				let left;
 				let right;
@@ -2830,7 +2830,7 @@ window.DefaultRules = (function() {
 						slave.devotion -= 5;
 					}
 					slave.trust -= 5;
-					slave.health -= 10;
+					healthDamage(slave, 10);
 					r += `<br>${slave.slaveName} has been branded on the `;
 					if (brandPlace === "left") {
 						slave.brand[left] = rule.brandDesign;
@@ -2850,7 +2850,7 @@ window.DefaultRules = (function() {
 						slave.devotion -= 10;
 					}
 					slave.trust -= 10;
-					slave.health -= 20;
+					healthDamage(slave, 20);
 					r += `<br>${slave.slaveName} has been branded on both ${rule.brandTarget}, with <span class="gold">fear</span>${slave.devotion < 18 ? `, <span class="mediumorchid">regard,</span>` : ``} and <span class="red">health</span> consequences.`;
 				}
 			}
diff --git a/src/js/assayJS.js b/src/js/assayJS.js
index f49bdbfd79a..634c7ae2cc9 100644
--- a/src/js/assayJS.js
+++ b/src/js/assayJS.js
@@ -1634,7 +1634,7 @@ window.Deadliness = function Deadliness(slave) {
 		deadliness += 1;
 	}
 
-	if (slave.health > 50) {
+	if (slave.health.condition > 50) {
 		deadliness += 1;
 	}
 
@@ -1662,7 +1662,7 @@ window.Deadliness = function Deadliness(slave) {
 		deadliness -= 1;
 	}
 
-	if (slave.health < -50) {
+	if (slave.health.condition < -50) {
 		deadliness -= 1;
 	}
 
diff --git a/src/js/datatypeCleanupJS.js b/src/js/datatypeCleanupJS.js
index 5a0079a59db..3480d653a5a 100644
--- a/src/js/datatypeCleanupJS.js
+++ b/src/js/datatypeCleanupJS.js
@@ -394,7 +394,16 @@ window.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() {
 		if (typeof slave.minorInjury !== "string") {
 			slave.minorInjury = 0;
 		}
-		slave.health = Math.clamp(+slave.health, -100, 100) || 0;
+		if (typeof slave.health === "number") {
+			const condition = slave.health;
+			slave.health = {};
+			slave.health.condition = condition;
+		}
+		slave.health.condition = Math.clamp(+slave.health.condition, -100, 100) || 0;
+		slave.health.shortDamage = Math.max(+slave.health.shortDamage, 0) || 0;
+		slave.health.longDamage = Math.max(+slave.health.longDamage, 0) || 0;
+		slave.health.illness = Math.max(+slave.health.illness, 0) || 0;
+		slave.health.tired = Math.clamp(+slave.health.tired, 0, 100) || 0;
 		slave.muscles = Math.clamp(+slave.muscles, -100, 100) || 0;
 		slave.weight = Math.clamp(+slave.weight, -100, 200) || 0;
 		slave.waist = Math.clamp(+slave.waist, -100, 100) || 0;
@@ -1072,7 +1081,16 @@ window.childPhysicalDatatypeCleanup = function childPhysicalDatatypeCleanup(chil
 	if (typeof child.minorInjury !== "string") {
 		child.minorInjury = 0;
 	}
-	child.health = Math.clamp(+child.health, -100, 100) || 0;
+	if (typeof child.health === "number") {
+		const condition = child.health;
+		child.health = {};
+		child.health.condition = condition;
+	}
+	child.health.condition = Math.clamp(+child.health.condition, -100, 100) || 0;
+	child.health.shortDamage = Math.max(+child.health.shortDamage, 0) || 0;
+	child.health.longDamage = Math.max(+child.health.longDamage, 0) || 0;
+	child.health.illness = Math.max(+child.health.illness, 0) || 0;
+	child.health.tired = Math.clamp(+child.health.tired, 0, 100) || 0;
 	child.muscles = Math.clamp(+child.muscles, -100, 100) || 0;
 	child.weight = Math.clamp(+child.weight, -100, 200) || 0;
 	child.waist = Math.clamp(+child.waist, -100, 100) || 0;
diff --git a/src/js/descriptionWidgets.js b/src/js/descriptionWidgets.js
index 511c802831b..fbc4d8c6639 100644
--- a/src/js/descriptionWidgets.js
+++ b/src/js/descriptionWidgets.js
@@ -348,15 +348,15 @@ App.Desc.ageAndHealth = function(slave) {
 	woman = (boy === "girl" ? "woman" : "man");
 
 	if (!slave.fuckdoll) {
-		if (slave.health < -90) {
+		if (slave.health.condition < -90) {
 			r += `${He} is nearly unresponsive. ${He}'s obviously <span class="red">dangerously sick,</span>`;
-		} else if (slave.health < -50) {
+		} else if (slave.health.condition < -50) {
 			r += `${He} seems <span class="red">very sick,</span>`;
-		} else if (slave.health < -20) {
+		} else if (slave.health.condition < -20) {
 			r += `${He} seems <span class="red">ill,</span>`;
-		} else if (slave.health <= 20) {
+		} else if (slave.health.condition <= 20) {
 			r += `${He} seems reasonably <span class="yellow">healthy,</span>`;
-		} else if (slave.health <= 50) {
+		} else if (slave.health.condition <= 50) {
 			r += `${He} shines with <span class="green">good health,</span>`;
 		} else {
 			r += `${He} almost gleams; ${he}'s in the absolute <span class="green">best of health,</span>`;
@@ -618,15 +618,15 @@ App.Desc.ageAndHealth = function(slave) {
 		}
 	} else {
 		r += ` The Fuckdoll gives no external indication of ${his} health or age, but upon query ${his} systems reports that ${he} is`;
-		if (slave.health < -90) {
+		if (slave.health.condition < -90) {
 			r += `<span class="red">dangerously sick</span>`;
-		} else if (slave.health < -50) {
+		} else if (slave.health.condition < -50) {
 			r += `<span class="red">very sick</span>`;
-		} else if (slave.health < -20) {
+		} else if (slave.health.condition < -20) {
 			r += `<span class="red">ill</span>`;
-		} else if (slave.health <= 20) {
+		} else if (slave.health.condition <= 20) {
 			r += `<span class="yellow">healthy</span>`;
-		} else if (slave.health <= 50) {
+		} else if (slave.health.condition <= 50) {
 			r += `<span class="green">very healthy</span>`;
 		} else {
 			r += `<span class="green">extremely healthy</span>`;
diff --git a/src/uncategorized/BackwardsCompatibility.tw b/src/uncategorized/BackwardsCompatibility.tw
index 5b845129fc5..e6341573196 100644
--- a/src/uncategorized/BackwardsCompatibility.tw
+++ b/src/uncategorized/BackwardsCompatibility.tw
@@ -52,6 +52,9 @@
 <<if def $spaSlaves>>
 	<<unset $spaSlaves>>
 <</if>>
+<<if ndef $spaSpots>>
+	<<set $spaSpots = 0>>
+<</if>>
 <<if def $nurserySlaves>>
 	<<unset $nurserySlaves>>
 <</if>>
diff --git a/src/uncategorized/slaveAssignmentsReport.tw b/src/uncategorized/slaveAssignmentsReport.tw
index 7b0d3451c15..38ef803e8ef 100644
--- a/src/uncategorized/slaveAssignmentsReport.tw
+++ b/src/uncategorized/slaveAssignmentsReport.tw
@@ -168,6 +168,7 @@ $NPCMarketShareLC = Math.trunc(($NPCSexSupply.lowerClass * 1000) / ($NPCSexSuppl
 	<<set $lowerClassSexDemandResult = 4,
 	$lowerClassSatisfied = 1>>
 <</if>>
+
 <br><br>
 
 <<for $i = 0; $i < _SL; $i++>>
@@ -628,6 +629,14 @@ $NPCMarketShareLC = Math.trunc(($NPCSexSupply.lowerClass * 1000) / ($NPCSexSuppl
 
 <</for>>
 
+/*Spa room*/
+<<if $spa > 0>>
+	<<set $spaSpots = ($spa - $SpaiIDs.length) * 20>>
+	<<if $Attendant != 0>>
+		<<set $spaSpots = Math.trunc($spaSpots * (1 + ($Attendant.skill.attendant / 400)))>> /*A skilled attendant improves available space by 25%*/
+	<</if>>
+<</if>>
+
 <<if $averageDick > 0>><<set $averageDick = $averageDick/$slavesWithWorkingDicks>><</if>>
 <<set $freeSexualEnergy = $PC.sexualEnergy-$fuckSlaves>>
 <<if $freeSexualEnergy > 0>>
-- 
GitLab