From b6bded6cbc7513c95b659eda3579864dad19be2f Mon Sep 17 00:00:00 2001
From: CloudyCoffee <Megieboy@gmail.com>
Date: Thu, 30 Sep 2021 12:33:06 +0200
Subject: [PATCH] merge sync

---
 CHANGELOG.md                                  |   5 +
 css/gui/slaveList/cardStyle.css               |  14 +-
 css/rulesAssistant/raSummary.css              |  11 +-
 .../slave variables documentation.md          |  92 +++---
 devTools/javaSanityCheck/ignoredVariables     |  11 -
 devTools/types/FC/RA.d.ts                     |  14 +-
 devTools/types/FC/gameState.d.ts              |   3 +
 devTools/types/FC/human.d.ts                  |   2 +-
 js/003-data/gameVariableData.js               |  33 +-
 js/003-data/slaveMods.js                      |  35 +++
 js/003-data/slaveSummaryData.js               |   2 +-
 src/Mods/Catmod/events/SoSBombing.js          | 135 ++++-----
 .../Catmod/events/reRecruit/punkFemcat.js     |   8 +-
 .../Catmod/events/reRecruit/punkSissycat.js   |   8 +-
 .../Catmod/events/reRecruit/runawayCat.js     |   4 +-
 src/Mods/SecExp/events/conflictReport.js      |  30 +-
 src/Mods/SecExp/js/edicts.js                  |   7 +-
 .../SecExp/js/reportingRelatedFunctions.js    |   4 +-
 src/Mods/SecExp/js/securityReport.js          |   2 +-
 src/arcologyBuilding/ManageArcology.js        |  32 +-
 src/arcologyBuilding/presets.js               |   2 +-
 src/art/vector/VectorArtJS.js                 |  75 +++--
 .../vector_revamp/vectorRevampedArtControl.js |  74 ++---
 src/budget/budget.js                          |  12 +-
 src/budget/repBudget.js                       |   2 +
 .../backwardsCompatibility/datatypeCleanup.js |  94 ++++--
 .../updateSlaveObject.js                      |   1 +
 src/descriptions/arcologyDescription.js       |   2 +-
 src/descriptions/familySummaries.js           |  24 +-
 src/endWeek/economics/reputation.js           |  12 +-
 src/endWeek/events/expire.js                  |   2 +-
 src/endWeek/nextWeek/nextWeek.js              |   4 +-
 src/endWeek/reports/penthouseReport.js        |  50 ++--
 src/endWeek/reports/spaReport.js              |   2 +-
 src/endWeek/saChoosesOwnJob.js                |   4 +-
 src/endWeek/saDevotion.js                     |   2 +
 src/endWeek/saDrugs.js                        |  12 +-
 src/endWeek/saLongTermEffects.js              |   6 +-
 src/endWeek/saLongTermMentalEffects.js        |  40 +--
 src/endWeek/saLongTermPhysicalEffects.js      |   2 +-
 src/endWeek/saRecruitGirls.js                 |   2 +-
 src/endWeek/saRelationships.js                |   2 +-
 src/endWeek/saRewardAndPunishment.js          |   2 +-
 src/endWeek/saServeThePublic.js               |   6 +-
 src/endWeek/saSmartPiercingEffects.js         |   2 +-
 src/endWeek/saSocialEffects.js                |   2 +-
 src/endWeek/saWhore.js                        |   6 +-
 src/events/JE/jeSlaveDisputeIndentureDeal.js  |  16 +-
 src/events/JE/jeSlaveDisputeSlaveDeal.js      |   2 +-
 src/events/JE/jeSlaveDisputeSlaveTraining.js  |  20 +-
 src/events/PE/peCombatTraining.js             |   4 +-
 src/events/PE/peLonelyBodyguard.js            |  11 +-
 src/events/PESS/pessBodyguardBedtime.js       |   2 +-
 src/events/PESS/pessLovingConcubine.js        |   2 +-
 src/events/PESS/pessLovingHeadgirl.js         |   4 +-
 src/events/PESS/pessWorriedHeadgirl.js        |   2 +-
 src/events/PETS/petsAggressiveWardeness.js    |   5 +-
 src/events/RE/reArcologyInspection.js         |   3 +-
 src/events/RE/reMalefactor.js                 |  24 +-
 src/events/RE/reRelativeRecruiter.js          |  39 +--
 src/events/RE/reRoyalBlood.js                 |  14 +-
 src/events/RE/reShippingContainer.js          |   4 +-
 src/events/RE/reShowerPunishment.js           |   2 +-
 src/events/RE/reSnatchAndGrabFollowup.js      |  67 ++---
 src/events/RE/reStandardPunishment.js         |   2 +-
 src/events/RECI/milf.js                       |   2 +-
 src/events/RECI/ugly.js                       |   2 +-
 src/events/REFI/reBoobslut.js                 |   2 +-
 src/events/REFI/reButtslut.js                 |   2 +-
 src/events/REFI/reMasochist.js                |   2 +-
 src/events/REFI/rePregnancy.js                |   9 +-
 src/events/REFI/reSadist.js                   |   2 +-
 src/events/REFS/refsBodyPurismEncounter.js    |   2 +-
 .../REFS/refsDegradationistEncounter.js       |   2 +-
 .../refsMaturityPreferentialistEncounter.js   |   2 +-
 src/events/REFS/refsPastoralistEncounter.js   |   2 +-
 src/events/REFS/refsPaternalistEncounter.js   |   2 +-
 .../REFS/refsPhysicalIdealistEncounter.js     |   2 +-
 src/events/REFS/refsRomanStoicism.js          |  56 ++++
 .../refsTransformationFetishismEncounter.js   |   2 +-
 src/events/REFS/refsWarhound.js               |   2 +-
 .../REFS/refsYouthPreferentialistEncounter.js |   2 +-
 src/events/RESS/PAFlirting.js                 |   2 +-
 src/events/RESS/bedSnuggle.js                 |   2 +-
 src/events/RESS/birthday.js                   |   2 +-
 src/events/RESS/comfortableSeat.js            |   2 +-
 src/events/RESS/impregnationPlease.js         |   6 +-
 src/events/RESS/languageLesson.js             |   4 +-
 src/events/RESS/moistPussy.js                 |   2 +-
 src/events/RESS/nightVisit.js                 |   2 +-
 src/events/RESS/obedientGirlish.js            |   4 +-
 src/events/RESS/obedientShemale.js            |   2 +-
 src/events/RESS/review/bondedLove.js          |  12 +-
 .../RESS/review/breastExpansionBlues.js       |   4 +-
 src/events/RESS/review/cumslutWhore.js        |   2 +-
 src/events/RESS/review/devotedOld.js          |   2 +-
 src/events/RESS/review/heavyPiercing.js       |   6 +-
 src/events/RESS/review/hormoneDysfunction.js  |   2 +-
 src/events/RESS/review/hugeNaturals.js        |   2 +-
 src/events/RESS/review/hugeTits.js            |   2 +-
 src/events/RESS/review/hugelyPregnant.js      |   4 +-
 src/events/RESS/review/ignorantHorny.js       |   4 +-
 src/events/RESS/review/implantInspection.js   |   2 +-
 src/events/RESS/review/inconvenientLabia.js   |   2 +-
 src/events/RESS/review/modsPlease.js          |  34 +--
 src/events/RESS/review/notMyName.js           |   2 +-
 src/events/RESS/review/resistantGelding.js    |   2 +-
 src/events/RESS/review/soreShoulders.js       |   2 +-
 src/events/RESS/review/spaBoobs.js            |   2 +-
 src/events/RESS/review/surgeryAddict.js       |   2 +-
 src/events/RESS/review/tendonFall.js          |   2 +-
 src/events/RESS/review/terrifiedInspection.js |   2 +-
 src/events/RESS/review/transitionAnxiety.js   |   2 +-
 src/events/RESS/review/vocalDisobedience.js   |   6 +-
 src/events/RESS/scrubbing.js                  |   2 +-
 src/events/RETS/reCockmilkInterception.js     |   2 +-
 src/events/RETS/reInterslaveBegging.js        |   4 +-
 src/events/assistant/assistantSP.js           |   2 +-
 .../daughters/pUndergroundRailroad.js         |   6 +-
 src/events/nonRandom/rival/pRivalryActions.js | 123 ++++----
 src/events/nonRandom/rival/pRivalryCapture.js |  26 +-
 src/events/nonRandom/stripClubAftermath.js    |  14 +-
 src/events/randomEvent.js                     |   1 +
 src/events/reRecruit/blessedVessel.js         |   4 +-
 src/events/reRecruit/blessedVirgin.js         |   4 +-
 src/events/reRecruit/blindHomeless.js         |   4 +-
 src/events/reRecruit/capturedTeen.js          |   4 +-
 src/events/reRecruit/ccsAngel.js              |   4 +-
 src/events/reRecruit/ccsDA.js                 |   4 +-
 src/events/reRecruit/desperateMILF.js         |   4 +-
 src/events/reRecruit/desperatePreg.js         |   7 +-
 .../reRecruit/desperateUniversityMILF.js      |   4 +-
 src/events/reRecruit/dgRunaway.js             |  18 +-
 src/events/reRecruit/embryoAppropriation.js   |   4 +-
 src/events/reRecruit/farmBull.js              |   2 +-
 src/events/reRecruit/farmCow.js               |   2 +-
 src/events/reRecruit/farmVirginCow.js         |   2 +-
 src/events/reRecruit/femaleDebtor.js          |   4 +-
 src/events/reRecruit/femaleRecruit.js         |  12 +-
 src/events/reRecruit/femaleRunaway.js         |  18 +-
 src/events/reRecruit/femaleSD.js              |   4 +-
 src/events/reRecruit/femaleSD2.js             |  20 +-
 src/events/reRecruit/gangLeader.js            |   8 +-
 src/events/reRecruit/handsomePC.js            |   6 +-
 src/events/reRecruit/heldPOW.js               |   4 +-
 src/events/reRecruit/hermRunaway.js           |  18 +-
 src/events/reRecruit/homelessBreakIn.js       |   4 +-
 src/events/reRecruit/immigrant.js             |   4 +-
 src/events/reRecruit/maleDebtor.js            |   4 +-
 src/events/reRecruit/maleRecruit.js           |  12 +-
 src/events/reRecruit/maleSD.js                |   4 +-
 src/events/reRecruit/overwhelmedFarmgirl.js   |   4 +-
 src/events/reRecruit/paternalistSwanSong.js   |  12 +-
 src/events/reRecruit/rogueCyborg.js           |   7 +-
 src/events/reRecruit/shemalePC.js             |  18 +-
 src/events/reRecruit/spoiledDaughter.js       |   4 +-
 src/events/reRecruit/starvingMigrant.js       |   4 +-
 src/events/reRecruit/tgAddict.js              |   4 +-
 src/events/reRecruit/whoreRecruit.js          |  20 +-
 src/events/reRecruit/womanlyPC.js             |  14 +-
 src/events/recETS/newSlaveIncestSex.js        |   4 +-
 .../recETS/recetsDesperateBroodmother.js      |   4 +-
 src/events/recETS/recetsPoshMotherDaughter.js |   2 +-
 src/events/recFS/recfsDegradationist.js       |  10 +-
 src/events/recFS/recfsDegradationistTwo.js    |  10 +-
 src/events/recFS/recfsHedonisticDecadence.js  |  22 +-
 src/events/recFS/recfsNeoImperialist.js       |   4 +-
 src/events/recFS/recfsPetiteAdmirationTwo.js  |   6 +-
 src/events/recFS/recfsSlaveProfessionalism.js |  10 +-
 src/events/scheduled/assholeKnight.js         |   1 +
 src/events/scheduled/murderAttempt.js         |  10 +-
 src/events/scheduled/newBaron.js              |  10 +-
 src/events/scheduled/pitFight.js              |  14 +-
 src/events/scheduled/pitFightLethal.js        |   2 +
 src/events/scheduled/pitFightNonlethal.js     |  14 +-
 src/events/scheduled/poorKnight.js            |   6 +-
 src/events/scheduled/seCoursing.js            |   6 +-
 src/events/scheduled/seFctvRemote.js          |   3 +-
 src/events/scheduled/sePCBirthday.desc.js     |   9 +-
 src/events/scheduled/seRecruiterSuccess.js    |  42 +--
 src/facilities/barracks.js                    |   9 +-
 .../bodyModification/bodyModification.js      | 178 +++++------
 src/facilities/brothel/brothel.js             | 153 ++++++----
 src/facilities/farmyard/animals/animals.js    |   4 +
 src/facilities/farmyard/farmyard.js           |   2 +-
 .../farmyard/shows/saFarmyardShows.js         |   2 +-
 src/facilities/geneLab.js                     |   2 +-
 .../nursery/nurseryDatatypeCleanup.js         |  40 ++-
 src/facilities/nursery/utils/nurseryUtils.js  |  17 +-
 src/facilities/penthouse/HGSelect.js          |   6 +-
 src/facilities/penthouse/RecruiterSelect.js   |   2 +-
 src/facilities/pit/pit.js                     |   2 +-
 src/facilities/surgery/multiImplant.js        |   7 +-
 .../surgery/surgeryPassageExotic.js           |   2 +-
 .../surgery/surgeryPassageExtreme.js          |   2 +-
 .../surgery/surgeryPassageFaceAndHair.js      |   2 +-
 src/facilities/surgery/surgeryPassageLower.js |   2 +-
 .../surgery/surgeryPassageStructural.js       |   8 +-
 src/facilities/surgery/surgeryPassageUpper.js |   6 +-
 src/facilities/toyShop/toyShop.js             |   4 +-
 src/gui/options/options.js                    |   1 +
 src/interaction/policies/policiesPassage.js   |   2 +
 src/interaction/prostheticLabPassage.js       |   2 +-
 src/interaction/sellSlave.js                  |   2 +-
 src/interaction/siFinancial.js                |   2 +-
 src/interaction/siRules.js                    |   4 +-
 src/interaction/universalRules.js             |   5 +-
 src/js/DefaultRules.js                        | 173 ++++++-----
 src/js/SlaveState.js                          | 145 +++++----
 src/js/economyJS.js                           |  73 +++++
 src/js/findSlave.js                           |   4 +-
 src/js/modification.js                        |  12 +-
 src/js/relationshipChecks.js                  |   9 +-
 src/js/rulesAssistant.js                      |  18 +-
 src/js/rulesAssistantOptions.js               | 245 +++++++++++----
 src/js/rulesAssistantSummary.js               |  13 +-
 src/js/slaveCostJS.js                         |   8 +-
 src/js/slaveSummaryHelpers.js                 |   6 +-
 src/js/slaveSummaryWidgets.js                 |   8 +-
 src/js/statsChecker/statsChecker.js           |  52 +---
 src/js/underperformingSlaves.js               |   1 +
 src/js/utilsMisc.js                           |  12 +-
 src/js/vignettes.js                           |   8 +-
 .../specificMarkets/householdLiquidator.js    |   2 +-
 .../specificMarkets/prestigiousSlave.js       | 132 ++++----
 src/markets/specificMarkets/slaveShelter.js   |   4 +-
 src/markets/theMarket/buySlaves.js            |   2 +-
 src/markets/theMarket/marketData.js           |   2 +-
 src/markets/theMarket/tradeMenials.js         |   4 +-
 src/neighbor/neighborInteract.js              |   2 +
 src/npc/children/ChildState.js                |  64 +---
 src/npc/children/childSummary.js              |   8 +-
 src/npc/children/longChildDescription.js      |  97 +++---
 src/npc/databases/cheatmodeDatabase.js        |  18 +-
 src/npc/databases/dSlavesDatabase.js          | 281 ++++++------------
 src/npc/databases/ddSlavesDatabase.js         |  99 ++----
 src/npc/databases/dfSlavesDatabase.js         |  44 +--
 src/npc/descriptions/belly/belly.js           |  14 +-
 src/npc/descriptions/boobs/boobs.js           |  24 +-
 src/npc/descriptions/boobs/piercing.js        |   4 +-
 src/npc/descriptions/crotch/dick.js           |   4 +-
 src/npc/descriptions/describePiercings.js     | 193 ++++++------
 src/npc/descriptions/face.js                  |   4 +-
 src/npc/descriptions/longSlave.js             |   2 +-
 src/npc/descriptions/upperBack.js             |   2 +-
 src/npc/generate/generateGenetics.js          |  15 +-
 src/npc/generate/generateMarketSlave.js       |  22 +-
 src/npc/generate/generateNewSlaveJS.js        |  28 +-
 src/npc/generate/generateRelatedSlave.js      |  30 +-
 src/npc/generate/lawCompliance.js             |  25 +-
 src/npc/generate/newSlaveIntro.js             |  28 +-
 src/npc/interaction/fAnus.js                  |   4 +-
 src/npc/interaction/fBeg.js                   |  10 +-
 src/npc/interaction/fBoobs.js                 |  10 +-
 src/npc/interaction/fButt.js                  |   8 +-
 src/npc/interaction/fCaress.js                |   2 +-
 src/npc/interaction/fDance.js                 |  24 +-
 src/npc/interaction/fDick.js                  |   8 +-
 src/npc/interaction/fFeelings.js              |   2 +-
 src/npc/interaction/fKiss.js                  |   2 +-
 src/npc/interaction/fLips.js                  |   4 +-
 src/npc/interaction/fPCImpreg.js              |   6 +-
 src/npc/interaction/fVagina.js                |  50 ++--
 src/npc/interaction/fondleBoobs.js            |  10 +-
 src/npc/interaction/fondleDick.js             |   4 +-
 src/npc/interaction/fondleVagina.js           |   4 +-
 src/npc/interaction/passage/fSlaveSlaveAss.js |   2 +-
 .../interaction/passage/fSlaveSlaveDick.js    |   4 +-
 src/npc/interaction/passage/fSlaveSlaveVag.js |   2 +-
 src/npc/startingGirls/startingGirls.js        |   6 +-
 src/npc/surgery/bodySwap/bodySwap.js          |  14 +-
 src/npc/surgery/bodySwap/bodySwapReaction.js  |  56 ++--
 src/npc/surgery/surgery.js                    |   6 +-
 src/npc/surgery/surgeryDegradation.js         |   3 +-
 src/personalAssistant/assistantOptions.js     |   2 +
 src/player/js/PlayerState.js                  |  70 +----
 src/player/personalAttentionSelect.js         |  20 +-
 src/pregmod/FCTV/FCTVshows.js                 |   2 +-
 src/pregmod/theBlackMarket.js                 |  10 +-
 279 files changed, 2337 insertions(+), 2404 deletions(-)
 create mode 100644 src/events/REFS/refsRomanStoicism.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 089e87ec49a..b2a39c87bee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 
 ## Unreleased
 
+* added a number of animal tail/ear/limb prosthetics
+* piercings overhauled
+* added better support for custom piercings
+* added a REFS event for Roman Revivalism
+
 ## 0.10.7.1-4.0.0-alpha.10 - 2021-09-12
 
 * fixes
diff --git a/css/gui/slaveList/cardStyle.css b/css/gui/slaveList/cardStyle.css
index 81e28b32e5e..6a07e857601 100644
--- a/css/gui/slaveList/cardStyle.css
+++ b/css/gui/slaveList/cardStyle.css
@@ -1,12 +1,8 @@
 div.card {
-	border-radius: 8px;
-	border-top: 2px #333333;
-	border-left: 2px #333333;
-	border-bottom: 0;
-	border-right: 0;
-	border-style: solid;
+	border: 2px solid #333333;
 	background-color: #1a1a1a;
-	box-shadow: 10px 10px 5px black;
-	padding: 10px;
-	margin-bottom: 15px;
+	box-shadow: 10px 10px 10px black,
+		-10px 10px 10px black;
+	padding: 1em;
+	margin-bottom: 1em;
 }
diff --git a/css/rulesAssistant/raSummary.css b/css/rulesAssistant/raSummary.css
index 7a4a27adb36..ee40575e92c 100644
--- a/css/rulesAssistant/raSummary.css
+++ b/css/rulesAssistant/raSummary.css
@@ -1,11 +1,5 @@
-.scroll {
-    overflow: auto;
-    height: 90vh
-}
-
 table.ra-sum {
     text-align: left;
-    border-collapse: separate;
     empty-cells: hide;
 }
 
@@ -18,6 +12,10 @@ td.ra-sum {
     overflow: hidden;
 }
 
+tr.ra-sum:nth-child(even) {
+    background-color: #444444;
+}
+
 tr.ra-sum.header {
     position:sticky;
     top:0px;
@@ -35,4 +33,5 @@ td.ra-sum.row-title {
     left: 0px;
     z-index:1;
     background:#111;
+    opacity: 0.8;
 }
diff --git a/devNotes/legacy files/slave variables documentation.md b/devNotes/legacy files/slave variables documentation.md
index 669b2081a5b..568709e95aa 100644
--- a/devNotes/legacy files/slave variables documentation.md	
+++ b/devNotes/legacy files/slave variables documentation.md	
@@ -2487,13 +2487,6 @@ accepts string
 "baby"
 "mixed"
 
-tonguePiercing:
-
-has tongue piercing
-0 - no
-1 - yes
-2 - heavy
-
 vagina:
 
 vagina type
@@ -2512,13 +2505,6 @@ how wet she is
 1 - wet
 2 - soaking wet
 
-vaginaPiercing:
-
-has vagina piercing
-0 - no
-1 - yes
-2 - heavy
-
 vaginaTat:
 
 vagina tattoo
@@ -2662,14 +2648,6 @@ clit size
 4 - penis-like
 5 - like a massive penis
 
-clitPiercing:
-
-is clit pierced
-0 - no
-1 - yes
-2 - heavy
-3 - smart
-
 clitSetting:
 
 smart piercing setting
@@ -2790,13 +2768,6 @@ has ovaries
 0 - no
 1 - yes
 
-anusPiercing:
-
-has anus piercing
-0 - no
-1 - yes
-2 - heavy
-
 anusTat:
 
 anus tattoo
@@ -2847,34 +2818,6 @@ brand:
 is an object
 keys include any place on a slave body that can receive a brand, values are a string for the brand.
 
-earPiercing:
-
-has pierced ears
-0 - no
-1 - yes
-2 - heavy
-
-nosePiercing:
-
-has pierced nose
-0 - no
-1 - yes
-2 - heavy
-
-eyebrowPiercing:
-
-has eyebrow piercing
-0 - no
-1 - yes
-2 - heavy
-
-navelPiercing:
-
-has navel piercing
-0 - no
-1 - yes
-2 - heavy
-
 shouldersTat:
 
 shoulder tattoo
@@ -3853,6 +3796,41 @@ currentRules: []
 array that holds active rules for the slave
 wouldn't mess with it
 
+piercing:
+
+encapsulates piercings
+piercing.ear
+piercing.nose
+piercing.eyebrow
+piercing.lips
+piercing.tongue
+piercing.nipple
+piercing.areola
+piercing.navel
+piercing.corset
+piercing.vagina
+piercing.dick
+piercing.anus
+piercing.genitals
+
+piercing.X.weight:
+
+How heavily X is pierced.
+0 - none
+1 - light
+2 - heavy
+
+piercing.X.desc:
+
+Contains a custom description.
+"" by default
+
+piercing.genitals.smart:
+
+Smart piercing presence.
+"false"
+"true"
+
 bellyTat:
 
 Slave has a tattoo that is only recognizable when she has a big belly.
diff --git a/devTools/javaSanityCheck/ignoredVariables b/devTools/javaSanityCheck/ignoredVariables
index 97d2d75fdbe..82cbd13ee1c 100644
--- a/devTools/javaSanityCheck/ignoredVariables
+++ b/devTools/javaSanityCheck/ignoredVariables
@@ -3,19 +3,8 @@ militiaMod
 mercMod
 SFMod
 enemyMod
-#re-added below 11/14
-############################
 acquire
-############################
 totalMerc
 dickSize
 dinnerParty
 seed
-# Only used within src/pregmod/widgets/pregmodWidgets.tw
-Hers
-Himself
-Daughter
-Sister
-Loli
-Wife
-Wives
diff --git a/devTools/types/FC/RA.d.ts b/devTools/types/FC/RA.d.ts
index fd19e4aa5a0..7b280c2b7eb 100644
--- a/devTools/types/FC/RA.d.ts
+++ b/devTools/types/FC/RA.d.ts
@@ -116,20 +116,8 @@ declare namespace FC {
 			markings: "remove beauty marks" | "remove birthmarks" | "remove both";
 			pubicHColor: string;
 			pubicHStyle: string;
-			nipplesPiercing: FC.PiercingType;
-			areolaePiercing: FC.PiercingType;
-			clitPiercing: FC.ClitoralPiercingType;
+			piercing: Object;
 			vaginaLube: number;
-			vaginaPiercing: FC.PiercingType;
-			dickPiercing: FC.PiercingType;
-			anusPiercing: FC.PiercingType;
-			lipsPiercing: FC.PiercingType;
-			tonguePiercing: FC.PiercingType;
-			earPiercing: FC.PiercingType;
-			nosePiercing: FC.PiercingType;
-			eyebrowPiercing: FC.PiercingType;
-			navelPiercing: FC.PiercingType;
-			corsetPiercing: FC.PiercingType;
 			boobsTat: string | number;
 			buttTat: string | number;
 			vaginaTat: string | number;
diff --git a/devTools/types/FC/gameState.d.ts b/devTools/types/FC/gameState.d.ts
index dc4b172fb47..8422c6fa492 100644
--- a/devTools/types/FC/gameState.d.ts
+++ b/devTools/types/FC/gameState.d.ts
@@ -22,6 +22,9 @@ declare namespace FC {
 		tastes: Zeroable<String>;
 	}
 
+	export type RecruiterTarget = "desperate whores" | "young migrants" | "recent divorcees" |
+		"expectant mothers" | "dissolute sissies" | "reassignment candidates" | "other arcologies";
+
 	interface DeprecatedGameVariables {
 		/** @deprecated */
 		events: string[];
diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts
index 1bffa07fa0a..9274ab78d34 100644
--- a/devTools/types/FC/human.d.ts
+++ b/devTools/types/FC/human.d.ts
@@ -293,7 +293,7 @@ declare global {
 		 * 0: no; 1: yes; 2: heavy
 		 */
 		type PiercingType = 0 | 1 | 2;
-		type ClitoralPiercingType = PiercingType | 3;
+		type Piercing = "ear" | "nose" | "eyebrow" | "lips" | "tongue" | "nipple" | "areola" | "navel" | "corset" | "genitals" | "vagina" | "dick" | "anus";
 		type Race = "amerindian" | "asian" | "black" | "indo-aryan" | "latina" | "malay" | "middle eastern" | "mixed race" |
 			"pacific islander" | "catgirl" | "semitic" | "southern european" | "white";
 		type SizingImplantType = WithNone<"normal" | "string" | "fillable" | "advanced fillable" | "hyper fillable">;
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index 678bbf0091a..9444df55937 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -79,7 +79,6 @@ App.Data.defaultGameStateVariables = {
 	difficultySwitch: 0,
 	disableLisping: 0,
 	displayAssignments: 1,
-	economy: 100,
 	expansionRequestsAllowed: 1,
 	extremeUnderage: 0,
 	formatNumbers: 1,
@@ -399,11 +398,9 @@ App.Data.resetOnNGPlus = {
 	slavesSacrificedThisWeek: 0,
 
 	mercenariesTitle: "",
-	hormones: 0,
 	FSReminder: 0,
 	facility: {},
 	boomerangStats: {},
-	FSNonconformist: "",
 	econAdvantage: 0,
 
 	SecExp: {},
@@ -437,12 +434,7 @@ App.Data.resetOnNGPlus = {
 	/** @type {string[]} */
 	lastWeeksRepErrors: [],
 
-	localEcon: 0,
 	econRate: 0,
-	drugsCost: 0,
-	rulesCost: 0,
-	modCost: 0,
-	surgeryCost: 0,
 	/** @type {FC.ArcologyState[]} */
 	arcologies: [],
 	HackingSkillMultiplier: 0,
@@ -598,7 +590,7 @@ App.Data.resetOnNGPlus = {
 	arcadeUpgradeHealth: -1,
 	arcadeName: "the Arcade",
 	arcade: 0,
-	fuckdollsSold: 0,
+	fuckdollsSold: 0, // TODO: This never increases
 	/** @type {FC.FutureSocietyDeco} */
 	cellblockDecoration: (/** @type {FC.FutureSocietyDeco} */ "standard"),
 	cellblockUpgrade: 0,
@@ -740,18 +732,15 @@ App.Data.resetOnNGPlus = {
 		lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0
 	},
 	arcadePrice: 2,
-	clubSlaveSexAmount: 0,
 	/** @type {App.Entity.SlaveState|number} */
 	shelterSlave: 0,
 	shelterSlaveBought: 0,
 	shelterAbuse: 0,
-	shelterSlaveGeneratedWeek: 0,
 
 	pregAccessibility: 0,
 	dickAccessibility: 0,
 	ballsAccessibility: 0,
 	buttAccessibility: 0,
-	ageMode: 0,
 	boughtItem: {
 		clothing: {
 			// alternate clothing access variables
@@ -896,7 +885,9 @@ App.Data.resetOnNGPlus = {
 	HeadGirlID: 0,
 	HGTimeInGrade: 0,
 	RecruiterID: 0,
+	/** @type {FC.RecruiterTarget} */
 	recruiterTarget: "desperate whores",
+	/** @type {FC.RecruiterTarget} */
 	oldRecruiterTarget: "desperate whores",
 	recruiterProgress: 0,
 	recruiterIdleRule: "number",
@@ -962,7 +953,7 @@ App.Data.resetOnNGPlus = {
 	/** @type {FC.Bool} */
 	hostageRescued: 0,
 	/** @type {FC.Bool} */
-	hostageGiveIn: 0,
+	hostageGiveIn: 0, // TODO: Set up code block to set to one. This is already checked in src/endWeek/saDevotion.js
 	/** @type {FC.SlaveStateOrZero} */
 	hostageWife: 0,
 	rivalSet: 0,
@@ -1061,12 +1052,8 @@ App.Data.resetOnNGPlus = {
 	puristRiotDone: 0,
 	subjectDeltaName: "Bubbles",
 	growingNewCat: 0,
-
 	noDeadShit: 0,
 
-	sniperEscape: 0,
-	sekhmetBombPlot: 0,
-
 	surgeryUpgrade: 0,
 
 	barracks: 0,
@@ -1116,6 +1103,12 @@ App.Data.resetOnNGPlus = {
 		drones: 0, hydro: 0, apron: 0, grid: 0, spire: 0
 	},
 
+	economy: 100,
+	localEcon: 0,
+	drugsCost: 0,
+	rulesCost: 0,
+	modCost: 0,
+	surgeryCost: 0,
 	AGrowth: 2,
 	ACitizens: 4250,
 	lowerClass: 3120,
@@ -1225,11 +1218,7 @@ App.Data.resetOnNGPlus = {
 	huskSlave: null,
 	huskSlaveOrdered: 0,
 
-	/* non-vanilla shit*/
-
-	targetAge: 18,
-	pubertyLength: 5,
-	maxGrowthAge: 24,
+	targetAge: 18, // non-vanilla shit
 
 	/* Job Fulfillment Center */
 	JFC: {
diff --git a/js/003-data/slaveMods.js b/js/003-data/slaveMods.js
index 755de404aa6..eb4ed4371ac 100644
--- a/js/003-data/slaveMods.js
+++ b/js/003-data/slaveMods.js
@@ -523,3 +523,38 @@ App.Medicine.Modification.teeth = new Map([
 		desc: ``,
 	}],
 ]);
+/**
+ * @type {Record<FC.Piercing, Object>} Use singular when possible
+ */
+App.Data.Piercings = {
+	"ear": {
+	},
+	"nose": {
+	},
+	"eyebrow": {
+	},
+	"lips": {
+	},
+	"tongue": {
+	},
+	"nipple": {
+		requirements: (s) => s.nipples !== "fuckable",
+	},
+	"areola": {
+	},
+	"navel": {
+	},
+	"corset": {
+	},
+	"genitals": {
+		smart: true,
+	},
+	"vagina": {
+		requirements: (s) => s.vagina > -1,
+	},
+	"dick": {
+		requirements: (s) => s.dick > 0,
+	},
+	"anus": {
+	},
+};
diff --git a/js/003-data/slaveSummaryData.js b/js/003-data/slaveSummaryData.js
index ea484cc1712..4c2c3e49e42 100644
--- a/js/003-data/slaveSummaryData.js
+++ b/js/003-data/slaveSummaryData.js
@@ -614,7 +614,7 @@ App.Data.SlaveSummary = {
 				99: {desc: "Expert whore", style: "skill"},
 				999: {desc: "Masterful whore", style: "skill"}
 			},
-			mss: {desc: "Masterful Sex Slave.", style: "skill"},
+			mss: {desc: "Masterful sex slave.", style: "skill"},
 			fighter: {desc: "Trained fighter.", style: "skill"},
 		},
 		sexDrive: {
diff --git a/src/Mods/Catmod/events/SoSBombing.js b/src/Mods/Catmod/events/SoSBombing.js
index 12a0f77e53f..610efd93750 100644
--- a/src/Mods/Catmod/events/SoSBombing.js
+++ b/src/Mods/Catmod/events/SoSBombing.js
@@ -8,15 +8,13 @@ App.Events.RESosBombing = class RESosBombing extends App.Events.BaseEvent {
 
 	execute(node) {
 		let r = [];
-
+		const impRaid = () => raidOutcome("Imperial Knights");
+		const romanRaid = () => raidOutcome("Roman");
+		const mercenaries = () => raidOutcome("Mercenaries");
+		const standard = () => raidOutcome("Standard");
+		const bombPlotHappened = either(1, 2, 3, 4) === 1;
 		V.encyclopedia = "The Sons of Sekhmet";
 
-		if (either(1, 2, 3, 4) === 1) {
-			V.sekhmetBombPlot = 1;
-		} else {
-			V.sekhmetBombPlot = 2;
-		}
-
 		r.push(`While working at your desk, your security team sends you an urgently-marked bulletin. The security update enclosed is fairly simple; the security staff think they've got a "reasonable lead" on a potential terrorist operation by the Sons of Sekhmet to bomb a few essential locations in the arcology, sometime in the next few days.`);
 		App.Events.addParagraph(node, r);
 		r = [];
@@ -35,88 +33,83 @@ App.Events.RESosBombing = class RESosBombing extends App.Events.BaseEvent {
 			choices.push(new App.Events.Result(`Authorize the raid, but transfer authority to your ${V.mercenariesTitle}`, mercenaries));
 		}
 		choices.push(new App.Events.Result(`Authorize the raid with standard drones and guard officers`, standard));
-		choices.push(new App.Events.Result(``, refuse));
-
+		choices.push(new App.Events.Result(`Refuse authorization`, refuse));
 		App.Events.addResponses(node, choices);
 
-		function impRaid() {
+		function refuse() {
 			const frag = new DocumentFragment();
 			let r = [];
-			if (V.sekhmetBombPlot === 1) {
-				r.push(`You authorize the raid, bringing in your Knights to captain the effort. Early in the morning the next day, the heavily-armed Knights burst into an old warehouse in the lower sectors, interrupting a group of Sekhmeti terrorists building a series of improvised bombs on a bunch of turned-over crates. As the bombmakers scramble for their weapons, your Knights absolutely slaughter the group, blasting the scene to pieces with heavy firepower and shrugging off the helpless potshots the terrorists make with their ultra-heavy Imperial Plate. Although the overzealous Knights don't leave you anything left to enslave, the media are on the scene within minutes, and the interviews with smiling, unscathed Knights in their elegant coats of armor in front of the scene of an utterly destroyed terrorist cell is a <span class="green">good look</span> for your arcology.`);
-
-				cashX(-5000, "event");
-				repX(2500, "event");
+			if (bombPlotHappened) {
+				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. Two days later, while you're working in your office, a distant booming sound rumbles out from outside the penthouse. Turning to look out the window, you see a column of smoke coming up from the marketplace, and the distant glow of a raging flame. A few seconds later, another muffled boom rings out, this time from the direction of the plaza, and then a third, and a fourth. Sounds of gunshots in the distance ring out shortly afterwards. From here, there's nothing you can do but watch as the series of explosions <span class="red">devastates</span> the arcology's hard-built prosperity - and its citizens. This time wasn't just a fluke, it seems. You don't even need to turn on the TV to imagine what the media is <span class="red">already saying</span> about your failure to stop this attack before it happened. It's not going to be good.`);
+				V.arcologies[0].prosperity -= 5;
+				cashX(-24000, "event");
+				repX(-5000, "event");
 			} else {
-				r.push(`You authorize the raid, bringing in your Knights to captain the effort. Early in the morning the next day, the heavily-armed Knights burst into a small apartment in the lower sectors, nearly giving the old woman in the living room a heart attack. Multiple men in ultra-heavy Imperial Plate all but burst through the walls of the apartment to tackle a single scrawny teenager in his room before they realize that this place probably isn't a radical Sons of Sekhmet cell. Even though this raid ended up being <span class="red">wasted money,</span> your Knights eloquently apologize to the edgy teenager they nearly crushed, and your arcology loves the romanticized Knights enough that there's no lasting reputation damage from the unfortunate raid.`);
-				cashX(-5000, "event");
+				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. A few days later, someone from the team bashfully sends you an "update" bulletin notifying you that it was a false alarm after all and they'd just gotten worked up over some intimidating posts on social media.`);
 			}
 			App.Events.addParagraph(frag, r);
 			return frag;
 		}
 
-		function romanRaid() {
+		/**
+		 * @param {String} operationalCommand 
+		 * @returns {DocumentFragment}
+		 */
+		function raidOutcome(operationalCommand) {
 			const frag = new DocumentFragment();
-			let r = [];
-			if (V.sekhmetBombPlot === 1) {
-				r.push(`You authorize the raid, but transfer authority for its execution over to a group of loyal, free citizens, who are all too eager to defend the Republic. Early in the morning the next day, a group of Praetorians in full gear burst into a small apartment in the lower sectors, interrupting a small group of Sekhmeti terrorists building a series of improvised bombs in the barren living room. Before the bombmakers can even grab their guns, the well-disciplined citizens gun them down in an explosive hail of fire, killing the whole cluster indiscriminately. Although the zealous citizenry don't leave anything left for you to enslave, a group of proud, well-trained free citizens voluntarily defending the arcology from a terrorist plot - and doing so without so much as a scratch - is a <span class="green">good look.</span>`);
-
-				cashX(-5000, "event");
-				repX(2500, "event");
-			} else {
-				r.push(`You authorize the raid, but transfer authority for its execution over to a group of loyal, free citizens, who are all too eager to defend the Republic. Early in the morning the next day, a group of Praetorians in full gear burst into a dilapidated warehouse in the lower sectors, shocking the small group of transport workers carrying crates around for some secondhand shipment. Although the citizens nearly fire on the rough-looking warehouse hands, they realize that this isn't a group of Sekhmeti radicals before they do and apologize for the insurrection. Although this raid ultimately turned out to be <span class="red">wasted money,</span> the free citizens conducting it and their disciplined Roman nature prevents any lasting reputation damage.`);
-
-				cashX(-5000, "event");
+			const r = ["You authorize the raid"];
+			switch(operationalCommand) {
+				case "Imperial Knights":
+					r.push("but bring in your Knights to captain the effort.");
+					break;
+				case "Roman":
+					r.push("but transfer authority for its execution over to a group of loyal, free citizens, who are all too eager to defend the Republic.");
+					break;
+				case "Mercenaries":
+					r.push(`but head up the effort with your better-trained ${V.mercenariesTitle}.`);
+					break;
+				case "Standard":
+					r.push("with no further comments.");
 			}
-			App.Events.addParagraph(frag, r);
-			return frag;
-		}
 
-		function mercenaries() {
-			const frag = new DocumentFragment();
-			let r = [];
-			if (V.sekhmetBombPlot === 1) {
-				r.push(`You authorize the raid, but head up the effort with your better-trained ${V.mercenariesTitle}. Early in the morning the next day, the deadly mercenaries kick down the door of a small office building in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs in the converted office space. The ${V.mercenariesTitle} blow the entire group to pieces with high-power weaponry, absolutely annihilating the careful plot with overwhelming force and indiscriminate destruction before they can fire off a single shot. Although the rough mercenaries don't leave anything left for you to enslave, the well-trained mercs emerging from the smoldering ruin of what used to be a terrorist field HQ is a <span class="green">good look</span> for the security of your arcology.`);
+			r.push("Early in the morning the next day,");
+			switch(operationalCommand) {
+				case "Imperial Knights":
+					if (bombPlotHappened) {
+						r.push(`the heavily-armed Knights burst into an old warehouse in the lower sectors, interrupting a group of Sekhmeti terrorists building a series of improvised bombs on a bunch of turned-over crates. As the bombmakers scramble for their weapons, your Knights absolutely slaughter the group, blasting the scene to pieces with heavy firepower and shrugging off the helpless potshots the terrorists make with their ultra-heavy Imperial Plate. Although the overzealous Knights don't leave you anything left to enslave, the media are on the scene within minutes, and the interviews with smiling, unscathed Knights in their elegant coats of armor in front of the scene of an utterly destroyed terrorist cell is a <span class="green">good look</span> for your arcology.`);
+					} else {
+						r.push(`the heavily-armed Knights burst into a small apartment in the lower sectors, nearly giving the old woman in the living room a heart attack. Multiple men in ultra-heavy Imperial Plate all but burst through the walls of the apartment to tackle a single scrawny teenager in his room before they realize that this place probably isn't a radical Sons of Sekhmet cell. Even though this raid ended up being <span class="red">wasted money,</span> your Knights eloquently apologize to the edgy teenager they nearly crushed, and your arcology loves the romanticized Knights enough that there's no lasting reputation damage from the unfortunate raid.`);
+					}
+					break;
+				case "Roman":
+					if (bombPlotHappened) {
+						r.push(`a group of Praetorians in full gear burst into a small apartment in the lower sectors, interrupting a small group of Sekhmeti terrorists building a series of improvised bombs in the barren living room. Before the bombmakers can even grab their guns, the well-disciplined citizens gun them down in an explosive hail of fire, killing the whole cluster indiscriminately. Although the zealous citizenry don't leave anything left for you to enslave, a group of proud, well-trained free citizens voluntarily defending the arcology from a terrorist plot - and doing so without so much as a scratch - is a <span class="green">good look.</span>`);
+					} else {
+						r.push(`a group of Praetorians in full gear burst into a dilapidated warehouse in the lower sectors, shocking the small group of transport workers carrying crates around for some secondhand shipment. Although the citizens nearly fire on the rough-looking warehouse hands, they realize that this isn't a group of Sekhmeti radicals before they do and apologize for the insurrection. Although this raid ultimately turned out to be <span class="red">wasted money,</span> the free citizens conducting it and their disciplined Roman nature prevents any lasting reputation damage.`);
+					}
+					break;
+				case "Mercenaries":
+					if (bombPlotHappened) {
+						r.push(`the deadly mercenaries kick down the door of a small office building in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs in the converted office space. The ${V.mercenariesTitle} blow the entire group to pieces with high-power weaponry, absolutely annihilating the careful plot with overwhelming force and indiscriminate destruction before they can fire off a single shot. Although the rough mercenaries don't leave anything left for you to enslave, the well-trained mercs emerging from the smoldering ruin of what used to be a terrorist field HQ is a <span class="green">good look</span> for the security of your arcology.`);
+					} else {
+						r.push(`the deadly mercenaries burst into the back of a small shop in the lower sectors, nearly giving the lower-class workers heart attacks with the sudden appearance of their scarred - over faces in full battle gear. Although they tackle two of the poor workers to the ground, it doesn't take the ${V.mercenariesTitle} long to realize that this isn't a radical Sons of Sekhmet terrorist cell, and they leave before the media can show up to report on it. Even though this raid turned out to be <span class="red">wasted money,</span> your mercenaries conduct themselves well enough that there's no lasting reputation damage.`);
+					}
+					break;
+				case "Standard":
+					if (bombPlotHappened) {
+						r.push(`a group of security officers burst into the back of a small shop in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs, having removed all the machinery from the back of the shop to make space. The drones fire their tasers at the Sons, but they're better-armed and trained than to get so easily disabled, and your officers and the bombmakers get drawn into a prolonged firefight over the next ten minutes that draws arcology media to the scene like a candle. Although a few of the officers involved limp out with bullet wounds and slashes, they manage to completely eradicate the terrorist cell, and brave officers coming out from the destroyed Sekhmeti HQ is a <span class="green">good look,</span> even if they didn't manage to leave you any of the terrorists alive to enslave.`);
+					} else {
+						r.push(`a group of security officers kick down the door of a small office building in the lower sectors, practically giving the workers inside heart attacks. One of the drones misinterprets a panicked worker dropping a file as an aggressive action and tases him, much to the chagrin of the rest of the officer team. Arcology media is on the scene in minutes, and on top of being <span class="red">a waste of money,</span> you've also got a PR nightmare on your hands as the tased worker complains on live media about the "unfair paranoia" of the arcology and how much his taser burns hurt. What a shit-show.`);
+					}
+			}
 
-				cashX(-5000, "event");
+			if (operationalCommand !== "Standard" && bombPlotHappened) {
 				repX(2500, "event");
 			} else {
-				r.push(`You authorize the raid, but head up the effort with your better-trained ${V.mercenariesTitle}. Early in the morning the next day, the deadly mercenaries burst into the back of a small shop in the lower sectors, nearly giving the lower-class workers heart attacks with the sudden appearance of their scarred - over faces in full battle gear. Although they tackle two of the poor workers to the ground, it doesn't take the ${V.mercenariesTitle} long to realize that this isn't a radical Sons of Sekhmet terrorist cell, and they leave before the media can show up to report on it. Even though this raid turned out to be <span class="red">wasted money,</span> your mercenaries conduct themselves well enough that there's no lasting reputation damage.`);
-
-				cashX(-5000, "event");
+				repX((bombPlotHappened ? 1500 : -500), "event");
 			}
-			App.Events.addParagraph(frag, r);
-			return frag;
-		}
-
-		function standard() {
-			const frag = new DocumentFragment();
-			let r = [];
-			if (V.sekhmetBombPlot === 1) {
-				r.push(`You authorize the raid with no further comments. Early in the morning the next day, a group of security officers burst into the back of a small shop in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs, having removed all the machinery from the back of the shop to make space. The drones fire their tasers at the Sons, but they're better-armed and trained than to get so easily disabled, and your officers and the bombmakers get drawn into a prolonged firefight over the next ten minutes that draws arcology media to the scene like a candle. Although a few of the officers involved limp out with bullet wounds and slashes, they manage to completely eradicate the terrorist cell, and brave officers coming out from the destroyed Sekhmeti HQ is a <span class="green">good look,</span> even if they didn't manage to leave you any of the terrorists alive to enslave.`);
-
-				cashX(-5000, "event");
-				repX(1500, "event");
-			} else {
-				r.push(`You authorize the raid with no further comments. Early in the morning the next day, a group of security officers kick down the door of a small office building in the lower sectors, practically giving the workers inside heart attacks. One of the drones misinterprets a panicked worker dropping a file as an aggressive action and tases him, much to the chagrin of the rest of the officer team. Arcology media is on the scene in minutes, and on top of being <span class="red">a waste of money,</span> you've also got a PR nightmare on your hands as the tased worker complains on live media about the "unfair paranoia" of the arcology and how much his taser burns hurt. What a shit-show.`);
 
-				cashX(-5000, "event");
-				repX(-500, "event");
-			}
-			App.Events.addParagraph(frag, r);
-			return frag;
-		}
-		function refuse() {
-			const frag = new DocumentFragment();
-			let r = [];
-			if (V.sekhmetBombPlot === 1) {
-				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. Two days later, while you're working in your office, a distant booming sound rumbles out from outside the penthouse. Turning to look out the window, you see a column of smoke coming up from the marketplace, and the distant glow of a raging flame. A few seconds later, another muffled boom rings out, this time from the direction of the plaza, and then a third, and a fourth. Sounds of gunshots in the distance ring out shortly afterwards. From here, there's nothing you can do but watch as the series of explosions <span class="red">devastates</span> the arcology's hard-built prosperity - and its citizens. This time wasn't just a fluke, it seems. You don't even need to turn on the TV to imagine what the media is <span class="red">already saying</span> about your failure to stop this attack before it happened. It's not going to be good.`);
-				V.arcologies[0].prosperity -= 5;
-				cashX(-24000, "event");
-				repX(-5000, "event");
-			} else {
-				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. A few days later, someone from the team bashfully sends you an "update" bulletin notifying you that it was a false alarm after all and they'd just gotten worked up over some intimidating posts on social media.`);
-			}
+			cashX(-5000, "event");
 			App.Events.addParagraph(frag, r);
 			return frag;
 		}
diff --git a/src/Mods/Catmod/events/reRecruit/punkFemcat.js b/src/Mods/Catmod/events/reRecruit/punkFemcat.js
index ae701669bd0..1d1c6561539 100644
--- a/src/Mods/Catmod/events/reRecruit/punkFemcat.js
+++ b/src/Mods/Catmod/events/reRecruit/punkFemcat.js
@@ -38,9 +38,7 @@ App.Events.recPunkFemcat = class recPunkFemcat extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -52,7 +50,7 @@ App.Events.recPunkFemcat = class recPunkFemcat extends App.Events.BaseEvent {
 			cashX(forceNeg(contractCost), "slaveTransfer", slave);
 			r.push(`You quickly fill out the paperwork to transfer the low-status cat${girl}'s legal ownership to yourself, before anyone else can notice how easy it'd be to snatch the unfortunate cat${girl} up for themselves. Making your way to the local guard station where ${he} is being kept, you tell the young ${woman} you're taking ${him} out of jail. Obviously not buying it, ${he} glowers at you as you take ${his} readings and calls you a`);
 			r.push(Spoken(slave, `"monkey fucker",`));
-			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ballgag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
+			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ball gag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
 			r.push(App.UI.newSlaveIntro(slave));
 			App.Events.addNode(el, r);
 			return el;
@@ -64,7 +62,7 @@ App.Events.recPunkFemcat = class recPunkFemcat extends App.Events.BaseEvent {
 			cashX(cost, "slaveTransfer");
 			r.push(`You quickly fill out the paperwork to transfer the low-status cat${girl}'s legal ownership to yourself, before anyone else can notice how easy it'd be to snatch the unfortunate cat${girl} up for themselves. Making your way to the local guard station where ${he} is being kept, you tell the young ${woman} you're taking ${him} out of jail. Obviously not buying it, ${he} glowers at you as you take ${his} readings and calls you a`);
 			r.push(Spoken(slave, `"monkey fucker",`));
-			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ballgag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
+			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ball gag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
 			App.Events.addNode(el, r);
 			return el;
 		}
diff --git a/src/Mods/Catmod/events/reRecruit/punkSissycat.js b/src/Mods/Catmod/events/reRecruit/punkSissycat.js
index 23dbc235c0d..2568a1fded5 100644
--- a/src/Mods/Catmod/events/reRecruit/punkSissycat.js
+++ b/src/Mods/Catmod/events/reRecruit/punkSissycat.js
@@ -38,9 +38,7 @@ App.Events.recPunkSissycat = class recPunkSissycat extends App.Events.BaseEvent
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -52,7 +50,7 @@ App.Events.recPunkSissycat = class recPunkSissycat extends App.Events.BaseEvent
 			cashX(forceNeg(contractCost), "slaveTransfer", slave);
 			r.push(`You quickly fill out the paperwork to transfer the low-status cat${girl}'s legal ownership to yourself, before anyone else can notice how easy it'd be to snatch the unfortunate cat${girl} up for themselves. Making your way to the local guard station where ${he} is being kept, you tell the young ${woman} you're taking ${him} out of jail. Obviously not buying it, ${he} glowers at you as you take ${his} readings and calls you a`);
 			r.push(Spoken(slave, `"monkey fucker",`));
-			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ballgag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
+			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ball gag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
 			r.push(App.UI.newSlaveIntro(slave));
 			App.Events.addNode(el, r);
 			return el;
@@ -64,7 +62,7 @@ App.Events.recPunkSissycat = class recPunkSissycat extends App.Events.BaseEvent
 			cashX(cost, "slaveTransfer");
 			r.push(`You quickly fill out the paperwork to transfer the low-status cat${girl}'s legal ownership to yourself, before anyone else can notice how easy it'd be to snatch the unfortunate cat${girl} up for themselves. Making your way to the local guard station where ${he} is being kept, you tell the young ${woman} you're taking ${him} out of jail. Obviously not buying it, ${he} glowers at you as you take ${his} readings and calls you a`);
 			r.push(Spoken(slave, `"monkey fucker",`));
-			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ballgag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
+			r.push(`blabbering on something about systemic cat oppression and plutocracy before you have the mouthy cat gagged. Sinking ${his} fangs into the ball gag you've had one of the officers shove into ${his} mouth and tightly cuffed, you tell the guards to keep ${him} tightly bound up until the slave trader you've sold ${him} to arrives. One of them smiles and says it'll be a pleasure, glancing over at the bound-up catslave.`);
 			App.Events.addNode(el, r);
 			return el;
 		}
diff --git a/src/Mods/Catmod/events/reRecruit/runawayCat.js b/src/Mods/Catmod/events/reRecruit/runawayCat.js
index 9b887667d52..fffebd00a92 100644
--- a/src/Mods/Catmod/events/reRecruit/runawayCat.js
+++ b/src/Mods/Catmod/events/reRecruit/runawayCat.js
@@ -37,9 +37,7 @@ App.Events.recRunawayCat = class recRunawayCat extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Return ${him} to ${his} owner`, sell, incomeText));
+		responses.push(new App.Events.Result(`Return ${him} to ${his} owner`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/Mods/SecExp/events/conflictReport.js b/src/Mods/SecExp/events/conflictReport.js
index 5413dd57ac8..dc2d639ecd1 100644
--- a/src/Mods/SecExp/events/conflictReport.js
+++ b/src/Mods/SecExp/events/conflictReport.js
@@ -1214,14 +1214,10 @@ App.Events.conflictReport = function() {
 							loss = Math.clamp(loss, 0, unit.troops);
 						}
 
-						if (inRebellion) {
-							if (type === "bots") {
-								r.push(`Security drones:`);
-							} else {
-								r.push(`${unit.platoonName} participated in the battle. They remained loyal to you.`);
-							}
+						if (inRebellion && type !== "bots" && !V.SecExp.war.rebellingID.includes(unit.ID)) {
+							r.push(`${unit.platoonName} participated in the battle. They remained loyal to you.`);
 						} else {
-							r.push(`${type !== "bots" ? `${unit.platoonName}` : "Security drones"}:`);
+							r.push(`${unit.platoonName}:`);
 						}
 						r.push(casualtiesReport(type, loss, unit));
 						if (type !== "bots") {
@@ -1316,10 +1312,10 @@ App.Events.conflictReport = function() {
 	} else {
 		if (result === -1) {
 			if (inRebellion) {
-				r.push(`Rather than waste the lives of your men you decided to surrender, hoping the rebels will cause less damage if you indulge them, this is however a big hit to your status.`);
+				r.push(`Rather than waste the lives of your men you decide to surrender, hoping the rebels will cause less damage if you indulge them. This is, however, a big hit to your status.`);
 				r.push(`Your <span class="red">reputation</span> and <span class="red">authority</span> are significantly impacted.`);
-				r.push(`The surrender allows the arcology to survive <span class="yellow">mostly intact</span>`);
-				r.push(`however reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
+				r.push(`The surrender allows the arcology to survive <span class="yellow">mostly intact.</span>`);
+				r.push(`However, reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
 				App.Events.addParagraph(node, r);
 				r = [];
 
@@ -1346,7 +1342,7 @@ App.Events.conflictReport = function() {
 				lostSlaves = Math.trunc((V.SecExp.war.attacker.troops - V.SecExp.war.attacker.losses) * 0.8);
 				App.SecExp.slavesDamaged(lostSlaves);
 			} else {
-				r.push(`Rather than waste the lives of your men you decided to surrender, hoping your enemy will cause less damage if you indulge them, this is however a big hit to your status. Your <span class="red">reputation</span> and <span class="red">authority</span> are significantly impacted.`);
+				r.push(`Rather than waste the lives of your men you decided to surrender, hoping your enemy will cause less damage if you indulge them. This is, however, a big hit to your status. Your <span class="red">reputation</span> and <span class="red">authority</span> are significantly impacted.`);
 				if (V.SecExp.war.attacker.type === "raiders") {
 					repX(forceNeg(600 * majorBattleMod), "war");
 					App.SecExp.authorityX(-600 * majorBattleMod);
@@ -1362,7 +1358,7 @@ App.Events.conflictReport = function() {
 				}
 				App.Events.addParagraph(node, r);
 				r = [];
-				r.push(`The surrender allows the arcology to survive <span class="red">mostly intact,</span> however reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
+				r.push(`The surrender allows the arcology to survive <span class="red">mostly intact</span> However, reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
 				r.push(`${IncreasePCSkills('engineering', 0.1)}`);
 				cashX(forceNeg(1000 * majorBattleMod), "war");
 				if (V.week <= 30) {
@@ -1388,13 +1384,13 @@ App.Events.conflictReport = function() {
 				}
 			}
 		} else if (result === 0) { // Battles only
-			r.push(`Unfortunately your adversary did not accept your money.`);
+			r.push(`Unfortunately your adversary do not accept your money.`);
 			if (V.SecExp.war.attacker.type === "freedom fighters") {
 				r.push(`Their ideological crusade would not allow such thing.`);
 			} else {
-				r.push(`They saw your attempt as nothing more than admission of weakness.`);
+				r.push(`They see your attempt as nothing more than an admission of weakness.`);
 			}
-			r.push(`There was no time to organize a defense and so the enemy walked into the arcology as it was his. Your reputation and authority suffer a hit.`);
+			r.push(`There is no time to organize a defense and so the enemy walks into the arcology as if it was theirs. Your reputation and authority suffer a hit.`);
 			if (V.SecExp.war.attacker.type === "raiders") {
 				repX(forceNeg(400 * majorBattleMod), "war");
 				App.SecExp.authorityX(-400 * majorBattleMod);
@@ -1410,7 +1406,7 @@ App.Events.conflictReport = function() {
 			}
 			App.Events.addParagraph(node, r);
 			r = [];
-			r.push(`Fortunately the arcology survives <span class="yellow">mostly intact,</span> however reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
+			r.push(`Fortunately the arcology survives <span class="yellow">mostly intact.</span> However, reports of <span class="red">mass looting and killing of citizens</span> flood your office for a few days.`);
 			r.push(`${IncreasePCSkills('engineering', 0.1)}`);
 			cashX(-1000, "war");
 			if (V.week <= 30) {
@@ -1435,7 +1431,7 @@ App.Events.conflictReport = function() {
 				V.arcologies[0].prosperity -= random(25) * majorBattleMod;
 			}
 		} else if (result === 1) { // Battles only
-			r.push(`The attackers wisely take the money offered them to leave your territory without further issues. The strength of the Free Cities was never in their guns but in their dollars, and today's events are the perfect demonstration of such strength.`);
+			r.push(`The attackers wisely take the money offered them and leave your territory without further incident. The strength of the Free Cities was never in their guns but in their dollars, and today's events are the perfect demonstration of such strength.`);
 			r.push(`Your <span class="green">reputation slightly increases.</span>`);
 			if (V.SecExp.war.attacker.type === "raiders") {
 				repX(500 * majorBattleMod, "war");
diff --git a/src/Mods/SecExp/js/edicts.js b/src/Mods/SecExp/js/edicts.js
index 09c5b0d60c9..5524f374c86 100644
--- a/src/Mods/SecExp/js/edicts.js
+++ b/src/Mods/SecExp/js/edicts.js
@@ -480,13 +480,13 @@ App.SecExp.edicts = function() {
 		let showFS = 0;
 		for (const [name, detail] of data) {
 			if (["Immigration limits", "Open Borders"].includes(name) && !r.includes(name)) {
-				App.UI.DOM.appendNewElement("h1", c, "Immigration:", "underline");
+				App.UI.DOM.appendNewElement("h2", c, "Immigration");
 				r.push(name);
 			} else if (name === "Weapons Law" && !r.includes(name)) {
-				App.UI.DOM.appendNewElement("h1", c, "Weapons:", "underline");
+				App.UI.DOM.appendNewElement("h2", c, "Weapons");
 				r.push(name);
 			} else if (V.FSAnnounced && ["traditions", "Teachings"].includes(name) && !showFS) {
-				App.UI.DOM.appendNewElement("h1", c, "Future Societies:", "underline");
+				App.UI.DOM.appendNewElement("h2", c, "Future Societies");
 				showFS = 1;
 			}
 			App.UI.DOM.appendNewElement("p", c, genMenu(name, detail));
@@ -956,6 +956,7 @@ App.SecExp.edicts = function() {
 
 	const count = (x) => V.SecExp[x].victories + V.SecExp[x].losses;
 	const node = new DocumentFragment();
+	App.UI.DOM.appendNewElement("h1", node, `Edicts`);
 	App.UI.DOM.appendNewElement("div", node, `Passing any edict will cost ${cashFormat(5000)} and some authority. More will become available as the arcology develops.`, "note");
 	const tabBar = new App.UI.Tabs.TabBar("SecExpEdicts");
 	tabBar.addTab("Society", "Society", Society());
diff --git a/src/Mods/SecExp/js/reportingRelatedFunctions.js b/src/Mods/SecExp/js/reportingRelatedFunctions.js
index 454295ed7cc..e477ff7aaf3 100644
--- a/src/Mods/SecExp/js/reportingRelatedFunctions.js
+++ b/src/Mods/SecExp/js/reportingRelatedFunctions.js
@@ -1006,12 +1006,12 @@ App.SecExp.upkeep = (function() {
 
 /** Reports changes to the supplied unit's loyalty.
  * @param {FC.SecExp.PlayerHumanUnitData} input the unit type to be checked.
- * @param {FC.SecExp.PlayerHumanUnitTypeModHuman} type
  * @returns {HTMLDivElement}
  */
-App.SecExp.humanLoyaltyChanges = function(input, type) {
+App.SecExp.humanLoyaltyChanges = function(input) {
 	let loyaltyChange = 0;
 	let el = document.createElement("div");
+	const type = App.SecExp.unit.checkID(input.ID);
 
 	el.append(`${input.platoonName}: `);
 	if (V.SecExp.buildings.barracks && V.SecExp.buildings.barracks.loyaltyMod >= 1) {
diff --git a/src/Mods/SecExp/js/securityReport.js b/src/Mods/SecExp/js/securityReport.js
index ca7f03a1bf6..2cb3922fcbf 100644
--- a/src/Mods/SecExp/js/securityReport.js
+++ b/src/Mods/SecExp/js/securityReport.js
@@ -453,7 +453,7 @@ App.SecExp.securityReport = function() {
 			V.SecExp.units.mercs.free = Math.clamp(V.SecExp.units.mercs.free, 0, 2000);
 		}
 
-		if (activeUnits > 0) { // loyalty and training
+		if (activeUnits > 0 && App.SecExp.unit.squads("human").length > 0) { // loyalty and training
 			for (const squad of App.SecExp.unit.squads("human")) {
 				r.push(App.SecExp.humanLoyaltyChanges(squad));
 			}
diff --git a/src/arcologyBuilding/ManageArcology.js b/src/arcologyBuilding/ManageArcology.js
index 0544bea99de..92a91074b52 100644
--- a/src/arcologyBuilding/ManageArcology.js
+++ b/src/arcologyBuilding/ManageArcology.js
@@ -218,8 +218,8 @@ App.UI.manageArcology = function() {
 		App.UI.DOM.appendNewElement("div", node, `The next major upgrade needed is an improvement of the arcology's electrical transmission lines to make efficient use of the additional power from the solar apron. This upgrade will cost ${cashFormat(arcUpgradeCost(50000))}.`, "note");
 		node.append(applyArcUpgrade("Upgrade transmission lines", "grid", 50000));
 	} else {
-		App.UI.DOM.appendNewElement("div", node, "The arcology's public areas are fully upgraded.", ["note", "indent"]);
-		App.UI.DOM.appendNewElement("div", node, App.Arcology.upgrades(V.building), "indent");
+		App.UI.DOM.appendNewElement("div", node, "The arcology's public areas are fully upgraded.");
+		App.UI.DOM.appendNewElement("div", node, App.Arcology.upgrades(V.building));
 	}
 
 	r = [];
@@ -230,16 +230,17 @@ App.UI.manageArcology = function() {
 		} else {
 			r.push(App.UI.DOM.makeElement("span", `concerned that this measure has not been taken already.`, "noteworthy"));
 		}
-		App.UI.DOM.appendNewElement("div", node, r.join(" "));
-		App.UI.DOM.appendNewElement("span", node, applyArcUpgrade("Apply weather cladding", "weatherCladding", 50000));
+		r.push(App.UI.DOM.makeElement("div", applyArcUpgrade("Apply weather cladding", "weatherCladding", 50000)));
 	} else {
 		r.push(`The arcology's exterior is jacketed with ${V.weatherCladding === 1 ? "unsightly but sturdy" : "gorgeously sculpted and fully functional"} weather cladding.`);
 		if (V.weatherCladding === 1 && V.building.sections.length > 0) {
-			r.push(`Your arcology is so prosperous that remodeling the cladding into something beautiful is within the realm of possibility. This massive project will cost ${cashFormat(arcUpgradeCost(3500000))} and without a doubt render your arcology one of the wonders of the world.`);
-			App.UI.DOM.appendNewElement("div", node, r.join(" "));
-			App.UI.DOM.appendNewElement("span", node, applyArcUpgrade("Remodel weather cladding", "weatherCladding", 3500000));
+			r.push(
+				`Your arcology is so prosperous that remodeling the cladding into something beautiful is within the realm of possibility. This massive project will cost ${cashFormat(arcUpgradeCost(3500000))} and without a doubt render your arcology one of the wonders of the world.`,
+				App.UI.DOM.makeElement("div", applyArcUpgrade("Remodel weather cladding", "weatherCladding", 3500000))
+			);
 		}
 	}
+	App.Events.addNode(node, r, "div");
 	App.UI.DOM.appendNewElement("div", node, "");
 
 	if (V.FCTV.receiver > -1 && !V.FCTV.weekEnabled) {
@@ -259,7 +260,7 @@ App.UI.manageArcology = function() {
 		} else if (V.FCTV.receiver === 1) {
 			r.push("Low viewership rates amongst your citizens limits the impact of FCTV on your societal goals.");
 		}
-		App.UI.DOM.appendNewElement("div", node, r.join(" "), "indent");
+		App.UI.DOM.appendNewElement("div", node, r.join(" "));
 	}
 	if (V.PC.skill.engineering >= 100 || V.PC.career === "arcology owner") {
 		node.append("Arcology upgrades are less expensive due to your ",
@@ -268,7 +269,6 @@ App.UI.manageArcology = function() {
 	}
 
 	if (V.secExpEnabled === 0) {
-		r = [];
 		if (V.weatherAwareness > 0) {
 			if (V.antiWeatherFreeze === 0) {
 				node.append("The extreme weather hurts your arcology's ability to function. Reinforcing your passenger terminals increase the weather range at which they can operate.");
@@ -417,9 +417,7 @@ App.UI.manageArcology = function() {
 
 	App.UI.DOM.appendNewElement("h2", node, "Slaves");
 	r = [];
-	r.push(`Your slaves have participated in approximately ${num(V.oralTotal + V.vaginalTotal+ V.analTotal)} sexual encounters: ${num(V.oralTotal)} primarily oral, ${num(V.vaginalTotal)} vanilla, ${num(V.mammaryTotal)} mammary, ${num(V.analTotal)} anal, and ${num(V.penetrativeTotal)} with the slave penetrating another. They have produced about ${num(V.milkTotal)} liters of marketable milk,`);
-	r.push(`${V.seeDicks !== 0 ? `about ${num(V.cumTotal)} deciliters of marketable cum,` : ``}`);
-	r.push(`and have given birth ${num(V.birthsTotal)} times.`);
+	r.push(`Your slaves have participated in approximately ${num(V.oralTotal + V.vaginalTotal+ V.analTotal)} sexual encounters: ${num(V.oralTotal)} primarily oral, ${num(V.vaginalTotal)} vanilla, ${num(V.mammaryTotal)} mammary, ${num(V.analTotal)} anal, and ${num(V.penetrativeTotal)} with the slave penetrating another. They have produced about ${num(V.milkTotal)} liters of marketable milk, ${V.seeDicks !== 0 ? `about ${num(V.cumTotal)} deciliters of marketable cum,` : ``} and have given birth ${num(V.birthsTotal)} times.`);
 	if (V.abortionsTotal > 0 && V.miscarriagesTotal > 0) {
 		r.push(`They have had a total of ${num(V.abortionsTotal)} abortions and ${num(V.miscarriagesTotal)} miscarriages.`);
 	} else if (V.abortionsTotal > 0) {
@@ -427,13 +425,13 @@ App.UI.manageArcology = function() {
 	} else if (V.miscarriagesTotal > 0) {
 		r.push(`They have had a total of ${num(V.miscarriagesTotal)} miscarriages.`);
 	}
-	if (V.fuckdollsSold > 0) {
+	if (V.fuckdollsSold > 0) { // TODO: This never increases.
 		r.push(`${V.fuckdollsSold} mindbroken arcade slaves have been converted into Fuckdolls and sold.`);
 	}
 	App.UI.DOM.appendNewElement("p", node, r.join(" "), "indent");
 
 	if (V.pitFightsTotal > 0 && V.pitKillsTotal > 0) {
-		App.UI.DOM.appendNewElement("p", node, `${arcName} has hosted ${numberWithPluralOne(V.pitFightsTotal, "pit fight")}, and ${numberWithPluralOne(V.pitKillsTotal, "slave")} slaves have died in your pit.`, "indent");
+		App.UI.DOM.appendNewElement("p", node, `${arcName} has hosted ${numberWithPluralOne(V.pitFightsTotal, "pit fight")}, and ${numberWithPluralOne(V.pitKillsTotal, "slave")} slaves ${V.pitKillsTotal === 1 ? `has` : `have`} died in your pit.`, "indent");
 	} else if (V.pitFightsTotal > 0) {
 		App.UI.DOM.appendNewElement("p", node, `${arcName} has hosted ${numberWithPluralOne(V.pitFightsTotal, "pit fight")}.`, "indent");
 	}
@@ -446,11 +444,7 @@ App.UI.manageArcology = function() {
 		App.UI.DOM.appendNewElement("h2", node, "Military");
 		r = [];
 
-		r.push(`Your army counts ${num(App.SecExp.unit.squads("human").reduce((acc, s) => acc + s.troops, 0) + SF)} total soldiers`);
-		if (V.SF.Toggle && V.SF.Active >= 1) {
-			r.push(`of which ${num(V.SF.ArmySize)} under the special force command and the rest under your direct control`);
-		}
-		r.push(r.pop() + ".");
+		r.push(`Your army counts ${num(App.SecExp.unit.squads("human").reduce((acc, s) => acc + s.troops, 0) + SF)} total soldiers${(V.SF.Toggle && V.SF.Active >= 1) ? ` of which ${num(V.SF.ArmySize)} under the special force command and the rest under your direct control` : ``}.`);
 		if (V.SecExp.settings.battle.enabled === 1 && count('battles') > 0) {
 			r.push(`Your troops were involved in ${num(count('battles'))} battles of which ${num(V.SecExp.battles.major)} were major engagements.`);
 			r.push("You won");
diff --git a/src/arcologyBuilding/presets.js b/src/arcologyBuilding/presets.js
index bf6ef7c7012..58de2807953 100644
--- a/src/arcologyBuilding/presets.js
+++ b/src/arcologyBuilding/presets.js
@@ -309,7 +309,7 @@ App.Arcology.upgrades = function(building) {
 	}
 
 	if (count === 0) {
-		return App.UI.DOM.makeElement("span", "The arcology structure is fully upgraded.", "note");
+		return App.UI.DOM.makeElement("span", "The arcology structure is fully upgraded.");
 	} else {
 		if (count === 1) {
 			outerDiv.prepend("The next major upgrade is...");
diff --git a/src/art/vector/VectorArtJS.js b/src/art/vector/VectorArtJS.js
index 972d206f27b..42f58dd8940 100644
--- a/src/art/vector/VectorArtJS.js
+++ b/src/art/vector/VectorArtJS.js
@@ -539,7 +539,7 @@ App.Art.vectorArtElement = (function() {
 		ArtVectorTorso();
 		ArtVectorPussy();
 		ArtVectorPubicHair();
-		if (slave.vaginaPiercing !== 0 || slave.clitPiercing !== 0) {
+		if (slave.piercing.vagina.weight !== 0 || slave.piercing.genitals.weight !== 0) {
 			ArtVectorPussyPiercings();
 		}
 		ArtVectorChastityBelt();
@@ -1326,9 +1326,9 @@ App.Art.vectorArtElement = (function() {
 	function ArtVectorBelly() {
 		if (slave.belly >= 2000) {
 			/* TODO: add check in penis control. do not draw penis atop belly if art_belly_scale_factor > 1. */
-			if (slave.navelPiercing === 1) {
+			if (slave.piercing.navel.weight === 1) {
 				svgQueue.add("Art_Vector_Belly_Pregnant_Piercing");
-			} else if (slave.navelPiercing === 2) {
+			} else if (slave.piercing.navel.weight === 2) {
 				svgQueue.add("Art_Vector_Belly_Pregnant_Piercing_Heavy");
 			} else {
 				svgQueue.add("Art_Vector_Belly");
@@ -1407,9 +1407,9 @@ App.Art.vectorArtElement = (function() {
 		}
 		/* belly piercings for flat bellies */
 		if (slave.belly === 0) {
-			if (slave.navelPiercing === 1) {
+			if (slave.piercing.navel.weight === 1) {
 				svgQueue.add("Art_Vector_Belly_Piercing");
-			} else if (slave.navelPiercing === 2) {
+			} else if (slave.piercing.navel.weight === 2) {
 				svgQueue.add("Art_Vector_Belly_Piercing_Heavy");
 			}
 		}
@@ -1563,7 +1563,7 @@ App.Art.vectorArtElement = (function() {
 					svgQueue.add(`Art_Vector_Boob_Outfit_${clothing2artSuffix(slave.clothes)}`);
 			}
 		}
-		if (V.showBodyMods === 1 && (slave.nipplesPiercing > 0 || slave.areolaePiercing > 0)) {
+		if (V.showBodyMods === 1 && (slave.piercing.nipple.weight > 0 || slave.piercing.areola.weight > 0)) {
 			/* shows nipple piercings in game when selected; piercings will show on the outfits listed below */
 			switch (slave.clothes) {
 				case "a bimbo outfit":
@@ -1601,15 +1601,15 @@ App.Art.vectorArtElement = (function() {
 				case "sport shorts":
 				case "striped panties":
 				case "uncomfortable straps":
-					if (slave.nipplesPiercing === 1) {
+					if (slave.piercing.nipple.weight === 1) {
 						svgQueue.add("Art_Vector_Boob_Piercing");
-					} else if (slave.nipplesPiercing > 1) {
+					} else if (slave.piercing.nipple.weight > 1) {
 						svgQueue.add("Art_Vector_Boob_Piercing_Heavy");
 					}
 
-					if (slave.areolaePiercing === 1) {
+					if (slave.piercing.areola.weight === 1) {
 						svgQueue.add("Art_Vector_Boob_Areola_Piercing");
-					} else if (slave.areolaePiercing > 1) {
+					} else if (slave.piercing.areola.weight > 1) {
 						svgQueue.add("Art_Vector_Boob_Areola_Piercingheavy");
 					}
 			}
@@ -2664,21 +2664,21 @@ App.Art.vectorArtElement = (function() {
 		}
 		/* END FACIAL APPEARANCE */
 
-		if (slave.eyebrowPiercing === 1) {
+		if (slave.piercing.eyebrow.weight === 1) {
 			svgQueue.add("Art_Vector_Eyebrow_Light");
-		} else if (slave.eyebrowPiercing === 2) {
+		} else if (slave.piercing.eyebrow.weight === 2) {
 			svgQueue.add("Art_Vector_Eyebrow_Heavy");
 		}
 
-		if (slave.nosePiercing === 1) {
+		if (slave.piercing.nose.weight === 1) {
 			svgQueue.add("Art_Vector_Nose_Light");
-		} else if (slave.nosePiercing === 2) {
+		} else if (slave.piercing.nose.weight === 2) {
 			svgQueue.add("Art_Vector_Nose_Heavy");
 		}
 
-		if (slave.lipsPiercing === 1) {
+		if (slave.piercing.lips.weight === 1) {
 			svgQueue.add("Art_Vector_Lip_Light");
-		} else if (slave.lipsPiercing === 2) {
+		} else if (slave.piercing.lips.weight === 2) {
 			svgQueue.add("Art_Vector_Lip_Heavy");
 		}
 
@@ -2917,19 +2917,18 @@ App.Art.vectorArtElement = (function() {
 			case "slutty jewelry":
 			case "uncomfortable straps":
 			case "Western clothing":
-				/* piercinglevel = 1, Light; piercinglevel = 2, Heavy; piercinglevel = 3, Smart; piercinglevel = 0, None */
-				if (slave.vaginaPiercing === 1) {
+				if (slave.piercing.vagina.weight === 1) {
 					svgQueue.add("Art_Vector_Pussy_Piercing");
-				} else if (slave.vaginaPiercing === 2) {
+				} else if (slave.piercing.vagina.weight === 2) {
 					svgQueue.add("Art_Vector_Pussy_Piercing_Heavy");
 				}
 
-				if (slave.clitPiercing === 1) {
+				if (slave.piercing.genitals.smart === true) {
+					svgQueue.add("Art_Vector_Clit_Piercing_Smart");
+				} else if (slave.piercing.genitals.weight === 1) {
 					svgQueue.add("Art_Vector_Clit_Piercing");
-				} else if (slave.clitPiercing === 2) {
+				} else if (slave.piercing.genitals.weight === 2) {
 					svgQueue.add("Art_Vector_Clit_Piercing_Heavy");
-				} else if (slave.clitPiercing === 3) {
-					svgQueue.add("Art_Vector_Clit_Piercing_Smart");
 				}
 		}
 	}
@@ -3208,17 +3207,17 @@ App.Art.legacyVectorArtElement = function() {
 		/* Vagina */
 		if (slave.vagina >= 0) {
 			addSkinImg(res, "vagina", skinFilter);
-			if (slave.clitPiercing === 1) {
+			if (slave.piercing.genitals.smart === true) {
+				addImg(res, "body/addon/clit piercing smart");
+			} else if (slave.piercing.genitals.weight === 1) {
 				addImg(res, "body/addon/clit piercing");
-			} else if (slave.clitPiercing === 2) {
+			} else if (slave.piercing.genitals.weight === 2) {
 				addImg(res, "body/addon/clit piercing heavy");
-			} else if (slave.clitPiercing === 3) {
-				addImg(res, "body/addon/clit piercing smart");
 			}
 
-			if (slave.vaginaPiercing === 1) {
+			if (slave.piercing.vagina.weight === 1) {
 				addImg(res, "body/addon/pussy piercing");
-			} else if (slave.vaginaPiercing === 2) {
+			} else if (slave.piercing.vagina.weight === 2) {
 				addImg(res, "body/addon/pussy piercing heavy");
 			}
 		}
@@ -3274,25 +3273,25 @@ App.Art.legacyVectorArtElement = function() {
 		/* if pregnant or has a belly */
 		if (slave.belly >= 5000) {
 			addSkinImg(res, "preg belly 5000", skinFilter);
-			if (slave.navelPiercing >= 1) { /* Navel Piercing*/
+			if (slave.piercing.navel.weight >= 1) { /* Navel Piercing*/
 				addImg(res, "body/addon/preg navel piercing");
 			}
-			if (slave.navelPiercing === 2) {
+			if (slave.piercing.navel.weight === 2) {
 				addImg(res, "body/addon/preg navel piercing heavy");
 			}
 		} else if (slave.belly <= -100) { /* condition is currently reversed until the vector can be fixed */
 			addSkinImg(res, "preg belly 100", skinFilter);
 			/*
-			if (slave.navelPiercing >= 1)/Navel Piercing/
+			if (slave.piercing.navel.weight >= 1)/Navel Piercing/
 				r += `<img class='paperdoll' src=${filePath}/body/addon/preg navel piercing.svg'/>`;
-			if (slave.navelPiercing === 2)
+			if (slave.piercing.navel.weight === 2)
 				r += `<img class='paperdoll' src=${filePath}/body/addon/preg navel piercing heavy.svg'/>`;
 			*/
 		} else {
-			if (slave.navelPiercing >= 1) { /* Navel Piercing*/
+			if (slave.piercing.navel.weight >= 1) { /* Navel Piercing*/
 				addImg(res, "body/addon/navel piercing");
 			}
-			if (slave.navelPiercing === 2) {
+			if (slave.piercing.navel.weight === 2) {
 				addImg(res, "body/addon/navel piercing heavy");
 			}
 		}
@@ -3425,13 +3424,13 @@ App.Art.legacyVectorArtElement = function() {
 		}
 
 		/* piercings */
-		if (slave.nipplesPiercing === 1) {
+		if (slave.piercing.nipple.weight === 1) {
 			addImg(res, `body/addon/boob ${boobSize} piercing`);
-		} else if (slave.nipplesPiercing === 2) {
+		} else if (slave.piercing.nipple.weight === 2) {
 			addImg(res, `body/addon/boob ${boobSize} piercing heavy`);
 		}
 
-		if (slave.areolaePiercing === 1) {
+		if (slave.piercing.areola.weight === 1) {
 			addImg(res, `body/addon/boob ${boobSize} areola piercing`);
 		}
 
diff --git a/src/art/vector_revamp/vectorRevampedArtControl.js b/src/art/vector_revamp/vectorRevampedArtControl.js
index 7c8414a746d..1095c10bd2f 100644
--- a/src/art/vector_revamp/vectorRevampedArtControl.js
+++ b/src/art/vector_revamp/vectorRevampedArtControl.js
@@ -169,7 +169,7 @@ class ArtStyleControl {
 	}
 
 	applySmartPiercingColor() {
-		if (this.artSlave.clitPiercing === 3) {
+		if (this.artSlave.piercing.genitals.smart === true) {
 			let setting = this.artSlave.clitSetting.replace(/\s+/g, '');
 			let colors = {
 				off: "#1A3F19",
@@ -1458,7 +1458,7 @@ class ClothingControl {
 		let col = this.randomItem(this.colorsUnderwear);
 		let pri_opa = 0.7+this.randomNumber(6751981)*0.3;
 		let strap = this.braStrapOpacity();
-		let pierc = this.slave.nipplesPiercing !== 2 && this.slave.areolaePiercing !== 2;
+		let pierc = this.slave.piercing.nipple.weight !== 2 && this.slave.piercing.areola.weight !== 2;
 		if (lace === 1) {
 			pri_opa = 0.5;
 		}
@@ -1479,7 +1479,7 @@ class ClothingControl {
 	}
 	get croptop() {
 		this.piecewiseClothing.croptop = true;
-		let pierc = this.slave.nipplesPiercing !== 2 && this.slave.areolaePiercing !== 2;
+		let pierc = this.slave.piercing.nipple.weight !== 2 && this.slave.piercing.areola.weight !== 2;
 		return {
 			bodySettings: {
 				showNipplesPiercings: pierc
@@ -2060,7 +2060,7 @@ class ClothingControl {
 		let col = this.randomItem(this.colorsSport, 77678);
 		let acc_col = this.randomItem(['#222222', '#DDDDDD'], 77678222);
 		let strap = this.braStrapOpacity();
-		let pierc = this.slave.nipplesPiercing !== 2 && this.slave.areolaePiercing !== 2;
+		let pierc = this.slave.piercing.nipple.weight !== 2 && this.slave.piercing.areola.weight !== 2;
 		return {
 			bodySettings: {
 				showNipplesPiercings: pierc
@@ -2169,7 +2169,7 @@ class ClothingControl {
 		let bow = this.randomItem([0, 1], 263);
 		let col = this.randomItem(this.colorsStripes, 7774737);
 		let bow_col = this.randomItem(this.colorsStripes.filter(a => a !== col), 7774737269);
-		let pierc = this.slave.nipplesPiercing !== 2 && this.slave.areolaePiercing !== 2;
+		let pierc = this.slave.piercing.nipple.weight !== 2 && this.slave.piercing.areola.weight !== 2;
 		let strap = this.braStrapOpacity();
 		return {
 			bodySettings: {
@@ -2879,18 +2879,18 @@ class RevampedArtControl {
 			return result;
 		}
 
-		if (this.artSlave.vaginaPiercing === 1) {
+		if (this.artSlave.piercing.vagina.weight === 1) {
 			result.push("Art_Vector_Revamp_Pussy_Piercing");
-		} else if (this.artSlave.vaginaPiercing === 2) {
+		} else if (this.artSlave.piercing.vagina.weight === 2) {
 			result.push("Art_Vector_Revamp_Pussy_Piercing_Heavy");
 		}
 
-		if (this.artSlave.clitPiercing === 1) {
+		if (this.artSlave.piercing.genitals.smart === true) {
+			result.push("Art_Vector_Revamp_Clit_Piercing_Smart");
+		} else if (this.artSlave.piercing.genitals.weight === 1) {
 			result.push("Art_Vector_Revamp_Clit_Piercing");
-		} else if (this.artSlave.clitPiercing === 2) {
+		} else if (this.artSlave.piercing.genitals.weight === 2) {
 			result.push("Art_Vector_Revamp_Clit_Piercing_Heavy");
-		} else if (this.artSlave.clitPiercing === 3) {
-			result.push("Art_Vector_Revamp_Clit_Piercing_Smart");
 		}
 
 		return result;
@@ -3290,21 +3290,21 @@ class RevampedArtControl {
 			result.push(`Art_Vector_Revamp_Belly_${this.bellyLevel}`);
 
 			if (this.showBellyPiercings) {
-				if (this.artSlave.navelPiercing >= 1) {
+				if (this.artSlave.piercing.navel.weight >= 1) {
 					result.push(`Art_Vector_Revamp_Belly_${this.bellyLevel}_Piercing`);
 				}
 
-				if (this.artSlave.navelPiercing === 2) {
+				if (this.artSlave.piercing.navel.weight === 2) {
 					result.push(`Art_Vector_Revamp_Belly_${this.bellyLevel}_Piercing_Heavy`);
 				}
 			}
 		} else {
 			if (this.showBellyPiercings) {
-				if (this.artSlave.navelPiercing >= 1) {
+				if (this.artSlave.piercing.navel.weight >= 1) {
 					result.push("Art_Vector_Revamp_Navel_Piercing");
 				}
 
-				if (this.artSlave.navelPiercing === 2) {
+				if (this.artSlave.piercing.navel.weight === 2) {
 					result.push("Art_Vector_Revamp_Navel_Piercing_Heavy");
 				}
 			}
@@ -3351,9 +3351,9 @@ class RevampedArtControl {
 				return result;
 			}
 
-			if (this.artSlave.dickPiercing === 1) {
+			if (this.artSlave.piercing.dick.weight === 1) {
 				result.push(`Art_Vector_Revamp_Penis_${penisSize}_Piercing`);
-			} else if (this.artSlave.dickPiercing === 2) {
+			} else if (this.artSlave.piercing.dick.weight === 2) {
 				result.push(`Art_Vector_Revamp_Penis_${penisSize}_Piercing_Heavy`);
 			}
 		} else {
@@ -3455,13 +3455,13 @@ class RevampedArtControl {
 				size = "Huge";
 			}
 
-			if (this.artSlave.nipplesPiercing === 1) {
+			if (this.artSlave.piercing.nipple.weight === 1) {
 				if (this.artSlave.boobs < 300) {
 					result.push("Art_Vector_Revamp_Boob_None_Piercing");
 				} else {
 					result.push(`Art_Vector_Revamp_Boob_${size}_Piercing`);
 				}
-			} else if (this.artSlave.nipplesPiercing === 2) {
+			} else if (this.artSlave.piercing.nipple.weight === 2) {
 				if (this.artSlave.boobs < 300) {
 					result.push("Art_Vector_Revamp_Boob_None_Piercing_Heavy");
 				} else {
@@ -3469,13 +3469,13 @@ class RevampedArtControl {
 				}
 			}
 
-			if (this.artSlave.areolaePiercing === 1) {
+			if (this.artSlave.piercing.areola.weight === 1) {
 				if (this.artSlave.boobs < 300) {
 					result.push("Art_Vector_Revamp_Boob_None_Areola_Piercing");
 				} else {
 					result.push(`Art_Vector_Revamp_Boob_${size}_Areola_Piercing`);
 				}
-			} else if (this.artSlave.areolaePiercing === 2) {
+			} else if (this.artSlave.piercing.areola.weight === 2) {
 				if (this.artSlave.boobs < 300) {
 					result.push("Art_Vector_Revamp_Boob_None_Areola_Piercing_Heavy");
 				} else {
@@ -3924,15 +3924,15 @@ class RevampedArtControl {
 			return result;
 		}
 
-		if (this.artSlave.earPiercing === 1) {
+		if (this.artSlave.piercing.ear.weight === 1) {
 			result.push("Art_Vector_Revamp_Head_Ear_Piercing");
-		} else if (this.artSlave.earPiercing === 2) {
+		} else if (this.artSlave.piercing.ear.weight === 2) {
 			result.push("Art_Vector_Revamp_Head_Ear_Piercing_Heavy");
 		}
 
-		if (this.artSlave.nosePiercing === 1) {
+		if (this.artSlave.piercing.nose.weight === 1) {
 			result.push("Art_Vector_Revamp_Head_Nose_Piercing");
-		} else if (this.artSlave.nosePiercing === 2) {
+		} else if (this.artSlave.piercing.nose.weight === 2) {
 			result.push("Art_Vector_Revamp_Head_Nose_Piercing_Heavy");
 		}
 
@@ -3951,9 +3951,9 @@ class RevampedArtControl {
 			result.push("Art_Vector_Revamp_Eyes_Happy_Highlights");
 
 			if (this.showHeadPiercings) {
-				if (this.artSlave.eyebrowPiercing === 1) {
+				if (this.artSlave.piercing.eyebrow.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Happy_Piercing");
-				} else if (this.artSlave.eyebrowPiercing === 2) {
+				} else if (this.artSlave.piercing.eyebrow.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Happy_Piercing_Heavy");
 				}
 			}
@@ -3962,9 +3962,9 @@ class RevampedArtControl {
 			result.push("Art_Vector_Revamp_Eyes_Shy_Highlights");
 
 			if (this.showHeadPiercings) {
-				if (this.artSlave.eyebrowPiercing === 1) {
+				if (this.artSlave.piercing.eyebrow.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Shy_Piercing");
-				} else if (this.artSlave.eyebrowPiercing === 2) {
+				} else if (this.artSlave.piercing.eyebrow.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Shy_Piercing_Heavy");
 				}
 			}
@@ -3972,9 +3972,9 @@ class RevampedArtControl {
 			result.push("Art_Vector_Revamp_Eyes_Closed");
 
 			if (this.showHeadPiercings) {
-				if (this.artSlave.eyebrowPiercing === 1) {
+				if (this.artSlave.piercing.eyebrow.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Closed_Piercing");
-				} else if (this.artSlave.eyebrowPiercing === 2) {
+				} else if (this.artSlave.piercing.eyebrow.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Closed_Piercing_Heavy");
 				}
 			}
@@ -3982,9 +3982,9 @@ class RevampedArtControl {
 			result.push("Art_Vector_Revamp_Eyes_Angry");
 			result.push("Art_Vector_Revamp_Eyes_Angry_Highlights");
 			if (this.showHeadPiercings) {
-				if (this.artSlave.eyebrowPiercing === 1) {
+				if (this.artSlave.piercing.eyebrow.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Angry_Piercing");
-				} else if (this.artSlave.eyebrowPiercing === 2) {
+				} else if (this.artSlave.piercing.eyebrow.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Eyebrow_Angry_Piercing_Heavy");
 				}
 			}
@@ -4020,9 +4020,9 @@ class RevampedArtControl {
 			result.push(`Art_Vector_Revamp_Mouth_Happy_${lipsSize}`);
 
 			if (this.showHeadPiercings) {
-				if (this.artSlave.lipsPiercing === 1) {
+				if (this.artSlave.piercing.lips.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Mouth_Happy_Piercing");
-				} else if (this.artSlave.lipsPiercing === 2) {
+				} else if (this.artSlave.piercing.lips.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Mouth_Happy_Piercing_Heavy");
 				}
 			}
@@ -4031,9 +4031,9 @@ class RevampedArtControl {
 			result.push(`Art_Vector_Revamp_Mouth_Angry_${lipsSize}`);
 
 			if (this.showHeadPiercings) {
-				if (this.artSlave.lipsPiercing === 1) {
+				if (this.artSlave.piercing.lips.weight === 1) {
 					result.push("Art_Vector_Revamp_Head_Mouth_Angry_Piercing");
-				} else if (this.artSlave.lipsPiercing === 2) {
+				} else if (this.artSlave.piercing.lips.weight === 2) {
 					result.push("Art_Vector_Revamp_Head_Mouth_Angry_Piercing_Heavy");
 				}
 			}
diff --git a/src/budget/budget.js b/src/budget/budget.js
index abd3ede0152..ddac3276940 100644
--- a/src/budget/budget.js
+++ b/src/budget/budget.js
@@ -126,7 +126,7 @@ App.Budget.table = function(budgetType) {
 			generateRowCategory("Dairy Operation", "dairy"),
 			generateRowCategory("Dairy Milkmaid", "slaveAssignmentMilkmaid"),
 			generateRowCategory("Dairy Cows", "slaveAssignmentDairy"),
-			generateRowCategory("Dairy Cows", "slaveAssignmentDairyVign")
+			generateRowCategory("Dairy CowsVign", "slaveAssignmentDairyVign")
 		]);
 
 		// FARMYARD
@@ -376,7 +376,7 @@ App.Budget.table = function(budgetType) {
 		const row = header.insertRow();
 		const cell = row.insertCell();
 		let pent = document.createElement("h1");
-		pent.textContent = "Budget Overview";
+		pent.textContent = (budgetType === "cash") ? "Budget Overview" : "Reputation Overview";
 		cell.appendChild(pent);
 
 		for (let column of ["Income", "Expense", "Totals"]) {
@@ -388,7 +388,7 @@ App.Budget.table = function(budgetType) {
 
 	function generateSummary() {
 		let row; let cell;
-		createSectionHeader("Budget Report");
+		createSectionHeader("Summary Report");
 
 		row = table.insertRow();
 		cell = row.insertCell();
@@ -477,7 +477,7 @@ App.Budget.table = function(budgetType) {
 			return row;
 		}
 
-		if (V[income][category] || V[expenses][category] || V.showAllEntries.costsBudget) {
+		if (V[income][category] || V[expenses][category] || V.showAllEntries[budgetType === "cash" ? "costsBudget" : "repBudget"]) {
 			const row = table.insertRow();
 			let cell = row.insertCell();
 			cell.append(node);
@@ -494,11 +494,11 @@ App.Budget.table = function(budgetType) {
 
 	function generateRowGroup(title, name) {
 		/** @type {string[]} */
-		const members = CategoryAssociatedGroup[name];
+		const members = (budgetType === "cash" ? CategoryAssociatedGroup[name] : CategoryAssociatedGroupRep[name]);
 		const groupIn = members.map((k) => V[income][k]).reduce((acc, cur) => acc + cur);
 		const groupEx = members.map((k) => V[expenses][k]).reduce((acc, cur) => acc + cur);
 
-		if (groupIn || groupEx || V.showAllEntries.costsBudget) {
+		if (groupIn || groupEx || V.showAllEntries[budgetType === "cash" ? "costsBudget" : "repBudget"]) {
 			const row = table.insertRow();
 			let cell = row.insertCell();
 			const headline = document.createElement('h3');
diff --git a/src/budget/repBudget.js b/src/budget/repBudget.js
index f899c07f515..d7df45658b2 100644
--- a/src/budget/repBudget.js
+++ b/src/budget/repBudget.js
@@ -5,6 +5,8 @@
 App.Budget.rep = function() {
 	const f = new DocumentFragment();
 
+	// App.UI.DOM.appendNewElement("h1", f, `Reputation Budget`);
+
 	f.append(intro());
 	f.append(settings());
 	// Table of Totals
diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js
index dd43ca9def6..9de73c1b1f5 100644
--- a/src/data/backwardsCompatibility/datatypeCleanup.js
+++ b/src/data/backwardsCompatibility/datatypeCleanup.js
@@ -469,7 +469,7 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() {
 		slaveBellyDatatypeCleanup(slave);
 		slaveGenitaliaDatatypeCleanup(slave);
 		slaveImplantsDatatypeCleanup(slave);
-		slavePiercingsDatatypeCleanup(slave);
+		App.Update.slavePiercingsDatatypeCleanup(slave);
 		slaveTattooDatatypeCleanup(slave);
 		slaveCosmeticsDatatypeCleanup(slave);
 		slaveDietDatatypeCleanup(slave);
@@ -538,7 +538,7 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() {
 		slave.health.illness = Math.max(+slave.health.illness, 0) || 0;
 		slave.health.tired = Math.clamp(+slave.health.tired, 0, 100) || 0;
 		updateHealth(slave);
-		
+
 		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;
@@ -791,25 +791,6 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() {
 		slave.hipsImplant = Math.clamp(+slave.hipsImplant, -10, 10) || 0;
 	}
 
-	/**
-	 * @param {App.Entity.SlaveState} slave
-	 */
-	function slavePiercingsDatatypeCleanup(slave) {
-		slave.earPiercing = Math.clamp(+slave.earPiercing, 0, 2) || 0;
-		slave.nosePiercing = Math.clamp(+slave.nosePiercing, 0, 2) || 0;
-		slave.eyebrowPiercing = Math.clamp(+slave.eyebrowPiercing, 0, 2) || 0;
-		slave.lipsPiercing = Math.clamp(+slave.lipsPiercing, 0, 2) || 0;
-		slave.tonguePiercing = Math.clamp(+slave.tonguePiercing, 0, 2) || 0;
-		slave.nipplesPiercing = Math.clamp(+slave.nipplesPiercing, 0, 2) || 0;
-		slave.areolaePiercing = Math.clamp(+slave.areolaePiercing, 0, 2) || 0;
-		slave.corsetPiercing = Math.clamp(+slave.corsetPiercing, 0, 1) || 0;
-		slave.navelPiercing = Math.clamp(+slave.navelPiercing, 0, 2) || 0;
-		slave.clitPiercing = Math.clamp(+slave.clitPiercing, 0, 3) || 0;
-		slave.vaginaPiercing = Math.clamp(+slave.vaginaPiercing, 0, 2) || 0;
-		slave.dickPiercing = Math.clamp(+slave.dickPiercing, 0, 2) || 0;
-		slave.anusPiercing = Math.clamp(+slave.anusPiercing, 0, 2) || 0;
-	}
-
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 */
@@ -904,22 +885,16 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() {
 		if (typeof slave.buttplugAttachment !== "string") {
 			slave.buttplugAttachment = "none";
 		}
-		if (typeof slave.headAccessory !== "string") {
-			slave.headAccessory = "none";
-		}
-		if (typeof slave.rearAccessory !== "string") {
-			slave.rearAccessory = "none";
-		}
-		if (typeof slave.backAccessory !== "string") {
-			slave.backAccessory = "none";
-		}
 		if (typeof slave.faceAccessory !== "string") {
 			slave.faceAccessory = "none";
 		}
 		if (typeof slave.mouthAccessory !== "string") {
 			slave.mouthAccessory = "none";
 		}
-		switch(slave.collar) {
+		for (const acc of ["headAccessory", "rearAccessory", "backAccessory"]) {
+			delete slave[acc];
+		}
+		switch (slave.collar) {
 			case "porcelain mask":
 				slave.faceAccessory = slave.collar;
 				slave.collar = "none";
@@ -1229,6 +1204,7 @@ globalThis.PCDatatypeCleanup = (function PCDatatypeCleanup() {
 		PCBellyDatatypeCleanup(PC);
 		PCGenitaliaDatatypeCleanup(PC);
 		PCImplantsDatatypeCleanup(PC);
+		App.Update.slavePiercingsDatatypeCleanup(PC);
 		PCCosmeticsDatatypeCleanup(PC);
 		PCDietDatatypeCleanup(PC);
 		PCRelationDatatypeCleanup(PC);
@@ -2403,7 +2379,7 @@ App.Entity.Utils.RARuleDatatypeCleanup = function() {
 		if (typeof (set.abortion) === "string") {
 			set.abortion = [set.abortion];
 		}
-		switch(set.collar) {
+		switch (set.collar) {
 			case "porcelain mask":
 				set.faceAccessory = set.collar;
 				set.collar = null;
@@ -2447,6 +2423,31 @@ App.Entity.Utils.RARuleDatatypeCleanup = function() {
 			set.clothes = null;
 			set.choosesOwnClothes = 1;
 		}
+
+		const oldPiercings = new Map([
+			["nipple", "nipples"],
+			["areola", "areolae"],
+			["genitals", "clit"]
+		]);
+		if (set.piercing === undefined) {
+			set.piercing = new App.Entity.completePiercingState();
+			for (const piercing of Object.keys(App.Data.Piercings)) {
+				const oldPiercing = `${oldPiercings.get(piercing) || piercing}Piercing`; // the old variable names were sometimes plural and sometimes singular.  The new standard is to use singular when possible.
+				set.piercing[piercing].desc = null;
+				if (piercing === "gentials" && set.piercing[piercing].smart === undefined) {
+					set.piercing[piercing].smart = null;
+				}
+				if (set.hasOwnProperty(oldPiercing)) {
+					if (set[oldPiercing] === 3) { // 3 used to indicate a smart piercing.  We now track this on a separate property as a bool.
+						set.piercing[piercing].weight = 2;
+						set.piercing[piercing].smart = true;
+					} else {
+						set.piercing[piercing].weight = set[oldPiercing];
+					}
+					delete set[oldPiercing];
+				}
+			}
+		}
 	}
 }();
 
@@ -2652,3 +2653,32 @@ App.Entity.Utils.PCCheatCleanup = function() {
 	V.upgradeMultiplierTrade = upgradeMultiplier('trading');
 	V.HackingSkillMultiplier = upgradeMultiplier('hacking');
 };
+
+
+/**
+ * @param {FC.HumanState} slave
+ */
+App.Update.slavePiercingsDatatypeCleanup = function(slave) {
+	slave.piercing = slave.piercing || new App.Entity.completePiercingState();
+	const oldPiercings = new Map([
+		["nipple", "nipples"],
+		["areola", "areolae"],
+		["genitals", "clit"]
+	]);
+	for (const piercing in App.Data.Piercings) {
+		slave.piercing[piercing] = slave.piercing[piercing] || new App.Entity.piercingState();
+		const oldPiercing = `${oldPiercings.get(piercing) || piercing}Piercing`; // the old variable names were sometimes plural and sometimes singular.  The new standard is to use singular when possible.
+		if (App.Data.Piercings[piercing].smart) {
+			slave.piercing[piercing].smart = slave.piercing[piercing].smart || false;
+		}
+		if (slave.hasOwnProperty(oldPiercing)) {
+			if (slave[oldPiercing] === 3) { // 3 used to indicate a smart piercing.  We now track this on a separate property as a bool.
+				slave.piercing[piercing].weight = 2;
+				slave.piercing[piercing].smart = true;
+			} else if (slave[oldPiercing]) {
+				slave.piercing[piercing].weight = slave[oldPiercing];
+			}
+			delete slave[oldPiercing];
+		}
+	}
+};
diff --git a/src/data/backwardsCompatibility/updateSlaveObject.js b/src/data/backwardsCompatibility/updateSlaveObject.js
index 7ffeb5adeb4..4a3c7ab3a72 100644
--- a/src/data/backwardsCompatibility/updateSlaveObject.js
+++ b/src/data/backwardsCompatibility/updateSlaveObject.js
@@ -930,6 +930,7 @@ App.Update.Slave = function(slave, genepool = false) {
 	}
 
 	if (slave.areoleaPiercing !== undefined) { delete slave.areoleaPiercing; }
+
 	if (slave.pregControl === undefined) { slave.pregControl = "none"; }
 	if (slave.pregControl === "labor supressors") {
 		slave.pregControl = "labor suppressors";
diff --git a/src/descriptions/arcologyDescription.js b/src/descriptions/arcologyDescription.js
index ce20191ffd7..543be5efe68 100644
--- a/src/descriptions/arcologyDescription.js
+++ b/src/descriptions/arcologyDescription.js
@@ -93,7 +93,7 @@ App.Desc.playerArcology = function(lastElement) {
 		} else if (V.weatherToday.severity === 3 && V.weatherType === 4) {
 			buffer.push(`A cloud of corrupt, polluted miasma hangs over the arcology from the fires of industry roaring all around it. Many citizens have donned masks to walk outside today, hopefully free of the pollutive smog.`);
 		} else if (V.weatherToday.severity === 3 && V.weatherType === 5) {
-			buffer.push(`It's a freezing day outside today, and citizens are wearing thick fur jackets and dusters to protect themselves from the bitter cold. Snow bites at the exterior of the arcology, dusting everything in a fine white layer, and many citizens have retreating inside the escape the chill.`);
+			buffer.push(`It's a freezing day outside today, and citizens are wearing thick fur jackets and dusters to protect themselves from the bitter cold. Snow bites at the exterior of the arcology, dusting everything in a fine white layer, and many citizens have retreated inside to escape the chill.`);
 		} else if (V.weatherToday.severity === 3 && V.weatherType === 6) {
 			buffer.push(`The arcology rumbles with the dangerous instability of the earth underneath its feet. Every so often, the arcology shakes, but its powerful supporting beams keep it locked securely in place.`);
 		} else if (V.weatherToday.severity === 4 && V.weatherType === 1) {
diff --git a/src/descriptions/familySummaries.js b/src/descriptions/familySummaries.js
index b1e91f5f543..cc11db585a1 100644
--- a/src/descriptions/familySummaries.js
+++ b/src/descriptions/familySummaries.js
@@ -143,26 +143,26 @@ App.Desc.family = (function() {
 				if (jsDef(mi)) {
 					if ((jsDef(fi)) && mi === fi) {
 						if (V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].father) {
-							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You impregnated yourself with ${his} sole biological parent.`);
+							r.push(`${He} is <span class="lightgreen">your grandchild. You impregnated yourself with ${his} sole biological parent.</span>`);
 						} else if (V.PC.ID === V.slaves[mi].mother) {
-							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} sole biological parent.`);
+							r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} sole biological parent.</span>`);
 						} else if (V.PC.ID === V.slaves[fi].father) {
-							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} sole biological parent.`);
+							r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} sole biological parent.</span>`);
 						}
 					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to both of ${his} parents.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to both of ${his} parents.</span>`);
 					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].father && V.PC.ID === V.slaves[fi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered both of ${his} parents.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered both of ${his} parents.</span>`);
 					} else if (V.PC.ID === V.slaves[mi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} mother.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} mother.</span>`);
 					} else if (V.PC.ID === V.slaves[mi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} mother.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} mother.</span>`);
 					}
 				} else if (jsDef(fi)) {
 					if (V.PC.ID === V.slaves[fi].mother) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} father.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You gave birth to ${his} father.</span>`);
 					} else if (V.PC.ID === V.slaves[fi].father) {
-						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} father.`);
+						r.push(`${He} is <span class="lightgreen">your grandchild. You fathered ${his} father.</span>`);
 					}
 				}
 			} else {
@@ -198,11 +198,11 @@ App.Desc.family = (function() {
 			if (jsDef(pcMother)) {
 				if ((jsDef(pcFather)) && pcMother === pcFather) {
 					if (slave.ID === pcMother.mother && slave.ID === pcFather.father) {
-						r.push(`${He} is <span class="lightgreen">your sole grandparent.</span> ${He} impregnated ${himself} with your sole parent ${pcMother.slaveName} who in turn impregnated themselves with you.`);
+						r.push(`${He} is <span class="lightgreen">your sole grandparent. ${He} impregnated ${himself} with your sole parent ${pcMother.slaveName} who in turn impregnated themselves with you.</span>`);
 					} else if (slave.ID === pcMother.mother) {
-						r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to ${pcMother.slaveName} who in turn impregnated themselves with you.`);
+						r.push(`${He} is <span class="lightgreen">your sole grandmother. ${He} gave birth to ${pcMother.slaveName} who in turn impregnated themselves with you.</span>`);
 					} else if (slave.ID === pcFather.father) {
-						r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered ${pcFather.slaveName} who in turn impregnated themselves with you.`);
+						r.push(`${He} is <span class="lightgreen">your sole grandfather. ${He} fathered ${pcFather.slaveName} who in turn impregnated themselves with you.</span>`);
 					}
 				} else if ((jsDef(pcFather)) && slave.ID === pcMother.mother && slave.ID === pcFather.mother) {
 					r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to both of your parents, ${pcMother.slaveName} and ${pcFather.slaveName}.`);
diff --git a/src/endWeek/economics/reputation.js b/src/endWeek/economics/reputation.js
index 959245f7f43..525a11fdf58 100644
--- a/src/endWeek/economics/reputation.js
+++ b/src/endWeek/economics/reputation.js
@@ -600,7 +600,7 @@ App.EndWeek.reputation = function() {
 			}
 			FutureSocieties.Change("Roman Revivalist", 5);
 		}
-		if (V.language !== "Latin") {
+		if (V.language !== App.Data.FutureSociety.records.FSRomanRevivalist.language) {
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than the storied Latin <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Roman Revivalist", -2);
 		}
@@ -626,7 +626,7 @@ App.EndWeek.reputation = function() {
 			r.push(`Society <span class="green">approves</span> of having a leader that is trained in the arts of war.`);
 			FutureSocieties.Change("Aztec Revivalist", 2);
 		}
-		if (V.language !== "Nahuatl") {
+		if (V.language !== App.Data.FutureSociety.records.FSAztecRevivalist.language) {
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than the revived Nahuatl <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Aztec Revivalist", -3);
 		}
@@ -666,7 +666,7 @@ App.EndWeek.reputation = function() {
 			r.push(`Society <span class="green">strongly approves</span> of how you own a cornucopia of different races, which advances the ancient Egyptian ideal of cosmopolitan sex slavery.`);
 			FutureSocieties.Change("Egyptian Revivalist", 5);
 		}
-		if (V.language !== "Ancient Egyptian") {
+		if (V.language !== App.Data.FutureSociety.records.FSEgyptianRevivalist.language) {
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than revived Ancient Egyptian <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Egyptian Revivalist", -2);
 		}
@@ -679,7 +679,7 @@ App.EndWeek.reputation = function() {
 			r.push(`Society <span class="green">approves</span> of your provision for cultural development by offering public servants and club slaves in a number that befits your reputation.`);
 			FutureSocieties.Change("Edo Revivalist", 2);
 		}
-		if (V.language !== "Japanese") {
+		if (V.language !== App.Data.FutureSociety.records.FSEdoRevivalist.language) { //
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than pure Japanese <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Edo Revivalist", -2);
 		}
@@ -691,7 +691,7 @@ App.EndWeek.reputation = function() {
 			r.push(`Society <span class="green">approves</span> of the size of your harem, feeling that you have a good number of fucktoys and slaves in your master suite for your reputation.`);
 			FutureSocieties.Change("Arabian Revivalist", 2);
 		}
-		if (V.language !== "Arabic") {
+		if (V.language !== App.Data.FutureSociety.records.FSArabianRevivalist.language) {
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than the Arabic in which the word of God was passed to Muhammad <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Arabian Revivalist", -2);
 		}
@@ -717,7 +717,7 @@ App.EndWeek.reputation = function() {
 			r.push(`and <span class="green">approves</span> of your keeping a Bodyguard, as befits a proper imperial palace.`);
 			FutureSocieties.Change("Chinese Revivalist", 2);
 		}
-		if (V.language !== "Chinese") {
+		if (V.language !== App.Data.FutureSociety.records.FSChineseRevivalist.language) {
 			r.push(`Continuing to use ${V.language} as the lingua franca of ${V.arcologies[0].name} rather than the Chinese of the Middle Kingdom <span class="red">disappoints</span> society and causes doubt about your revivalist project.`);
 			FutureSocieties.Change("Chinese Revivalist", -2);
 		}
diff --git a/src/endWeek/events/expire.js b/src/endWeek/events/expire.js
index a1112621ee7..e9ac09b1c20 100644
--- a/src/endWeek/events/expire.js
+++ b/src/endWeek/events/expire.js
@@ -109,7 +109,7 @@ App.Events.SEExpiration = class SEExpiration extends App.Events.BaseEvent {
 				} else {
 					r.push(Spoken(slave, `"Please, don't send me away,"`));
 					r.push(`${he} sobs.`);
-					r.push(Spoken(slave, "I love you! I'll d-do anything — I'll be your slave! Please, enslave me. I l-love you..."));
+					r.push(Spoken(slave, `"I love you! I'll d-do anything — I'll be your slave! Please, enslave me. I l-love you..."`));
 					r.push(`${he} moans, trailing off into convulsive blubbering.`);
 				}
 
diff --git a/src/endWeek/nextWeek/nextWeek.js b/src/endWeek/nextWeek/nextWeek.js
index 1d6af1b90b9..a3371a95011 100644
--- a/src/endWeek/nextWeek/nextWeek.js
+++ b/src/endWeek/nextWeek/nextWeek.js
@@ -167,13 +167,13 @@ App.EndWeek.nextWeek = function() {
 		if (slave.vagina < 0) {
 			slave.vaginalAccessory = "none";
 			slave.chastityVagina = 0;
-			slave.vaginaPiercing = 0;
+			slave.piercing.vagina.weight = 0;
 		}
 		if (slave.dick === 0) {
 			slave.dickAccessory = "none";
 			slave.chastityPenis = 0;
 			slave.dickTat = 0;
-			slave.dickPiercing = 0;
+			slave.piercing.dick.weight = 0;
 		}
 		/* I don't trust these */
 		if (!hasAnyArms(slave)) {
diff --git a/src/endWeek/reports/penthouseReport.js b/src/endWeek/reports/penthouseReport.js
index 1fe638b39fd..825f4741703 100644
--- a/src/endWeek/reports/penthouseReport.js
+++ b/src/endWeek/reports/penthouseReport.js
@@ -526,16 +526,16 @@ App.EndWeek.penthouseReport = function() {
 
 		function piercingCheck() {
 			let piercingForbidden = 0;
-			if (slave.earPiercing === 0 && slave.earShape !== "none") {
+			if (slave.piercing.ear.weight === 0 && slave.earShape !== "none") {
 				if (V.arcologies[0].FSDegradationist !== "unset") {
-					slave.earPiercing = 2;
+					slave.piercing.ear.weight = 2;
 				} else {
-					slave.earPiercing = 1;
+					slave.piercing.ear.weight = 1;
 				}
 				RulesDeconfliction(slave);
-				if (slave.earPiercing !== V.slaveAfterRA.earPiercing) {
+				if (slave.piercing.ear.weight !== V.slaveAfterRA.piercing.ear.weight) {
 					piercingForbidden = 1;
-					slave.earPiercing = 0;
+					slave.piercing.ear.weight = 0;
 				} else {
 					if (V.arcologies[0].FSDegradationist !== "unset") {
 						r.push(`${S.HeadGirl.slaveName} knows that ${slave.slaveName} needs to adjust to life as a slave${girl2}, so ${he} has the slave's ears pierced. This will be a constant reminder that ${he2} is simply a sexual object here.`);
@@ -546,16 +546,16 @@ App.EndWeek.penthouseReport = function() {
 					return;
 				}
 			}
-			if (slave.nosePiercing === 0) {
+			if (slave.piercing.nose.weight === 0) {
 				if (V.arcologies[0].FSDegradationist !== "unset") {
-					slave.nosePiercing = 2;
+					slave.piercing.nose.weight = 2;
 				} else {
-					slave.nosePiercing = 1;
+					slave.piercing.nose.weight = 1;
 				}
 				RulesDeconfliction(slave);
-				if (slave.nosePiercing !== V.slaveAfterRA.nosePiercing) {
+				if (slave.piercing.nose.weight !== V.slaveAfterRA.piercing.nose.weight) {
 					piercingForbidden = 1;
-					slave.nosePiercing = 0;
+					slave.piercing.nose.weight = 0;
 				} else {
 					if (V.arcologies[0].FSDegradationist !== "unset") {
 						r.push(`${S.HeadGirl.slaveName} knows that ${slave.slaveName} needs to adjust to life as a slave${girl2}, so ${he} gives the slave nasal studs and a large septum ring. It should push ${slave.slaveName} to see ${himself2} as a sexual object for others to use.`);
@@ -566,16 +566,16 @@ App.EndWeek.penthouseReport = function() {
 					return;
 				}
 			}
-			if (slave.eyebrowPiercing === 0) {
+			if (slave.piercing.eyebrow.weight === 0) {
 				if (V.arcologies[0].FSDegradationist !== "unset") {
-					slave.eyebrowPiercing = 2;
+					slave.piercing.eyebrow.weight = 2;
 				} else {
-					slave.eyebrowPiercing = 1;
+					slave.piercing.eyebrow.weight = 1;
 				}
 				RulesDeconfliction(slave);
-				if (slave.eyebrowPiercing !== V.slaveAfterRA.eyebrowPiercing) {
+				if (slave.piercing.eyebrow.weight !== V.slaveAfterRA.piercing.eyebrow.weight) {
 					piercingForbidden = 1;
-					slave.eyebrowPiercing = 0;
+					slave.piercing.eyebrow.weight = 0;
 				} else {
 					if (V.arcologies[0].FSDegradationist !== "unset") {
 						r.push(`${S.HeadGirl.slaveName} knows that ${slave.slaveName} needs to adjust to life as a slave${girl2}, so ${he} gives the slave multiple eyebrow piercings. A slutty touch for a slave${girl2} should help ${him2} feel a little hungrier for cock.`);
@@ -586,16 +586,16 @@ App.EndWeek.penthouseReport = function() {
 					return;
 				}
 			}
-			if (slave.lipsPiercing === 0) {
+			if (slave.piercing.lips.weight === 0) {
 				if (V.arcologies[0].FSDegradationist !== "unset") {
-					slave.lipsPiercing = 2;
+					slave.piercing.lips.weight = 2;
 				} else {
-					slave.lipsPiercing = 1;
+					slave.piercing.lips.weight = 1;
 				}
 				RulesDeconfliction(slave);
-				if (slave.lipsPiercing !== V.slaveAfterRA.lipsPiercing) {
+				if (slave.piercing.lips.weight !== V.slaveAfterRA.piercing.lips.weight) {
 					piercingForbidden = 1;
-					slave.lipsPiercing = 0;
+					slave.piercing.lips.weight = 0;
 				} else {
 					if (V.arcologies[0].FSDegradationist !== "unset") {
 						r.push(`${S.HeadGirl.slaveName} knows that ${slave.slaveName} needs to adjust to life as a slave${girl2}, so ${he} has the slave's lower lip pierced. ${His2} mouth is for pleasing penises now, so it'll help ${him2} if it looks like it.`);
@@ -606,16 +606,16 @@ App.EndWeek.penthouseReport = function() {
 					return;
 				}
 			}
-			if (slave.navelPiercing === 0) {
+			if (slave.piercing.navel.weight === 0) {
 				if (V.arcologies[0].FSDegradationist !== "unset") {
-					slave.navelPiercing = 2;
+					slave.piercing.navel.weight = 2;
 				} else {
-					slave.navelPiercing = 1;
+					slave.piercing.navel.weight = 1;
 				}
 				RulesDeconfliction(slave);
-				if (slave.navelPiercing !== V.slaveAfterRA.navelPiercing) {
+				if (slave.piercing.navel.weight !== V.slaveAfterRA.piercing.navel.weight) {
 					piercingForbidden = 1;
-					slave.navelPiercing = 0;
+					slave.piercing.navel.weight = 0;
 				} else {
 					if (V.arcologies[0].FSDegradationist !== "unset") {
 						r.push(`${S.HeadGirl.slaveName} knows that ${slave.slaveName} needs help adjusting to life as a slave${girl2}, so ${he} has the slave's navel pierced with a big ring. Whatever ${he2} thinks in ${his2} mind, ${S.HeadGirl.slaveName} makes clear to ${him2} that ${his2} body belongs to you.`);
diff --git a/src/endWeek/reports/spaReport.js b/src/endWeek/reports/spaReport.js
index d6137936960..0b1327e0326 100644
--- a/src/endWeek/reports/spaReport.js
+++ b/src/endWeek/reports/spaReport.js
@@ -296,7 +296,7 @@ App.EndWeek.spaReport = function() {
 				attendantEntry,
 				[
 					App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"),
-					`is serving as the Attendant in ${V.spaName}`,
+					`is serving as the Attendant in ${V.spaName}.`,
 					App.SlaveAssignment.standardSlaveReport(slave, false),
 				]
 			);
diff --git a/src/endWeek/saChoosesOwnJob.js b/src/endWeek/saChoosesOwnJob.js
index b6f78b013b5..29a2986f389 100644
--- a/src/endWeek/saChoosesOwnJob.js
+++ b/src/endWeek/saChoosesOwnJob.js
@@ -45,7 +45,9 @@ App.SlaveAssignment.choosesOwnJob = (function() {
 		({
 			He, he, him, his, himself, girl,
 		} = getPronouns(slave));
-
+		/*
+		"I suspect something might be awry with that too" - Pregmodder - 2021-09-26
+		*/
 		if (slave.choosesOwnAssignment === 0 || slave.fuckdoll > 0 || slave.fetish === "mindbroken") {
 			// nothing to do
 		} else if (slave.choosesOwnAssignment === 2) {
diff --git a/src/endWeek/saDevotion.js b/src/endWeek/saDevotion.js
index 673db853faf..f492d066726 100644
--- a/src/endWeek/saDevotion.js
+++ b/src/endWeek/saDevotion.js
@@ -115,10 +115,12 @@ App.SlaveAssignment.devotion = (function() {
 				r.push(`You <span class="trust inc">saved ${slave.slaveName} from a living nightmare</span> under your rival's rule. ${He} <span class="devotion inc">tries ${his} best to adapt to ${his} savior's wishes.</span>`);
 				slave.devotion += 10;
 				slave.trust += 10;
+			/* TODO: Setup setter code block. Already defined within js/003-Data/gameVariableData.js 
 			} else if (V.hostageGiveIn === 1) {
 				r.push(`Since you are <span class="trust inc">indulging</span> ${slave.slaveName}'s desires, ${he} <span class="devotion inc">likes you more.</span>`);
 				slave.devotion += 5;
 				slave.trust += 5;
+			*/
 			} else if (V.rivalryDuration > 20 && slave.devotion < 5) {
 				if (gettingPersonalAttention) {
 					r.push(`You took everything from ${slave.slaveName} and <span class="devotion dec">${he} hates you for it.</span> Since you won't give ${him} what ${he} wants, ${he} <span class="trust dec">refuses to trust you.</span> Since you are putting such a personal touch into ${his} care, ${he} can't find it in ${him} to rebel as strongly.`);
diff --git a/src/endWeek/saDrugs.js b/src/endWeek/saDrugs.js
index 1a3fcdf341c..99eec5cc452 100644
--- a/src/endWeek/saDrugs.js
+++ b/src/endWeek/saDrugs.js
@@ -933,6 +933,8 @@ App.SlaveAssignment.drugs = (function() {
 				if (growth > 0) {
 					// age modifier
 					let ageMod = 1;
+					const pubertyLength = 5;
+					const maxGrowthAge = 24;
 
 					if (slave.geneMods.NCS === 1) {
 						r += ` ${His} <span class="orange">NCS</span> inhibits ${his} body response to the treatment.`;
@@ -944,10 +946,10 @@ App.SlaveAssignment.drugs = (function() {
 						} else if (slave.pubertyXY === 0 && slave.physicalAge > 3) {
 							r += ` ${His} young body eagerly responds to the stimulants.`;
 							ageMod = 1.5;
-						} else if (slave.physicalAge <= (slave.pubertyAgeXY + V.pubertyLength)) {
+						} else if (slave.physicalAge <= (slave.pubertyAgeXY + pubertyLength)) {
 							r += ` Due to ${his} recent puberty, ${his} body welcomes the treatment with open arms.`;
 							ageMod = 2;
-						} else if (slave.physicalAge <= V.maxGrowthAge) {
+						} else if (slave.physicalAge <= maxGrowthAge) {
 							r += ` With ${his} puberty concluded, ${his} body resists the stimulants.`;
 							ageMod = 1;
 						} else {
@@ -961,10 +963,10 @@ App.SlaveAssignment.drugs = (function() {
 						} else if (slave.pubertyXX === 0 && slave.physicalAge > 3) {
 							r += ` ${His} young body eagerly responds to the stimulants.`;
 							ageMod = 1.5;
-						} else if (slave.physicalAge <= (slave.pubertyAgeXX + V.pubertyLength)) {
+						} else if (slave.physicalAge <= (slave.pubertyAgeXX + pubertyLength)) {
 							r += ` Due to ${his} recent puberty, ${his} body welcomes the treatment with open arms.`;
 							ageMod = 2;
-						} else if (slave.physicalAge <= V.maxGrowthAge) {
+						} else if (slave.physicalAge <= maxGrowthAge) {
 							r += ` With ${his} puberty concluded, ${his} body resists the stimulants.`;
 							ageMod = 1;
 						} else {
@@ -1007,7 +1009,7 @@ App.SlaveAssignment.drugs = (function() {
 						r += ` The stimulants stressed ${slave.slaveName}'s body more than expected, <span class="health dec">damaging ${his} health.</span>`;
 						healthDamage(slave, 10);
 					}
-					if (slave.physicalAge > V.maxGrowthAge) {
+					if (slave.physicalAge > maxGrowthAge) {
 						if (jsRandom(1, 6) === 1) {
 							r += ` Since ${his} body already concluded ${his} natural growth processes, the treatment <span class="health dec">weakens ${him} considerably.</span>`;
 							healthDamage(slave, 15);
diff --git a/src/endWeek/saLongTermEffects.js b/src/endWeek/saLongTermEffects.js
index deece56ec54..d53d09a2853 100644
--- a/src/endWeek/saLongTermEffects.js
+++ b/src/endWeek/saLongTermEffects.js
@@ -289,13 +289,13 @@ App.SlaveAssignment.longTermEffects = (function() {
 	 */
 	function piercingEffects(slave) {
 		let masochistic = 0;
-		if (slave.vaginaPiercing > 1) {
+		if (slave.piercing.vagina.weight > 1) {
 			if (slave.vagina > -1 && slave.labia < 2 && random(1, 100) > 90) {
 				r.push(`The weight of ${his} labial piercings <span class="change positive">stretches out ${his} pussylips a bit.</span>`);
 				slave.labia += 1;
 			}
 		}
-		if (slave.nipplesPiercing === 1) {
+		if (slave.piercing.nipple.weight === 1) {
 			if (slave.nipples === "tiny") {
 				if (random(1, 100) > 95) {
 					r.push(`${His} piercings keep ${his} nipples half-hard all the time, and <span class="change positive">${his} nipples have stretched out a bit.</span>`);
@@ -337,7 +337,7 @@ App.SlaveAssignment.longTermEffects = (function() {
 					slave.nipples = "huge";
 				}
 			}
-		} else if (slave.nipplesPiercing === 2) {
+		} else if (slave.piercing.nipple.weight === 2) {
 			if (slave.nipples === "tiny") {
 				if (random(1, 100) > 80) {
 					r.push(`${He}'s got so much metal in ${his} nipples that the weight <span class="change positive">stretches and lengthens them.</span>`);
diff --git a/src/endWeek/saLongTermMentalEffects.js b/src/endWeek/saLongTermMentalEffects.js
index 929772f879c..456f87633c7 100644
--- a/src/endWeek/saLongTermMentalEffects.js
+++ b/src/endWeek/saLongTermMentalEffects.js
@@ -136,9 +136,9 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 				if (slave.genes === "XY") {
 					switch (random(1, 5)) {
 						case 1:
-							if (slave.nosePiercing) {
+							if (slave.piercing.nose.weight) {
 								t.push(`${He}'s fascinated by ${his}`);
-								if (slave.nosePiercing > 1) {
+								if (slave.piercing.nose.weight > 1) {
 									t.push(`slutty nose piercings, and unconsciously thinks of ${himself} as <span class="positive">prettier and more suited to take dick.</span>`);
 								} else {
 									t.push(`nice little nasal piercing, and feels like <span class="positive">more of a girly girl.</span>`);
@@ -147,9 +147,9 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 							}
 							break;
 						case 2:
-							if (slave.eyebrowPiercing) {
+							if (slave.piercing.eyebrow.weight) {
 								t.push(`${His}`);
-								if (slave.eyebrowPiercing > 1) {
+								if (slave.piercing.eyebrow.weight > 1) {
 									t.push(`degrading eyebrow piercings make ${him} feel <span class="positive">a little less disinclined to accept being on the bottom.</span>`);
 								} else {
 									t.push(`cute eyebrow piercing makes ${him} feel <span class="positive">a little girlier.</span>`);
@@ -158,9 +158,9 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 							}
 							break;
 						case 3:
-							if (slave.lipsPiercing) {
+							if (slave.piercing.lips.weight) {
 								t.push(`${He} kind of likes ${his} `);
-								if (slave.lipsPiercing > 1) {
+								if (slave.piercing.lips.weight > 1) {
 									t.push(`whorish lip ring, and seems <span class="positive">less disturbed by the idea of ${his} mouth as a fuckhole.</span>`);
 								} else {
 									t.push(`pretty little lip piercing, and feels like <span class="positive">${he} has a nice mouth.</span>`);
@@ -169,7 +169,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 							}
 							break;
 						case 4:
-							if (slave.navelPiercing) {
+							if (slave.piercing.navel.weight) {
 								t.push(`${He} sometimes`);
 								if (canSee(slave)) {
 									t.push(`stares at`);
@@ -177,7 +177,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 									t.push(`considers`);
 								}
 								t.push(`${his}`);
-								if (slave.navelPiercing > 1) {
+								if (slave.piercing.navel.weight > 1) {
 									t.push(`navel chain, turning this way and that to make it move, unconsciously <span class="positive">getting used to ${his} fuckable body.</span>`);
 								} else {
 									t.push(`little feminine navel piercing, and seems to think <span class="positive">${his} lower half is kind of pretty.</span>`);
@@ -186,17 +186,17 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 							}
 							break;
 						case 5:
-							if (slave.earPiercing) {
+							if (slave.piercing.ear.weight) {
 								if (canSee(slave)) {
 									t.push(`Every morning, ${he}'s greeted by ${his} girly reflection in the mirror,`);
-									if (slave.earPiercing > 1) {
+									if (slave.piercing.ear.weight > 1) {
 										t.push(`whose slutty ear piercings make ${him} <span class="positive">feel more fuckable.</span>`);
 									} else {
 										t.push(`complete with pretty pierced ears <span class="positive">like a good slave girl.</span>`);
 									}
 								} else {
 									t.push(`${His} girly pierced ears make ${him} feel `);
-									if (slave.earPiercing > 1) {
+									if (slave.piercing.ear.weight > 1) {
 										t.push(`<span class="positive">like a hot slut.</span>`);
 									} else {
 										t.push(`<span class="positive">like a cute girl.</span>`);
@@ -567,7 +567,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 					}
 					break;
 			}
-			if (slave.clitPiercing !== 3) {
+			if (!slave.piercing.genitals.smart) {
 				if (fetishChangeChance(slave) > random(0, 100)) {
 					switch (slave.behavioralQuirk) {
 						case "confident":
@@ -783,7 +783,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 					}
 					break;
 			}
-			if (slave.clitPiercing !== 3) {
+			if (!slave.piercing.genitals.smart) {
 				if (fetishChangeChance(slave) > random(0, 100)) {
 					switch (slave.sexualQuirk) {
 						case "gagfuck queen":
@@ -1069,7 +1069,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 		if (slave.fetishStrength + slave.devotion + slave.trust > random(1, 500)) {
 			if (slave.sexualQuirk === "none") {
 				if (slave.sexualFlaw === "hates anal") {
-					if (slave.anusPiercing) {
+					if (slave.piercing.anus.weight) {
 						r.push(`The constant stimulation ${his} guiche piercings give ${him} most intimate areas helps ${him} with ${his} anal hang-ups, <span class="flaw break">softening ${his} hatred of anal into an appetite for anal pain.</span> ${He} still struggles if ${he}'s fucked in the ass, but ${he} gets off on it anyway.`);
 						SoftenSexualFlaw(slave);
 					} else if (slave.fetish === "buttslut" && slave.fetishKnown === 1) {
@@ -1080,7 +1080,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 						SoftenSexualFlaw(slave);
 					}
 				} else if (slave.sexualFlaw === "hates oral") {
-					if (slave.tonguePiercing) {
+					if (slave.piercing.tongue.weight) {
 						r.push(`${He} can't stop sucking on ${his} tongue piercings, and ${he} gets over ${his} oral hang-ups, <span class="flaw break">softening ${his} hatred of oral into a willingness to be roughly throatfucked.</span> ${He} still gags, but it's a good gagging, now.`);
 						SoftenSexualFlaw(slave);
 					} else if (slave.fetish === "cumslut" && slave.fetishKnown === 1) {
@@ -1091,7 +1091,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 						SoftenSexualFlaw(slave);
 					}
 				} else if (slave.sexualFlaw === "hates penetration") {
-					if (slave.vaginaPiercing) {
+					if (slave.piercing.vagina.weight) {
 						r.push(`${His} pussy piercings get ${him} used to the idea that it's a fuckhole, not ${his} precious womanhood, <span class="flaw break">softening ${his} hatred of penetration into an appetite for abusive sex.</span> ${He} still cries, but ${he} climaxes as ${he} cries.`);
 						SoftenSexualFlaw(slave);
 					} else if (slave.fetish === "buttslut" && slave.fetishKnown === 1) {
@@ -1155,7 +1155,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 				}
 			} else {
 				if (slave.sexualFlaw === "hates anal") {
-					if (slave.anusPiercing) {
+					if (slave.piercing.anus.weight) {
 						r.push(`The constant stimulation ${his} guiche piercings give ${him} most intimate areas helps ${him} with ${his} anal hang-ups, so <span class="flaw break">${his} previous hesitations about buttsex vanish.</span>`);
 						slave.sexualFlaw = "none";
 					} else if (slave.fetish === "buttslut" && slave.fetishKnown === 1) {
@@ -1166,7 +1166,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 						slave.sexualFlaw = "none";
 					}
 				} else if (slave.sexualFlaw === "hates oral") {
-					if (slave.tonguePiercing) {
+					if (slave.piercing.tongue.weight) {
 						r.push(`${He} can't stop sucking on ${his} tongue piercings, so <span class="flaw break">${he} gets over ${his} oral hang-ups.</span>`);
 						slave.sexualFlaw = "none";
 					} else if (slave.fetish === "cumslut" && slave.fetishKnown === 1) {
@@ -1177,7 +1177,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 						slave.sexualFlaw = "none";
 					}
 				} else if (slave.sexualFlaw === "hates penetration") {
-					if (slave.vaginaPiercing) {
+					if (slave.piercing.vagina.weight) {
 						r.push(`${His} pussy piercings get ${him} used to the idea that it's a fuckhole, not ${his} precious womanhood, so <span class="flaw break">${his} previous hesitations about getting fucked vanish.</span>`);
 						slave.sexualFlaw = "none";
 					} else if (slave.fetish === "buttslut" && slave.fetishKnown === 1) {
@@ -1879,7 +1879,7 @@ App.SlaveAssignment.longTermMentalEffects = (function() {
 				}
 			}
 		}
-		if (slave.clitPiercing !== 3 || slave.clitSetting === "off" || slave.clitSetting === "none" || slave.clitSetting === "all" || slave.clitSetting === "men" || slave.clitSetting === "women") {
+		if (!slave.piercing.genitals.smart || slave.clitSetting === "off" || slave.clitSetting === "none" || slave.clitSetting === "all" || slave.clitSetting === "men" || slave.clitSetting === "women") {
 			if (canDoAnal(slave)) {
 				if (slave.vagina > -1 && !canDoVaginal(slave)) {
 					if (slave.fetishStrength <= 95) {
diff --git a/src/endWeek/saLongTermPhysicalEffects.js b/src/endWeek/saLongTermPhysicalEffects.js
index c4dee8e9450..8f056ce2783 100644
--- a/src/endWeek/saLongTermPhysicalEffects.js
+++ b/src/endWeek/saLongTermPhysicalEffects.js
@@ -1205,7 +1205,7 @@ App.SlaveAssignment.longTermPhysicalEffects = (function() {
 		} else if (slave.nipples === "flat" && (slave.boobsImplant / slave.boobs < 0.75)) {
 			r.push(`With ${his} breasts no longer being overstretched by implants, ${his} flat nipples regain a more normal shape. They now <span class="change positive">protrude hugely.</span>`);
 			slave.nipples = "huge";
-		} else if (slave.boobShape === "spherical" && slave.nipples !== "flat" && slave.lactation === 0 && slave.nipplesPiercing === 0) { // Lactation and piercings discourage flattening and convert flat nipples to huge ones.
+		} else if (slave.boobShape === "spherical" && slave.nipples !== "flat" && slave.lactation === 0 && slave.piercing.nipple.weight === 0) { // Lactation and piercings discourage flattening and convert flat nipples to huge ones.
 			r.push(`With the skin of ${his} breasts stretched so thin by ${his} implants, it's only natural that ${his} nipples are soon <span class="change negative">pulled flat</span> as well.`);
 			slave.nipples = "flat";
 		}
diff --git a/src/endWeek/saRecruitGirls.js b/src/endWeek/saRecruitGirls.js
index 8fb9ea10f46..e901877d7e8 100644
--- a/src/endWeek/saRecruitGirls.js
+++ b/src/endWeek/saRecruitGirls.js
@@ -1227,7 +1227,7 @@ App.SlaveAssignment.recruitGirls = (function() {
 			}
 		}
 		if (arcology.FSBodyPurist !== "unset") {
-			if (slave.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+			if (slave.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 				if (slave.boobsImplant === 0 && slave.buttImplant === 0 && slave.waist >= -95) {
 					pushFS(`${He} exhibits pure sexuality in a lovely, artistic gallery of erotic photos posted this week that displays every natural ${V.showInches === 2 ? `inch` : `centimeter`} of ${his} body.`);
 				} else if (slave.boobsImplant === 0 && slave.buttImplant === 0) {
diff --git a/src/endWeek/saRelationships.js b/src/endWeek/saRelationships.js
index be4c6ac75c3..5fcab058fc1 100644
--- a/src/endWeek/saRelationships.js
+++ b/src/endWeek/saRelationships.js
@@ -793,7 +793,7 @@ App.SlaveAssignment.relationships = (function() {
 				case 4: // lovers
 					r.push(`and ${friend.slaveName} are lovers.`);
 					break;
-				default: // married
+				case 5: // married
 					r.push(`has a slave ${wife2}, ${friend.slaveName}.`);
 					if (V.arcologies[0].FSChattelReligionist !== "unset") {
 						r.push(`Society <span class="reputation inc">approves</span> of their marriage, which advances the slave sacrament.`);
diff --git a/src/endWeek/saRewardAndPunishment.js b/src/endWeek/saRewardAndPunishment.js
index ab974a0ccd7..fb431b73484 100644
--- a/src/endWeek/saRewardAndPunishment.js
+++ b/src/endWeek/saRewardAndPunishment.js
@@ -84,7 +84,7 @@ App.SlaveAssignment.rewardAndPunishment = (function() {
 		orgasm: function() {
 			let r = [];
 			r.push(`${He}'s <span class="hotpink">rewarded</span> with`);
-			if (slave.clitPiercing === 3) {
+			if (slave.piercing.genitals.smart) {
 				r.push(`sustained orgasm from ${his}`);
 				if (slave.dick === 0) {
 					r.push(`clit`);
diff --git a/src/endWeek/saServeThePublic.js b/src/endWeek/saServeThePublic.js
index aee7713c35c..30533eaa274 100644
--- a/src/endWeek/saServeThePublic.js
+++ b/src/endWeek/saServeThePublic.js
@@ -659,7 +659,7 @@ App.SlaveAssignment.serveThePublic = (function() {
 		} else {
 			if ((modScore.total > 15) || (modScore.piercing > 8 && modScore.tat > 5)) {
 				r += ` ${He} has so much body art that most potential patrons don't think ${he} needs any more.`;
-			} else if (slave.corsetPiercing !== 0 || modScore.piercing >= 3 || modScore.tat >= 2) {
+			} else if (slave.piercing.corset.weight !== 0 || modScore.piercing >= 3 || modScore.tat >= 2) {
 				r += ` ${His} body art helps attract patrons to use ${him} freely.`;
 			}
 		}
@@ -965,9 +965,9 @@ App.SlaveAssignment.serveThePublic = (function() {
 			r += ` A few of ${his} fans recognize ${him} and eagerly make use of ${him}.`;
 		}
 
-		if (slave.clitPiercing === 3 && slave.devotion >= -20) {
+		if (slave.piercing.genitals.smart && slave.devotion >= -20) {
 			r += ` Almost everyone loves ${his} orgasms encouraged by ${his} smart piercing.`;
-		} else if (slave.clitPiercing === 3) {
+		} else if (slave.piercing.genitals.smart) {
 			r += ` Almost everyone appreciates ${his} reduced reluctance caused by ${his} smart piercing.`;
 		}
 
diff --git a/src/endWeek/saSmartPiercingEffects.js b/src/endWeek/saSmartPiercingEffects.js
index 668386f184b..1b7e936f37b 100644
--- a/src/endWeek/saSmartPiercingEffects.js
+++ b/src/endWeek/saSmartPiercingEffects.js
@@ -412,7 +412,7 @@ App.SlaveAssignment.saSmartPiercingEffects = function(slave) {
 	const hasSmartBV = dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator";
 	const hasDildoVibe = slave.vaginalAttachment === "vibrator";
 	const hasSmartDildoVibe = slave.vaginalAttachment === "smart vibrator";
-	const hasSP = slave.clitPiercing === 3;
+	const hasSP = slave.piercing.genitals.smart;
 	const piercing = hasSP ? `smart ${(slave.vagina > -1) ? "clit" : "frenulum"} piercing` : ``;
 	const hasSmartVibe = hasSmartDildoVibe || hasSmartBV;
 	const hasDumbVibe = hasDildoVibe || hasBV;
diff --git a/src/endWeek/saSocialEffects.js b/src/endWeek/saSocialEffects.js
index ea35e246582..3682c374157 100644
--- a/src/endWeek/saSocialEffects.js
+++ b/src/endWeek/saSocialEffects.js
@@ -573,7 +573,7 @@ App.SlaveAssignment.saSocialEffects = function(slave) {
 				t.push(new SocialEffect("Body Purist", -1, `Implants`,
 					`Society <span class="red">disapproves</span> of ${slave.slaveName}'s implants; this holds back acceptance of the idea that slaves should be all-natural.`));
 			}
-			if (slave.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+			if (slave.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 				t.push(new SocialEffect("Body Purist", 1, `Minimal piercings/tats`,
 					`Society <span class="green">approves</span> of ${his} unmarked, unblemished skin, advancing the fashion for unspoiled slaves.`));
 			}
diff --git a/src/endWeek/saWhore.js b/src/endWeek/saWhore.js
index c78c72a459e..1c3ed934afc 100644
--- a/src/endWeek/saWhore.js
+++ b/src/endWeek/saWhore.js
@@ -742,7 +742,7 @@ App.SlaveAssignment.whore = (function() {
 		} else {
 			if ((modScore.total > 15) || (modScore.piercing > 8 && modScore.tat > 5)) {
 				r += ` ${He} has so much body art that most customers don't think ${he} needs any more.`;
-			} else if (slave.corsetPiercing !== 0 || modScore.piercing >= 3 || modScore.tat >= 2) {
+			} else if (slave.piercing.corset.weight !== 0 || modScore.piercing >= 3 || modScore.tat >= 2) {
 				r += ` ${His} body art helps attract customers.`;
 			}
 		}
@@ -1048,9 +1048,9 @@ App.SlaveAssignment.whore = (function() {
 			r += ` A few of ${his} fans recognize ${him} and eagerly patronize ${him}.`;
 		}
 
-		if (slave.clitPiercing === 3 && slave.devotion >= -20) {
+		if (slave.piercing.genitals.smart && slave.devotion >= -20) {
 			r += ` Almost everyone loves ${his} enthusiasm for sex encouraged by ${his} smart piercing.`;
-		} else if (slave.clitPiercing === 3) {
+		} else if (slave.piercing.genitals.smart) {
 			r += ` Almost everyone appreciates ${his} reduced reluctance towards sex encouraged by ${his} smart piercing.`;
 		}
 
diff --git a/src/events/JE/jeSlaveDisputeIndentureDeal.js b/src/events/JE/jeSlaveDisputeIndentureDeal.js
index 51b8e32078b..3b2332d21c6 100644
--- a/src/events/JE/jeSlaveDisputeIndentureDeal.js
+++ b/src/events/JE/jeSlaveDisputeIndentureDeal.js
@@ -34,14 +34,14 @@ App.Events.JESlaveDisputeIndentureDeal = class JESlaveDisputeIndentureDeal exten
 		slave.buttImplantType = "normal";
 		slave.lips += 10;
 		slave.lipsImplant = 10;
-		slave.lipsPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.earPiercing = 1;
-		slave.nosePiercing = 1;
-		slave.eyebrowPiercing = 1;
-		slave.navelPiercing = 1;
-		slave.nipplesPiercing = 1;
-		slave.clitPiercing = 1;
+		slave.piercing.lips.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.ear.weight = 1;
+		slave.piercing.nose.weight = 1;
+		slave.piercing.eyebrow.weight = 1;
+		slave.piercing.navel.weight = 1;
+		slave.piercing.nipple.weight = 1;
+		slave.piercing.genitals.weight = 1;
 		slave.stampTat = either("flowers", "tribal patterns");
 		const {
 			He,
diff --git a/src/events/JE/jeSlaveDisputeSlaveDeal.js b/src/events/JE/jeSlaveDisputeSlaveDeal.js
index eb27448341b..09f67a30ab0 100644
--- a/src/events/JE/jeSlaveDisputeSlaveDeal.js
+++ b/src/events/JE/jeSlaveDisputeSlaveDeal.js
@@ -22,7 +22,7 @@ App.Events.JESlaveDisputeSlaveDeal = class JESlaveDisputeSlaveDeal extends App.E
 		slave.trust = slave.devotion - 20;
 		slave.oldDevotion = slave.devotion;
 		setHealth(slave, jsRandom(0, 20));
-		slave.earPiercing = 1;
+		slave.piercing.ear.weight = 1;
 		slave.vagina = random(1, 2);
 		slave.ovaries = 1;
 		slave.counter.birthsTotal = 1;
diff --git a/src/events/JE/jeSlaveDisputeSlaveTraining.js b/src/events/JE/jeSlaveDisputeSlaveTraining.js
index 019c0932e41..6720cee7c79 100644
--- a/src/events/JE/jeSlaveDisputeSlaveTraining.js
+++ b/src/events/JE/jeSlaveDisputeSlaveTraining.js
@@ -29,16 +29,16 @@ App.Events.JESlaveDisputeSlaveTraining = class JESlaveDisputeSlaveTraining exten
 		slave.skill.oral = 35;
 		slave.skill.whoring = 35;
 		slave.skill.entertainment = 35;
-		slave.nipplesPiercing = 1;
-		slave.clitPiercing = 1;
-		slave.dickPiercing = 1;
-		slave.anusPiercing = 1;
-		slave.lipsPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.earPiercing = 1;
-		slave.nosePiercing = 1;
-		slave.eyebrowPiercing = 1;
-		slave.navelPiercing = 1;
+		slave.piercing.nipple.weight = 1;
+		slave.piercing.genitals.weight = 1;
+		slave.piercing.dick.weight = 1;
+		slave.piercing.anus.weight = 1;
+		slave.piercing.lips.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.ear.weight = 1;
+		slave.piercing.nose.weight = 1;
+		slave.piercing.eyebrow.weight = 1;
+		slave.piercing.navel.weight = 1;
 		slave.boobsTat = either("advertisements", "degradation", "rude words");
 		slave.buttTat = either("advertisements", "degradation", "rude words");
 		slave.vaginaTat = either("advertisements", "degradation", "rude words");
diff --git a/src/events/PE/peCombatTraining.js b/src/events/PE/peCombatTraining.js
index 04b94a4b771..41aa70af441 100644
--- a/src/events/PE/peCombatTraining.js
+++ b/src/events/PE/peCombatTraining.js
@@ -66,9 +66,9 @@ App.Events.PECombatTraining = class PECombatTraining extends App.Events.BaseEven
 
 		function willTake() {
 			if (canDoVaginal(S.Bodyguard) && (S.Bodyguard.vagina === 0)) {
-				return "This option will take virginity";
+				return `This option will take ${his} virginity`;
 			} else if (!canDoVaginal(S.Bodyguard) && (S.Bodyguard.anus === 0)) {
-				return "This option will take anal virginity";
+				return `This option will take ${his} anal virginity`;
 			}
 		}
 	}
diff --git a/src/events/PE/peLonelyBodyguard.js b/src/events/PE/peLonelyBodyguard.js
index 05d50609e22..e147ed8ec3a 100644
--- a/src/events/PE/peLonelyBodyguard.js
+++ b/src/events/PE/peLonelyBodyguard.js
@@ -3,6 +3,7 @@ App.Events.PELonelyBodyguard = class PELonelyBodyguard extends App.Events.BaseEv
 		return [
 			() => !!S.Bodyguard,
 			() => S.Bodyguard.rules.relationship === "permissive",
+			() => S.Bodyguard.relationship === 0,
 			() => S.Bodyguard.fetish !== "mindbroken",
 		];
 	}
@@ -33,7 +34,11 @@ App.Events.PELonelyBodyguard = class PELonelyBodyguard extends App.Events.BaseEv
 
 		App.Events.drawEventArt(node, [BG, crush]);
 
-		App.Events.addParagraph(node, [`You take an unusually close interest in ${BG.slaveName}'s health and mental well-being, since your health and mental well-being may rely on ${his} combat effectiveness. ${He} performs ${his} duties acceptably, difficult though they are. ${Hers} is a life of long hours and constant vigilance, and ${he} has very little time to ${himself}. The daily wear hasn't really affected ${him} yet, but it may.`]);
+		App.Events.addParagraph(node, [
+			`You take an unusually close interest in`,
+			App.UI.DOM.combineNodes(App.UI.DOM.slaveDescriptionDialog(BG), `'s`),
+			`health and mental well-being, since your health and mental well-being may rely on ${his} combat effectiveness. ${He} performs ${his} duties acceptably, difficult though they are. ${Hers} is a life of long hours and constant vigilance, and ${he} has very little time to ${himself}. The daily wear hasn't really affected ${him} yet, but it may.`
+		]);
 
 		r.push(`On a whim, you ask ${him} whether ${he} feels lonely. Caught off guard, ${he}`);
 		if (!canTalk(BG)) {
@@ -41,7 +46,9 @@ App.Events.PELonelyBodyguard = class PELonelyBodyguard extends App.Events.BaseEv
 		} else {
 			r.push(`${say}s hesitantly "I'm all right, ${Master}. I love being near you; that's enough for me."`);
 		}
-		r.push(`The slight hesitation is explained the next time ${crush.slaveName} comes to your office. ${BG.slaveName} watches everyone who sees you, of course, but you catch ${his} eye running appreciatively up and down ${crush.slaveName}'s body as ${he2} leaves.`);
+		r.push(`The slight hesitation is explained the next time`,
+			App.UI.DOM.slaveDescriptionDialog(crush),
+			`comes to your office. ${BG.slaveName} watches everyone who sees you, of course, but you catch ${his} eye running appreciatively up and down ${crush.slaveName}'s body as ${he2} leaves.`);
 
 		App.Events.addParagraph(node, r);
 
diff --git a/src/events/PESS/pessBodyguardBedtime.js b/src/events/PESS/pessBodyguardBedtime.js
index a748e699145..0b5b5a99baa 100644
--- a/src/events/PESS/pessBodyguardBedtime.js
+++ b/src/events/PESS/pessBodyguardBedtime.js
@@ -39,7 +39,7 @@ App.Events.pessBodyguardBedtime = class pessBodyguardBedtime extends App.Events.
 
 		App.Events.addResponses(node, [
 			new App.Events.Result(`Let ${him} up in bed with you`, inBed),
-			new App.Events.Result(`Commend and reward ${him} the next morning`, morning, (S.Bodyguard.anus === 0 || S.Bodyguard.vagina === 0) ? `This option will take virginity` : ``)
+			new App.Events.Result(`Commend and reward ${him} the next morning`, morning, (S.Bodyguard.anus === 0 || S.Bodyguard.vagina === 0) ? `This option will take ${his} virginity` : ``)
 		]);
 
 		function inBed() {
diff --git a/src/events/PESS/pessLovingConcubine.js b/src/events/PESS/pessLovingConcubine.js
index 3840a3b629f..048a3c70402 100644
--- a/src/events/PESS/pessLovingConcubine.js
+++ b/src/events/PESS/pessLovingConcubine.js
@@ -108,7 +108,7 @@ App.Events.pessLovingConcubine = class pessLovingConcubine extends App.Events.Ba
 			} else if (canTalk(S.Concubine)) {
 				r.push(
 					`${say}ing,`,
-					Spoken(S.Concubine, `"${Master}, I love you."`)
+					Spoken(S.Concubine, `"${capFirstChar(Master)}, I love you."`)
 				);
 			} else {
 				r.push(`giving you a sultry look`);
diff --git a/src/events/PESS/pessLovingHeadgirl.js b/src/events/PESS/pessLovingHeadgirl.js
index 7df2a3064e5..a539fd99929 100644
--- a/src/events/PESS/pessLovingHeadgirl.js
+++ b/src/events/PESS/pessLovingHeadgirl.js
@@ -26,7 +26,7 @@ App.Events.pessLovingHeadgirl = class pessLovingHeadgirl extends App.Events.Base
 		r.push(`The business is brief and inconsequential, but it's good to speak with ${him}. When you're done, ${he} gets halfway to the door before coming quickly back to give you a light kiss on the cheek.`);
 		if (S.HeadGirl.lips > 70) {
 			r.push(`"Ah love you, ${Master}," ${he} lisps, huge lips grazing your ear,`);
-		} else if (S.HeadGirl.lipsPiercing + S.HeadGirl.tonguePiercing > 2) {
+		} else if (S.HeadGirl.piercing.lips.weight + S.HeadGirl.piercing.tongue.weight > 2) {
 			r.push(`"Ah love you, ${Master}," ${he} lisps, oral piercings grazing your ear,`);
 		} else {
 			r.push(`"I love you, ${Master}," ${he} whispers into your ear,`);
@@ -139,7 +139,7 @@ App.Events.pessLovingHeadgirl = class pessLovingHeadgirl extends App.Events.Base
 			r.push(`${subSlave.slaveName} only manages one kick of ${his2} legs before you pin them and ram yourself up ${his2} butt. ${His2} howl of protest, directed against ${S.HeadGirl.slaveName}'s privates, sends a shiver through your Head Girl.`);
 			if (S.HeadGirl.lips > 70) {
 				r.push(`"Oh pleathe make ${him2} moan, ${Master}," ${he} lisps through ${his} huge lips.`);
-			} else if (S.HeadGirl.lipsPiercing+S.HeadGirl.tonguePiercing > 2) {
+			} else if (S.HeadGirl.piercing.lips.weight+S.HeadGirl.piercing.tongue.weight > 2) {
 				r.push(`"Oh pleathe make ${him2} moan, ${Master}," ${he} lisps through ${his} face full of piercings.`);
 			} else {
 				r.push(`"I love it when you make ${him2} moan, ${Master}," ${he} groans.`);
diff --git a/src/events/PESS/pessWorriedHeadgirl.js b/src/events/PESS/pessWorriedHeadgirl.js
index a3d9c630cb7..514e43e5a3e 100644
--- a/src/events/PESS/pessWorriedHeadgirl.js
+++ b/src/events/PESS/pessWorriedHeadgirl.js
@@ -64,7 +64,7 @@ App.Events.pessWorriedHeadgirl = class pessWorriedHeadgirl extends App.Events.Ba
 			}
 			r.push(`fitting neatly against your side.`);
 		}
-		r.push(Spoken(S.HeadGirl, `"${Master}, I don't know if the other ${girl}s know how lucky they are, to be safe here."`));
+		r.push(Spoken(S.HeadGirl, `"${Master}, I don't know if the other slaves know how lucky they are, to be safe here."`));
 		App.Events.addParagraph(node, r);
 
 
diff --git a/src/events/PETS/petsAggressiveWardeness.js b/src/events/PETS/petsAggressiveWardeness.js
index 07484ab01bd..836ec65f433 100644
--- a/src/events/PETS/petsAggressiveWardeness.js
+++ b/src/events/PETS/petsAggressiveWardeness.js
@@ -28,11 +28,10 @@ App.Events.petsAggressiveWardeness = class petsAggressiveWardeness extends App.E
 			`As you pass the entrance to the hall of cells where`,
 			App.UI.DOM.slaveDescriptionDialog(S.Wardeness),
 			`breaks bitches late one night, you hear some muffled cursing, followed by moans. Curious, you lean into the one cell with an open door and are treated to the sight of ${S.Wardeness.slaveName} holding`,
-			App.UI.DOM.combineNodes(contextualIntro(S.Wardeness, subSlave, "DOM"), `'s head`)
+			App.UI.DOM.combineNodes(contextualIntro(S.Wardeness, subSlave, "DOM"), `'s head`),
+			`${hasBothLegs(S.Wardeness) ? `between ${his} legs` : `at ${his} groin`}, receiving what is very obviously non-consensual oral sex. ${S.Wardeness.slaveName} is clearly enjoying ${himself}, but gathers ${himself} together and greets you properly, without stopping.`
 		]);
 
-		App.Events.addParagraph(node, [`${hasBothLegs(S.Wardeness) ? `between ${his} legs` : `at ${his} groin`}, receiving what is very obviously non-consensual oral sex. ${S.Wardeness.slaveName} is clearly enjoying ${himself}, but gathers ${himself} together and greets you properly, without stopping.`]);
-
 		App.Events.addParagraph(node, [
 			Spoken(S.Wardeness, `"Told this whore I wasn't turning the lights off in ${his2} cell until ${he2} got me off. ${He2} can't sleep with 'em on, and bitches do anything for a little sleep,"`),
 			`${he} explains.`
diff --git a/src/events/RE/reArcologyInspection.js b/src/events/RE/reArcologyInspection.js
index d405fe60916..8254c119c2e 100644
--- a/src/events/RE/reArcologyInspection.js
+++ b/src/events/RE/reArcologyInspection.js
@@ -106,8 +106,7 @@ App.Events.REArcologyInspection = class REArcologyInspection extends App.Events.
 		if (!agent) {
 			t.push(`and currently doesn't have a permanent occupant,`);
 		}
-		t.push(`but it's nicely appointed and comfortable.`);
-		t.push(`Your gracious host suggests some other things that you could do while you're here, but you know you'll only really have time for one before you head back to ${home.name}:`);
+		t.push(`but it's nicely appointed and comfortable. Your gracious host suggests some other things that you could do while you're here, but you know you'll only really have time for one before you head back to ${home.name}.`);
 		App.Events.addParagraph(node, t);
 
 		const chosenFS = dipFSes.shared.filter(fs => arcology[fs] < 80).random();
diff --git a/src/events/RE/reMalefactor.js b/src/events/RE/reMalefactor.js
index f2437de13b3..0cb6652b99c 100644
--- a/src/events/RE/reMalefactor.js
+++ b/src/events/RE/reMalefactor.js
@@ -49,7 +49,6 @@ App.Events.REMalefactor = class REMalefactor extends App.Events.BaseEvent {
 
 		/** @type {App.Entity.SlaveState} */
 		const slave = makeMalefactor();
-		let pram;
 
 		const {
 			He, His,
@@ -621,6 +620,7 @@ App.Events.REMalefactor = class REMalefactor extends App.Events.BaseEvent {
 
 		function makeMalefactor() {
 			let slave;
+			let pram;
 			switch (malefactor) {
 				case "addict":
 					slave = GenerateNewSlave(null);
@@ -644,10 +644,10 @@ App.Events.REMalefactor = class REMalefactor extends App.Events.BaseEvent {
 					slave.skill.oral = 15;
 					slave.skill.anal = 35;
 					slave.skill.whoring = 15;
-					slave.earPiercing = 1;
-					slave.nosePiercing = 1;
-					slave.nipplesPiercing = 1;
-					slave.clitPiercing = 1;
+					slave.piercing.ear.weight = 1;
+					slave.piercing.nose.weight = 1;
+					slave.piercing.nipple.weight = 1;
+					slave.piercing.genitals.weight = 1;
 					slave.behavioralFlaw = "odd";
 					break;
 				case "escapee":
@@ -786,13 +786,13 @@ App.Events.REMalefactor = class REMalefactor extends App.Events.BaseEvent {
 					slave.buttImplantType = "normal";
 					slave.lips += 10;
 					slave.lipsImplant = 10;
-					slave.lipsPiercing = 1;
-					slave.tonguePiercing = 1;
-					slave.earPiercing = 1;
-					slave.nosePiercing = 1;
-					slave.eyebrowPiercing = 1;
-					slave.nipplesPiercing = 1;
-					slave.clitPiercing = 1;
+					slave.piercing.lips.weight = 1;
+					slave.piercing.tongue.weight = 1;
+					slave.piercing.ear.weight = 1;
+					slave.piercing.nose.weight = 1;
+					slave.piercing.eyebrow.weight = 1;
+					slave.piercing.nipple.weight = 1;
+					slave.piercing.genitals.weight = 1;
 					slave.sexualFlaw = "hates penetration";
 					slave.hStyle = "strip";
 					slave.custom.tattoo = "$He has a teardrop tattooed under each eye.";
diff --git a/src/events/RE/reRelativeRecruiter.js b/src/events/RE/reRelativeRecruiter.js
index aa161df46f2..089e57ec444 100644
--- a/src/events/RE/reRelativeRecruiter.js
+++ b/src/events/RE/reRelativeRecruiter.js
@@ -348,19 +348,10 @@ App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.Ba
 				slave.lipsImplant = 0;
 				slave.shouldersImplant = 0;
 				slave.voiceImplant = 0;
-				slave.areolaePiercing = 0;
-				slave.anusPiercing = 0;
-				slave.clitPiercing = 0;
-				slave.corsetPiercing = 0;
-				slave.dickPiercing = 0;
-				slave.earPiercing = 0;
-				slave.eyebrowPiercing = 0;
-				slave.lipsPiercing = 0;
-				slave.navelPiercing = 0;
-				slave.nipplesPiercing = 0;
-				slave.nosePiercing = 0;
-				slave.tonguePiercing = 0;
-				slave.vaginaPiercing = 0;
+				for (const piercing in slave.piercing) {
+					slave.piercing[piercing].weight = 0;
+				}
+				slave.piercing.genitals.smart = false;
 				slave.anusTat = 0;
 				slave.armsTat = 0;
 				slave.backTat = 0;
@@ -410,11 +401,11 @@ App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.Ba
 					slave.skill.anal += random(30, 50);
 					slave.skill.entertainment += random(0, 20);
 					slave.skill.whoring += random(30, 50);
-					slave.nipplesPiercing = 1;
-					slave.lipsPiercing = 1;
-					slave.tonguePiercing = 1;
-					slave.vaginaPiercing = 1;
-					slave.earPiercing = 1;
+					slave.piercing.nipple.weight = 1;
+					slave.piercing.lips.weight = 1;
+					slave.piercing.tongue.weight = 1;
+					slave.piercing.vagina.weight = 1;
+					slave.piercing.ear.weight = 1;
 					slave.makeup = 1;
 					slave.nails = 4;
 					slave.hStyle = either("luxurious", "neat", "tails", "up");
@@ -434,10 +425,10 @@ App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.Ba
 					slave.skill.whoring += random(30, 50);
 					slave.lips = random(60, 90);
 					slave.lipsImplant = 40;
-					slave.lipsPiercing = 1;
-					slave.tonguePiercing = 1;
-					slave.vaginaPiercing = 1;
-					slave.earPiercing = 1;
+					slave.piercing.lips.weight = 1;
+					slave.piercing.tongue.weight = 1;
+					slave.piercing.vagina.weight = 1;
+					slave.piercing.ear.weight = 1;
 					slave.makeup = 1;
 					slave.nails = 4;
 					slave.hStyle = "tails";
@@ -491,7 +482,7 @@ App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.Ba
 				}
 
 				function applySexToy() { // either sex
-					slave.tonguePiercing = 1;
+					slave.piercing.tongue.weight = 1;
 					slave.makeup = 1;
 					if (slave.balls < 4 && slave.balls > 0) {
 						slave.balls = 4;
@@ -535,7 +526,7 @@ App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.Ba
 					slave.butt += slave.buttImplant;
 					slave.lipsImplant = random(60, 80);
 					slave.lips = Math.clamp(slave.lips + slave.lipsImplant, 0, 100);
-					slave.nipplesPiercing = 2;
+					slave.piercing.nipple.weight = 2;
 					if (slave.vagina > -1) {
 						slave.vagina = 3;
 					}
diff --git a/src/events/RE/reRoyalBlood.js b/src/events/RE/reRoyalBlood.js
index 9fc199d862c..9eb028389bc 100644
--- a/src/events/RE/reRoyalBlood.js
+++ b/src/events/RE/reRoyalBlood.js
@@ -73,7 +73,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 		if (activeSF) {
 			if (V.rep > princessSF) {
 				choices.push(new App.Events.Result(
-					`Dispatch a ${V.SF.Lower} on a night time raid to acquire a pretty princess.`,
+					`Dispatch a ${V.SF.Lower} on a night time raid to acquire a pretty princess`,
 					() => getPrincess(false),
 					`You will be despised for this action, and trade will be greatly damaged.`));
 			} else {
@@ -101,7 +101,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 			if (activeSF) {
 				if (V.rep > princeSF) {
 					choices.push(new App.Events.Result(
-						`Dispatch ${V.SF.Lower} on a night time raid to acquire the crown prince.`,
+						`Dispatch ${V.SF.Lower} on a night time raid to acquire the crown prince`,
 						() => getPrince(false),
 						`You will be despised for this action, and trade will be greatly damaged.`
 					));
@@ -125,7 +125,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 			if (activeSF) {
 				if (V.rep > princeAndPrincessSF) {
 					choices.push(new App.Events.Result(
-						`Dispatch ${V.SF.Lower} on a night time raid to acquire both the prince and princess.`,
+						`Dispatch ${V.SF.Lower} on a night time raid to acquire both the prince and princess`,
 						() => getPrinceAndPrincess(false),
 						`You will be despised for this action, and trade will be greatly damaged.`
 					));
@@ -152,7 +152,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 		if (activeSF) {
 			if (V.rep > courtLadiesCostSF) {
 				choices.push(new App.Events.Result(
-					`Dispatch ${V.SF.Lower} on a night time raid to acquire a handful of court ladies.`,
+					`Dispatch ${V.SF.Lower} on a night time raid to acquire a handful of court ladies`,
 					() => getCourtLadies(false),
 					`You will be disliked for this action and trade will be damaged.`
 				));
@@ -205,7 +205,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 		if (activeSF) {
 			if (V.rep >= princessAndQueenSF) {
 				choices.push(new App.Events.Result(
-					`Dispatch ${V.SF.Lower} on a night time raid to acquire both the princess and Queen.`,
+					`Dispatch ${V.SF.Lower} on a night time raid to acquire both the princess and Queen`,
 					() => getPrincessAndQueen(false),
 					`You will be despised for this action, and trade will be greatly damaged.`
 				));
@@ -231,7 +231,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 		if (activeSF) {
 			if (V.rep >= queenAndCourtSF) {
 				choices.push(new App.Events.Result(
-					`Dispatch ${V.SF.Lower} on a night time raid to acquire the Queen and ${his3} court ladies.`,
+					`Dispatch ${V.SF.Lower} on a night time raid to acquire the Queen and ${his3} court ladies`,
 					() => getQueenAndCourt(false),
 					`You will be despised for this action, and trade will be greatly damaged.`
 				));
@@ -254,7 +254,7 @@ App.Events.RERoyalBlood = class RERoyalBlood extends App.Events.BaseEvent {
 
 			if (activeSF) {
 				choices.push(new App.Events.Result(
-					`Dispatch ${V.SF.Lower} on a night time raid to take everything of value.`,
+					`Dispatch ${V.SF.Lower} on a night time raid to take everything of value`,
 					() => getEntireCourt(false),
 					`You will be loathed for this action and trade will be crippled.`
 				));
diff --git a/src/events/RE/reShippingContainer.js b/src/events/RE/reShippingContainer.js
index a7bdf5b6f04..05661da1cce 100644
--- a/src/events/RE/reShippingContainer.js
+++ b/src/events/RE/reShippingContainer.js
@@ -1,12 +1,12 @@
 App.Events.REShippingContainer = class REShippingContainer extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
-			() => minimumSlaveCost() > 3000,
+			() => minimumSlaveCost(true) > minimumSlaveCost(false),
 		];
 	}
 
 	get weight() {
-		return random(0, 1);
+		return (V.debugMode && V.debugModeEventSelection) ? 1 : random(0, 1);
 	}
 
 	execute(node) {
diff --git a/src/events/RE/reShowerPunishment.js b/src/events/RE/reShowerPunishment.js
index 1b15322f0c7..67038a7136c 100644
--- a/src/events/RE/reShowerPunishment.js
+++ b/src/events/RE/reShowerPunishment.js
@@ -109,7 +109,7 @@ App.Events.REShowerPunishment = class REShowerPunishment extends App.Events.Base
 			r.push(`shredded abs.`);
 		} else if (S.HeadGirl.weight > 10) {
 			r.push(`plush belly.`);
-		} else if (S.HeadGirl.navelPiercing > 0) {
+		} else if (S.HeadGirl.piercing.navel.weight > 0) {
 			r.push(`pierced belly button.`);
 		} else if (S.HeadGirl.waist < -10) {
 			if (S.HeadGirl.waist < -95) {
diff --git a/src/events/RE/reSnatchAndGrabFollowup.js b/src/events/RE/reSnatchAndGrabFollowup.js
index 5c24cab02d4..52b48d67563 100644
--- a/src/events/RE/reSnatchAndGrabFollowup.js
+++ b/src/events/RE/reSnatchAndGrabFollowup.js
@@ -80,9 +80,24 @@ App.Events.RESnatchAndGrabFollowup = class RESnatchAndGrabFollowup extends App.E
 		choices.push(new App.Events.Result(`Let it be`, ignore));
 		App.Events.addResponses(node, choices);
 
+		function flawBreak() {
+			if (snatched.behavioralQuirk === "none") {
+				if (snatched.behavioralFlaw === "odd") {
+					snatched.behavioralFlaw = "none";
+				}
+				snatched.behavioralQuirk = "funny";
+				return `Over the next few weeks, you also begin to notice some significant changes in behavior. ${snatched.slaveName} is now <span class="flaw break">funny.</span>`;
+			} else if (snatched.sexualQuirk === "none") {
+				if (snatched.sexualFlaw === "repressed") {
+					snatched.sexualFlaw = "none";
+				}
+				snatched.sexualQuirk = "perverted";
+				return `Over the next few weeks, you also begin to notice some significant changes in behavior. Although ${snatched.slaveName} has always been remarkably horny, ${he} has become much more <span class="flaw break">perverted.</span>`;
+			}
+		}
+
 		function finish() {
-			const frag = new DocumentFragment();
-			let r = [];
+			const r = new SpacedTextAccumulator();
 			cashX(forceNeg(surgeryCost), "slaveSurgery", snatched);
 			surgeryDamage(snatched, 40);
 			snatched.chem += 100;
@@ -100,29 +115,19 @@ App.Events.RESnatchAndGrabFollowup = class RESnatchAndGrabFollowup extends App.E
 				r.push(`centimeters,`);
 			}
 			r.push(`leaving small needle marks that fade out within minutes. Despite not leaving lasting evidence, the process is very invasive work, and leaves ${him} <span class="health dec">feeling weak and tired.</span> Gradually, though, you begin to notice a marked increase in ${his} cognitive function.`);
-			App.Events.addParagraph(frag, r);
-			if (snatched.behavioralQuirk === "none") {
-				if (snatched.behavioralFlaw === "odd") {
-					snatched.behavioralFlaw = "none";
-				}
-				snatched.behavioralQuirk = "funny";
-				App.Events.addParagraph(frag, [`Over the next few weeks, you also begin to notice some significant changes in behavior. ${snatched.slaveName} is now <span class="flaw break">funny.</span>`]);
-				r.push();
-			} else if (snatched.sexualQuirk === "none") {
-				if (snatched.sexualFlaw === "repressed") {
-					snatched.sexualFlaw = "none";
-				}
-				snatched.sexualQuirk = "perverted";
-				App.Events.addParagraph(frag, [`Over the next few weeks, you also begin to notice some significant changes in behavior. Although ${snatched.slaveName} has always been remarkably horny, ${he} has become much more <span class="flaw break">perverted.</span>`]);
+			r.toParagraph();
+
+			const broken = flawBreak();
+			if (broken) {
+				r.push(broken);
+				r.toParagraph();
 			}
 
-			App.Events.addParagraph(frag, r);
-			return frag;
+			return r.container();
 		}
 
 		function deactivate() {
-			const frag = new DocumentFragment();
-			let r = [];
+			const r = new SpacedTextAccumulator();
 			cashX(forceNeg(V.surgeryCost * 4), "slaveSurgery", snatched);
 			surgeryDamage(snatched, 40);
 			snatched.chem += 100;
@@ -140,23 +145,15 @@ App.Events.RESnatchAndGrabFollowup = class RESnatchAndGrabFollowup extends App.E
 				r.push(`centimeters,`);
 			}
 			r.push(`leaving small needle marks that fade out within minutes. Despite not leaving lasting evidence, the process is very invasive work, and leaves ${him} <span class="health dec">feeling weak and tired.</span> Gradually, though, you begin to notice a marked decline in ${his} cognitive function.`);
-			App.Events.addParagraph(frag, r);
-			if (snatched.behavioralQuirk === "none") {
-				if (snatched.behavioralFlaw === "odd") {
-					snatched.behavioralFlaw = "none";
-				}
-				snatched.behavioralQuirk = "funny";
-				App.Events.addParagraph(frag, [`Over the next few weeks, you also begin to notice some significant changes in behavior. ${snatched.slaveName} is now <span class="flaw break">funny.</span>`]);
-			} else if (snatched.sexualQuirk === "none") {
-				if (snatched.sexualFlaw === "repressed") {
-					snatched.sexualFlaw = "none";
-				}
-				snatched.sexualQuirk = "perverted";
-				App.Events.addParagraph(frag, [`Over the next few weeks, you also begin to notice some significant changes in behavior. Although ${snatched.slaveName} has always been remarkably horny, ${he} has become much more <span class="flaw break">perverted.</span>`]);
+			r.toParagraph();
+
+			const broken = flawBreak();
+			if (broken) {
+				r.push(broken);
+				r.toParagraph();
 			}
 
-			App.Events.addParagraph(frag, r);
-			return frag;
+			return r.container();
 		}
 
 		function ignore() {
diff --git a/src/events/RE/reStandardPunishment.js b/src/events/RE/reStandardPunishment.js
index 9f6b3a09180..74e339eecf2 100644
--- a/src/events/RE/reStandardPunishment.js
+++ b/src/events/RE/reStandardPunishment.js
@@ -384,7 +384,7 @@ App.Events.REStandardPunishment = class REStandardPunishment extends App.Events.
 			const frag = new DocumentFragment();
 			let r = [];
 			r.push(`Since you use chastity as a punishment, you're accustomed to using your office for supervising sexual denial. You order ${him} to place ${his} ${hasBothArms(slave) ? "hands" : "hand"} in one of the many sets of restraints set high up on the office walls for the purpose.`);
-			if (slave.clitPiercing !== 3) {
+			if (!slave.piercing.genitals.smart) {
 				r.push(`You equip ${him} with a set of smart vibrators. The first is attached`);
 				if (slave.dick > 0) {
 					r.push(`to ${his} dickhead,`);
diff --git a/src/events/RECI/milf.js b/src/events/RECI/milf.js
index 05ccc3f1ebc..d573765ec87 100644
--- a/src/events/RECI/milf.js
+++ b/src/events/RECI/milf.js
@@ -654,7 +654,7 @@ App.Events.RECIMilf = class RECIMilf extends App.Events.BaseEvent {
 			} else {
 				t.push(`You`);
 			}
-			if (eventSlave.nipplesPiercing > 0) {
+			if (eventSlave.piercing.nipple.weight > 0) {
 				t.push(`gently tug on ${his} nipple piercings, earning a gentle intake of breath.`);
 			} else if (eventSlave.nipples === "huge") {
 				t.push(`run a feather-light touch along ${his} long nipples, earning a gasp as they stiffen.`);
diff --git a/src/events/RECI/ugly.js b/src/events/RECI/ugly.js
index 13a30211cb5..8cdac2782cd 100644
--- a/src/events/RECI/ugly.js
+++ b/src/events/RECI/ugly.js
@@ -97,7 +97,7 @@ App.Events.RECIUgly = class RECIUgly extends App.Events.BaseEvent {
 			let frag = document.createDocumentFragment();
 
 			t = [];
-			t.push(`You tell ${him} to head down to the wardrobe and put on the outfit that'll be laid out for ${him} there. ${He} obeys promptly, but does not return for some time, having gotten instructions from ${assistant.name} along the way to put extra effort into ${his} grooming. When ${he} finally returns, the effect is striking.`);
+			t.push(`You tell ${him} to head down to the wardrobe and put on the outfit that'll be laid out for ${him} there. ${He} obeys promptly, but does not return for some time, having gotten instructions from ${V.assistant.name} along the way to put extra effort into ${his} grooming. When ${he} finally returns, the effect is striking.`);
 			if (eventSlave.face > 10) {
 				t.push(`${He}'s a gorgeous ${girl} with or without makeup, dressed up or naked, but ${he}'s especially luscious tonight.`);
 			} else {
diff --git a/src/events/REFI/reBoobslut.js b/src/events/REFI/reBoobslut.js
index 07edc12568f..4d7c2029a2f 100644
--- a/src/events/REFI/reBoobslut.js
+++ b/src/events/REFI/reBoobslut.js
@@ -151,7 +151,7 @@ App.Events.REFIBoobslut = class REFIBoobslut extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} ${say}s through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing + eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight + eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} ${say}s through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} ${say}s,`);
diff --git a/src/events/REFI/reButtslut.js b/src/events/REFI/reButtslut.js
index e4e441f1611..515bdd3d200 100644
--- a/src/events/REFI/reButtslut.js
+++ b/src/events/REFI/reButtslut.js
@@ -128,7 +128,7 @@ App.Events.REFIButtslut = class REFIButtslut extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} ${say}s through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} ${say}s through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} ${say}s,`);
diff --git a/src/events/REFI/reMasochist.js b/src/events/REFI/reMasochist.js
index 9140f74415f..1bef1dbd92f 100644
--- a/src/events/REFI/reMasochist.js
+++ b/src/events/REFI/reMasochist.js
@@ -236,7 +236,7 @@ App.Events.REFIMasochist = class REFIMasochist extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} asks through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} asks through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} asks,`);
diff --git a/src/events/REFI/rePregnancy.js b/src/events/REFI/rePregnancy.js
index 1b43ca45e94..978ae5733c0 100644
--- a/src/events/REFI/rePregnancy.js
+++ b/src/events/REFI/rePregnancy.js
@@ -212,9 +212,7 @@ App.Events.REFIPregnancy = class REFIPregnancy extends App.Events.BaseEvent {
 
 		App.Events.addParagraph(node, t);
 
-		const responses = [
-			new App.Events.Result(`Steer ${him} away from fertility obsession for the moment`, steer),
-		];
+		const responses = [];
 		if (canPenetrate(eventSlave) && ((V.PC.preg >= 28 && V.PC.pregMood === 2) || V.PC.preg >= 36) && eventSlave.belly < 5000) {
 			responses.push(new App.Events.Result(`Sate your libido by giving ${him} a taste of lusty pregnant sex`, sate, "This option will penetrate you"));
 		}
@@ -230,6 +228,7 @@ App.Events.REFIPregnancy = class REFIPregnancy extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(`Turn ${him} into another fertility whore despite ${his} barrenness`, turnBarren, ));
 		}
+		responses.push(new App.Events.Result(`Steer ${him} away from fertility obsession for the moment`, steer));
 
 		App.Events.addResponses(node, responses);
 
@@ -261,7 +260,7 @@ App.Events.REFIPregnancy = class REFIPregnancy extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} asks through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} asks through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} asks,`);
@@ -489,7 +488,7 @@ App.Events.REFIPregnancy = class REFIPregnancy extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} ${say}s through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} ${say}s through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} ${say}s,`);
diff --git a/src/events/REFI/reSadist.js b/src/events/REFI/reSadist.js
index e13d435d85e..c97192b6128 100644
--- a/src/events/REFI/reSadist.js
+++ b/src/events/REFI/reSadist.js
@@ -144,7 +144,7 @@ App.Events.REFISadist = class REFISadist extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} asks through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} asks through ${his} big oral piercings,`);
 				} else {
 					t.push(`${He} asks,`);
diff --git a/src/events/REFS/refsBodyPurismEncounter.js b/src/events/REFS/refsBodyPurismEncounter.js
index e25d6f740b1..fcff36844e4 100644
--- a/src/events/REFS/refsBodyPurismEncounter.js
+++ b/src/events/REFS/refsBodyPurismEncounter.js
@@ -34,7 +34,7 @@ App.Events.refsBodyPurismEncounter = class refsBodyPurismEncounter extends App.E
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Pay for a day of treatment for ${him}`, pay, `The treatment will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to promote ${him}.`));
diff --git a/src/events/REFS/refsDegradationistEncounter.js b/src/events/REFS/refsDegradationistEncounter.js
index 386c16d0da4..9a3c07e87aa 100644
--- a/src/events/REFS/refsDegradationistEncounter.js
+++ b/src/events/REFS/refsDegradationistEncounter.js
@@ -28,7 +28,7 @@ App.Events.refsDegradationistEncounter = class refsDegradationistEncounter exten
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Alert your drones and keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Take the pampered slave ${girl} into your custody`, enslave, `Will cost ${cashFormat(cost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}.`));
diff --git a/src/events/REFS/refsMaturityPreferentialistEncounter.js b/src/events/REFS/refsMaturityPreferentialistEncounter.js
index 59ce1573235..2eeaccdd4cf 100644
--- a/src/events/REFS/refsMaturityPreferentialistEncounter.js
+++ b/src/events/REFS/refsMaturityPreferentialistEncounter.js
@@ -38,7 +38,7 @@ App.Events.refsMaturityPreferentialistEncounter = class refsMaturityPreferential
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Let them pass`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Fuck ${him} over dinner`, pay, `This will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to promote ${him}.`));
diff --git a/src/events/REFS/refsPastoralistEncounter.js b/src/events/REFS/refsPastoralistEncounter.js
index 9616155f36f..1db2ce3eda7 100644
--- a/src/events/REFS/refsPastoralistEncounter.js
+++ b/src/events/REFS/refsPastoralistEncounter.js
@@ -30,7 +30,7 @@ App.Events.refsPastoralistEncounter = class refsPastoralistEncounter extends App
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Offer to sponsor ${him} for a promotional video`, sponsor, `This will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to promote ${him}.`));
diff --git a/src/events/REFS/refsPaternalistEncounter.js b/src/events/REFS/refsPaternalistEncounter.js
index 96d330edbce..79aa01a49de 100644
--- a/src/events/REFS/refsPaternalistEncounter.js
+++ b/src/events/REFS/refsPaternalistEncounter.js
@@ -29,7 +29,7 @@ App.Events.refsPaternalistEncounter = class refsPaternalistEncounter extends App
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Alert your drones and keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Take the poor slave ${girl} into your custody`, enslave, `Will cost ${cashFormat(cost)}`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}.`));
diff --git a/src/events/REFS/refsPhysicalIdealistEncounter.js b/src/events/REFS/refsPhysicalIdealistEncounter.js
index df81309a9b4..4fa773cb528 100644
--- a/src/events/REFS/refsPhysicalIdealistEncounter.js
+++ b/src/events/REFS/refsPhysicalIdealistEncounter.js
@@ -26,7 +26,7 @@ App.Events.refsPhysicalIdealistEncounter = class refsPhysicalIdealistEncounter e
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Offer to sponsor ${him} for a promotional video`, sponsor, `This will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to promote ${him}.`));
diff --git a/src/events/REFS/refsRomanStoicism.js b/src/events/REFS/refsRomanStoicism.js
new file mode 100644
index 00000000000..a0bcbdc2181
--- /dev/null
+++ b/src/events/REFS/refsRomanStoicism.js
@@ -0,0 +1,56 @@
+App.Events.refsRomanStoicism = class refsRomanStoicism extends App.Events.BaseEvent {
+	eventPrerequisites() {
+		return [
+			() => V.arcologies[0].FSPaternalist > random(25, 100) || (V.debugMode > 0 && V.debugModeEventSelection > 0),
+			() => V.arcologies[0].FSRomanRevivalist > random(25, 100) || (V.debugMode > 0 && V.debugModeEventSelection > 0),
+		];
+	}
+
+	execute(node) {
+		const cost = 3000;
+
+		App.Events.addParagraph(node, [`Reviving the ancient Roman civilization in ${V.arcologies[0].name} was a turning point for many of your citizens. At first they only wore togas and stolas to cosplay in their kinky games with their spouse and slaves. But with patience and money, you managed to show them the true meaning of pursuing the vision of a new Rome. You transformed a group of slavers and opportunists into a city of patriotic citizens ready to defend their home and their newfound culture. For your wealthiest peers, choosing the Roman way of life included philosophizing like one. As such they studied stoicism and created a new version fitting of this renewed Roman era. Those dedicated stoics even bought slaves to teach them then philosophize with them.`]);
+
+		App.Events.addParagraph(node, [`While strolling on a market plaza, you stumble upon a group of citizens listening to one of those stoicism philosophers. But unlike your well-known wealthy thinkers, this stoic and his audience all appear to be poor citizens. Some of his listeners looked even poorer and more desperate. They're terrified of their ineluctable enslavement caused by debts and in need of advice. Or at least in need of hope.`]);
+
+		const choices = [];
+		choices.push(new App.Events.Result(`Keep walking`, ignore));
+		if (V.cash >= cost) {
+			choices.push(new App.Events.Result(`Offer financial support to the poorest`, pay, `Will cost ${cashFormat(cost)}`));
+		} else {
+			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to pay their debts`));
+		}
+		choices.push(new App.Events.Result(`Philosophize with the stoic`, talk));
+		App.Events.addResponses(node, choices);
+
+		function ignore() {
+			let r = [];
+			r.push (`You don't feel the need to intervene. This kind philosopher seems to know exactly what to answer to your citizens on the verge of enslavement. First they can choose the protective nature of indentured servitude. The paternalist nature of your slaveowning citizens is another reason why they shouldn't fear enslavement.`);
+			return r;
+		}
+
+		function pay() {
+			let r = [];
+			repX(1500, "event");
+			cashX(-cost, "event");
+			r.push (`Your presence is rapidly noted as you move through the audience to join the philosopher and the poor citizens. You tell them their worries have been heard and they shouldn't be fearful of the future. They may one day be subjected to enslavement and you reassure them that, in your paternalistic society, they'll be well cared for, but today they'll remain free as you'll pay their current debts. The thankful citizens have no words strong enough to repay your generosity and will spend the rest of the week <span class="reputation inc">blessing your name</span> to everyone they cross paths with.`);
+			return r;
+		}
+
+		function talk() {
+			let r = [];
+			r.push (`You express your wish to discuss with the stoic. The audience grows silent as the philosopher and you debate of paternalist ideals and post-apocalyptic stoicism. Your interlocutor and the audience`);
+			if (V.PC.rumor === "care") {
+				repX(300, "event");
+				r.push (`feels genuinely convinced by your words and your desire to make your ${V.arcologies[0].name} a haven where every citizen and slave is well cared for. You managed to dissipate their fear of enslavement and <span class="reputation inc">earned their respect.</span>`);
+			} else if (V.PC.rumor === "force") {
+				repX(-200, "event");
+				r.push (`are doubtful of your words. Hearing the ideals of paternalism come from the mouth of someone known to use force to get what they want is not at all convincing. The thought of being enslaved by someone like you is even <span class="reputation dec">more terrifying</span> than they feared.`);
+			} else {
+				repX(100, "event");
+				r.push (`listen carefully, but can only trust your words based on your achievements. The simple fact you managed to convince slaveowners to share your paternalist views is enough for the audience to have <span class="reputation inc">a little faith in you.</span>`);
+			}
+			return r;
+		}
+	}
+};
\ No newline at end of file
diff --git a/src/events/REFS/refsTransformationFetishismEncounter.js b/src/events/REFS/refsTransformationFetishismEncounter.js
index f69254b557d..f85cbabb869 100644
--- a/src/events/REFS/refsTransformationFetishismEncounter.js
+++ b/src/events/REFS/refsTransformationFetishismEncounter.js
@@ -36,7 +36,7 @@ App.Events.refsTransformationFetishismEncounter = class refsTransformationFetish
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Keep walking`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Pay for ${his} treatment`, pay, `This will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to promote ${him}.`));
diff --git a/src/events/REFS/refsWarhound.js b/src/events/REFS/refsWarhound.js
index 85e04a063f6..b841a48fe9d 100644
--- a/src/events/REFS/refsWarhound.js
+++ b/src/events/REFS/refsWarhound.js
@@ -85,7 +85,7 @@ App.Events.refsWarhound = class refsWarhound extends App.Events.BaseEvent {
 		const enormousCash = 20000;
 		const choices = [];
 		if (V.cash >= enormousCash) {
-			choices.push(new App.Events.Result(`Buy the Warbeast`, buy, cashFormat(enormousCash)));
+			choices.push(new App.Events.Result(`Buy the Warbeast`, buy, `Costs ${cashFormat(enormousCash)}`));
 		}
 
 		choices.push(new App.Events.Result(`Decline the merchant's offer`, refuse));
diff --git a/src/events/REFS/refsYouthPreferentialistEncounter.js b/src/events/REFS/refsYouthPreferentialistEncounter.js
index 5cff93a936f..1da2d1ad756 100644
--- a/src/events/REFS/refsYouthPreferentialistEncounter.js
+++ b/src/events/REFS/refsYouthPreferentialistEncounter.js
@@ -36,7 +36,7 @@ App.Events.refsYouthPreferentialistEncounter = class refsYouthPreferentialistEnc
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Let them pass`, ignore));
-		if (V.cash >= (cost)) {
+		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Fuck ${him} over dinner`, pay, `This will cost ${cashFormat(cost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to take ${him} on a date.`));
diff --git a/src/events/RESS/PAFlirting.js b/src/events/RESS/PAFlirting.js
index d007fc21f76..ae84a2113a1 100644
--- a/src/events/RESS/PAFlirting.js
+++ b/src/events/RESS/PAFlirting.js
@@ -577,7 +577,7 @@ App.Events.RESSPAFlirting = class RESSPAFlirting extends App.Events.BaseEvent {
 					}
 					r.push(`At different intervals, an undulation moves down the dildo, forcing ${him} to stretch wide to allow it to pass into ${his} body. Each "egg" forced into ${him} coincides with another blast from the ejaculating model, and it's filled ${him} so completely that each gush of fake cum flows down ${his} legs to join the puddle on the floor.`);
 			}
-			r.push(`"<span class="devotion inc">Good ${girl},</span>" ${V.assistant.name} says. The new slave turns resolutely away from the arresting sight and gets on with the inspection, doing ${hisU} best to ignore the lewd noises coming from that part of the room.`);
+			r.push(`<span class="devotion inc">"Good ${girl},"</span> ${V.assistant.name} says. The new slave turns resolutely away from the arresting sight and gets on with the inspection, doing ${hisU} best to ignore the lewd noises coming from that part of the room.`);
 			eventSlave.devotion += 4;
 			App.Events.addParagraph(frag, r);
 			return frag;
diff --git a/src/events/RESS/bedSnuggle.js b/src/events/RESS/bedSnuggle.js
index f5093e2c5ec..e5c6419ac7f 100644
--- a/src/events/RESS/bedSnuggle.js
+++ b/src/events/RESS/bedSnuggle.js
@@ -97,7 +97,7 @@ App.Events.RESSBedSnuggle = class RESSBedSnuggle extends App.Events.BaseEvent {
 		} else {
 			r.push("chest.");
 		}
-		r.push(contextualIntro(V.PC, eventSlave, "DOM"));
+		r.push(contextualIntro(V.PC, eventSlave, "DOM", false, true));
 		r.push(`has snuggled up against you in ${his} sleep. ${He}'s nude, and so are you; everyone sleeps naked in your penthouse. The sheet is down at your hips, leaving your upper bodies bare.`);
 		if (!hasAnyArms(eventSlave)) {
 			r.push(`${He}'s wormed ${his}`);
diff --git a/src/events/RESS/birthday.js b/src/events/RESS/birthday.js
index 4683b549407..1f3d770e57a 100644
--- a/src/events/RESS/birthday.js
+++ b/src/events/RESS/birthday.js
@@ -74,7 +74,7 @@ App.Events.RESSBirthday = class RESSBirthday extends App.Events.BaseEvent {
 			r.push(`to ingrain ${his} birthday back in ${his} mind. When the cake is done, you quickly dust it with confectionary sugar, stand a hot wax candle in the middle of it, and invite ${him} to think of a wish and blow it out. ${He} sits on your lap and the two of you take turns feeding each other warm cake. When the cake is gone ${he} gets up to do the dishes and you turn to go. As you go, ${he} asks`);
 			if (eventSlave.lips > 70) {
 				r.push(`through ${his} massive dick-sucking lips,`);
-			} else if ((eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2)) {
+			} else if ((eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2)) {
 				r.push(`through ${his} inconvenient oral piercings,`);
 			}
 			r.push(Spoken(eventSlave, `"${Master}, may I tell you what my wish was?"`));
diff --git a/src/events/RESS/comfortableSeat.js b/src/events/RESS/comfortableSeat.js
index cd26a7f81e6..4f75a2eae23 100644
--- a/src/events/RESS/comfortableSeat.js
+++ b/src/events/RESS/comfortableSeat.js
@@ -89,7 +89,7 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba
 		} else if (eventSlave.dick > 0) {
 			t.push(`${His} ${dickSize} dick is as soft as ever, but there's a string of precum running between ${eventSlave.foreskin === 0 ? "its smooth tip" : "the soft foreskin that completely covers its tip"} and ${his} inner thigh.`);
 		} else if (eventSlave.clit > 0) {
-			t.push(`${His} ${eventSlave.clit > 1 ? "formidable" : "big"} clit is visibly erect. ${eventSlave.clitPiercing > 1 ? `${His} sizable clit piercing never lets its hood completely cover hide ${his} bitch button, but it's completely retracted now,` : `${His} delicate clitoral hood has been pushed back by ${his} female erection,`} leaving ${him} proudly aroused.`);
+			t.push(`${His} ${eventSlave.clit > 1 ? "formidable" : "big"} clit is visibly erect. ${eventSlave.piercing.genitals.weight > 1 ? `${His} sizable clit piercing never lets its hood completely cover hide ${his} bitch button, but it's completely retracted now,` : `${His} delicate clitoral hood has been pushed back by ${his} female erection,`} leaving ${him} proudly aroused.`);
 		} else if (eventSlave.labia > 0) {
 			t.push(`${His} ${eventSlave.labia > 1 ? "dangling" : "thick"} labia are visibly swollen, flushing and growing prouder as the blood rushes to ${his} womanhood.`);
 		} else if (eventSlave.vagina === -1) {
diff --git a/src/events/RESS/impregnationPlease.js b/src/events/RESS/impregnationPlease.js
index 2539b762a4a..27ef0f4b2a8 100644
--- a/src/events/RESS/impregnationPlease.js
+++ b/src/events/RESS/impregnationPlease.js
@@ -162,7 +162,7 @@ App.Events.RESSImpregnationPlease = class RESSImpregnationPlease extends App.Eve
 				r.push(Spoken(eventSlave, `"Please put another baby in me, ${Master}, I have plenty of room still,"`));
 				if (eventSlave.lips > 70) {
 					r.push(`${he} begs through ${his} dick-sucking lips.`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`${he} begs through ${his} ridiculous piercings.`);
 				} else {
 					r.push(`${he} begs.`);
@@ -202,7 +202,7 @@ App.Events.RESSImpregnationPlease = class RESSImpregnationPlease extends App.Eve
 				r.push(Spoken(eventSlave, `"Please knock me up, ${Master},"`));
 				if (eventSlave.lips > 70) {
 					r.push(`${he} begs through ${his} dick-sucking lips.`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`${he} begs through ${his} ridiculous piercings.`);
 				} else {
 					r.push(`${he} begs.`);
@@ -309,7 +309,7 @@ App.Events.RESSImpregnationPlease = class RESSImpregnationPlease extends App.Eve
 			r.push(`${He} starts blubbering inelegantly and`);
 			if (!canTalk(eventSlave)) {
 				r.push(`gesturing`);
-			} else if ((eventSlave.lips > 70) || (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2)) {
+			} else if ((eventSlave.lips > 70) || (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2)) {
 				r.push(`lisping`);
 			} else {
 				r.push(`whimpering`);
diff --git a/src/events/RESS/languageLesson.js b/src/events/RESS/languageLesson.js
index 46269aa9779..7650b34c1f2 100644
--- a/src/events/RESS/languageLesson.js
+++ b/src/events/RESS/languageLesson.js
@@ -67,12 +67,12 @@ App.Events.RESSLanguageLesson = class RESSLanguageLesson extends App.Events.Base
 			}
 			r.push(`intently for any indication that ${he}'s misunderstood you. Once there, ${he} stops, knees bent partway as ${he} second-guesses ${himself} about whether ${he}'s supposed to sit. Sighing internally, you grab`);
 			if (eventSlave.belly >= 5000) {
-				if (eventSlave.navelPiercing > 0) {
+				if (eventSlave.piercing.navel.weight > 0) {
 					r.push(`the piercing dangling from ${his} ${belly} belly`);
 				} else {
 					r.push(`${his} ${belly} belly`);
 				}
-			} else if (eventSlave.nipplesPiercing > 0) {
+			} else if (eventSlave.piercing.nipple.weight > 0) {
 				r.push(`a nipple piercing`);
 			} else if (eventSlave.nipples === "fuckable") {
 				r.push(`a nipplecunt`);
diff --git a/src/events/RESS/moistPussy.js b/src/events/RESS/moistPussy.js
index 190b6e58afe..b332252b6f0 100644
--- a/src/events/RESS/moistPussy.js
+++ b/src/events/RESS/moistPussy.js
@@ -290,7 +290,7 @@ App.Events.RESSMoistPussy = class RESSMoistPussy extends App.Events.BaseEvent {
 				t.push(`body.`);
 			}
 			t.push(`You keep your fingers where they are until ${he}'s licked them really clean. ${His} hot tongue runs repeatedly between each of your fingers`);
-			if (eventSlave.tonguePiercing > 0) {
+			if (eventSlave.piercing.tongue.weight > 0) {
 				t.push(`and the smooth hardness of ${his} tongue piercing brushes against them`);
 			}
 			t.push(t.pop() + ".");
diff --git a/src/events/RESS/nightVisit.js b/src/events/RESS/nightVisit.js
index e66a0a900e0..c13bd519833 100644
--- a/src/events/RESS/nightVisit.js
+++ b/src/events/RESS/nightVisit.js
@@ -54,7 +54,7 @@ App.Events.RESSNightVisit = class RESSNightVisit extends App.Events.BaseEvent {
 		} else {
 			if (eventSlave.lips > 70) {
 				r.push(`${he} says meekly through ${his} massive dick-sucking lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`${he} says meekly through ${his} inconvenient oral piercings,`);
 			} else {
 				r.push(`${he} says meekly,`);
diff --git a/src/events/RESS/obedientGirlish.js b/src/events/RESS/obedientGirlish.js
index de35831fd01..5d50f0ec3db 100644
--- a/src/events/RESS/obedientGirlish.js
+++ b/src/events/RESS/obedientGirlish.js
@@ -84,7 +84,7 @@ App.Events.RESSObedientGirlish = class RESSObedientGirlish extends App.Events.Ba
 		function dress() {
 			t = [];
 
-			t.push(`You let ${eventSlave.slaveName} don a nice dress and take ${him} out ${!canWalk(eventSlave) ? "in a wheelchair" : ""}. ${He}'s a little suspicious at first but when you reach the first balcony on your lazy route around the huge building the sun on ${his} face and the gentle breeze around ${his} ears convince ${him} there's no trick. ${He} watches you shyly as you lead ${him} around, soaking in the sights and relaxing. Though you still speak as ${his} ${getWrittenTitle(eventSlave)}, you chat about goings on around the arcology, and you buy ${him} a fresh fruit from a vendor. The unexpected show of care and compassion has ${him} quite agog. By the time you take ${him} out onto another park-like balcony and fuck ${him} on a bench,`);
+			t.push(`You let ${eventSlave.slaveName} don a nice dress and take ${him} out${!canWalk(eventSlave) ? ` in a wheelchair` : ``}. ${He}'s a little suspicious at first but when you reach the first balcony on your lazy route around the huge building the sun on ${his} face and the gentle breeze around ${his} ears convince ${him} there's no trick. ${He} watches you shyly as you lead ${him} around, soaking in the sights and relaxing. Though you still speak as ${his} ${getWrittenTitle(eventSlave)}, you chat about goings on around the arcology, and you buy ${him} a fresh fruit from a vendor. The unexpected show of care and compassion has ${him} quite agog. By the time you take ${him} out onto another park-like balcony and fuck ${him} on a bench,`);
 			if (eventSlave.dick > 0 && eventSlave.chastityPenis === 1 && eventSlave.chastityAnus === 1) {
 				t.push(`${his} combined chastity cage and anal chastity belt makes ${him} move awkwardly.`);
 			} else if (eventSlave.dick > 0 && eventSlave.chastityPenis === 1) {
@@ -122,7 +122,7 @@ App.Events.RESSObedientGirlish = class RESSObedientGirlish extends App.Events.Ba
 			} else {
 				if (eventSlave.lips > 70) {
 					t.push(`${He} protests through ${his} huge lips,`);
-				} else if (eventSlave.lipsPiercing + eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight + eventSlave.piercing.tongue.weight > 2) {
 					t.push(`${He} protests through ${his} piercings,`);
 				} else {
 					t.push(`${He} protests,`);
diff --git a/src/events/RESS/obedientShemale.js b/src/events/RESS/obedientShemale.js
index 3a0faff2b53..4c6e0216c49 100644
--- a/src/events/RESS/obedientShemale.js
+++ b/src/events/RESS/obedientShemale.js
@@ -41,7 +41,7 @@ App.Events.RESSObedientShemale = class RESSObedientShemale extends App.Events.Ba
 		if (canTalk(eventSlave)) {
 			if (eventSlave.lips > 70) {
 				t.push(`${He} begs meekly through ${his} massive dick-sucking lips,`);
-			} else if (eventSlave.lipsPiercing + eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight + eventSlave.piercing.tongue.weight > 2) {
 				t.push(`${He} begs meekly through ${his} mouthful of piercings,`);
 			} else {
 				t.push(`${He} begs meekly,`);
diff --git a/src/events/RESS/review/bondedLove.js b/src/events/RESS/review/bondedLove.js
index bc5a96b46cf..6afe5b46dd8 100644
--- a/src/events/RESS/review/bondedLove.js
+++ b/src/events/RESS/review/bondedLove.js
@@ -146,7 +146,7 @@ App.Events.RESSBondedLove = class RESSBondedLove extends App.Events.BaseEvent {
 			r.push(`${his} generous petals, flushed and a little full from the warmth of the shower, offer soft, healthy advertisement of ${his} womanhood.`);
 		} else if (eventSlave.clit > 0) {
 			r.push(`${his} prominent clit, flushed and a little full from the warmth of the shower, offers soft testament to ${his} female sexuality.`);
-		} else if (eventSlave.clitPiercing > 0) {
+		} else if (eventSlave.piercing.genitals.weight > 0) {
 			r.push(`${his} glinting`);
 			if (eventSlave.dick === 0) {
 				r.push(`clit`);
@@ -170,7 +170,7 @@ App.Events.RESSBondedLove = class RESSBondedLove extends App.Events.BaseEvent {
 		r.push(`to bring ${his}`);
 		if (eventSlave.lips > 40) {
 			r.push(`pillowy`);
-		} else if (eventSlave.lipsPiercing > 0) {
+		} else if (eventSlave.piercing.lips.weight > 0) {
 			r.push(`pierced`);
 		}
 		r.push(`lips next to your ear.`);
@@ -191,11 +191,9 @@ App.Events.RESSBondedLove = class RESSBondedLove extends App.Events.BaseEvent {
 
 		function good() {
 			const r = new SpacedTextAccumulator();
-			r.push(`Without turning your head, you tell ${him} ${he}'s a very good slave. ${He} laughs happily`);
-			if (canTalk(eventSlave)) {
-				r.addToLast(`, though of course this is silent,`);
-			} else {
-				r.push(`throatily,`);
+			r.push(`Without turning your head, you tell ${him} ${he}'s a very good slave. ${He} laughs happily,`);
+			if (!canTalk(eventSlave)) {
+				r.addToLast(`though of course this is silent,`);
 			}
 			r.push(`${his} warm breath gusting against your ear. It took confidence for ${him} to come in here and tell ${him} ${he} loved you, and ${he} <span class="trust inc">trusts you more</span> for responding this way. ${He} plants a light kiss on your cheek and walks quickly out of your office, hurrying to go about ${his} day's business, but careful to strut ${his} stuff for you on ${his} way out.`);
 			if (eventSlave.butt < 3) {
diff --git a/src/events/RESS/review/breastExpansionBlues.js b/src/events/RESS/review/breastExpansionBlues.js
index f4ba466ceac..58056f9dc7f 100644
--- a/src/events/RESS/review/breastExpansionBlues.js
+++ b/src/events/RESS/review/breastExpansionBlues.js
@@ -312,7 +312,7 @@ App.Events.RESSBreastExpansionBlues = class RESSBreastExpansionBlues extends App
 			if (eventSlave.nipples === "inverted") {
 				r.push(`cruelly pop ${his} inverted nipples out and`);
 			}
-			if (eventSlave.nipplesPiercing === 0) {
+			if (eventSlave.piercing.nipple.weight === 0) {
 				r.push(`attach a clip to each of`);
 				if (eventSlave.nipples === "inverted") {
 					r.push(`them.`);
@@ -320,7 +320,7 @@ App.Events.RESSBreastExpansionBlues = class RESSBreastExpansionBlues extends App
 					r.push(`${his} nipples.`);
 				}
 				r.push(`The clips aren't painful, not yet, but they're very robust, and the reason is immediately apparent to ${him}.`);
-			} else if (eventSlave.nipplesPiercing === 1) {
+			} else if (eventSlave.piercing.nipple.weight === 1) {
 				r.push(`remove ${his} nipple piercings, one by one, and replace them with big rings. Then you give each of them a tug to ensure it's ready to bear some serious pulling.`);
 			} else {
 				r.push(`give each of ${his} nipple rings a tug to ensure it's ready to bear some serious pulling.`);
diff --git a/src/events/RESS/review/cumslutWhore.js b/src/events/RESS/review/cumslutWhore.js
index 3a5bbed6a78..042588bccdd 100644
--- a/src/events/RESS/review/cumslutWhore.js
+++ b/src/events/RESS/review/cumslutWhore.js
@@ -107,7 +107,7 @@ App.Events.RESSCumslutWhore = class RESSCumslutWhore extends App.Events.BaseEven
 				r.push(`${he} ${say}s`);
 				if (eventSlave.lips > 70) {
 					r.push(`past ${his} enormous lips`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`past ${his} mouthful of piercings`);
 				}
 				r.push(r.pop() + `.`);
diff --git a/src/events/RESS/review/devotedOld.js b/src/events/RESS/review/devotedOld.js
index 9c585823fd3..30a736be188 100644
--- a/src/events/RESS/review/devotedOld.js
+++ b/src/events/RESS/review/devotedOld.js
@@ -39,7 +39,7 @@ App.Events.RESSDevotedOld = class RESSDevotedOld extends App.Events.BaseEvent {
 		r.push(Spoken(eventSlave, `"${Master}, I'm so sorry you noticed,"`));
 		if (eventSlave.lips > 70) {
 			r.push(`${he} lisps through ${his} dick-sucking lips.`);
-		} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+		} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 			r.push(`${he} lisps through ${his} ridiculous piercings.`);
 		} else {
 			r.push(`${he} ${say}s penitently.`);
diff --git a/src/events/RESS/review/heavyPiercing.js b/src/events/RESS/review/heavyPiercing.js
index 4a63ab25bf8..1321b23cc23 100644
--- a/src/events/RESS/review/heavyPiercing.js
+++ b/src/events/RESS/review/heavyPiercing.js
@@ -7,9 +7,9 @@ App.Events.RESSHeavyPiercing = class RESSHeavyPiercing extends App.Events.BaseEv
 		return [
 			[ // single event slave
 				s => s.fetish !== "mindbroken",
-				s => s.vaginaPiercing > 1,
-				s => s.nipplesPiercing > 1,
-				s => s.clitPiercing > 1,
+				s => s.piercing.vagina.weight > 1,
+				s => s.piercing.nipple.weight > 1,
+				s => s.piercing.genitals.weight > 1,
 				s => s.devotion > 20 || s.trust < -20,
 				s => s.devotion <= 50,
 				s => canDoAnal(s) || canDoVaginal(s)
diff --git a/src/events/RESS/review/hormoneDysfunction.js b/src/events/RESS/review/hormoneDysfunction.js
index 4b946aa270a..ed984fb39a3 100644
--- a/src/events/RESS/review/hormoneDysfunction.js
+++ b/src/events/RESS/review/hormoneDysfunction.js
@@ -38,7 +38,7 @@ App.Events.RESSHormoneDysfunction = class RESSHormoneDysfunction extends App.Eve
 		} else {
 			if (eventSlave.lips > 70) {
 				r.push(`penis and ${say}s through ${his} huge lips,`);
-			} else if (eventSlave.lipsPiercing + eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight + eventSlave.piercing.tongue.weight > 2) {
 				r.push(`penis and ${say}s through ${his} piercings,`);
 			} else {
 				r.push(`penis and ${say}s,`);
diff --git a/src/events/RESS/review/hugeNaturals.js b/src/events/RESS/review/hugeNaturals.js
index 18fbbdecd60..7d36ce64f3b 100644
--- a/src/events/RESS/review/hugeNaturals.js
+++ b/src/events/RESS/review/hugeNaturals.js
@@ -45,7 +45,7 @@ App.Events.RESSHugeNaturals = class RESSHugeNaturals extends App.Events.BaseEven
 		} else {
 			if (eventSlave.lips > 70) {
 				r.push(`murmurs through ${his} huge lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`murmurs through ${his} piercings,`);
 			} else {
 				r.push(`murmurs,`);
diff --git a/src/events/RESS/review/hugeTits.js b/src/events/RESS/review/hugeTits.js
index cd6d9abc3fc..75bca13c25f 100644
--- a/src/events/RESS/review/hugeTits.js
+++ b/src/events/RESS/review/hugeTits.js
@@ -41,7 +41,7 @@ App.Events.RESSHugeTits = class RESSHugeTits extends App.Events.BaseEvent {
 		);
 		if (eventSlave.lips > 70) {
 			r.push(`through ${his} huge lips,`);
-		} else if ((eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2)) {
+		} else if ((eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2)) {
 			r.push(`through ${his} piercings,`);
 		} else {
 			r.push(`piteously,`);
diff --git a/src/events/RESS/review/hugelyPregnant.js b/src/events/RESS/review/hugelyPregnant.js
index ccc55d5af97..59ec5846473 100644
--- a/src/events/RESS/review/hugelyPregnant.js
+++ b/src/events/RESS/review/hugelyPregnant.js
@@ -91,7 +91,7 @@ App.Events.RESSHugelyPregnant = class RESSHugelyPregnant extends App.Events.Base
 			} else {
 				if (eventSlave.lips > 70) {
 					r.push(`${He} murmurs through ${his} huge lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`${He} murmurs through ${his} piercings,`);
 				} else {
 					r.push(`${He} murmurs,`);
@@ -151,7 +151,7 @@ App.Events.RESSHugelyPregnant = class RESSHugelyPregnant extends App.Events.Base
 			} else {
 				if (eventSlave.lips > 70) {
 					r.push(`${He} murmurs through ${his} huge lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`${He} murmurs through ${his} piercings,`);
 				} else {
 					r.push(`${He} murmurs,`);
diff --git a/src/events/RESS/review/ignorantHorny.js b/src/events/RESS/review/ignorantHorny.js
index 50b9147148a..69965f2e82c 100644
--- a/src/events/RESS/review/ignorantHorny.js
+++ b/src/events/RESS/review/ignorantHorny.js
@@ -66,7 +66,7 @@ App.Events.RESSIgnorantHorny = class RESSIgnorantHorny extends App.Events.BaseEv
 		r = [];
 		if (eventSlave.aphrodisiacs > 0 || eventSlave.inflationType === "aphrodisiac") {
 			r.push(`The aphrodisiacs racing through ${his} system have ${him} desperate to get off, right now.`);
-		} else if (eventSlave.clitPiercing === 3 && eventSlave.clitSetting !== "none") {
+		} else if (eventSlave.piercing.genitals.smart && eventSlave.clitSetting !== "none") {
 			r.push(His);
 			if (eventSlave.vagina > -1) {
 				r.push(`clit`);
@@ -100,7 +100,7 @@ App.Events.RESSIgnorantHorny = class RESSIgnorantHorny extends App.Events.BaseEv
 			r.push(`You explain the effects of the`);
 			if (eventSlave.aphrodisiacs > 0 || eventSlave.inflationType === "aphrodisiac") {
 				r.push(`sex drugs`);
-			} else if (eventSlave.clitPiercing === 3 && eventSlave.clitSetting !== "none") {
+			} else if (eventSlave.piercing.genitals.smart && eventSlave.clitSetting !== "none") {
 				r.push(`advanced`);
 				if (eventSlave.vagina > -1) {
 					r.push(`clit`);
diff --git a/src/events/RESS/review/implantInspection.js b/src/events/RESS/review/implantInspection.js
index f63ae9f25e9..d9a4058bd5b 100644
--- a/src/events/RESS/review/implantInspection.js
+++ b/src/events/RESS/review/implantInspection.js
@@ -48,7 +48,7 @@ App.Events.RESSImplantInspection = class RESSImplantInspection extends App.Event
 		} else {
 			if (eventSlave.lips > 70) {
 				r.push(`murmurs through ${his} huge lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`murmurs through ${his} piercings,`);
 			} else {
 				r.push(`murmurs,`);
diff --git a/src/events/RESS/review/inconvenientLabia.js b/src/events/RESS/review/inconvenientLabia.js
index 005e6e999bf..ed38d3ec3c7 100644
--- a/src/events/RESS/review/inconvenientLabia.js
+++ b/src/events/RESS/review/inconvenientLabia.js
@@ -49,7 +49,7 @@ App.Events.RESSInconvenientLabia = class RESSInconvenientLabia extends App.Event
 		} else {
 			if (eventSlave.lips > 70) {
 				r.push(`${He} lisps through ${his} massive lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`${He} lisps through ${his} huge piercings,`);
 			}
 			r.push(
diff --git a/src/events/RESS/review/modsPlease.js b/src/events/RESS/review/modsPlease.js
index 82e69a4913f..db2e32032af 100644
--- a/src/events/RESS/review/modsPlease.js
+++ b/src/events/RESS/review/modsPlease.js
@@ -18,12 +18,12 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 				s => s.dick !== 0 || s.vagina !== -1,
 				s => s.nipples !== "fuckable",
 				s => s.rules.speech === "permissive",
-				s => s.corsetPiercing === 0,
-				s => s.tonguePiercing === 0,
-				s => s.anusPiercing === 0,
-				s => s.nipplesPiercing === 0,
-				s => s.dickPiercing === 0,
-				s => s.vaginaPiercing === 0,
+				s => s.piercing.corset.weight === 0,
+				s => s.piercing.tongue.weight === 0,
+				s => s.piercing.anus.weight === 0,
+				s => s.piercing.nipple.weight === 0,
+				s => s.piercing.dick.weight === 0,
+				s => s.piercing.vagina.weight === 0,
 				s => s.lipsTat === 0 || s.lipsTat === "none",
 				s => s.vaginaTat === 0 || s.vaginaTat === "none",
 			]
@@ -253,7 +253,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 						r.push(`gingerly feeling around ${his} new piercings.`);
 					}
 					r.push(`${He} <span class="devotion inc">smiles devotedly,</span> and asks you when ${he}'ll be healed enough that ${he} can be laced up.`);
-					eventSlave.corsetPiercing = 1;
+					eventSlave.piercing.corset.weight = 1;
 				} else if (eventSlave.fetish === "cumslut") {
 					r.push(`hold ${his} mouth agape and place the first piercing. ${He} can't make much of a facial expression with ${his} mouth that wide, but there is a lewd`);
 					if (canSee(eventSlave)) {
@@ -262,7 +262,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 						r.push(`look on ${his} face`);
 					}
 					r.push(`when ${he} realizes ${he}'s getting more than one. When you're done, ${he}'s sore enough that ${he} gestures ${his} thanks, <span class="devotion inc">smiling devotedly,</span> and begs you to try ${him} out when ${he}'s healed up.`);
-					eventSlave.tonguePiercing = 2;
+					eventSlave.piercing.tongue.weight = 2;
 				} else if (eventSlave.fetish === "humiliation") {
 					r.push(`activate the ink gun, its low buzzing drawing a moan of anticipation out of ${eventSlave.slaveName}. Working at a touchscreen, you exercise your artistic talents, inscribing the slave's status as a sex object on ${his} forehead. The pain is intense, but ${he} tolerates it, the tears running fast out of the corners of ${his} eyes and low groans rising out of ${his} throat. When ${he}'s finally allowed to rise`);
 					if (canSee(eventSlave)) {
@@ -274,7 +274,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 					eventSlave.lipsTat = "degradation";
 				} else if (eventSlave.fetish === "buttslut") {
 					r.push(`place a spreader to keep ${his} legs and cheeks apart and start piercing. ${He} whines with the pain, and then gasps when ${he} realizes that the piercing is going on much longer than ${he} expected. You give ${him} a couple of huge piercings below ${his} anus, big enough that ${he}'ll never be free of them rubbing against ${his} slutty butthole. Not done yet, you put some small, smooth studs around it, just to make sure nobody can possibly misunderstand where to fuck this bitch. ${He} gets up gingerly, but <span class="devotion inc">smiling sluttily.</span>`);
-					eventSlave.anusPiercing = 2;
+					eventSlave.piercing.anus.weight = 2;
 				} else if (eventSlave.fetish === "boobs") {
 					if (eventSlave.nipples.includes("inverted")) {
 						r.push(`use a couple of its actuators to stimulate ${his} nipples until they're almost all the way protruded, and then direct them to pull them out all the way. ${He} screams wholeheartedly at the pain, yelling on and on until ${he}'s out of breath and relaxes against the restraints, gasping and crying.`);
@@ -282,7 +282,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 						r.push(`use its actuators to pull ${his} nipples out as far as they will go, forcing a gasp of pain out of ${him}.`);
 					}
 					r.push(`${He} expects a simple nipple piercing, one for each boob; what ${he} gets is a set of heavy rings in each nipple. ${He}'s no masochist, so the pleasure will come later, but ${he} moans as ${he} feels the gradual addition of weight to ${his} nipples. ${He} rises very carefully, trying to keep ${his} boobs still, and <span class="devotion inc">smiles devotedly</span> at you. Soon enough, ${he}'ll be able to orgasm by walking.`);
-					eventSlave.nipplesPiercing = 2;
+					eventSlave.piercing.nipple.weight = 2;
 				} else if (eventSlave.fetish === "pregnancy") {
 					if (eventSlave.belly >= 10001) {
 						r.push(`hold ${his} ${belly} stomach steady and pierce ${his} navel with the largest, heaviest ring available. There is a lewd`);
@@ -292,7 +292,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 							r.push(`look on ${his} face`);
 						}
 						r.push(`as ${he} feels the new weight settle against ${his} middle. ${He} rises very carefully, trying to keep ${his} new piercing from moving, and <span class="devotion inc">smiles devotedly</span> at you. Soon enough, all eyes will be on ${his} belly as ${he} waddles by.`);
-						eventSlave.navelPiercing = 2;
+						eventSlave.piercing.navel.weight = 2;
 					} else {
 						r.push(`activate the ink gun, its low buzzing drawing a moan of anticipation out of ${eventSlave.slaveName}. Working at a touchscreen, you exercise your artistic talents, beautifying ${his}`);
 						if (eventSlave.belly >= 150) {
@@ -328,7 +328,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 				} else if (eventSlave.fetish === "sadist") {
 					if (canAchieveErection(eventSlave)) {
 						r.push(`take hold of ${his} most intimate parts and put a set of massive piercings straight through ${his} shaft. ${He} shrieks with agony, the noise going on and on before diminishing into breathless sobbing. Much later, when ${he} gets gingerly up from the chair, ${he} doesn't look eager to stick ${his} cock in anything, but ${he}'s <span class="devotion inc">thankful enough.</span>`);
-						eventSlave.dickPiercing = 2;
+						eventSlave.piercing.dick.weight = 2;
 					} else if (eventSlave.dick > 0) {
 						r.push(`hold ${his} mouth agape and place the first piercing. ${He} can't make much of a facial expression with ${his} mouth that wide, but there is a lewd`);
 						if (canSee(eventSlave)) {
@@ -337,19 +337,19 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 							r.push(`look on ${his} face`);
 						}
 						r.push(`when ${he} realizes ${he}'s getting more than one. When you're done, ${he}'s sore enough that ${he} gestures ${his} thanks, <span class="devotion inc">smiling devotedly;</span> ${he} looks eager to try out ${his} new piercing on a fresh pussy.`);
-						eventSlave.tonguePiercing = 2;
+						eventSlave.piercing.tongue.weight = 2;
 					} else {
 						r.push(`take hold of ${his} most intimate parts and put a set of massive piercings straight through ${his} pussylips. ${He} shrieks with agony, the noise going on and on before diminishing into breathless sobbing. Much later, when ${he} gets gingerly up from the chair, ${he} doesn't look eager to trib anything, but ${he}'s <span class="devotion inc">thankful enough.</span>`);
-						eventSlave.vaginaPiercing = 2;
+						eventSlave.piercing.vagina.weight = 2;
 					}
 				} else if (eventSlave.fetish === "masochist") {
 					r.push(`take hold of ${his} most intimate parts and put a series of massive piercing straight through ${his}`);
 					if (eventSlave.dick > 0) {
 						r.push(`shaft.`);
-						eventSlave.dickPiercing = 2;
+						eventSlave.piercing.dick.weight = 2;
 					} else {
 						r.push(`pussylips.`);
-						eventSlave.vaginaPiercing = 2;
+						eventSlave.piercing.vagina.weight = 2;
 					}
 					r.push(`${He} shrieks with agony and then orgasms as strongly as you've ever seen a slave climax, ${his} every fiber tensing against the restraints. For a long, long time ${he} has to work to breathe, the overstimulation clearing slowly. When you finally let ${him} up, ${he} hasn't remembered how to talk yet, but ${his} gaze says it for ${him}. It looks like ${he}'s just had <span class="devotion inc">the best sex of ${his} life.</span>`);
 				}
@@ -366,7 +366,7 @@ App.Events.RESSModsPlease = class RESSModsPlease extends App.Events.BaseEvent {
 					r.push(`listens to your description of ${him},`);
 				}
 				r.push(`looking pleased.`);
-				eventSlave.nipplesPiercing = 1;
+				eventSlave.piercing.nipple.weight = 1;
 			}
 			eventSlave.devotion += 5; // TODO: consider surgeryDamage
 			App.Events.addParagraph(frag, r);
diff --git a/src/events/RESS/review/notMyName.js b/src/events/RESS/review/notMyName.js
index 030c829ad19..785018df39f 100644
--- a/src/events/RESS/review/notMyName.js
+++ b/src/events/RESS/review/notMyName.js
@@ -40,7 +40,7 @@ App.Events.RESSNotMyName = class RESSNotMyName extends App.Events.BaseEvent {
 		r.push(`is not yet broken to your will. With your experience with slaves, you've been expecting ${him} to take some opportunity of exercising ${his} remaining independence. You don't have long to wait. One day, you give ${him} inconsequential orders, naturally addressing ${him} by ${his} slave name, ${eventSlave.slaveName}. ${He} replies`);
 		if (eventSlave.lips > 70) {
 			r.push(`waspishly through ${his} dick-sucking lips,`);
-		} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+		} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 			r.push(`waspishly through ${his} heavily-pierced lips,`);
 		} else {
 			r.push(`waspishly,`);
diff --git a/src/events/RESS/review/resistantGelding.js b/src/events/RESS/review/resistantGelding.js
index 54c8ec9dc98..1b4f336d8c2 100644
--- a/src/events/RESS/review/resistantGelding.js
+++ b/src/events/RESS/review/resistantGelding.js
@@ -85,7 +85,7 @@ App.Events.RESSResistantGelding = class RESSResistantGelding extends App.Events.
 			} else {
 				if (eventSlave.lips > 70) {
 					r.push(`${he} begs meekly through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`${he} begs meekly through ${his} mouthful of piercings,`);
 				} else {
 					r.push(`${he} begs meekly,`);
diff --git a/src/events/RESS/review/soreShoulders.js b/src/events/RESS/review/soreShoulders.js
index 60961c4a438..795174ec4e7 100644
--- a/src/events/RESS/review/soreShoulders.js
+++ b/src/events/RESS/review/soreShoulders.js
@@ -68,7 +68,7 @@ App.Events.RESSSoreShoulders = class RESSSoreShoulders extends App.Events.BaseEv
 
 		function virginityWarning() {
 			if ((eventSlave.anus === 0 && canDoAnal(eventSlave)) || (eventSlave.vagina === 0 && canDoVaginal(eventSlave))) {
-				return `This option will take virginity`;
+				return `This option will take ${his} virginity`;
 			}
 		}
 
diff --git a/src/events/RESS/review/spaBoobs.js b/src/events/RESS/review/spaBoobs.js
index b002ad272c2..8eda0b852cf 100644
--- a/src/events/RESS/review/spaBoobs.js
+++ b/src/events/RESS/review/spaBoobs.js
@@ -132,7 +132,7 @@ App.Events.RESSSpaBoobs = class RESSSpaBoobs extends App.Events.BaseEvent {
 			r.push(`and ${he} ${say}s`);
 			if (eventSlave.lips > 70) {
 				r.push(`through ${his} huge lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`through ${his} piercings,`);
 			} else {
 				r.push(`quietly,`);
diff --git a/src/events/RESS/review/surgeryAddict.js b/src/events/RESS/review/surgeryAddict.js
index 5f197291fb1..3f2f55b59ba 100644
--- a/src/events/RESS/review/surgeryAddict.js
+++ b/src/events/RESS/review/surgeryAddict.js
@@ -48,7 +48,7 @@ App.Events.RESSSurgeryAddict = class RESSSurgeryAddict extends App.Events.BaseEv
 		r.push(`the equipment. ${He}'s not breaking any rules, but this behavior is so strange you investigate. ${He} asks`);
 		if (eventSlave.lips > 70) {
 			r.push(`hesitantly through ${his} huge lips,`);
-		} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+		} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 			r.push(`hesitantly through ${his} piercings,`);
 		} else {
 			r.push(`hesitantly,`);
diff --git a/src/events/RESS/review/tendonFall.js b/src/events/RESS/review/tendonFall.js
index 7a936f9309e..cf1ab85041b 100644
--- a/src/events/RESS/review/tendonFall.js
+++ b/src/events/RESS/review/tendonFall.js
@@ -49,7 +49,7 @@ App.Events.RESSTendonFall = class RESSTendonFall extends App.Events.BaseEvent {
 		r.push(`body. ${He} takes off ${his} heels to shower, making ${him} unable to stand independently. Apparently, ${he} lost ${his} grip on the handrail while trying to soap ${himself}, and having fallen, can't seem to reach the rail to haul ${himself} up again. ${He} pleads`);
 		if (eventSlave.lips > 70) {
 			r.push(`through ${his} huge lips`);
-		} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+		} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 			r.push(`through ${his} piercings`);
 		}
 		r.addToLast(`, "Help me, ${Master}!"`);
diff --git a/src/events/RESS/review/terrifiedInspection.js b/src/events/RESS/review/terrifiedInspection.js
index 40a938c2d00..c74b93faa5c 100644
--- a/src/events/RESS/review/terrifiedInspection.js
+++ b/src/events/RESS/review/terrifiedInspection.js
@@ -164,7 +164,7 @@ App.Events.RESSTerrifiedInspection = class RESSTerrifiedInspection extends App.E
 				r.push(`"I, I haven't been feeling good in the morning,`);
 			} else if (eventSlave.health.condition < -20) {
 				r.push(`"I, I don't feel very good,`);
-			} else if (eventSlave.preg > 0 && eventSlave.preg < eventSlave.pregData.normalBirth/6.66) {
+			} else if (eventSlave.preg.isBetween(0, eventSlave.pregData.normalBirth / 6.66)) {
 				r.push(`"I, I feel a little off. The food`);
 				if (canTaste(eventSlave)) {
 					r.push(Spoken(eventSlave, `tastes`));
diff --git a/src/events/RESS/review/transitionAnxiety.js b/src/events/RESS/review/transitionAnxiety.js
index d5b09fa3c01..51013ad3269 100644
--- a/src/events/RESS/review/transitionAnxiety.js
+++ b/src/events/RESS/review/transitionAnxiety.js
@@ -190,7 +190,7 @@ App.Events.RESSTransitionAnxiety = class RESSTransitionAnxiety extends App.Event
 					r.push(`thin`);
 				}
 				r.push(`waist, running your hands across ${his} skin. Then you`);
-				if (eventSlave.clitPiercing === 3) {
+				if (eventSlave.piercing.genitals.smart) {
 					r.push(`activate ${his} smart frenulum piercing.`);
 				} else {
 					r.push(`secure a couple of little egg vibes to ${his} dick.`);
diff --git a/src/events/RESS/review/vocalDisobedience.js b/src/events/RESS/review/vocalDisobedience.js
index e565691c54d..d049af5b059 100644
--- a/src/events/RESS/review/vocalDisobedience.js
+++ b/src/events/RESS/review/vocalDisobedience.js
@@ -45,7 +45,7 @@ App.Events.RESSVocalDisobedience = class RESSVocalDisobedience extends App.Event
 			r.push(`boldly through ${his}`);
 			if (eventSlave.lips > 70) {
 				r.push(`massive dick-sucking lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`inconvenient oral piercings,`);
 			} else {
 				r.push(`lisp,`);
@@ -111,7 +111,7 @@ App.Events.RESSVocalDisobedience = class RESSVocalDisobedience extends App.Event
 			r.push(`You spank ${him} severely, leaving ${his} buttocks bright pink. ${He} must count the strokes or have ${his} punishment start over. Sobbing, ${he} counts`);
 			if (eventSlave.lips > 70) {
 				r.push(`through ${his} massive dick-sucking lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`through ${his} inconvenient oral piercings`);
 			}
 			r.push(
@@ -146,7 +146,7 @@ App.Events.RESSVocalDisobedience = class RESSVocalDisobedience extends App.Event
 			r.push(`${he} begins to cry. ${He} begs`);
 			if (eventSlave.lips > 70) {
 				r.push(`through ${his} massive dick-sucking lips,`);
-			} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+			} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 				r.push(`through ${his} inconvenient oral piercings,`);
 			} else {
 				r.push(`through ${his} tears,`);
diff --git a/src/events/RESS/scrubbing.js b/src/events/RESS/scrubbing.js
index 1c0e3c8e922..001ae712412 100644
--- a/src/events/RESS/scrubbing.js
+++ b/src/events/RESS/scrubbing.js
@@ -168,7 +168,7 @@ App.Events.RESSScrubbing = class RESSScrubbing extends App.Events.BaseEvent {
 			} else {
 				if (eventSlave.lips > 70) {
 					r.push(`meekly through ${his} massive dick-sucking lips,`);
-				} else if (eventSlave.lipsPiercing+eventSlave.tonguePiercing > 2) {
+				} else if (eventSlave.piercing.lips.weight+eventSlave.piercing.tongue.weight > 2) {
 					r.push(`meekly through ${his} inconvenient oral piercings,`);
 				} else {
 					r.push(`meekly,`);
diff --git a/src/events/RETS/reCockmilkInterception.js b/src/events/RETS/reCockmilkInterception.js
index 8a4722bd358..35775d9ee82 100644
--- a/src/events/RETS/reCockmilkInterception.js
+++ b/src/events/RETS/reCockmilkInterception.js
@@ -607,7 +607,7 @@ App.Events.RETSCockmilkInterception = class RETSCockmilkInterception extends App
 			t.push(`that ${he}'s going to get ${his} drink of cum, just from a different source.`);
 			if (slave.trust > 20) {
 				t.push(`${He} runs ${his}`);
-				if (slave.tonguePiercing) {
+				if (slave.piercing.tongue.weight) {
 					t.push(`pierced`);
 				} else {
 					t.push(`pink`);
diff --git a/src/events/RETS/reInterslaveBegging.js b/src/events/RETS/reInterslaveBegging.js
index 598d70ab690..d57ba9eaefa 100644
--- a/src/events/RETS/reInterslaveBegging.js
+++ b/src/events/RETS/reInterslaveBegging.js
@@ -744,8 +744,8 @@ App.Events.RETSInterslaveBegging = class RETSInterslaveBegging extends App.Event
 			V.universalRulesConsent = 0;
 			const {HisA, heA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
 
-			t.push(`You clear your throat for the slaves' attention and verbally order ${assistant.name > 0 ? assistant.name : "your assistant"} to rescind the penthouse rule against interslave rape. ${HisA} avatar pops up nearby and confirms the rules change.`);
-			if (assistant.personality > 0) {
+			t.push(`You clear your throat for the slaves' attention and verbally order ${V.assistant.name} to rescind the penthouse rule against interslave rape. ${HisA} avatar pops up nearby and confirms the rules change.`);
+			if (V.assistant.personality > 0) {
 				t.push(`"Done," ${heA} says. "And I approve. Poor ${girl}s like ${eventSlave.slaveName} should be able to take what they need."`);
 			} else {
 				t.push(`"Done," ${heA} says.`);
diff --git a/src/events/assistant/assistantSP.js b/src/events/assistant/assistantSP.js
index f69fabab30e..c8a94673629 100644
--- a/src/events/assistant/assistantSP.js
+++ b/src/events/assistant/assistantSP.js
@@ -28,7 +28,7 @@ App.Events.assistantSP = class assistantSP extends App.Events.BaseEvent {
 		App.Events.addParagraph(node, r);
 		r = [];
 		r.push(`${HeA} continues more seriously,`);
-		if (V.slaves.some(s => s.clitPiercing === 3)) {
+		if (V.slaves.some(s => s.piercing.genitals.smart)) {
 			r.push(`"You may have noticed that the smart implants you've got your slaves wearing are working a little bit better than when I was a boring old secretary type. I'm not a true artificial intelligence, but I can adapt with experience, and I've had a lot of lovely experience lately! Also, a lot of the computing power I use to be sexy helps me adapt smart piercings to individual slaves' sexualities."`);
 		} else {
 			r.push(`"I'm sure you've seen those expensive smart piercings the body mod studio can implant. I think they would work a little bit better now than when I was a boring old secretary type. I'm not a true artificial intelligence, but I can adapt with experience, and I've had a lot of lovely experience lately! Also, a lot of the computing power I use to be sexy would help me adapt smart piercings to individual slaves' sexualities."`);
diff --git a/src/events/nonRandom/daughters/pUndergroundRailroad.js b/src/events/nonRandom/daughters/pUndergroundRailroad.js
index aa369811348..4470899dfae 100644
--- a/src/events/nonRandom/daughters/pUndergroundRailroad.js
+++ b/src/events/nonRandom/daughters/pUndergroundRailroad.js
@@ -38,7 +38,7 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 			if (canTalk(traitor)) {
 				if (traitor.lips > 70) {
 					r.push(`lisps through ${his} huge lips`);
-				} else if (traitor.lipsPiercing + traitor.tonguePiercing > 2) {
+				} else if (traitor.piercing.lips.weight + traitor.piercing.tongue.weight > 2) {
 					r.push(`lisps through ${his} piercings`);
 				} else {
 					r.push(`shouts`);
@@ -158,7 +158,7 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 				if (canTalk(traitor)) {
 					if (traitor.lips > 70) {
 						r.push(`lisps through ${his} huge lips,`);
-					} else if (traitor.lipsPiercing + traitor.tonguePiercing > 2) {
+					} else if (traitor.piercing.lips.weight + traitor.piercing.tongue.weight > 2) {
 						r.push(`lisps through ${his} piercings,`);
 					} else {
 						r.push(`shouts,`);
@@ -172,7 +172,7 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 				if (canTalk(traitor)) {
 					if (traitor.lips > 70) {
 						r.push(`lisps meekly through ${his} huge lips`);
-					} else if (traitor.lipsPiercing + traitor.tonguePiercing > 2) {
+					} else if (traitor.piercing.lips.weight + traitor.piercing.tongue.weight > 2) {
 						r.push(`lisps meekly through ${his} piercings`);
 					} else {
 						r.push(`mumbles meekly`);
diff --git a/src/events/nonRandom/rival/pRivalryActions.js b/src/events/nonRandom/rival/pRivalryActions.js
index 46c3f3ec2ee..f9cfe54b370 100644
--- a/src/events/nonRandom/rival/pRivalryActions.js
+++ b/src/events/nonRandom/rival/pRivalryActions.js
@@ -125,18 +125,19 @@ App.Events.pRivalryActions = function() {
 						V.hostage.counter.vaginal += 50;
 						V.hostage.counter.anal += 50;
 						V.hostage.counter.mammary += 50;
-						V.hostage.earPiercing = 1;
-						V.hostage.nosePiercing = 1;
-						V.hostage.nipplesPiercing = 0;
-						V.hostage.lipsPiercing = 0;
-						V.hostage.vaginaPiercing = 0;
-						V.hostage.anusPiercing = 0;
-						V.hostage.clitPiercing = 0;
-						V.hostage.eyebrowPiercing = 0;
-						V.hostage.navelPiercing = 0;
-						V.hostage.corsetPiercing = 0;
-						V.hostage.areolaePiercing = 0;
-						V.hostage.tonguePiercing = 0;
+						V.hostage.piercing.ear.weight = 1;
+						V.hostage.piercing.nose.weight = 1;
+						V.hostage.piercing.nipple.weight = 0;
+						V.hostage.piercing.lips.weight = 0;
+						V.hostage.piercing.vagina.weight = 0;
+						V.hostage.piercing.anus.weight = 0;
+						V.hostage.piercing.genitals.weight = 0;
+						V.hostage.piercing.genitals.smart = false;
+						V.hostage.piercing.eyebrow.weight = 0;
+						V.hostage.piercing.navel.weight = 0;
+						V.hostage.piercing.corset.weight = 0;
+						V.hostage.piercing.areola.weight = 0;
+						V.hostage.piercing.tongue.weight = 0;
 						V.hostage.boobsTat = 0;
 						V.hostage.buttTat = 0;
 						V.hostage.vaginaTat = 0;
@@ -413,18 +414,18 @@ App.Events.pRivalryActions = function() {
 						V.hostage.counter.anal += 50;
 						V.hostage.counter.mammary += 50;
 						V.hostage.heels = 1;
-						V.hostage.earPiercing = 1;
-						V.hostage.nosePiercing = 1;
-						V.hostage.nipplesPiercing = 1;
-						V.hostage.lipsPiercing = 1;
-						V.hostage.vaginaPiercing = 0;
-						V.hostage.anusPiercing = 0;
-						V.hostage.clitPiercing = 1;
-						V.hostage.eyebrowPiercing = 0;
-						V.hostage.navelPiercing = 1;
-						V.hostage.corsetPiercing = 0;
-						V.hostage.areolaePiercing = 0;
-						V.hostage.tonguePiercing = 1;
+						V.hostage.piercing.ear.weight = 1;
+						V.hostage.piercing.nose.weight = 1;
+						V.hostage.piercing.nipple.weight = 1;
+						V.hostage.piercing.lips.weight = 1;
+						V.hostage.piercing.vagina.weight = 0;
+						V.hostage.piercing.anus.weight = 0;
+						V.hostage.piercing.genitals.weight = 1;
+						V.hostage.piercing.eyebrow.weight = 0;
+						V.hostage.piercing.navel.weight = 1;
+						V.hostage.piercing.corset.weight = 0;
+						V.hostage.piercing.areola.weight = 0;
+						V.hostage.piercing.tongue.weight = 1;
 						V.hostage.boobsTat = "degradation";
 						V.hostage.backTat = "degradation";
 						V.hostage.stampTat = "degradation";
@@ -851,18 +852,18 @@ App.Events.pRivalryActions = function() {
 						V.hostage.counter.anal += 50;
 						V.hostage.counter.mammary += 50;
 						V.hostage.voice = 0;
-						V.hostage.earPiercing = 2;
-						V.hostage.nosePiercing = 2;
-						V.hostage.nipplesPiercing = 1;
-						V.hostage.lipsPiercing = 1;
-						V.hostage.vaginaPiercing = 1;
-						V.hostage.anusPiercing = 0;
-						V.hostage.clitPiercing = 1;
-						V.hostage.eyebrowPiercing = 1;
-						V.hostage.navelPiercing = 2;
-						V.hostage.corsetPiercing = 0;
-						V.hostage.areolaePiercing = 1;
-						V.hostage.tonguePiercing = 1;
+						V.hostage.piercing.ear.weight = 2;
+						V.hostage.piercing.nose.weight = 2;
+						V.hostage.piercing.nipple.weight = 1;
+						V.hostage.piercing.lips.weight = 1;
+						V.hostage.piercing.vagina.weight = 1;
+						V.hostage.piercing.anus.weight = 0;
+						V.hostage.piercing.genitals.weight = 1;
+						V.hostage.piercing.eyebrow.weight = 1;
+						V.hostage.piercing.navel.weight = 2;
+						V.hostage.piercing.corset.weight = 0;
+						V.hostage.piercing.areola.weight = 1;
+						V.hostage.piercing.tongue.weight = 1;
 						V.hostage.buttTat = "degradation";
 						V.hostage.vaginaTat = "degradation";
 						V.hostage.shouldersTat = "degradation";
@@ -1266,18 +1267,18 @@ App.Events.pRivalryActions = function() {
 						V.hostage.counter.anal += 50;
 						V.hostage.counter.mammary += 50;
 						eyeSurgery(V.hostage, "both", "blind");
-						V.hostage.earPiercing = 2;
-						V.hostage.nosePiercing = 2;
-						V.hostage.nipplesPiercing = 2;
-						V.hostage.lipsPiercing = 1;
-						V.hostage.vaginaPiercing = 1;
-						V.hostage.anusPiercing = 1;
-						V.hostage.clitPiercing = 1;
-						V.hostage.eyebrowPiercing = 2;
-						V.hostage.navelPiercing = 2;
-						V.hostage.corsetPiercing = 1;
-						V.hostage.areolaePiercing = 1;
-						V.hostage.tonguePiercing = 2;
+						V.hostage.piercing.ear.weight = 2;
+						V.hostage.piercing.nose.weight = 2;
+						V.hostage.piercing.nipple.weight = 2;
+						V.hostage.piercing.lips.weight = 1;
+						V.hostage.piercing.vagina.weight = 1;
+						V.hostage.piercing.anus.weight = 1;
+						V.hostage.piercing.genitals.weight = 1;
+						V.hostage.piercing.eyebrow.weight = 2;
+						V.hostage.piercing.navel.weight = 2;
+						V.hostage.piercing.corset.weight = 1;
+						V.hostage.piercing.areola.weight = 1;
+						V.hostage.piercing.tongue.weight = 2;
 						V.hostage.lipsTat = "degradation";
 						V.hostage.anusTat = "degradation";
 						if (seed < 40) {
@@ -1470,7 +1471,7 @@ App.Events.pRivalryActions = function() {
 						V.hostage.energy += 5;
 						V.hostage.addict += 2;
 						V.hostage.fetishStrength = 100;
-						V.hostage.tonguePiercing = 1;
+						V.hostage.piercing.tongue.weight = 1;
 						V.hostage.stampTat = "'Princess' is tattooed over $his rear.";
 						V.hostage.hLength += 7;
 						V.hostage.lips = Math.clamp(V.hostage.lips + 5, 0, 100);
@@ -1624,18 +1625,18 @@ App.Events.pRivalryActions = function() {
 						V.hostage.counter.anal += 50;
 						V.hostage.counter.mammary += 50;
 						removeLimbs(V.hostage, "all");
-						V.hostage.earPiercing = 2;
-						V.hostage.nosePiercing = 2;
-						V.hostage.nipplesPiercing = 2;
-						V.hostage.lipsPiercing = 2;
-						V.hostage.vaginaPiercing = 2;
-						V.hostage.anusPiercing = 2;
-						V.hostage.clitPiercing = 2;
-						V.hostage.eyebrowPiercing = 2;
-						V.hostage.navelPiercing = 2;
-						V.hostage.corsetPiercing = 1;
-						V.hostage.areolaePiercing = 1;
-						V.hostage.tonguePiercing = 2;
+						V.hostage.piercing.ear.weight = 2;
+						V.hostage.piercing.nose.weight = 2;
+						V.hostage.piercing.nipple.weight = 2;
+						V.hostage.piercing.lips.weight = 2;
+						V.hostage.piercing.vagina.weight = 2;
+						V.hostage.piercing.anus.weight = 2;
+						V.hostage.piercing.genitals.weight = 2;
+						V.hostage.piercing.eyebrow.weight = 2;
+						V.hostage.piercing.navel.weight = 2;
+						V.hostage.piercing.corset.weight = 1;
+						V.hostage.piercing.areola.weight = 1;
+						V.hostage.piercing.tongue.weight = 2;
 						if (seed < 40) {
 							App.Medicine.Modification.addScar(V.hostage, "anus", "burn", 2);
 						} else if (seed < 80) {
diff --git a/src/events/nonRandom/rival/pRivalryCapture.js b/src/events/nonRandom/rival/pRivalryCapture.js
index 008b042fe5a..b3a05152432 100644
--- a/src/events/nonRandom/rival/pRivalryCapture.js
+++ b/src/events/nonRandom/rival/pRivalryCapture.js
@@ -127,11 +127,11 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 15;
 				slave.skill.entertainment = 100;
 				slave.skill.combat = 0;
-				slave.clitPiercing = 2;
-				slave.nipplesPiercing = 1;
-				slave.earPiercing = 1;
-				slave.tonguePiercing = 1;
-				slave.eyebrowPiercing = 1;
+				slave.piercing.genitals.weight = 2;
+				slave.piercing.nipple.weight = 1;
+				slave.piercing.ear.weight = 1;
+				slave.piercing.tongue.weight = 1;
+				slave.piercing.eyebrow.weight = 1;
 				slave.behavioralFlaw = "odd";
 				slave.behavioralQuirk = "confident";
 				slave.sexualFlaw = "judgemental";
@@ -163,7 +163,7 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 15;
 				slave.skill.entertainment = 100;
 				slave.skill.combat = 0;
-				slave.dickPiercing = 2;
+				slave.piercing.dick.weight = 2;
 				slave.fetish = "pregnancy";
 				slave.fetishStrength = 100;
 				slave.behavioralFlaw = "odd";
@@ -195,7 +195,7 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 0;
 				slave.skill.entertainment = 100;
 				slave.skill.combat = 0;
-				slave.dickPiercing = 2;
+				slave.piercing.dick.weight = 2;
 				slave.pubertyXY = 1;
 				slave.fetish = "pregnancy";
 				slave.fetishStrength = 100;
@@ -297,8 +297,8 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 0;
 				slave.skill.entertainment = 0;
 				slave.skill.combat = 1;
-				slave.clitPiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.behavioralFlaw = "hates men";
 				slave.behavioralQuirk = "fitness";
 				slave.sexualFlaw = "hates penetration";
@@ -460,8 +460,8 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 35;
 				slave.skill.entertainment = 35;
 				slave.skill.combat = 0;
-				slave.clitPiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.behavioralFlaw = "arrogant";
 				slave.behavioralQuirk = "insecure";
 				slave.sexualFlaw = "crude";
@@ -494,8 +494,8 @@ globalThis.pRivalryCapture = function(condition) {
 				slave.skill.whoring = 100;
 				slave.skill.entertainment = 0;
 				slave.skill.combat = 0;
-				slave.clitPiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.behavioralFlaw = "bitchy";
 				slave.behavioralQuirk = "funny";
 				slave.sexualFlaw = "crude";
diff --git a/src/events/nonRandom/stripClubAftermath.js b/src/events/nonRandom/stripClubAftermath.js
index 7130029bb78..92597477faf 100644
--- a/src/events/nonRandom/stripClubAftermath.js
+++ b/src/events/nonRandom/stripClubAftermath.js
@@ -48,13 +48,13 @@ App.Events.PStripClubAftermath = class PStripClubAftermath extends App.Events.Ba
 			slave.boobs += 600;
 			slave.boobsImplant = 600;
 			slave.boobsImplantType = "string";
-			slave.lipsPiercing = 1;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 1;
-			slave.eyebrowPiercing = 1;
-			slave.navelPiercing = 1;
-			slave.nipplesPiercing = 1;
-			slave.clitPiercing = 1;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
+			slave.piercing.navel.weight = 1;
+			slave.piercing.nipple.weight = 1;
+			slave.piercing.genitals.weight = 1;
 			slave.hStyle = "strip";
 			cost = slaveCost(slave);
 		}
diff --git a/src/events/randomEvent.js b/src/events/randomEvent.js
index 44e6aa56694..e5094ece96f 100644
--- a/src/events/randomEvent.js
+++ b/src/events/randomEvent.js
@@ -286,6 +286,7 @@ App.Events.getNonindividualEvents = function() {
 		new App.Events.refsPastoralistEncounter(),
 		new App.Events.refsPaternalistEncounter(),
 		new App.Events.refsPhysicalIdealistEncounter(),
+		new App.Events.refsRomanStoicism(),
 		new App.Events.refsTotallyLegitCatgirls(),
 		new App.Events.refsTransformationFetishismEncounter(),
 		new App.Events.refsWarhound(),
diff --git a/src/events/reRecruit/blessedVessel.js b/src/events/reRecruit/blessedVessel.js
index 71e857295aa..e669ab0aa81 100644
--- a/src/events/reRecruit/blessedVessel.js
+++ b/src/events/reRecruit/blessedVessel.js
@@ -62,9 +62,7 @@ App.Events.recBlessedVessel = class recBlessedVessel extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 		App.Events.addResponses(node, responses);
 
 		function enslave() {
diff --git a/src/events/reRecruit/blessedVirgin.js b/src/events/reRecruit/blessedVirgin.js
index 8759a759ac2..6824df81498 100644
--- a/src/events/reRecruit/blessedVirgin.js
+++ b/src/events/reRecruit/blessedVirgin.js
@@ -58,9 +58,7 @@ App.Events.recBlessedVirgin = class recBlessedVirgin extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/blindHomeless.js b/src/events/reRecruit/blindHomeless.js
index e9058c623ac..66110dfafec 100644
--- a/src/events/reRecruit/blindHomeless.js
+++ b/src/events/reRecruit/blindHomeless.js
@@ -50,9 +50,7 @@ App.Events.recBlindHomeless = class recBlindHomeless extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/capturedTeen.js b/src/events/reRecruit/capturedTeen.js
index b7144259d69..47733a99c61 100644
--- a/src/events/reRecruit/capturedTeen.js
+++ b/src/events/reRecruit/capturedTeen.js
@@ -51,9 +51,7 @@ App.Events.recCapturedTeen = class recCapturedTeen extends App.Events.BaseEvent
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/ccsAngel.js b/src/events/reRecruit/ccsAngel.js
index bf314e5c288..2a2e781cab9 100644
--- a/src/events/reRecruit/ccsAngel.js
+++ b/src/events/reRecruit/ccsAngel.js
@@ -55,9 +55,7 @@ App.Events.recCcsAngel = class recCcsAngel extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/ccsDA.js b/src/events/reRecruit/ccsDA.js
index 2105811123c..694f2650d49 100644
--- a/src/events/reRecruit/ccsDA.js
+++ b/src/events/reRecruit/ccsDA.js
@@ -55,9 +55,7 @@ App.Events.recCcsDA = class recCcsDA extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/desperateMILF.js b/src/events/reRecruit/desperateMILF.js
index bd6c710ea8e..b3ff9c95c58 100644
--- a/src/events/reRecruit/desperateMILF.js
+++ b/src/events/reRecruit/desperateMILF.js
@@ -48,9 +48,7 @@ App.Events.recDesperateMILF = class recDesperateMILF extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/desperatePreg.js b/src/events/reRecruit/desperatePreg.js
index 5af1c3bcfdc..87a87328a0c 100644
--- a/src/events/reRecruit/desperatePreg.js
+++ b/src/events/reRecruit/desperatePreg.js
@@ -35,9 +35,7 @@ App.Events.recDesperatePreg = class recDesperatePreg extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -97,7 +95,8 @@ App.Events.recDesperatePreg = class recDesperatePreg extends App.Events.BaseEven
 			SetBellySize(slave);
 			slave.fetish = "none";
 			slave.fetishKnown = 0;
-			setHealth(slave, jsRandom(-40, -20), undefined, undefined, undefined, 50);
+			setHealth(slave, random(-40, -20), undefined, undefined, undefined, 50);
+			slave.face = normalRandInt(50, 50, 10, 95);
 			return slave;
 		}
 	}
diff --git a/src/events/reRecruit/desperateUniversityMILF.js b/src/events/reRecruit/desperateUniversityMILF.js
index ca255e8c31c..eaa9e9fc4a6 100644
--- a/src/events/reRecruit/desperateUniversityMILF.js
+++ b/src/events/reRecruit/desperateUniversityMILF.js
@@ -42,9 +42,7 @@ App.Events.recDesperateUniversityMILF = class recDesperateUniversityMILF extends
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/dgRunaway.js b/src/events/reRecruit/dgRunaway.js
index 68322ce4db7..d9d3f100299 100644
--- a/src/events/reRecruit/dgRunaway.js
+++ b/src/events/reRecruit/dgRunaway.js
@@ -39,9 +39,7 @@ App.Events.recDgRunaway = class recDgRunaway extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -95,13 +93,13 @@ App.Events.recDgRunaway = class recDgRunaway extends App.Events.BaseEvent {
 			slave.behavioralFlaw = "hates men";
 			slave.behavioralQuirk = "insecure";
 			slave.sexualFlaw = "apathetic";
-			slave.lipsPiercing = 1;
-			slave.tonguePiercing = 1;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 2;
-			slave.navelPiercing = 1;
-			slave.nipplesPiercing = 2;
-			slave.clitPiercing = 2;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 2;
+			slave.piercing.navel.weight = 1;
+			slave.piercing.nipple.weight = 2;
+			slave.piercing.genitals.weight = 2;
 			slave.custom.tattoo = "$He has a barcode tattooed on $his neck.";
 			slave.attrXY = 20;
 			return slave;
diff --git a/src/events/reRecruit/embryoAppropriation.js b/src/events/reRecruit/embryoAppropriation.js
index 886a82fa523..353557dccc5 100644
--- a/src/events/reRecruit/embryoAppropriation.js
+++ b/src/events/reRecruit/embryoAppropriation.js
@@ -50,9 +50,7 @@ App.Events.recEmbryoAppropriation = class recEmbryoAppropriation extends App.Eve
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/farmBull.js b/src/events/reRecruit/farmBull.js
index 635ce827026..f14e173cc54 100644
--- a/src/events/reRecruit/farmBull.js
+++ b/src/events/reRecruit/farmBull.js
@@ -90,7 +90,7 @@ App.Events.recFarmBull = class recFarmBull extends App.Events.BaseEvent {
 			slave.muscles = random(10, 50);
 			slave.shoulders = random(1, 2);
 			slave.intelligence = random(-95, 50);
-			slave.nosePiercing = 2;
+			slave.piercing.nose.weight = 2;
 			slave.career = "a slave";
 			slave.fetish = "pregnancy";
 			slave.behavioralQuirk = "adores women";
diff --git a/src/events/reRecruit/farmCow.js b/src/events/reRecruit/farmCow.js
index 9903cce230a..e8b844bf001 100644
--- a/src/events/reRecruit/farmCow.js
+++ b/src/events/reRecruit/farmCow.js
@@ -96,7 +96,7 @@ App.Events.recFarmCow = class recFarmCow extends App.Events.BaseEvent {
 			slave.muscles = random(0, 15);
 			slave.shoulders = random(0, 2);
 			slave.intelligence = random(-95, 50);
-			slave.nosePiercing = 2;
+			slave.piercing.nose.weight = 2;
 			slave.career = "a slave";
 			slave.fetish = "pregnancy";
 			slave.behavioralQuirk = "advocate";
diff --git a/src/events/reRecruit/farmVirginCow.js b/src/events/reRecruit/farmVirginCow.js
index 54566d748f3..db574b77d1f 100644
--- a/src/events/reRecruit/farmVirginCow.js
+++ b/src/events/reRecruit/farmVirginCow.js
@@ -79,7 +79,7 @@ App.Events.recFarmVirginCow = class recFarmVirginCow extends App.Events.BaseEven
 			slave.muscles = random(0, 40);
 			slave.shoulders = random(-1, 2);
 			slave.intelligence = random(-95, 50);
-			slave.nosePiercing = 2;
+			slave.piercing.nose.weight = 2;
 			slave.career = "a slave";
 			slave.fetish = "pregnancy";
 			slave.behavioralQuirk = "insecure";
diff --git a/src/events/reRecruit/femaleDebtor.js b/src/events/reRecruit/femaleDebtor.js
index 812074143db..c72c48d64a8 100644
--- a/src/events/reRecruit/femaleDebtor.js
+++ b/src/events/reRecruit/femaleDebtor.js
@@ -30,9 +30,7 @@ App.Events.recFemaleDebtor = class recFemaleDebtor extends App.Events.BaseEvent
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/femaleRecruit.js b/src/events/reRecruit/femaleRecruit.js
index 7d79f308f3b..8c440a5fe13 100644
--- a/src/events/reRecruit/femaleRecruit.js
+++ b/src/events/reRecruit/femaleRecruit.js
@@ -41,9 +41,7 @@ App.Events.recFemaleRecruit = class recFemaleRecruit extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -99,10 +97,10 @@ App.Events.recFemaleRecruit = class recFemaleRecruit extends App.Events.BaseEven
 			slave.skill.vaginal = 15;
 			slave.skill.oral = 15;
 			slave.skill.anal = 0;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 1;
-			slave.eyebrowPiercing = 1;
-			slave.navelPiercing = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
+			slave.piercing.navel.weight = 1;
 			slave.behavioralFlaw = "arrogant";
 			generateSalonModifications(slave);
 			slave.hStyle = "fashionable for a Free Cities girl, long, with the left half shaved";
diff --git a/src/events/reRecruit/femaleRunaway.js b/src/events/reRecruit/femaleRunaway.js
index e0eeb6827bc..2ab24cd99ff 100644
--- a/src/events/reRecruit/femaleRunaway.js
+++ b/src/events/reRecruit/femaleRunaway.js
@@ -44,9 +44,7 @@ App.Events.recFemaleRunaway = class recFemaleRunaway extends App.Events.BaseEven
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -104,13 +102,13 @@ App.Events.recFemaleRunaway = class recFemaleRunaway extends App.Events.BaseEven
 			slave.behavioralFlaw = "hates men";
 			slave.behavioralQuirk = "insecure";
 			slave.sexualFlaw = "apathetic";
-			slave.lipsPiercing = 1;
-			slave.tonguePiercing = 1;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 2;
-			slave.navelPiercing = 1;
-			slave.nipplesPiercing = 2;
-			slave.clitPiercing = 2;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 2;
+			slave.piercing.navel.weight = 1;
+			slave.piercing.nipple.weight = 2;
+			slave.piercing.genitals.weight = 2;
 			slave.custom.tattoo = "$He has a barcode tattooed on $his neck.";
 			slave.attrXY = 20;
 			return slave;
diff --git a/src/events/reRecruit/femaleSD.js b/src/events/reRecruit/femaleSD.js
index bb5f9349eba..de03a6ea3bf 100644
--- a/src/events/reRecruit/femaleSD.js
+++ b/src/events/reRecruit/femaleSD.js
@@ -51,9 +51,7 @@ App.Events.recFemaleSD = class recFemaleSD extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/femaleSD2.js b/src/events/reRecruit/femaleSD2.js
index d1887a099f9..1a18bb6742b 100644
--- a/src/events/reRecruit/femaleSD2.js
+++ b/src/events/reRecruit/femaleSD2.js
@@ -56,9 +56,7 @@ App.Events.recFemaleSD2 = class recFemaleSD2 extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -116,14 +114,14 @@ App.Events.recFemaleSD2 = class recFemaleSD2 extends App.Events.BaseEvent {
 			slave.hLength = 5;
 			slave.pubicHStyle = "very bushy";
 			slave.underArmHStyle = "bushy";
-			slave.nosePiercing = 1;
-			slave.tonguePiercing = 1;
-			slave.earPiercing = 2;
-			slave.nipplesPiercing = 1;
-			slave.lipsPiercing = 1;
-			slave.vaginaPiercing = 1;
-			slave.eyebrowPiercing = 1;
-			slave.navelPiercing = 1;
+			slave.piercing.nose.weight = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.ear.weight = 2;
+			slave.piercing.nipple.weight = 1;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.vagina.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
+			slave.piercing.navel.weight = 1;
 			slave.override_H_Color = 1;
 			slave.hColor = either("blue", "green", "purple");
 			return slave;
diff --git a/src/events/reRecruit/gangLeader.js b/src/events/reRecruit/gangLeader.js
index 3b189a35c7a..794465901fe 100644
--- a/src/events/reRecruit/gangLeader.js
+++ b/src/events/reRecruit/gangLeader.js
@@ -46,9 +46,7 @@ App.Events.recGangLeader = class recGangLeader extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		App.Events.addResponses(node, responses);
 
@@ -123,8 +121,8 @@ App.Events.recGangLeader = class recGangLeader extends App.Events.BaseEvent {
 			slave.career = "a criminal";
 			slave.sexualFlaw = "hates oral";
 			slave.behavioralFlaw = "arrogant";
-			slave.tonguePiercing = 1;
-			slave.eyebrowPiercing = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
 			slave.custom.tattoo = "$He has a tear tattooed under $his left eye.";
 			return slave;
 		}
diff --git a/src/events/reRecruit/handsomePC.js b/src/events/reRecruit/handsomePC.js
index 25456e927ed..70ddc462cab 100644
--- a/src/events/reRecruit/handsomePC.js
+++ b/src/events/reRecruit/handsomePC.js
@@ -55,9 +55,7 @@ App.Events.recHandsomePC = class recHandsomePC extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 		App.Events.addResponses(node, responses);
 
 		function enslave() {
@@ -96,7 +94,7 @@ App.Events.recHandsomePC = class recHandsomePC extends App.Events.BaseEvent {
 				slave.skill.vaginal = 15;
 			}
 			slave.birthWeek = random(0, 2);
-			slave.earPiercing = either(0, 1);
+			slave.piercing.ear.weight = either(0, 1);
 			return slave;
 		}
 	}
diff --git a/src/events/reRecruit/heldPOW.js b/src/events/reRecruit/heldPOW.js
index 0a2aa1c041a..d2a00ff2fd2 100644
--- a/src/events/reRecruit/heldPOW.js
+++ b/src/events/reRecruit/heldPOW.js
@@ -65,9 +65,7 @@ App.Events.recHeldPOW = class recHeldPOW extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/hermRunaway.js b/src/events/reRecruit/hermRunaway.js
index 1febd04d2cd..3901e71dac4 100644
--- a/src/events/reRecruit/hermRunaway.js
+++ b/src/events/reRecruit/hermRunaway.js
@@ -44,9 +44,7 @@ App.Events.recHermRunaway = class recHermRunaway extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -106,13 +104,13 @@ App.Events.recHermRunaway = class recHermRunaway extends App.Events.BaseEvent {
 			slave.behavioralFlaw = "hates men";
 			slave.behavioralQuirk = "insecure";
 			slave.sexualFlaw = "apathetic";
-			slave.lipsPiercing = 1;
-			slave.tonguePiercing = 1;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 2;
-			slave.navelPiercing = 1;
-			slave.nipplesPiercing = 2;
-			slave.clitPiercing = 2;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 2;
+			slave.piercing.navel.weight = 1;
+			slave.piercing.nipple.weight = 2;
+			slave.piercing.genitals.weight = 2;
 			slave.custom.tattoo = "$He has a barcode tattooed on $his neck.";
 			slave.attrXY = 20;
 			return slave;
diff --git a/src/events/reRecruit/homelessBreakIn.js b/src/events/reRecruit/homelessBreakIn.js
index 6ff4318ec25..db9351c0377 100644
--- a/src/events/reRecruit/homelessBreakIn.js
+++ b/src/events/reRecruit/homelessBreakIn.js
@@ -45,9 +45,7 @@ App.Events.recHomelessBreakIn = class recHomelessBreakIn extends App.Events.Base
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 		App.Events.addResponses(node, responses);
 
 		function enslave() {
diff --git a/src/events/reRecruit/immigrant.js b/src/events/reRecruit/immigrant.js
index aa8ab006452..c5819c43520 100644
--- a/src/events/reRecruit/immigrant.js
+++ b/src/events/reRecruit/immigrant.js
@@ -32,9 +32,7 @@ App.Events.recImmigrant = class recImmigrant extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/maleDebtor.js b/src/events/reRecruit/maleDebtor.js
index 65a4e933b20..2115c3fe30e 100644
--- a/src/events/reRecruit/maleDebtor.js
+++ b/src/events/reRecruit/maleDebtor.js
@@ -29,9 +29,7 @@ App.Events.recMaleDebtor = class recMaleDebtor extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/maleRecruit.js b/src/events/reRecruit/maleRecruit.js
index 3f33670b2f8..2a4691e207a 100644
--- a/src/events/reRecruit/maleRecruit.js
+++ b/src/events/reRecruit/maleRecruit.js
@@ -37,9 +37,7 @@ App.Events.recMaleRecruit = class recMaleRecruit extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -93,10 +91,10 @@ App.Events.recMaleRecruit = class recMaleRecruit extends App.Events.BaseEvent {
 			slave.anus = 0;
 			slave.skill.oral = 15;
 			slave.skill.anal = 0;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 1;
-			slave.eyebrowPiercing = 1;
-			slave.navelPiercing = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
+			slave.piercing.navel.weight = 1;
 			slave.behavioralFlaw = "arrogant";
 			generateSalonModifications(slave);
 			slave.hStyle = "fashionable for a Free Cities trap, long, with the right half shaved";
diff --git a/src/events/reRecruit/maleSD.js b/src/events/reRecruit/maleSD.js
index 2160a4fb353..66e61256dfd 100644
--- a/src/events/reRecruit/maleSD.js
+++ b/src/events/reRecruit/maleSD.js
@@ -52,9 +52,7 @@ App.Events.recMaleSD = class recMaleSD extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/overwhelmedFarmgirl.js b/src/events/reRecruit/overwhelmedFarmgirl.js
index 7c1705b5e02..acdbd4196b3 100644
--- a/src/events/reRecruit/overwhelmedFarmgirl.js
+++ b/src/events/reRecruit/overwhelmedFarmgirl.js
@@ -35,9 +35,7 @@ App.Events.recOverwhelmedFarmgirl = class recOverwhelmedFarmgirl extends App.Eve
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/paternalistSwanSong.js b/src/events/reRecruit/paternalistSwanSong.js
index 3dbbc6a48e5..8b4ba725462 100644
--- a/src/events/reRecruit/paternalistSwanSong.js
+++ b/src/events/reRecruit/paternalistSwanSong.js
@@ -42,9 +42,7 @@ App.Events.recPaternalistSwanSong = class recPaternalistSwanSong extends App.Eve
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -88,10 +86,10 @@ App.Events.recPaternalistSwanSong = class recPaternalistSwanSong extends App.Eve
 			slave.skill.vaginal = 0;
 			slave.skill.oral = 0;
 			slave.skill.anal = 0;
-			slave.earPiercing = 0;
-			slave.nosePiercing = 0;
-			slave.eyebrowPiercing = 0;
-			slave.navelPiercing = 0;
+			slave.piercing.ear.weight = 0;
+			slave.piercing.nose.weight = 0;
+			slave.piercing.eyebrow.weight = 0;
+			slave.piercing.navel.weight = 0;
 			slave.behavioralFlaw = "none";
 			slave.hStyle = "neat";
 			slave.pubicHStyle = "waxed";
diff --git a/src/events/reRecruit/rogueCyborg.js b/src/events/reRecruit/rogueCyborg.js
index 8abf57c1822..d3ada444949 100644
--- a/src/events/reRecruit/rogueCyborg.js
+++ b/src/events/reRecruit/rogueCyborg.js
@@ -35,9 +35,7 @@ App.Events.recRogueCyborg = class recRogueCyborg extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 		App.Events.addResponses(node, responses);
 
 		function enslave() {
@@ -92,7 +90,8 @@ App.Events.recRogueCyborg = class recRogueCyborg extends App.Events.BaseEvent {
 			slave.fetish = "none";
 			slave.fetishStrength = 96;
 			slave.fetishKnown = 0;
-			slave.clitPiercing = 0;
+			slave.piercing.genitals.weight = 0;
+			slave.piercing.genitals.smart = false;
 			slave.boobsTat = "$He has the characters 'z-23' printed across $his left breast.";
 			return slave;
 		}
diff --git a/src/events/reRecruit/shemalePC.js b/src/events/reRecruit/shemalePC.js
index 5fab48f0251..11142b4a1fa 100644
--- a/src/events/reRecruit/shemalePC.js
+++ b/src/events/reRecruit/shemalePC.js
@@ -43,9 +43,7 @@ App.Events.recShemalePC = class recShemalePC extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -98,13 +96,13 @@ App.Events.recShemalePC = class recShemalePC extends App.Events.BaseEvent {
 			slave.lipsImplant = 10;
 			slave.face = Math.clamp(slave.face + 20, -100, 100);
 			slave.faceImplant = 15;
-			slave.earPiercing = either(0, 1);
-			slave.navelPiercing = either(0, 1);
-			slave.nosePiercing = either(0, 1);
-			slave.eyebrowPiercing = either(0, 1);
-			slave.lipsPiercing = either(0, 1);
-			slave.clitPiercing = either(0, 1);
-			slave.nipplesPiercing = either(0, 1);
+			slave.piercing.ear.weight = either(0, 1);
+			slave.piercing.navel.weight = either(0, 1);
+			slave.piercing.nose.weight = either(0, 1);
+			slave.piercing.eyebrow.weight = either(0, 1);
+			slave.piercing.lips.weight = either(0, 1);
+			slave.piercing.genitals.weight = either(0, 1);
+			slave.piercing.nipple.weight = either(0, 1);
 			slave.stampTat = either("advertisements", "degradation", "flowers", "rude words", "tribal patterns", 0, 0);
 			slave.anusTat = either("bleached");
 			slave.pubicHStyle = "waxed";
diff --git a/src/events/reRecruit/spoiledDaughter.js b/src/events/reRecruit/spoiledDaughter.js
index 9f1d34e0ad4..b8e0ee7f97c 100644
--- a/src/events/reRecruit/spoiledDaughter.js
+++ b/src/events/reRecruit/spoiledDaughter.js
@@ -42,9 +42,7 @@ App.Events.recSpoiledDaughter = class recSpoiledDaughter extends App.Events.Base
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
 		responses.push(new App.Events.Result(`Contact ${his} father`, father));
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/starvingMigrant.js b/src/events/reRecruit/starvingMigrant.js
index 43dc614b78d..ba6eeb16b1e 100644
--- a/src/events/reRecruit/starvingMigrant.js
+++ b/src/events/reRecruit/starvingMigrant.js
@@ -49,9 +49,7 @@ App.Events.recStarvingMigrant = class recStarvingMigrant extends App.Events.Base
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/tgAddict.js b/src/events/reRecruit/tgAddict.js
index 2b56ebb5e2a..948989b1880 100644
--- a/src/events/reRecruit/tgAddict.js
+++ b/src/events/reRecruit/tgAddict.js
@@ -31,9 +31,7 @@ App.Events.recTgAddict = class recTgAddict extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
diff --git a/src/events/reRecruit/whoreRecruit.js b/src/events/reRecruit/whoreRecruit.js
index 98eb2642d68..80f3d8f95de 100644
--- a/src/events/reRecruit/whoreRecruit.js
+++ b/src/events/reRecruit/whoreRecruit.js
@@ -39,9 +39,7 @@ App.Events.recWhoreRecruit = class recWhoreRecruit extends App.Events.BaseEvent
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -96,14 +94,14 @@ App.Events.recWhoreRecruit = class recWhoreRecruit extends App.Events.BaseEvent
 			slave.buttImplantType = "normal";
 			slave.lips += 10;
 			slave.lipsImplant = 10;
-			slave.lipsPiercing = 1;
-			slave.tonguePiercing = 1;
-			slave.earPiercing = 1;
-			slave.nosePiercing = 1;
-			slave.eyebrowPiercing = 1;
-			slave.navelPiercing = 1;
-			slave.nipplesPiercing = 1;
-			slave.clitPiercing = 1;
+			slave.piercing.lips.weight = 1;
+			slave.piercing.tongue.weight = 1;
+			slave.piercing.ear.weight = 1;
+			slave.piercing.nose.weight = 1;
+			slave.piercing.eyebrow.weight = 1;
+			slave.piercing.navel.weight = 1;
+			slave.piercing.nipple.weight = 1;
+			slave.piercing.genitals.weight = 1;
 			generateSalonModifications(slave);
 			slave.hStyle = "strip";
 			slave.pubicHStyle = "waxed";
diff --git a/src/events/reRecruit/womanlyPC.js b/src/events/reRecruit/womanlyPC.js
index 6436ac45ef9..3521828f60c 100644
--- a/src/events/reRecruit/womanlyPC.js
+++ b/src/events/reRecruit/womanlyPC.js
@@ -47,9 +47,7 @@ App.Events.recWomanlyPC = class recWomanlyPC extends App.Events.BaseEvent {
 		} else {
 			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
 		}
-		const incomeText = new DocumentFragment();
-		incomeText.append(`This will bring in `, App.UI.DOM.cashFormat(cost), `.`);
-		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, incomeText));
+		responses.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost)}`));
 
 		node.append(App.Desc.longSlave(slave, {market: "generic"}));
 
@@ -89,11 +87,11 @@ App.Events.recWomanlyPC = class recWomanlyPC extends App.Events.BaseEvent {
 			slave.skill.oral = 15;
 			slave.vagina = 1;
 			slave.skill.vaginal = 15;
-			slave.earPiercing = either(0, 1);
-			slave.navelPiercing = either(0, 1);
-			slave.nosePiercing = either(0, 1);
-			slave.clitPiercing = either(0, 1);
-			slave.nipplesPiercing = either(0, 1);
+			slave.piercing.ear.weight = either(0, 1);
+			slave.piercing.navel.weight = either(0, 1);
+			slave.piercing.nose.weight = either(0, 1);
+			slave.piercing.genitals.weight = either(0, 1);
+			slave.piercing.nipple.weight = either(0, 1);
 			slave.shouldersTat = either("flowers", "tribal patterns", 0, 0);
 			slave.stampTat = either("flowers", "tribal patterns", 0, 0);
 			return slave;
diff --git a/src/events/recETS/newSlaveIncestSex.js b/src/events/recETS/newSlaveIncestSex.js
index b15da728a30..a50c170aad6 100644
--- a/src/events/recETS/newSlaveIncestSex.js
+++ b/src/events/recETS/newSlaveIncestSex.js
@@ -5,7 +5,7 @@
  * @returns {HTMLElement}
  */
 globalThis.newSlaveIncestSex = function(relative, relative2) {
-	const eventName = V.event ? V.event.eventName.replace("incest", "").toLowerCase() : "";
+	const eventName = V.event ? V.event.eventName.replace("incest", "").replace(" ", "-").toLowerCase() : "";
 	const div = document.createElement("div");
 	App.Events.drawEventArt(div, [relative, relative2], "no clothing");
 	const {
@@ -117,7 +117,7 @@ globalThis.newSlaveIncestSex = function(relative, relative2) {
 		}
 		App.Events.addParagraph(frag, r);
 
-		App.Events.addParagraph(frag, [`You can tell how uncomfortable they are with you watching them, but as they become increasingly worked up, they lose their inhibitions. Soon, you are watching some fairly enthralling ${eventName} incest action at your office${(actions.length) ? `, including some enthusiastic ${actions.join(" and ")}`: ``}. Eventually, they bring each other to impressive mutual orgasms. Their lusty moans are muffled only by each others' crotches. Spent, exhausted, and with their faces covered in each others ${secretions.join(" and ")}, they untangle to rest comfortably on your couch.`]);
+		App.Events.addParagraph(frag, [`You can tell how uncomfortable they are with you watching them, but as they become increasingly worked up, they lose their inhibitions. Soon, you are watching some fairly enthralling ${eventName}-incest action at your office${(actions.length) ? `, including some enthusiastic ${actions.join(" and ")}`: ``}. Eventually, they bring each other to impressive mutual orgasms. Their lusty moans are muffled only by each others' crotches. Spent, exhausted, and with their faces covered in each others ${secretions.join(" and ")}, they untangle to rest comfortably on your couch.`]);
 
 		App.Events.addParagraph(frag, [`You indicate them to present themselves to you. Still shaking from the aftershocks of their orgasms, they stand side by side in front of you, panting, naked and with their ${genitals} dripping mixed juices. You simply nod, showing your approval. They are visibly relieved, and not only sexually. They are more confident of having made the right choice in enslaving themselves to you, since you seem <span class="mediumaquamarine">trustworthy</span> and <span class="hotpink">sympathetic.</span> They hug again, kissing and licking the sexual fluids off each others' stained faces.`]);
 
diff --git a/src/events/recETS/recetsDesperateBroodmother.js b/src/events/recETS/recetsDesperateBroodmother.js
index a2fdadcfd3d..50821b4322b 100644
--- a/src/events/recETS/recetsDesperateBroodmother.js
+++ b/src/events/recETS/recetsDesperateBroodmother.js
@@ -208,9 +208,9 @@ App.Events.recetsDesperateBroodmother = class recetsDesperateBroodmother extends
 		const choices = [];
 
 		if (V.cash >= contractCost) {
-			choices.push(new App.Events.Result(`Enslave the mother`, enslave, `This will cost ${contractCost}`));
+			choices.push(new App.Events.Result(`Enslave the mother`, enslave, `This will cost ${cashFormat(contractCost)}`));
 			if (V.cash >= (contractCost * 2)) {
-				choices.push(new App.Events.Result(`Accept ${his} offer`, both, `This will cost ${2 * contractCost}`));
+				choices.push(new App.Events.Result(`Accept ${his} offer`, both, `This will cost ${cashFormat(2 * contractCost)}`));
 			}
 		} else {
 			choices.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}.`));
diff --git a/src/events/recETS/recetsPoshMotherDaughter.js b/src/events/recETS/recetsPoshMotherDaughter.js
index 3feeb519eaa..90e7231a1ea 100644
--- a/src/events/recETS/recetsPoshMotherDaughter.js
+++ b/src/events/recETS/recetsPoshMotherDaughter.js
@@ -76,7 +76,7 @@ App.Events.recetsPoshMotherDaughter = class recetsPoshMotherDaughter extends App
 		const choices = [];
 
 		if (V.cash >= contractCost) {
-			choices.push(new App.Events.Result(`Enslave the mother`, enslave, `This will cost ${contractCost}`));
+			choices.push(new App.Events.Result(`Enslave the mother`, enslave, `This will cost ${cashFormat(contractCost)}`));
 			choices.push(new App.Events.Result(`Sell ${him} immediately`, sell, `This will bring in ${cashFormat(cost - contractCost)}`));
 			if (V.cash >= (contractCost * 2)) {
 				choices.push(new App.Events.Result(`Manipulate ${him} to enslave both mother and ${daughter2}`, both, `This will cost ${cashFormat(contractCost * 2)}`));
diff --git a/src/events/recFS/recfsDegradationist.js b/src/events/recFS/recfsDegradationist.js
index b25b844a9fd..3f07a9a3647 100644
--- a/src/events/recFS/recfsDegradationist.js
+++ b/src/events/recFS/recfsDegradationist.js
@@ -43,11 +43,11 @@ App.Events.recFSDegradationist = class recFSDegradationist extends App.Events.Ba
 		slave.anus = 2;
 		slave.vagina = 2;
 		slave.weight = 0;
-		slave.clitPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.nipplesPiercing = 1;
-		slave.nosePiercing = 1;
-		slave.earPiercing = 1;
+		slave.piercing.genitals.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.nipple.weight = 1;
+		slave.piercing.nose.weight = 1;
+		slave.piercing.ear.weight = 1;
 		slave.skill.vaginal = random(50, 100);
 		slave.skill.oral = random(50, 100);
 		slave.skill.anal = random(50, 100);
diff --git a/src/events/recFS/recfsDegradationistTwo.js b/src/events/recFS/recfsDegradationistTwo.js
index cb8411873fe..976df08f74c 100644
--- a/src/events/recFS/recfsDegradationistTwo.js
+++ b/src/events/recFS/recfsDegradationistTwo.js
@@ -29,11 +29,11 @@ App.Events.recFSDegradationistTwo = class recFSDegradationistTwo extends App.Eve
 		slave.anus = 2;
 		slave.vagina = 2;
 		slave.weight = 0;
-		slave.clitPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.nipplesPiercing = 1;
-		slave.nosePiercing = 1;
-		slave.earPiercing = 1;
+		slave.piercing.genitals.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.nipple.weight = 1;
+		slave.piercing.nose.weight = 1;
+		slave.piercing.ear.weight = 1;
 		slave.pubicHStyle = "waxed";
 		slave.behavioralFlaw = either("arrogant", "bitchy");
 
diff --git a/src/events/recFS/recfsHedonisticDecadence.js b/src/events/recFS/recfsHedonisticDecadence.js
index 6420a6a5754..262d9785a3e 100644
--- a/src/events/recFS/recfsHedonisticDecadence.js
+++ b/src/events/recFS/recfsHedonisticDecadence.js
@@ -34,17 +34,17 @@ App.Events.recFSHedonisticDecadence = class recFSHedonisticDecadence extends App
 		slave.pubicHStyle = "bushy";
 		slave.behavioralFlaw = "gluttonous";
 		slave.sexualQuirk = "size queen";
-		slave.tonguePiercing = 2;
-		slave.nipplesPiercing = 2;
-		slave.nosePiercing = 2;
-		slave.earPiercing = 2;
-		slave.lipsPiercing = 2;
-		slave.vaginaPiercing = 2;
-		slave.anusPiercing = 2;
-		slave.eyebrowPiercing = 2;
-		slave.navelPiercing = 2;
-		slave.corsetPiercing = 1;
-		slave.areolaePiercing = 1;
+		slave.piercing.tongue.weight = 2;
+		slave.piercing.nipple.weight = 2;
+		slave.piercing.nose.weight = 2;
+		slave.piercing.ear.weight = 2;
+		slave.piercing.lips.weight = 2;
+		slave.piercing.vagina.weight = 2;
+		slave.piercing.anus.weight = 2;
+		slave.piercing.eyebrow.weight = 2;
+		slave.piercing.navel.weight = 2;
+		slave.piercing.corset.weight = 1;
+		slave.piercing.areola.weight = 1;
 		slave.clothes = "a slutty outfit";
 		slave.shoes = "heels";
 		slave.inflation = 3;
diff --git a/src/events/recFS/recfsNeoImperialist.js b/src/events/recFS/recfsNeoImperialist.js
index cf18c3d35a7..f84bbaa8bf2 100644
--- a/src/events/recFS/recfsNeoImperialist.js
+++ b/src/events/recFS/recfsNeoImperialist.js
@@ -41,7 +41,7 @@ App.Events.recFSNeoImperialist = class recFSNeoImperialist extends App.Events.Ba
 		r.push(`You receive so many messages, as a noted titan of the new Free Cities world, that ${V.assistant.name} has to be quite draconian in culling them. ${HeA} lets only the most important through to you. One category of message that always gets through regardless of content, though, is requests for voluntary enslavement. As the new world takes shape, they've become less rare than they once were.`);
 		App.Events.addParagraph(node, r);
 		r = [];
-		r.push(`The call comes in from a private old world apartment. The caller is a ${woman} who speaks in a gruff and serious tone, explaining that ${he} was a soldier in an Old World military who served with distinction for years before being dishonorably discharged due to some incident that ${he} refuses to talk about when you ask. ${He} says that there's no room left for tired dogs in the crumbling economy of the old world for those without money, and ${his} only real options are to submit to menial servitude or open slavery. ${He} says that ${he}'s heard that your Imperial society values warriors and honor, and that ${he}'d prefer living somewhere where ${his} skills are worth something - even as a slave. At your request, ${he} sends over a dossier containing ${his} personal data.`);
+		r.push(`The call comes in from a private old world apartment. The caller is a ${woman} who speaks in a gruff and serious tone, explaining that ${he} was a soldier in an Old World military who served with distinction for years before being dishonorably discharged due to some incident that ${he} refuses to talk about when you ask. ${He} says that there's no room left for tired dogs in the crumbling economy of the old world for those without money, and ${his} only real options are to submit to menial servitude or open slavery. ${He} says that ${he}'s heard that your Imperial society values warriors and honor, and that ${he}'d prefer living somewhere where ${his} skills are worth something — even as a slave. At your request, ${he} sends over a dossier containing ${his} personal data.`);
 
 		App.Events.addParagraph(node, r);
 
@@ -77,7 +77,7 @@ App.Events.recFSNeoImperialist = class recFSNeoImperialist extends App.Events.Ba
 
 		function sell() {
 			cashX(cost, "slaveTransfer");
-			return `${He} arrives stoic and gruff, refusing to allow the strange new smells and sounds of the arcology to have any apparent effect on ${his} psyche. It seems as though ${he}'s already made up ${his} mind about the decision to become your slave, and doesn't allow even the slightest trace of doubt to enter - until you order ${him} to hang a price placard over ${his} chest. ${He} stares at you for a moment with cold eyes that communicate a deeply-felt betrayal, then silently leaves, accompanied by one of your slaves. Whether ${his} submission was to deny you the pleasure of a reaction or simple stoicism, you can't tell.`;
+			return `${He} arrives stoic and gruff, refusing to allow the strange new smells and sounds of the arcology to have any apparent effect on ${his} psyche. It seems as though ${he}'s already made up ${his} mind about the decision to become your slave, and doesn't allow even the slightest trace of doubt to enter — until you order ${him} to hang a price placard over ${his} chest. ${He} stares at you for a moment with cold eyes that communicate a deeply-felt betrayal, then silently leaves, accompanied by one of your slaves. Whether ${his} submission was to deny you the pleasure of a reaction or simple stoicism, you can't tell.`;
 		}
 	}
 };
diff --git a/src/events/recFS/recfsPetiteAdmirationTwo.js b/src/events/recFS/recfsPetiteAdmirationTwo.js
index 10c47a1508d..b6dbb744d43 100644
--- a/src/events/recFS/recfsPetiteAdmirationTwo.js
+++ b/src/events/recFS/recfsPetiteAdmirationTwo.js
@@ -45,9 +45,9 @@ App.Events.recFSPetiteAdmirationTwo = class recFSPetiteAdmirationTwo extends App
 		slave.anus = 2;
 		slave.vagina = 2;
 		slave.weight = random(-20, 20);
-		slave.clitPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.earPiercing = 1;
+		slave.piercing.genitals.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.ear.weight = 1;
 		slave.skill.vaginal = 100;
 		slave.skill.oral = 100;
 		slave.skill.anal = 100;
diff --git a/src/events/recFS/recfsSlaveProfessionalism.js b/src/events/recFS/recfsSlaveProfessionalism.js
index fe4909ad05a..dde6785e21b 100644
--- a/src/events/recFS/recfsSlaveProfessionalism.js
+++ b/src/events/recFS/recfsSlaveProfessionalism.js
@@ -33,11 +33,11 @@ App.Events.recFSSlaveProfessionalism = class recFSSlaveProfessionalism extends A
 		slave.anus = 2;
 		slave.vagina = 2;
 		slave.weight = random(-40, 10);
-		slave.clitPiercing = 1;
-		slave.tonguePiercing = 1;
-		slave.nipplesPiercing = 1;
-		slave.nosePiercing = 1;
-		slave.earPiercing = 1;
+		slave.piercing.genitals.weight = 1;
+		slave.piercing.tongue.weight = 1;
+		slave.piercing.nipple.weight = 1;
+		slave.piercing.nose.weight = 1;
+		slave.piercing.ear.weight = 1;
 		slave.skill.vaginal = 100;
 		slave.skill.oral = 100;
 		slave.skill.anal = 100;
diff --git a/src/events/scheduled/assholeKnight.js b/src/events/scheduled/assholeKnight.js
index 9c5a195f978..c93aa374234 100644
--- a/src/events/scheduled/assholeKnight.js
+++ b/src/events/scheduled/assholeKnight.js
@@ -55,6 +55,7 @@ App.Events.SEAssholeKnight = class SEAssholeKnight extends App.Events.BaseEvent
 			assholeKnight.balls = random(2, 4);
 			assholeKnight.scrotum = assholeKnight.balls;
 			assholeKnight.prostate = 1;
+			assholeKnight.accent = random(0, 1);
 			r.push(App.UI.newSlaveIntro(assholeKnight));
 			App.Events.addParagraph(frag, r);
 			return frag;
diff --git a/src/events/scheduled/murderAttempt.js b/src/events/scheduled/murderAttempt.js
index ae72e5f4454..746b6fb810f 100644
--- a/src/events/scheduled/murderAttempt.js
+++ b/src/events/scheduled/murderAttempt.js
@@ -105,8 +105,8 @@ App.Events.MurderAttempt = class MurderAttempt extends App.Events.BaseEvent {
 					break;
 			}
 			App.Events.addResponses(fragment, [
-				new App.Events.Result(`${yesText}; invite them to a private meeting.`, invite),
-				new App.Events.Result(`You are not going to waste your time on something as vague as a "${noText}".`, endEvent)
+				new App.Events.Result(`${yesText}; invite them to a private meeting`, invite),
+				new App.Events.Result(`You are not going to waste your time on something as vague as a "${noText}"`, endEvent)
 			]);
 		}
 
@@ -148,9 +148,9 @@ App.Events.MurderAttempt = class MurderAttempt extends App.Events.BaseEvent {
 				App.Events.addParagraph(fragment, r);
 
 				App.Events.addResponses(fragment, [
-					new App.Events.Result(`Order ${him} to leave for making such a request.`, endEvent),
-					new App.Events.Result(`${S.Bodyguard.slaveName} goes everywhere and does everything with you. ${HeBG} stays.`, bgStaysRoute),
-					new App.Events.Result(`This better be worth it. Order ${S.Bodyguard.slaveName} to leave.`, bgLeavesRoute)
+					new App.Events.Result(`Order ${him} to leave for making such a request`, endEvent),
+					new App.Events.Result(`${S.Bodyguard.slaveName} goes everywhere and does everything with you. ${HeBG} stays`, bgStaysRoute),
+					new App.Events.Result(`This better be worth it. Order ${S.Bodyguard.slaveName} to leave`, bgLeavesRoute)
 				]);
 			} else {
 				noSlaveRoute(fragment, r, false);
diff --git a/src/events/scheduled/newBaron.js b/src/events/scheduled/newBaron.js
index 5e1cd120b15..be34ca48bff 100644
--- a/src/events/scheduled/newBaron.js
+++ b/src/events/scheduled/newBaron.js
@@ -13,11 +13,11 @@ App.Events.SENewBaron = class SENewBaron extends App.Events.BaseEvent {
 		V.newBaron = 1;
 		V.imperialEventWeek = App.Events.effectiveWeek();
 
-		App.Events.addParagraph(node, [`${V.arcologies[0].name} is prospering. New citizens flood to your gates, filling out the marketplaces and houses with new goods, slaves, and desires. Although every new citizen and visitor on the bustling trams lines more money into your pocket, it also comes with the challenge of new bureaucracy. The original group of Barons you appointed to micromanage each district has been valiantly struggling to manage increasingly larger clusters of people, but it has become quite clear, even if the Barons refuse to admit it, that a new addition to their hallowed ranks is needed to administrate your ever-greater Arcology.`]);
+		App.Events.addParagraph(node, [`${V.arcologies[0].name} is prospering. New citizens flood to your gates, filling out the marketplaces and houses with new goods, slaves, and desires. Although every new citizen and visitor on the bustling trams lines more money into your pocket, it also comes with the challenge of new bureaucracy. The original group of Barons you appointed to micromanage each district has been valiantly struggling to manage increasingly larger clusters of people, but it has become quite clear, even if the Barons refuse to admit it, that a new addition to their hallowed ranks is needed to manage your ever-expanding arcology.`]);
 
-		App.Events.addParagraph(node, [`The appointment of a new Baron is not something to be taken lightly; it is undoubtedly the most desired title in your arcology, and a veritable horde of citizens and millionaires hound your inbox and parties with hints and implications, subtly attempting to display their qualifications, because the Barons posses something even the wealthiest trillionaire in the Free Cities does not - security. The golden band of office of an Imperial Baron brings with it a penthouse, a sense of nobility, and a guaranteed sector of people to rule; so long as the Arcology continues to exist, the Barons will rule in your name, free from worries about petty market fluctuations and slave prices. Short of your personal intervention or the total collapse of the Arcology, nothing can unseat a Baron once they're appointed.`]);
+		App.Events.addParagraph(node, [`The appointment of a new Baron is not something to be taken lightly; it is undoubtedly the most desired title in your arcology, and a veritable horde of citizens and millionaires hound your inbox and parties with hints and implications, subtly attempting to display their qualifications, because the Barons possess something even the wealthiest trillionaire in the Free Cities does not – security. The golden band of office of an Imperial Baron brings with it a penthouse, a sense of nobility, and a guaranteed sector of people to rule; so long as the arcology continues to exist, the Barons will rule in your name, free from worries about petty market fluctuations and slave prices. Short of your personal intervention or the total collapse of the arcology, nothing can unseat a Baron once they're appointed.`]);
 
-		App.Events.addParagraph(node, [`The hunger for such security among your upper class leaves you in an interesting position. You have dozens of citizens that you could give the title to, with various skills and proficiencies from your diverse arcology, and anyone who's handed a noble title will be certain to show their gratitude. The only real question on your mind - and on the minds of the waiting elites - is who you plan to promote.`]);
+		App.Events.addParagraph(node, [`The hunger for such security among your upper class leaves you in an interesting position. You have dozens of citizens that you could give the title to, with various skills and proficiencies from your diverse arcology, and anyone who's handed a noble title will be certain to show their gratitude. The only real question on your mind – and on the minds of the waiting elites – is who you plan to promote.`]);
 
 		const choices = [];
 		choices.push(new App.Events.Result(`Appoint a wealthy executive`, executive));
@@ -33,13 +33,13 @@ App.Events.SENewBaron = class SENewBaron extends App.Events.BaseEvent {
 
 		function bureaucrat() {
 			V.arcologies[0].prosperity += 3;
-			return `You select an unimportant but accomplished bureaucrat within the lower ranks of your administration, one of the cornerstone accountants that keeps the trains running on time. The rail-thin woman is clearly surprised that you'd choose her over a wealthier, more influential elite, but nevertheless accepts the golden band with overflowing joy. Although she may not turn any eyebrows, you can tell without a fact that she'll <span class="green">keep your arcology efficient and prosperous</span> - after all, if it collapses, then her 'guaranteed' barony vanishes too.`;
+			return `You select an unimportant but accomplished bureaucrat within the lower ranks of your administration, one of the cornerstone accountants that keeps the trains running on time. The rail-thin woman is clearly surprised that you'd choose her over a wealthier, more influential elite, but nevertheless accepts the golden band with overflowing joy. Although she may not turn any eyebrows, you can tell without a fact that she'll <span class="green">keep your arcology efficient and prosperous</span> – after all, if it collapses, then her 'guaranteed' barony vanishes too.`;
 		}
 
 		function veteran() {
 			repX(+2500, "event");
 			V.arcologies[0].prosperity += 1;
-			return `You select one of your Imperial Knights, a heavily scarred and muscular man who bears his rose-and-hawk coat of arms like a purple heart on his broad chest. The grizzled soldier is somewhat taken aback at your decision, but regains his composure almost immediately and accepts the golden band of a Baron with a scarred-over smirk. The ex-Knight takes to his new duty with surprising gusto, and quickly proves himself an <span class="green">extraordinarily popular figure</span> among the commoners, who see the scarred and athletic figure both as proof that duty is rewarded in your arcology and as an example of what a proper Imperial noble should be - martial, confident, and nearly unbeatable in a duel.`;
+			return `You select one of your Imperial Knights, a heavily scarred and muscular man who bears his rose-and-hawk coat of arms like a purple heart on his broad chest. The grizzled soldier is somewhat taken aback at your decision, but regains his composure almost immediately and accepts the golden band of a Baron with a scarred-over smirk. The ex-Knight takes to his new duty with surprising gusto, and quickly proves himself an <span class="green">extraordinarily popular figure</span> among the commoners, who see the scarred and athletic figure both as proof that duty is rewarded in your arcology and as an example of what a proper Imperial noble should be – martial, confident, and nearly unbeatable in a duel.`;
 		}
 	}
 };
diff --git a/src/events/scheduled/pitFight.js b/src/events/scheduled/pitFight.js
index 018827d10a1..693417a9631 100644
--- a/src/events/scheduled/pitFight.js
+++ b/src/events/scheduled/pitFight.js
@@ -13,7 +13,7 @@ App.Events.SEPitFight = class SEPitFight extends App.Events.BaseEvent {
 	castActors() {
 		const available = [...new Set(V.pit.fighterIDs)];
 
-		if (V.pit.slavesFighting.length !== 2) {
+		if (V.pit.fighters === 4 && V.pit.slavesFighting.length !== 2) {
 			V.pit.fighters = 0;
 			V.pit.slavesFighting = [];
 		}
@@ -26,14 +26,20 @@ App.Events.SEPitFight = class SEPitFight extends App.Events.BaseEvent {
 			const fighters = V.pit.fighters;
 
 			if (available.length > 0) {
-				if (fighters === 4 && V.pit.slavesFighting.every(a => available.includes(a))) {
+				if (fighters === 4
+					&& V.pit.slavesFighting.length === 2
+					&& V.pit.slavesFighting.every(a => available.includes(a))) {
 					this.actors.push(...V.pit.slavesFighting);
 				} else if (fighters === 3) {
 					V.pit.fighters = random(2);
+
+					if (V.pit.fighters === 2 && (V.active.canine || V.active.hooved || V.active.feline)) {
+						V.pit.slaveFightingAnimal = available.pluck();
+					}
 				}
 
 				// first fighter
-				if (S.Bodyguard && fighters === 1) {
+				if (S.Bodyguard && V.pit.fighters === 1) {
 					available.delete(S.Bodyguard.ID);
 					this.actors.push(S.Bodyguard.ID);
 				} else {
@@ -41,7 +47,7 @@ App.Events.SEPitFight = class SEPitFight extends App.Events.BaseEvent {
 				}
 
 				// second fighter
-				if (fighters !== 2) {
+				if (V.pit.fighters !== 2 || (!V.active.canine && !V.active.hooved && !V.active.feline)) {
 					if (available.length > 0) {
 						this.actors.push(available.pluck());
 					} else {
diff --git a/src/events/scheduled/pitFightLethal.js b/src/events/scheduled/pitFightLethal.js
index 686bb908871..b0ca132fa0e 100644
--- a/src/events/scheduled/pitFightLethal.js
+++ b/src/events/scheduled/pitFightLethal.js
@@ -46,6 +46,8 @@ App.Facilities.Pit.lethalFight = function(fighters) {
 	postFight(frag);
 
 	V.pit.slaveFightingBodyguard = null;
+	V.pit.slaveFightingAnimal = null;
+	V.pit.slavesFighting = [];
 
 	return frag;
 
diff --git a/src/events/scheduled/pitFightNonlethal.js b/src/events/scheduled/pitFightNonlethal.js
index 21b15e86b93..ef0acdda561 100644
--- a/src/events/scheduled/pitFightNonlethal.js
+++ b/src/events/scheduled/pitFightNonlethal.js
@@ -16,7 +16,7 @@ App.Facilities.Pit.nonlethalFight = function(fighters) {
 		animals.push(V.active.feline);
 	}
 
-	if (V.pit.fighters === 2 || V.pit.slaveFightingAnimal) {
+	if ((V.pit.fighters === 2 || V.pit.slaveFightingAnimal) && animals.length > 0) {
 		animal = V.pit.animal === 'random'
 			? animals.random()
 			: V.pit.animal;
@@ -54,6 +54,10 @@ App.Facilities.Pit.nonlethalFight = function(fighters) {
 	fight(frag);
 	postFight(frag);
 
+	V.pit.slaveFightingBodyguard = null;
+	V.pit.slaveFightingAnimal = null;
+	V.pit.slavesFighting = [];
+
 	return frag;
 
 	/**
@@ -572,7 +576,7 @@ App.Facilities.Pit.nonlethalFight = function(fighters) {
 
 					cashX(1000, "pit", winner);
 				}
-			} else if (loser.eyebrowPiercing > 0) {
+			} else if (loser.piercing.eyebrow.weight > 0) {
 				r.push(`The fight starts slowly, with the two trading jabs. Just as the spectators are getting bored, ${loser.slaveName} takes a glancing blow to the eyebrow. ${His2} piercing catches on ${winner.slaveName}'s glove and tears out. ${loser.slaveName} goes after ${his2} tormentor in fury, streaming blood, the piercing forgotten on the mat. Any tendency ${winner.slaveName} might have had to feel badly about this is extinguished by the assault, and soon ${winner.slaveName} is even willing to follow up on the success by targeting pierced body parts. The fight ends with poor ${loser.slaveName} writhing in pain on the mat, `, App.UI.DOM.makeElement("span", `leaking blood,`, ["health", "dec"]), ` from several terribly shredded areas.`);
 
 				if (V.pit.audience === "free") {
@@ -1184,15 +1188,15 @@ App.Facilities.Pit.nonlethalFight = function(fighters) {
 				if (loser.sexualFlaw === "self hating") {
 					r.push(`${loser.slaveName} feels ${he2} `, App.UI.DOM.makeElement("span", `deserved this.`, ["devotion", "inc"]));
 
-					loser.devotion -= 5;
+					loser.devotion += 5;
 				} else if (loser.fetish === "masochist" && loser.fetishStrength > 60 && loser.fetishKnown) {
 					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `gets off`, ["devotion", "inc"]), ` on being beaten and molested.`);
 
-					loser.devotion -= 5;
+					loser.devotion += 5;
 				} else if (loser.fetish === "humiliation" && loser.fetishStrength > 60 && loser.fetishKnown) {
 					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `enjoys`, ["devotion", "inc"]), ` the humiliation of being openly beaten and raped.`);
 
-					loser.devotion -= 5;
+					loser.devotion += 5;
 				} else if (loser.devotion < 50) {
 					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `resents`, ["devotion", "dec"]), ` being beaten and molested and `, trustSpan, ` that it will happen again.`);
 
diff --git a/src/events/scheduled/poorKnight.js b/src/events/scheduled/poorKnight.js
index 8733e1141e9..26f2c5f940f 100644
--- a/src/events/scheduled/poorKnight.js
+++ b/src/events/scheduled/poorKnight.js
@@ -23,12 +23,12 @@ App.Events.SEPoorKnight = class SEPoorKnight extends App.Events.BaseEvent {
 		const quietCost = 500;
 		const choices = [];
 		if (V.cash >= festiveCost) {
-			choices.push(new App.Events.Result(`Knight him in a Grand Festival`, festival, `costing ${cashFormat(festiveCost)}.`));
+			choices.push(new App.Events.Result(`Knight him in a grand festival`, festival, `Costs ${cashFormat(festiveCost)}.`));
 		} else {
-			choices.push(new App.Events.Result(null, null, `Cannot afford a Grand Festival.`));
+			choices.push(new App.Events.Result(null, null, `Cannot afford a grand festival.`));
 		}
 		if (V.cash >= quietCost) {
-			choices.push(new App.Events.Result(`Knight him in a Quiet Ceremony`, quiet, `costing ${cashFormat(quietCost)}.`));
+			choices.push(new App.Events.Result(`Knight him in a quiet ceremony`, quiet, `Costs ${cashFormat(quietCost)}.`));
 		} else {
 			choices.push(new App.Events.Result(null, null, `Cannot afford even a quiet ceremony. Maybe, uh, Valentin could spot you a few ¤?`));
 		}
diff --git a/src/events/scheduled/seCoursing.js b/src/events/scheduled/seCoursing.js
index 2bc20683fec..2d245e075df 100644
--- a/src/events/scheduled/seCoursing.js
+++ b/src/events/scheduled/seCoursing.js
@@ -382,7 +382,7 @@ App.Events.SECoursing = class SECoursing extends App.Events.BaseEvent {
 				r.push(`${He2}'s so massively pregnant it'll be lucky if ${he2} even makes it anywhere.`);
 				hareSpeed -= 10;
 			} else if (slave.belly >= 10000) {
-				r.push(`${He2} pregnant belly will probably stop ${him2} from running at all.`);
+				r.push(`${His2} pregnant belly will probably stop ${him2} from running at all.`);
 				hareSpeed -= 5;
 			} else if (slave.belly >= 5000) {
 				r.push(`${He2}'s visibly pregnant and likely to be cautious and unsure about running.`);
@@ -417,12 +417,12 @@ App.Events.SECoursing = class SECoursing extends App.Events.BaseEvent {
 			const result = {
 				slave: slave, number: num, origin: origin, speed: hareSpeed, row: row
 			};
-			r.push(App.UI.DOM.link(
+			r.push(App.UI.DOM.makeElement("div", App.UI.DOM.link(
 				`The ${ordinalSuffixWords(num)} hare`,
 				() => {
 					jQuery(node).empty().append(coursingRace(result));
 				}
-			));
+			), ['indent']));
 			App.Events.addNode(row, r);
 			return result;
 		}
diff --git a/src/events/scheduled/seFctvRemote.js b/src/events/scheduled/seFctvRemote.js
index 216464eae1b..850ad0c0f59 100644
--- a/src/events/scheduled/seFctvRemote.js
+++ b/src/events/scheduled/seFctvRemote.js
@@ -128,7 +128,8 @@ App.Events.SEfctvRemote = class SEfctvRemote extends App.Events.BaseEvent {
 			} = getPronouns(customer).appendSuffix("2");
 
 			/* set up tech */
-			tech.clitPiercing = 3;
+			tech.piercing.genitals.weight = 2;
+			tech.piercing.genitals.smart = true;
 			let backTat;
 			if (V.seeDicks === 0) {
 				backTat = "clits";
diff --git a/src/events/scheduled/sePCBirthday.desc.js b/src/events/scheduled/sePCBirthday.desc.js
index 16f4d057f62..1edaa99dba7 100644
--- a/src/events/scheduled/sePCBirthday.desc.js
+++ b/src/events/scheduled/sePCBirthday.desc.js
@@ -83,7 +83,7 @@ App.Events.pcBirthday.Desc = (function(bday) {
 				}
 
 				html += ` bids you hello, you find streamers and festive, sparkling decorations emerging from nooks
-					and crannies of your bedroom that you forgot were even there. The letters spelling <em>HAPPY BIRTHDAY</em>, strung along the wall across from you,
+					and crannies of your bedroom that you forgot were even there. The letters spelling <em>"HAPPY BIRTHDAY"</em>, strung along the wall across from you,
 					explain the subdued giggling you sometimes heard behind your back. Seeing you are now awake and aware, ${data.planner.slave.slaveName} prowls up your
 					body, `;
 
@@ -93,7 +93,7 @@ App.Events.pcBirthday.Desc = (function(bday) {
 					html += `${data.planner.pn.his} engorged dick coming to a rest on your crotch. `;
 				}
 
-				html += `${data.planner.pn.She} brings ${data.planner.pn.his} mouth to your ear and whispers a soft and sensual <em>"Happy birthday, ${data.planner.slave.custom.title}"</em>
+				html += `${data.planner.pn.She} brings ${data.planner.pn.his} mouth to your ear and whispers a soft and sensual <em>"Happy birthday, ${getWrittenTitle(data.planner.slave)}"</em>
 					in your ear before nibbling your lobe.
 				</p>
 				<p>
@@ -111,7 +111,10 @@ App.Events.pcBirthday.Desc = (function(bday) {
 
 					${data.planner.pn.She} explains that if you decline the social event, ${data.planner.pn.she} has a business partner of yours set up to attend in your
 					stead; a favor to be repaid one day. And if you prefer to see what it's all about, there will be plenty of stiff-dicked attendees there to sate
-					${data.planner.pn.her}, so there's no reason to feel obliged to stay put. "${properMaster()} will get ${getPronouns(V.PC).his} wish."
+					${data.planner.pn.her}, so there's no reason to feel obliged to stay put.
+				</p>
+				<p>
+					"${properMaster()} will get ${getPronouns(V.PC).his} wish."
 				</p>`;
 
 				const frag = fragment(html);
diff --git a/src/events/scheduled/seRecruiterSuccess.js b/src/events/scheduled/seRecruiterSuccess.js
index e7c5ac22785..68e7acbdab7 100644
--- a/src/events/scheduled/seRecruiterSuccess.js
+++ b/src/events/scheduled/seRecruiterSuccess.js
@@ -25,7 +25,7 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 				slave.skill.vaginal = random(15, 40);
 			}
 			slave.skill.anal = 0;
-			slave.earPiercing = pierceMe();
+			slave.piercing.ear.weight = pierceMe();
 		} else if (V.recruiterTarget === "recent divorcees") {
 			slave = GenerateNewSlave(null, {minAge: 30, maxAge: 45, disableDisability: 1});
 			slave.origin = "$He submitted to enslavement for a better quality of life than $he had as a recent divorcee.";
@@ -38,7 +38,7 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 				slave.skill.vaginal = random(15, 40);
 			}
 			slave.skill.anal = 0;
-			slave.earPiercing = pierceMe();
+			slave.piercing.ear.weight = pierceMe();
 		} else if (V.recruiterTarget === "reassignment candidates") {
 			slave = GenerateNewSlave("XY", {disableDisability: 1});
 			generateSalonModifications(slave);
@@ -50,9 +50,9 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 				slave.balls = random(1, 3);
 			}
 
-			slave.tonguePiercing = pierceMe();
-			slave.earPiercing = pierceMe();
-			slave.nosePiercing = pierceMe();
+			slave.piercing.tongue.weight = pierceMe();
+			slave.piercing.ear.weight = pierceMe();
+			slave.piercing.nose.weight = pierceMe();
 			slave.behavioralFlaw = "hates women";
 		} else if (V.recruiterTarget === "dissolute sissies") {
 			slave = GenerateNewSlave("XY", {disableDisability: 1});
@@ -69,14 +69,14 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 			slave.skill.anal = random(15, 40);
 			slave.faceImplant = 20*pierceMe();
 			slave.face = Math.clamp(slave.face+(slave.faceImplant), -100, 100);
-			slave.lipsPiercing = pierceMe();
-			slave.tonguePiercing = pierceMe();
-			slave.earPiercing = pierceMe();
-			slave.nosePiercing = pierceMe();
-			slave.eyebrowPiercing = pierceMe();
-			slave.navelPiercing = pierceMe();
-			slave.nipplesPiercing = pierceMe();
-			slave.clitPiercing = pierceMe();
+			slave.piercing.lips.weight = pierceMe();
+			slave.piercing.tongue.weight = pierceMe();
+			slave.piercing.ear.weight = pierceMe();
+			slave.piercing.nose.weight = pierceMe();
+			slave.piercing.eyebrow.weight = pierceMe();
+			slave.piercing.navel.weight = pierceMe();
+			slave.piercing.nipple.weight = pierceMe();
+			slave.piercing.genitals.weight = pierceMe();
 			slave.behavioralFlaw = "hates women";
 		} else if (V.recruiterTarget === "expectant mothers") {
 			slave = GenerateNewSlave("XX", {minAge: Math.max(V.fertilityAge, V.minimumSlaveAge), ageOverridesPedoMode: 1, disableDisability: 1});
@@ -126,14 +126,14 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 			}
 			slave.lipsImplant = either(0, 10);
 			slave.lips += slave.lipsImplant;
-			slave.lipsPiercing = pierceMe();
-			slave.tonguePiercing = pierceMe();
-			slave.earPiercing = pierceMe();
-			slave.nosePiercing = pierceMe();
-			slave.eyebrowPiercing = pierceMe();
-			slave.navelPiercing = pierceMe();
-			slave.nipplesPiercing = pierceMe();
-			slave.clitPiercing = pierceMe();
+			slave.piercing.lips.weight = pierceMe();
+			slave.piercing.tongue.weight = pierceMe();
+			slave.piercing.ear.weight = pierceMe();
+			slave.piercing.nose.weight = pierceMe();
+			slave.piercing.eyebrow.weight = pierceMe();
+			slave.piercing.navel.weight = pierceMe();
+			slave.piercing.nipple.weight = pierceMe();
+			slave.piercing.genitals.weight = pierceMe();
 		}
 
 		if (V.recruiterEugenics === 1) {
diff --git a/src/facilities/barracks.js b/src/facilities/barracks.js
index 9199d0e4a53..aa117a90848 100644
--- a/src/facilities/barracks.js
+++ b/src/facilities/barracks.js
@@ -177,7 +177,7 @@ App.UI.barracks = function() {
 
 		if (V.arcologies[0].FSYouthPreferentialist !== "unset") {
 			r.push(`${yetAnotherMerc(vignette)} mercenary is getting a blowjob from a young slave. He's playing with ${hisU}`);
-			if (V.seeDicks !== 100) {
+			if (hisU === "her") {
 				r.push(`fresh pussy`);
 			} else {
 				r.push(`tight little anus`);
@@ -232,12 +232,19 @@ App.UI.barracks = function() {
 		}
 
 		if (V.arcologies[0].FSRomanRevivalist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSNeoImperialist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSAztecRevivalist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSEgyptianRevivalist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSEdoRevivalist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSArabianRevivalist !== "unset") {
+			// TODO:
 		} else if (V.arcologies[0].FSChineseRevivalist !== "unset") {
+			// TODO:
 		}
 	}
 
diff --git a/src/facilities/bodyModification/bodyModification.js b/src/facilities/bodyModification/bodyModification.js
index 669fd838414..c9bf7f798ca 100644
--- a/src/facilities/bodyModification/bodyModification.js
+++ b/src/facilities/bodyModification/bodyModification.js
@@ -10,7 +10,7 @@ App.UI.bodyModification = function(slave, cheat = false) {
 		He, His,
 		he, his, him, himself
 	} = getPronouns(slave);
-	let piercingLevel;
+	let piercingLevel = 1;
 	let modReaction = "";
 	/** @type {string|0} */
 	let tattooChoice = "";
@@ -197,22 +197,37 @@ App.UI.bodyModification = function(slave, cheat = false) {
 	function piercings() {
 		const el = new DocumentFragment();
 		let r = [];
-		const piercingLocations = ["ear", "nose", "eyebrow", "lips", "tongue", "nipples", "areolae", "navel", "corset", "clit", "vagina", "dick", "anus"];
+		const piercingLocations = Object.keys(App.Data.Piercings);
 		// DESCRIPTIONS
 		App.UI.DOM.appendNewElement("h2", el, "Piercings");
 
-		for (const piercing of piercingLocations.concat(["chastity"])) {
-			if (piercing === "nipples") {
-				r.push(App.UI.DOM.makeElement("div", App.Desc.piercing(slave, "nipple"))); // This is stupid, but the variable is slave.nipplesPiercing, plural nipples, but in almost all other places we refer to plural body parts as singular (eyebrow, ear, nose, etc).
-			} else {
-				r.push(App.UI.DOM.makeElement("div", App.Desc.piercing(slave, piercing)));
+		let pierced = false;
+		let options = new App.UI.OptionsGroup();
+		for (const piercing in slave.piercing) {
+			if (slave.piercing[piercing].weight > 0) {
+				const option = options.addOption(`${slave.piercing[piercing].weight === 1 ? 'L': 'H'} ${capFirstChar(piercing)} `, "desc", slave.piercing[piercing]);
+				if (slave.piercing[piercing].desc) {
+					option.addValue("Default", "")
+						.showTextBox({large:true});
+				} else {
+					option.addValue("Edit", " ")
+						.addComment(App.Desc.piercing(slave, piercing));
+				}
+				pierced = true;
 			}
 		}
-		if (r.length === 0) {
-			r.push(App.UI.DOM.makeElement("div", `${His} smooth ${slave.skin} skin is completely unpierced.`));
+		const chastity = App.Desc.piercing(slave, "chastity");
+		if (chastity) {
+			options.addComment(chastity);
+			pierced = true;
 		}
-		App.Events.addNode(el, r);
-		r = [];
+
+		if (pierced) {
+			App.UI.DOM.appendNewElement("div", el, `Reminder for writing custom content: slave pronouns are usually written in the masculine, and start with '$'.  "$His earlobes" becomes "Her earlobes" in text.`, "note");
+		} else {
+			options.addComment(`${His} smooth ${slave.skin} skin is completely unpierced.`);
+		}
+		el.append(options.render());
 
 		// Apply piercings
 		r.push(`Choose piercing style:`);
@@ -220,7 +235,6 @@ App.UI.bodyModification = function(slave, cheat = false) {
 			["Remove", 0],
 			["Light", 1],
 			["Heavy", 2],
-			["Smart", 3]
 		]);
 		let linkArray = [];
 		for (const [title, num] of piercingLevelNames) {
@@ -243,104 +257,76 @@ App.UI.bodyModification = function(slave, cheat = false) {
 		r = [];
 
 		// Determine parts that cannot be pierced
-		let validPiercingLocations = Array.from(piercingLocations);
+		let validPiercingLocations;
 
-		if (piercingLevel !== 0) { // Sometimes a piercing winds up in a place that is no longer valid. Make sure players can always remove an existing piercing.
-			if (slave.nipples === "fuckable") {
-				removePiercingLocation("nipples");
-			}
-
-			if (slave.vagina === -1) {
-				removePiercingLocation("vagina");
-			}
-
-			if (slave.dick === 0) {
-				removePiercingLocation("dick");
-				if (slave.vagina === -1) {
-					removePiercingLocation("clit");
+		if (piercingLevel === 0) { // Sometimes a piercing winds up in a place that is no longer valid. Make sure players can always remove an existing piercing.
+			validPiercingLocations = Array.from(piercingLocations);
+		} else {
+			validPiercingLocations = [];
+			for (const location of piercingLocations) {
+				const locationData = App.Data.Piercings[location];
+				if (locationData.hasOwnProperty("requirements") && !locationData.requirements(slave)) {
+					continue;
+				} else {
+					validPiercingLocations.push(location);
 				}
 			}
 		}
 
-		function removePiercingLocation(location) {
-			const index = validPiercingLocations.indexOf(location);
-			validPiercingLocations.splice(index, 1);
+		if (piercingLevel === 0) {
+			r.push(`Remove piercings from:`);
+		} else if (piercingLevel === 1) {
+			r.push(`Lightly pierce ${his}:`);
+		} else if (piercingLevel === 2) {
+			r.push(`Heavily pierce ${his}:`);
 		}
-
-		if (piercingLevel < 3) {
-			if (piercingLevel === 0) {
-				r.push(`Remove piercings from:`);
-			} else if (piercingLevel === 1) {
-				r.push(`Lightly pierce ${his}:`);
-			} else if (piercingLevel === 2) {
-				r.push(`Heavily pierce ${his}:`);
-			}
-			// Entire body
-			linkArray = [];
-			linkArray.push(
-				App.UI.DOM.link(
-					"Entire body",
-					() => {
-						for (const location of validPiercingLocations) {
-							if (slave[`${location}Piercing`] !== piercingLevel) {
-								modReaction += App.Medicine.Modification.setPiercing(slave, location, piercingLevel);
-								billPiercing(piercingLevel);
-								if (piercingLevel > 1) {
-									degradation += 1;
-								}
+		// Entire body
+		linkArray = [];
+		linkArray.push(
+			App.UI.DOM.link(
+				"Entire body",
+				() => {
+					for (const location of validPiercingLocations) {
+						if (slave.piercing[location].weight !== piercingLevel) {
+							modReaction += App.Medicine.Modification.setPiercing(slave, location, piercingLevel);
+							billPiercing(piercingLevel);
+							if (piercingLevel > 1) {
+								degradation += 1;
 							}
 						}
-						refresh();
 					}
-				)
-			);
-
-			// Each individual piercing
-			for (const location of validPiercingLocations) {
-				if (slave[`${location}Piercing`] !== piercingLevel) {
-					linkArray.push(
-						App.UI.DOM.link(
-							capFirstChar(location),
-							() => {
-								modReaction = App.Medicine.Modification.setPiercing(slave, location, piercingLevel);
-								billPiercing(piercingLevel);
-								if (piercingLevel > 1) {
-									degradation += 1;
-								}
-								refresh();
-							}
-						)
-					);
+					refresh();
 				}
-			}
-			r.push(App.UI.DOM.generateLinksStrip(linkArray));
-		} else if (piercingLevel === 3) {
-			// Smart piercings
-			if (slave.vagina !== -1 || slave.dick !== 0) {
-				if (slave.clitPiercing !== 3) {
-					r.push(`Give ${him} a`);
-					r.push(
-						App.UI.DOM.link(
-							"smart piercing",
-							() => {
-								modReaction = App.Medicine.Modification.setPiercing(slave, "clit", 3);
-								billPiercing(3);
-								slave.clitSetting = "all";
+			)
+		);
+
+		// Each individual piercing
+		for (const location of validPiercingLocations) {
+			if (slave.piercing[location].weight !== piercingLevel) {
+				linkArray.push(
+					App.UI.DOM.link(
+						capFirstChar(location),
+						() => {
+							modReaction = App.Medicine.Modification.setPiercing(slave, location, piercingLevel);
+							billPiercing(piercingLevel);
+							if (piercingLevel > 1) {
 								degradation += 1;
-								refresh();
-							},
-							[],
-							"",
-							cheat ? "Unlocks options to mold sexuality" :
-								`Costs ${cashFormat(V.SPcost)}, unlocks options to mold sexuality`
-						)
-					);
-				} else {
-					r.push(`${He} already has a smart piercing!`);
-				}
+							}
+							refresh();
+						}
+					)
+				);
 			}
 		}
+		r.push(App.UI.DOM.generateLinksStrip(linkArray));
 		App.Events.addNode(el, r, "div");
+		options = new App.UI.OptionsGroup();
+		if (slave.piercing.genitals.weight) {
+			options.addOption(`Smart vibe for ${his} genital piercing`, "smart", slave.piercing.genitals)
+				.addValue("Installed", true).on()
+				.addValue("Empty", false).off();
+		}
+		el.append(options.render());
 		return el;
 	}
 
diff --git a/src/facilities/brothel/brothel.js b/src/facilities/brothel/brothel.js
index 968aef7d262..5075abf7012 100644
--- a/src/facilities/brothel/brothel.js
+++ b/src/facilities/brothel/brothel.js
@@ -75,60 +75,107 @@ App.Facilities.Brothel.brothel = class Brothel extends App.Facilities.Facility {
 
 	/** @returns {FC.Facilities.Expand} */
 	get expand() {
-		// TODO: redo this without ternaries
+		const is = num => num === 1 ? `is` : `are`;
+		const text = [];
+
+		text.push(`It can support ${num(V.brothel)} whores. There ${is(this.facility.hostedSlaves)} currently ${numberWithPluralOne(this.facility.hostedSlaves, 'whore')} working in ${V.brothelName}.`);
+
+		if (V.brothelAdsSpending > 0) {
+			text.push(`Screens outside the entrance are showing porn to advertise ${V.brothelName}.`);
+
+			if (V.brothelAdsOld === 1) {
+				text.push(`The featured slave actresses are all MILFs.`);
+			} else if (V.brothelAdsOld === -1) {
+				text.push(`The featured slave actresses are all nice and young.`);
+			} else if (V.brothelAdsOld === -2) {
+				text.push(`The featured slave actresses are all teenagers.`);
+			} else if (V.brothelAdsOld === -3) {
+				text.push(`The featured slave actresses are all lolis.`);
+			} else {
+				text.push(`The featured slave actresses vary in age.`);
+			}
+
+			if (V.brothelAdsStacked === 1) {
+				text.push(`Lots of bouncing breasts and butts`);
+			} else if (V.brothelAdsStacked === -1) {
+				text.push(`Lots of trim breasts and shapely butts`);
+			} else {
+				text.push(`A variety of breast and butt sizes and shapes`);
+			}
+
+			text.push(`are on display, and`);
+
+			if (V.brothelAdsImplanted === 1) {
+				text.push(`most of these are augmented by implants.`);
+			} else if (V.brothelAdsImplanted === -1) {
+				text.push(`they're all natural.`);
+			} else {
+				text.push(`some are augmented by implants.`);
+			}
+
+			if (V.seePreg) {
+				if (V.brothelAdsPreg === 1) {
+					text.push(`Most of the slaves have firm, rounded bellies.`);
+				} else if (V.brothelAdsPreg === -1) {
+					text.push(`Most of the slaves have firm, flat bellies.`);
+				} else {
+					text.push(`Some of the slaves are pregnant.`);
+				}
+			}
+
+			if (V.brothelAdsModded === 1) {
+				text.push(`Everything is heavily pierced and tattooed.`);
+			} else if (V.brothelAdsModded === -1) {
+				text.push(`Everything is free of tattoos and piercings.`);
+			} else {
+				text.push(`Some of these assets are tattooed and pierced, and some aren't.`);
+			}
+
+			text.push(`The slaves in the ads are`);
+
+			if (V.brothelAdsXX === 1) {
+				text.push(`sucking dick and taking cock in their pussies and asses.`);
+			} else if (V.brothelAdsXX === -1) {
+				text.push(`sucking dick and taking cock in their pussies and asses.`);
+			} else {
+				if (V.brothelAdsXX) {
+					text.push(`sucking cock and being assfucked while their dicks flop around.`);
+				} else {
+					text.push(`sucking dick and taking anal, and the ones that have pussies are being fucked there, too.`);
+				}
+			}
+
+			text.push(`The ads are shown on media across ${V.arcologies[0].name}.`);
+
+			if (V.brothelAdsXX === 1 && V.brothelAdsImplanted === 1 && V.brothelAdsStacked === 1) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to rent a${V.brothelAdsPreg ? ` pregnant` : ``} bimbo's pussy.`);
+			} else if (V.brothelAdsXX === 1 && V.brothelAdsOld === 1) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to rent a${V.brothelAdsPreg ? ` pregnant` : ``} MILF's tits.`);
+			} else if (V.brothelAdsXX === 1 && V.brothelAdsOld === -3) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to rent${V.brothelAdsPreg ? ` a pregnant` : ``}${V.brothelAdsStacked ? V.brothelAdsPreg !== 1 ? ` an` : `` : `oppai`} loli.`);
+			} else if (V.brothelAdsXX === 1 && V.brothelAdsPreg === 1) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to pound some pregnant pussy.`);
+			} else if (V.brothelAdsXX === -1 && V.brothelAdsStacked === 1) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to rent a shemale's asspussy.`);
+			} else if (V.brothelAdsXX === -1 && V.brothelAdsStacked === -1) {
+				text.push(`As a result, ${V.brothelName} is known as the place to go if you want to rent a trap's tight ass.`);
+			}
+		}
+
+		if (this.facility.hostedSlaves > 2) {
+			text.push(`${capFirstChar(V.brothelName)} is bustling with activity. Customers are coming and going and slave girls are displaying themselves. When a slave catches a customer's eye, he leads her back into a little cubicle.`);
+		} else if (this.facility.hostedSlaves > 0) {
+			text.push(`${capFirstChar(V.brothelName)} is working steadily. Customers are present and slave girls are on offer. When a slave catches a customer's eye, he leads her back into a little cubicle.`);
+		} else if (S.Madam) {
+			text.push(`${S.Madam.slaveName} is alone in ${V.brothelName}, and has nothing to do but keep the place clean and plan future sales efforts.`);
+		} else {
+			text.push(`${capFirstChar(V.brothelName)} is empty and desolate.`);
+		}
+
+		const desc = text.join(' ');
+
 		return {
-			desc: `It can support ${num(V.brothel)} whores. There ${this.facility.hostedSlaves === 1 ? `is currently ${num(this.facility.hostedSlaves)} whore` : `are currently ${num(this.facility.hostedSlaves)} whores`} working in ${V.brothelName}. ${V.brothelAdsSpending > 0
-				? `Screens outside the entrance are showing porn to advertise ${V.brothelName}. ${V.brothelAdsOld === 1
-					? `The featured slave actresses are all MILFs.`
-					: V.brothelAdsOld === -1
-						? `The featured slave actresses are all nice and young.`
-						: V.brothelAdsOld === -2
-							? `The featured slave actresses are all teenagers.`
-							: V.brothelAdsOld === -3
-								? `The featured slave actresses are all lolis.`
-								: `The featured slave actresses vary in age.`}${V.brothelAdsStacked === 1
-					? `Lots of bouncing breasts and butts`
-					: V.brothelAdsStacked === -1
-						? `Lots of trim breasts and shapely butts`
-						: `A variety of breast and butt sizes and shapes`} are on display, and ${V.brothelAdsImplanted === 100
-					? `most of these are augmented by implants.`
-					: V.brothelAdsImplanted === -1
-						? `they're all natural.`
-						: `some are augmented by implants.`} ${V.seePreg
-					? V.brothelAdsPreg
-						? `Most of the slaves have firm, rounded bellies.`
-						: V.brothelAdsPreg === -1
-							? `Most of the slaves have firm, flat bellies.`
-							: `Some of the slaves are pregnant.` : ``} ${V.brothelAdsModded === 1
-					? `Everything is heavily pierced and tattooed.`
-					: V.brothelAdsModded === -1
-						? `Everything is free of tattoos and piercings.`
-						: `Some of these assets are tattooed and pierced, and some aren't.`} The slaves in the ads are ${V.brothelAdsXX === 1
-					? `sucking dick and taking cock in their pussies and asses.`
-					: V.brothelAdsXX === -1
-						? `sucking dick and taking cock in their pussies and asses.`
-						: V.brothelAdsXX
-							? `sucking cock and being assfucked while their dicks flop around.`
-							: `sucking dick and taking anal, and the ones that have pussies are being fucked there, too.`} The ads are shown on media across ${V.arcologies[0].name}. ${V.brothelAdsXX === 1 && V.brothelAdsImplanted === 1 && V.brothelAdsStacked === 1
-					? `As a result, ${V.brothelName} is known as the place to go if you want to rent a${V.brothelAdsPreg ? ` pregnant` : ``} bimbo's pussy.`
-					: V.brothelAdsXX === 1 && V.brothelAdsOld === 1
-						? `As a result, ${V.brothelName} is known as the place to go if you want to rent a${V.brothelAdsPreg ? ` pregnant` : ``} MILF's tits.`
-						: V.brothelAdsXX === 1 && V.brothelAdsOld === -3
-							? `As a result, ${V.brothelName} is known as the place to go if you want to rent${V.brothelAdsPreg ? ` a pregnant` : ``}${V.brothelAdsStacked ? V.brothelAdsPreg !== 1 ? ` an` : `` : `oppai`} loli.`
-							: V.brothelAdsXX === 1 && V.brothelAdsPreg === 1
-								? `As a result, ${V.brothelName} is known as the place to go if you want to pound some pregnant pussy.`
-								: V.brothelAdsXX === -1 && V.brothelAdsStacked === 1
-									? `As a result, ${V.brothelName} is known as the place to go if you want to rent a shemale's asspussy.`
-									: V.brothelAdsXX === -1 && V.brothelAdsStacked === -1
-										? `As a result, ${V.brothelName} is known as the place to go if you want to rent a trap's tight ass.`
-										: ``}`
-				: ``} ${this.facility.hostedSlaves > 2
-				? `${capFirstChar(V.brothelName)} is bustling with activity. Customers are coming and going and slave girls are displaying themselves. When a slave catches a customer's eye, he leads her back into a little cubicle.`
-				: this.facility.hostedSlaves > 0 ?
-					`${capFirstChar(V.brothelName)} is working steadily. Customers are present and slave girls are on offer. When a slave catches a customer's eye, he leads her back into a little cubicle.`
-					: S.Madam
-						? `${S.Madam.slaveName} is alone in ${V.brothelName}, and has nothing to do but keep the place clean and plan future sales efforts.`
-						: `${capFirstChar(V.brothelName)} is empty and desolate.`}`,
+			desc,
 			removeSlave: "whore",
 		};
 	}
diff --git a/src/facilities/farmyard/animals/animals.js b/src/facilities/farmyard/animals/animals.js
index 026936c130d..d8dee352963 100644
--- a/src/facilities/farmyard/animals/animals.js
+++ b/src/facilities/farmyard/animals/animals.js
@@ -39,6 +39,10 @@ App.Entity.Animal = class {
 	purchase() {
 		V[this.type].push(this);
 
+		if (V.pit && !V.pit.animal) {
+			V.pit.animal = this;
+		}
+
 		return this;
 	}
 
diff --git a/src/facilities/farmyard/farmyard.js b/src/facilities/farmyard/farmyard.js
index d9011d4d686..8526081510b 100644
--- a/src/facilities/farmyard/farmyard.js
+++ b/src/facilities/farmyard/farmyard.js
@@ -151,7 +151,7 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 					},
 					{
 						value: 1,
-						text: `${this.facility.nameCaps} is currently using the basic water pump that it came with.`,
+						text: `${this.facility.nameCaps} is a more efficient model, slightly improving the amount of crops it produces.`,
 					},
 				],
 				object: V.farmyardUpgrades,
diff --git a/src/facilities/farmyard/shows/saFarmyardShows.js b/src/facilities/farmyard/shows/saFarmyardShows.js
index 6cec96a4c09..37de257a9c5 100644
--- a/src/facilities/farmyard/shows/saFarmyardShows.js
+++ b/src/facilities/farmyard/shows/saFarmyardShows.js
@@ -399,7 +399,7 @@ App.Facilities.Farmyard.putOnShows = function(slave) {
 
 	switch (slave.behavioralFlaw) {
 		case "arrogant":
-			r.push(`Because ${he} is so arrogant, ${he} tries ${his} hardest to avoid ${V.seeBestiality ? `fucking animals` : `putting on shows`}, <span class="cash dec">which affects ${his} profits</span> and <span class="reputation dec">your reputation.</span>`);
+			r.push(`${He} tries ${his} hardest to avoid ${V.seeBestiality ? `fucking animals` : `putting on shows`} because of ${his} arrogance, <span class="cash dec">which affects ${his} profits</span> and <span class="reputation dec">your reputation.</span>`);
 			break;
 
 		case "devout":
diff --git a/src/facilities/geneLab.js b/src/facilities/geneLab.js
index ff819f00469..57f22234473 100644
--- a/src/facilities/geneLab.js
+++ b/src/facilities/geneLab.js
@@ -2,7 +2,7 @@ App.UI.geneLab = function() {
 	const node = new DocumentFragment();
 	const PCSkillCheck = Math.min(V.upgradeMultiplierMedicine, V.HackingSkillMultiplier);
 
-	App.UI.DOM.appendNewElement("h2", node, `The Gene Lab`);
+	App.UI.DOM.appendNewElement("h1", node, `The Gene Lab`);
 
 	if (V.geneticMappingUpgrade === 1) {
 		App.UI.DOM.appendNewElement("div", node, `The gene lab is fully operational. It is capable of mapping a slave's genes, identifying genetic traits and abnormalities. It can be used to modify a slave's genome should you obtain the data necessary to adjust it.`, "note");
diff --git a/src/facilities/nursery/nurseryDatatypeCleanup.js b/src/facilities/nursery/nurseryDatatypeCleanup.js
index 18fd5780e5c..c4def25f184 100644
--- a/src/facilities/nursery/nurseryDatatypeCleanup.js
+++ b/src/facilities/nursery/nurseryDatatypeCleanup.js
@@ -220,19 +220,24 @@ App.Facilities.Nursery.ChildDatatypeCleanup = function(child) {
 	}
 
 	function childPiercingsDatatypeCleanup(child) {
-		child.earPiercing = Math.clamp(+child.earPiercing, 0, 2) || 0;
-		child.nosePiercing = Math.clamp(+child.nosePiercing, 0, 2) || 0;
-		child.eyebrowPiercing = Math.clamp(+child.eyebrowPiercing, 0, 2) || 0;
-		child.lipsPiercing = Math.clamp(+child.lipsPiercing, 0, 2) || 0;
-		child.tonguePiercing = Math.clamp(+child.tonguePiercing, 0, 2) || 0;
-		child.nipplesPiercing = Math.clamp(+child.nipplesPiercing, 0, 2) || 0;
-		child.areolaePiercing = Math.clamp(+child.areolaePiercing, 0, 2) || 0;
-		child.corsetPiercing = Math.clamp(+child.corsetPiercing, 0, 1) || 0;
-		child.navelPiercing = Math.clamp(+child.navelPiercing, 0, 2) || 0;
-		child.clitPiercing = Math.clamp(+child.clitPiercing, 0, 3) || 0;
-		child.vaginaPiercing = Math.clamp(+child.vaginaPiercing, 0, 2) || 0;
-		child.dickPiercing = Math.clamp(+child.dickPiercing, 0, 2) || 0;
-		child.anusPiercing = Math.clamp(+child.anusPiercing, 0, 2) || 0;
+		child.piercing = child.piercing || {}; //areolae and nipples
+		const oldPiercings = new Map([
+			["nipple", "nipples"],
+			["areola", "areolae"],
+		]);
+		for (const piercing of Object.keys(App.Data.Piercings)) {
+			child.piercing[piercing] = child.piercing[piercing] || new App.Entity.piercingState();
+			const oldPiercing = `${oldPiercings.get(piercing) || piercing}Piercing`; // the old variable names were sometimes plural and sometimes singular.  The new standard is to use singular when possible.
+			if (child.hasOwnProperty(oldPiercing)) {
+				if (child[oldPiercing] === 3) { // 3 used to indicate a smart piercing.  We now track this on a separate property as a bool.
+					child.piercing[piercing].weight = 2;
+					child.piercing[piercing].smart = true;
+				} else if (child[oldPiercing]) {
+					child.piercing[piercing].weight = child[oldPiercing];
+				}
+				delete child[oldPiercing];
+			}
+		}
 	}
 
 	function childTattooDatatypeCleanup(child) {
@@ -334,15 +339,6 @@ App.Facilities.Nursery.ChildDatatypeCleanup = function(child) {
 		if (typeof child.buttplugAttachment !== "string") {
 			child.buttplugAttachment = "none";
 		}
-		if (typeof child.headAccessory !== "string") {
-			child.headAccessory = "none";
-		}
-		if (typeof child.rearAccessory !== "string") {
-			child.rearAccessory = "none";
-		}
-		if (typeof child.backAccessory !== "string") {
-			child.backAccessory = "none";
-		}
 		if (typeof child.faceAccessory !== "string") {
 			child.faceAccessory = "none";
 		}
diff --git a/src/facilities/nursery/utils/nurseryUtils.js b/src/facilities/nursery/utils/nurseryUtils.js
index 249c1cf68b1..d105359f3c6 100644
--- a/src/facilities/nursery/utils/nurseryUtils.js
+++ b/src/facilities/nursery/utils/nurseryUtils.js
@@ -81,18 +81,16 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	};
 	child.analArea = 0;
 	child.anus = 0;
-	child.anusPiercing = 0;
+	child.piercing = new App.Entity.completePiercingState();
 	child.anusTat = 0;
 	child.aphrodisiacs = 0;
 	child.areolae = 0;
-	child.areolaePiercing = 0;
 	child.areolaeShape = "circle";
 	child.armAccessory = "none";
 	child.armsTat = 0;
 	child.attrKnown = 0;
 	child.attrXX = 0;
 	child.attrXY = 0;
-	child.backAccessory = "none";
 	child.backTat = 0;
 	child.bald = 0;
 	child.balls = 0;
@@ -127,10 +125,8 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.chem = 0;
 	child.choosesOwnClothes = 0;
 	child.clit = jsRandom(0, 2);
-	child.clitPiercing = 0;
 	child.clothes = "no clothing";
 	child.collar = "none";
-	child.corsetPiercing = 0;
 	child.counter = {
 		PCChildrenFathered: 0,
 		PCKnockedUp: 0,
@@ -163,7 +159,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.devotion = 40;	// TODO:
 	child.dick = 0;
 	child.dickAccessory = "none";
-	child.dickPiercing = 0;
 	child.dickTat = 0;
 	child.diet = "healthy";
 	child.dietCum = 0;
@@ -181,13 +176,11 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 		child.earT = "cat";
 		child.earTColor = child.hColor;
 	}
-	child.earPiercing = 0;
 	child.earwear = "none";
 	child.electrolarynx = 0;
 	child.energy = 0;
 	child.eyebrowFullness = "natural";
 	child.eyebrowHStyle = "natural";
-	child.eyebrowPiercing = 0;
 	child.eyewear = "none";
 	child.faceImplant = 0;
 	child.fertKnown = 1;
@@ -203,7 +196,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.hLength = jsRandom(30, 70);
 	child.hStyle = "long";
 	child.haircuts = 0;
-	child.headAccessory = "none";
 	child.health = {};
 	setHealth(child, jsRandom(80, 100), 0, 0, 0, 0);
 	child.hears = 0;
@@ -229,7 +221,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.legsTat = 0;
 	child.lips = jsRandom(10, 30);
 	child.lipsImplant = 0;
-	child.lipsPiercing = 0;
 	child.lipsTat = 0;
 	child.rules.living = "normal";
 	child.makeup = 0;
@@ -238,7 +229,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.mpreg = 0;
 	child.muscles = jsRandom(-10, 10);
 	child.nails = 0;
-	child.navelPiercing = 0;
 	child.need = 0;
 	if (child.boobs > 500 || child.weight > 95) {
 		child.nipples = jsEither(["cute", "puffy", "partially inverted", "inverted", "tiny"]);
@@ -246,8 +236,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 		child.nipples = jsEither(["cute", "cute", "cute", "tiny"]);
 	}
 	child.nipplesAccessory = "none";
-	child.nipplesPiercing = 0;
-	child.nosePiercing = 0;
 	child.oldDevotion = 0;
 	child.oldTrust = 0;
 	child.onDiet = 0;
@@ -296,7 +284,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.pubicHColor = "black";
 	child.pubicHStyle = "bushy";
 	child.readyOva = 0;
-	child.rearAccessory = "none";
 	child.relationship = 0;
 	child.rules.relationship = "restrictive";
 	child.relationshipTarget = 0;
@@ -348,13 +335,11 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	}
 	child.tastes = 0;
 	child.teeth = "baby";
-	child.tonguePiercing = 0;
 	child.training = 0;
 	child.trust = 0;
 	child.underArmHStyle = "natural";
 	child.vagina = child.genes === "XX" ? 0 : -1;
 	child.vaginaLube = 0;
-	child.vaginaPiercing = 0;
 	child.vaginaTat = 0;
 	child.vaginalAccessory = "none";
 	child.vaginalAttachment = "none";
diff --git a/src/facilities/penthouse/HGSelect.js b/src/facilities/penthouse/HGSelect.js
index 7057a563a8a..12af30da4b2 100644
--- a/src/facilities/penthouse/HGSelect.js
+++ b/src/facilities/penthouse/HGSelect.js
@@ -27,7 +27,7 @@ App.Facilities.HGSelect = function() {
 		[], "Main"
 		));
 
-		App.UI.DOM.appendNewElement("div", f, `Slave training`, "bold");
+		App.UI.DOM.appendNewElement("h2", f, `Slave training`);
 		App.UI.DOM.appendNewElement("div", f, `${HGName} will prioritize enabled items in the following order`, "note");
 
 		div.append(App.UI.DOM.makeCheckbox("headGirlTrainsHealth"), " Health");
@@ -84,7 +84,7 @@ App.Facilities.HGSelect = function() {
 		div.append(App.UI.DOM.makeCheckbox("headGirlTrainsSkills"), " Skills");
 		App.UI.DOM.appendNewElement("div", f, div, "indent");
 
-		App.UI.DOM.appendNewElement("div", f, "Training methods: ", "underline");
+		App.UI.DOM.appendNewElement("h2", f, "Training methods");
 
 		r = [];
 		if (V.HGSeverity === 1) {
@@ -131,7 +131,7 @@ App.Facilities.HGSelect = function() {
 		App.Events.addNode(f, r, "div", "indent");
 
 		r = [];
-		App.UI.DOM.appendNewElement("div", f, "Behavior towards you: ", "underline");
+		App.UI.DOM.appendNewElement("h2", f, "Behavior");
 		if (V.HGFormality === 1) {
 			r.push(`${HGName} will be <span class="bold">formal:</span> you will always be called ${getWrittenTitle(S.HeadGirl)}, just like any other slave.`);
 			r.push(App.UI.DOM.link("Allow private informality", () => {
diff --git a/src/facilities/penthouse/RecruiterSelect.js b/src/facilities/penthouse/RecruiterSelect.js
index a7fbe0e1ef2..ca4d22c6bab 100644
--- a/src/facilities/penthouse/RecruiterSelect.js
+++ b/src/facilities/penthouse/RecruiterSelect.js
@@ -28,7 +28,7 @@ App.Facilities.RecruiterSelect = function() {
 			f.append("they will be skilled but unhealthy. ");
 		} else if (V.recruiterTarget === "young migrants") {
 			f.append("they will be young and inexperienced but unhealthy. ");
-		} else if (V.recruiterTarget === "Will be mature") {
+		} else if (V.recruiterTarget === "recent divorcees") {
 			f.append("they will be mature. ");
 		} else if (V.recruiterTarget === "expectant mothers") {
 			f.append("they will be pregnant and likely unhealthy. ");
diff --git a/src/facilities/pit/pit.js b/src/facilities/pit/pit.js
index c81568672dd..7b934982aa4 100644
--- a/src/facilities/pit/pit.js
+++ b/src/facilities/pit/pit.js
@@ -150,7 +150,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 				{
 					property: "animal",
 					prereqs: [
-						() => V.pit.fighters === 2,
+						() => V.pit.fighters === 2 || V.pit.fighters === 3,
 						() => !!animal,
 					],
 					options: [
diff --git a/src/facilities/surgery/multiImplant.js b/src/facilities/surgery/multiImplant.js
index 854f54716fe..5752a878f00 100644
--- a/src/facilities/surgery/multiImplant.js
+++ b/src/facilities/surgery/multiImplant.js
@@ -402,9 +402,10 @@ App.UI.multipleOrganImplant = function() {
 		}
 		frag.append(applyFrag);
 
-		if (any) {
-			App.UI.DOM.appendNewElement("h1", frag, "Implant Organs");
-		}
+		// TODO: what is this for?
+		// if (any) {
+		// 	App.UI.DOM.appendNewElement("h1", frag, "Implant Organs");
+		// }
 		return frag;
 	}
 };
diff --git a/src/facilities/surgery/surgeryPassageExotic.js b/src/facilities/surgery/surgeryPassageExotic.js
index 0f72df77e73..3c13e31a7a8 100644
--- a/src/facilities/surgery/surgeryPassageExotic.js
+++ b/src/facilities/surgery/surgeryPassageExotic.js
@@ -305,7 +305,7 @@ App.UI.surgeryPassageExotic = function(slave, cheat = false) {
 		function makeLink(title, surgeryType, func, costMult = 1, note = "") {
 			const cost = Math.trunc(V.surgeryCost * costMult);
 			const tooltip = new DocumentFragment();
-			App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`);
+			App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`);
 			if (note) {
 				App.UI.DOM.appendNewElement("div", tooltip, note);
 			}
diff --git a/src/facilities/surgery/surgeryPassageExtreme.js b/src/facilities/surgery/surgeryPassageExtreme.js
index 68b9a27aa9a..3620ede5f9e 100644
--- a/src/facilities/surgery/surgeryPassageExtreme.js
+++ b/src/facilities/surgery/surgeryPassageExtreme.js
@@ -99,7 +99,7 @@ App.UI.surgeryPassageExtreme = function(slave, cheat = false) {
 		function makeLink(title, surgeryType, func, costMult = 1, note = "") {
 			const cost = Math.trunc(V.surgeryCost * costMult);
 			const tooltip = new DocumentFragment();
-			App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`);
+			App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`);
 			if (note) {
 				App.UI.DOM.appendNewElement("div", tooltip, note);
 			}
diff --git a/src/facilities/surgery/surgeryPassageFaceAndHair.js b/src/facilities/surgery/surgeryPassageFaceAndHair.js
index 3474835fc6c..e9a2ef2e3df 100644
--- a/src/facilities/surgery/surgeryPassageFaceAndHair.js
+++ b/src/facilities/surgery/surgeryPassageFaceAndHair.js
@@ -1009,7 +1009,7 @@ App.UI.surgeryPassageHairAndFace = function(slave, refreshParent, cheat = false)
 			},
 			[],
 			"",
-			cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`
+			cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`
 		);
 	}
 
diff --git a/src/facilities/surgery/surgeryPassageLower.js b/src/facilities/surgery/surgeryPassageLower.js
index 65202b31eae..f1df10eb499 100644
--- a/src/facilities/surgery/surgeryPassageLower.js
+++ b/src/facilities/surgery/surgeryPassageLower.js
@@ -941,7 +941,7 @@ App.UI.surgeryPassageLower = function(slave, refreshParent, cheat = false) {
 	function makeLink(title, surgeryType, func, costMult = 1, note = "") {
 		const cost = Math.trunc(V.surgeryCost * costMult);
 		const tooltip = new DocumentFragment();
-		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`);
+		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`);
 		if (note) {
 			App.UI.DOM.appendNewElement("div", tooltip, note);
 		}
diff --git a/src/facilities/surgery/surgeryPassageStructural.js b/src/facilities/surgery/surgeryPassageStructural.js
index f03d789e881..506bc0e154f 100644
--- a/src/facilities/surgery/surgeryPassageStructural.js
+++ b/src/facilities/surgery/surgeryPassageStructural.js
@@ -22,8 +22,10 @@ App.UI.surgeryPassageStructural = function(slave, refreshParent, cheat = false)
 		if (hasAllNaturalLimbs(slave)) {
 			frag.append(limbLength(), tendons());
 		}
-		App.UI.DOM.appendNewElement("h3", frag, `Amputation`);
-		frag.append(amputate());
+		if (slave.indenture < 0) {
+			App.UI.DOM.appendNewElement("h3", frag, `Amputation`);
+			frag.append(amputate());
+		}
 		App.UI.DOM.appendNewElement("h3", frag, `Prosthetics`);
 		frag.append(prostheticInterface(), tail(), back(), App.Medicine.OrganFarm.fullMenu(slave));
 
@@ -514,7 +516,7 @@ App.UI.surgeryPassageStructural = function(slave, refreshParent, cheat = false)
 	function makeLink(title, surgeryType, func, costMult = 1, note = "") {
 		const cost = Math.trunc(V.surgeryCost * costMult);
 		const tooltip = new DocumentFragment();
-		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`);
+		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`);
 		if (note) {
 			App.UI.DOM.appendNewElement("div", tooltip, note);
 		}
diff --git a/src/facilities/surgery/surgeryPassageUpper.js b/src/facilities/surgery/surgeryPassageUpper.js
index b549ae55f5d..5b3ac6180e7 100644
--- a/src/facilities/surgery/surgeryPassageUpper.js
+++ b/src/facilities/surgery/surgeryPassageUpper.js
@@ -263,11 +263,11 @@ App.UI.surgeryPassageUpper = function(slave, refreshParent, cheat = false) {
 								"nippleCunts",
 								() => {
 									slave.nipples = "fuckable";
-									slave.nipplesPiercing = 0;
+									slave.piercing.nipple.weight = 0;
 									surgeryDamage(slave, 20);
 								},
 								1,
-								(slave.nipplesPiercing > 0) ? `Will remove piercings` : ``
+								(slave.piercing.nipple.weight > 0) ? `Will remove piercings` : ``
 							));
 						}
 					}
@@ -803,7 +803,7 @@ App.UI.surgeryPassageUpper = function(slave, refreshParent, cheat = false) {
 	function makeLink(title, surgeryType, func, costMult = 1, note = "") {
 		const cost = Math.trunc(V.surgeryCost * costMult);
 		const tooltip = new DocumentFragment();
-		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}.` : `Free.`);
+		App.UI.DOM.appendNewElement("div", tooltip, cost !== 0 ? `Costs ${cashFormat(cost)}` : `Free`);
 		if (note) {
 			App.UI.DOM.appendNewElement("div", tooltip, note);
 		}
diff --git a/src/facilities/toyShop/toyShop.js b/src/facilities/toyShop/toyShop.js
index eaae76f4ac5..4e910d977a1 100644
--- a/src/facilities/toyShop/toyShop.js
+++ b/src/facilities/toyShop/toyShop.js
@@ -44,8 +44,8 @@ App.UI.toyShop = function() {
 
 	function intro() {
 		const el = new DocumentFragment();
-		App.UI.DOM.appendNewElement("h1", el, "Toy Shop");
-		App.UI.DOM.appendNewElement("div", el, `The room is filled with the smell of rubber, latex, and various synthetic materials and solvents. A series of screens allows you to design toys of various shapes and sizes, and then produce them at scale. A bin of defects sits in the corner, glistening a bit under a layer of lubrication.`, "scene-intro");
+		// App.UI.DOM.appendNewElement("h1", el, "The Toy Shop");
+		App.UI.DOM.appendNewElement("div", el, `The toy shop is filled with the smell of rubber, latex, and various synthetic materials and solvents. A series of screens allows you to design toys of various shapes and sizes, and then produce them at scale. A bin of defects sits in the corner, glistening a bit under a layer of lubrication.`, "scene-intro");
 		return el;
 	}
 
diff --git a/src/gui/options/options.js b/src/gui/options/options.js
index 017e3d3369e..d104de2a6fe 100644
--- a/src/gui/options/options.js
+++ b/src/gui/options/options.js
@@ -1,5 +1,6 @@
 App.UI.optionsPassage = function() {
 	const el = new DocumentFragment();
+	App.UI.DOM.appendNewElement("h1", el, `Game Options`);
 	V.passageSwitchHandler = App.EventHandlers.optionsChanged;
 	el.append(intro());
 
diff --git a/src/interaction/policies/policiesPassage.js b/src/interaction/policies/policiesPassage.js
index c8d055a12e0..bcb03f1d5b0 100644
--- a/src/interaction/policies/policiesPassage.js
+++ b/src/interaction/policies/policiesPassage.js
@@ -1,6 +1,8 @@
 App.UI.policies = function() {
 	const node = new DocumentFragment();
 
+	App.UI.DOM.appendNewElement("h1", node, `Policies`);
+
 	const r = [];
 	r.push(`Passing any law will cost ${cashFormat(5000)} and`);
 	if (V.rep >= 1000) {
diff --git a/src/interaction/prostheticLabPassage.js b/src/interaction/prostheticLabPassage.js
index 109fe9d9575..6c2858a02d3 100644
--- a/src/interaction/prostheticLabPassage.js
+++ b/src/interaction/prostheticLabPassage.js
@@ -6,7 +6,7 @@ App.UI.prostheticLab = function() {
 	const staff = V.researchLab.hired + V.researchLab.menials;
 	let linkArray = [];
 
-	App.UI.DOM.appendNewElement("h1", node, "Prosthetic Lab");
+	App.UI.DOM.appendNewElement("h1", node, "The Prosthetics Lab");
 
 	if (V.adjustProsthetics.length > V.adjustProstheticsCompleted) {
 		App.UI.DOM.appendNewElement("h2", node, "External contract workers");
diff --git a/src/interaction/sellSlave.js b/src/interaction/sellSlave.js
index d466d5c9bca..0c292c78e5e 100644
--- a/src/interaction/sellSlave.js
+++ b/src/interaction/sellSlave.js
@@ -2881,7 +2881,7 @@ App.Interact.sellSlave = function(slave) {
 			desc = ` from a citizen who likes traps.`;
 		} else if ((slave.dick > 0) && (slave.balls > 0) && (slave.boobs > 600) && (random(1, 100) > 80)) {
 			desc = ` from a citizen who likes lusty shemales.`;
-		} else if ((slave.anusPiercing > 1) && (slave.nipplesPiercing > 1) && (random(1, 100) > 80)) {
+		} else if ((slave.piercing.anus.weight > 1) && (slave.piercing.nipple.weight > 1) && (random(1, 100) > 80)) {
 			desc = ` from a citizen who is clearly fascinated by ${his} lewd piercings.`;
 		} else if ((slave.anusTat > 1) && (slave.buttTat > 1) && (random(1, 100) > 80)) {
 			desc = ` from a citizen who is clearly aroused by ${his} slutty tattoos.`;
diff --git a/src/interaction/siFinancial.js b/src/interaction/siFinancial.js
index c6d2f9cdadb..55a09bdd875 100644
--- a/src/interaction/siFinancial.js
+++ b/src/interaction/siFinancial.js
@@ -168,7 +168,7 @@ App.UI.SlaveInteract.financial = function(slave, refresh) {
 					r.push(`${He} lacks the fame in porn needed to discern what ${his} feed is getting tagged as.`);
 				} else {
 					if (slave.porn.prestige > 0) {
-						r.push(`${He} is known for ${slave.porn.fameType}${(slave.porn.prestige > 1) ? ` and viewers have grown to expect it from ${him}` : ``}.`);
+						r.push(`${He} is known for ${slave.porn.fameType === "generic" ? `standard, vanilla` : slave.porn.fameType} porn${(slave.porn.prestige > 1) ? ` and viewers have grown to expect it from ${him}` : ``}.`);
 					}
 					if (slave.porn.focus === "none") {
 						r.push(`You are allowing ${his} viewers to guide the direction of ${his} content.`);
diff --git a/src/interaction/siRules.js b/src/interaction/siRules.js
index 19623750589..90dd8a73dd7 100644
--- a/src/interaction/siRules.js
+++ b/src/interaction/siRules.js
@@ -404,7 +404,7 @@ App.UI.SlaveInteract.rules = function(slave, refresh) {
 		const smartBulletVibe = dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator";
 		const smartDildoVibe = slave.vaginalAttachment === "smart vibrator";
 
-		if (slave.clitPiercing === 3 || smartBulletVibe || smartDildoVibe) {
+		if (slave.piercing.genitals.smart || smartBulletVibe || smartDildoVibe) {
 			const level = new Map();
 			const bodyPart = new Map();
 			const BDSM = new Map();
@@ -435,7 +435,7 @@ App.UI.SlaveInteract.rules = function(slave, refresh) {
 			gender.set(`Anti-men`, `anti-men`);
 			gender.set(`Anti-women`, `anti-women`);
 			let label = null;
-			if (slave.clitPiercing === 3) {
+			if (slave.piercing.genitals.smart) {
 				label = `Smart ${slave.dick < 1 ? "clit" : "frenulum"} piercing `;
 				label += (smartBulletVibe || smartDildoVibe) ? `and smart vibrator setting: ` : `setting: `;
 			} else if (smartBulletVibe) {
diff --git a/src/interaction/universalRules.js b/src/interaction/universalRules.js
index aaa5716cfad..718b8a99954 100644
--- a/src/interaction/universalRules.js
+++ b/src/interaction/universalRules.js
@@ -8,7 +8,10 @@ App.UI.universalRules = function() {
 	if (V.seePreg) {
 		tabBar.addTab("Babies", "babies", babies());
 	}
-	node.append(tabBar.render());
+	node.append(
+		// App.UI.DOM.makeElement("h1", `Universal Rules`),
+		tabBar.render()
+	);
 	return node;
 
 	function permissions() {
diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js
index f0e7f63c8b1..48e02ee256c 100644
--- a/src/js/DefaultRules.js
+++ b/src/js/DefaultRules.js
@@ -2492,13 +2492,13 @@ globalThis.DefaultRules = (function() {
 	 * @param {FC.RA.RuleSetters} rule
 	 */
 	function ProcessPiercings(slave, rule) {
-		if (rule.nipplesPiercing !== undefined && (rule.nipplesPiercing !== null)) {
-			if (slave.nipplesPiercing !== rule.nipplesPiercing) {
-				if (rule.nipplesPiercing === 0) {
-					slave.nipplesPiercing = 0;
+		if (rule.piercing.nipple.weight !== undefined && (rule.piercing.nipple.weight !== null)) {
+			if (slave.piercing.nipple.weight !== rule.piercing.nipple.weight) {
+				if (rule.piercing.nipple.weight === 0) {
+					slave.piercing.nipple.weight = 0;
 					r += `<br>${slave.slaveName}'s nipple piercings have been removed.`;
 				} else if (slave.nipples !== "fuckable") {
-					slave.nipplesPiercing = rule.nipplesPiercing;
+					slave.piercing.nipple.weight = rule.piercing.nipple.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s nipples have been pierced.`;
 				} else {
@@ -2507,54 +2507,49 @@ globalThis.DefaultRules = (function() {
 			}
 		}
 
-		if (rule.areolaePiercing !== undefined && (rule.areolaePiercing !== null)) {
-			if (slave.areolaePiercing !== rule.areolaePiercing) {
-				if (rule.areolaePiercing === 0) {
-					slave.areolaePiercing = 0;
+		if (rule.piercing.areola.weight !== undefined && (rule.piercing.areola.weight !== null)) {
+			if (slave.piercing.areola.weight !== rule.piercing.areola.weight) {
+				if (rule.piercing.areola.weight === 0) {
+					slave.piercing.areola.weight = 0;
 					r += `<br>${slave.slaveName}'s areolae piercings have been removed.`;
 				} else {
-					slave.areolaePiercing = rule.areolaePiercing;
+					slave.piercing.areola.weight = rule.piercing.areola.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s areolae have been given stud piercings.`;
 				}
 			}
 		}
 
-		if (rule.clitPiercing !== undefined && (rule.clitPiercing !== null)) {
-			if (slave.clitPiercing !== rule.clitPiercing) {
-				if (rule.clitPiercing === 0) {
-					slave.clitPiercing = 0;
+		if (rule.piercing.genitals.weight !== undefined && (rule.piercing.genitals.weight !== null)) {
+			if (slave.piercing.genitals.weight !== rule.piercing.genitals.weight) {
+				if (rule.piercing.genitals.weight === 0) {
+					slave.piercing.genitals.weight = 0;
+					slave.piercing.genitals.smart = false;
 					if (slave.dick > 0) {
 						r += `<br>${slave.slaveName}'s frenulum piercing has been removed.`;
 					} else {
 						r += `<br>${slave.slaveName}'s clit piercing has been removed.`;
 					}
 				} else if ((slave.vagina !== -1) || (slave.dick !== 0)) {
-					slave.clitPiercing = rule.clitPiercing;
+					slave.piercing.genitals.weight = rule.piercing.genitals.weight;
+					cashX(forceNeg(V.SPcost), "slaveMod", slave);
 					if (slave.dick > 0) {
 						r += `<br>${slave.slaveName}'s frenulum has been pierced.`;
 					} else {
 						r += `<br>${slave.slaveName}'s clit has been pierced.`;
 					}
-
-					if (rule.clitPiercing === 3) {
-						cashX(forceNeg(V.SPcost), "slaveMod", slave);
-						slave.clitSetting = "all";
-					} else {
-						cashX(forceNeg(V.modCost), "slaveMod", slave);
-					}
 				}
 			}
 		}
 
 		if (slave.vagina !== -1) {
-			if (rule.vaginaPiercing !== undefined && (rule.vaginaPiercing !== null)) {
-				if (slave.vaginaPiercing !== rule.vaginaPiercing) {
-					if (rule.vaginaPiercing === 0) {
-						slave.vaginaPiercing = 0;
+			if (rule.piercing.vagina.weight !== undefined && (rule.piercing.vagina.weight !== null)) {
+				if (slave.piercing.vagina.weight !== rule.piercing.vagina.weight) {
+					if (rule.piercing.vagina.weight === 0) {
+						slave.piercing.vagina.weight = 0;
 						r += `<br>${slave.slaveName}'s labia piercings have been removed.`;
 					} else {
-						slave.vaginaPiercing = rule.vaginaPiercing;
+						slave.piercing.vagina.weight = rule.piercing.vagina.weight;
 						cashX(forceNeg(V.modCost), "slaveMod", slave);
 						r += `<br>${slave.slaveName}'s pussylips have been pierced.`;
 					}
@@ -2563,13 +2558,13 @@ globalThis.DefaultRules = (function() {
 		}
 
 		if (slave.dick > 0) {
-			if (rule.dickPiercing !== undefined && (rule.dickPiercing !== null)) {
-				if (slave.dickPiercing !== rule.dickPiercing) {
-					if (rule.dickPiercing === 0) {
-						slave.dickPiercing = 0;
+			if (rule.piercing.dick.weight !== undefined && (rule.piercing.dick.weight !== null)) {
+				if (slave.piercing.dick.weight !== rule.piercing.dick.weight) {
+					if (rule.piercing.dick.weight === 0) {
+						slave.piercing.dick.weight = 0;
 						r += `<br>${slave.slaveName}'s shaft piercings have been removed.`;
 					} else {
-						slave.dickPiercing = rule.dickPiercing;
+						slave.piercing.dick.weight = rule.piercing.dick.weight;
 						cashX(forceNeg(V.modCost), "slaveMod", slave);
 						r += `<br>${slave.slaveName}'s shaft has been pierced.`;
 					}
@@ -2577,109 +2572,139 @@ globalThis.DefaultRules = (function() {
 			}
 		}
 
-		if (rule.anusPiercing !== undefined && (rule.anusPiercing !== null)) {
-			if (slave.anusPiercing !== rule.anusPiercing) {
-				if (rule.anusPiercing === 0) {
-					slave.anusPiercing = 0;
+		if (rule.piercing.genitals.smart !== undefined && rule.piercing.genitals.smart !== null) {
+			if (slave.piercing.genitals.smart !== rule.piercing.genitals.smart) {
+				if (rule.piercing.genitals.smart === false) {
+					slave.piercing.genitals.smart = false;
+					cashX(forceNeg(V.modCost), "slaveMod", slave);
+					r += `<br>${slave.slaveName}'s ${slave.dick > 0 ? "frenulum" : "clit"} piercing's smart vibe capability has been removed.`;
+				} else if (slave.piercing.genitals.weight) {
+					slave.piercing.genitals.smart = true;
+					cashX(forceNeg(V.SPcost), "slaveMod", slave);
+					slave.clitSetting = "all";
+					r += `<br>${slave.slaveName}'s ${slave.dick > 0 ? "frenulum" : "clit"} piercing has been upgraded with smart vibe functionality.`;
+				}
+			}
+		}
+
+		if (rule.piercing.anus.weight !== undefined && (rule.piercing.anus.weight !== null)) {
+			if (slave.piercing.anus.weight !== rule.piercing.anus.weight) {
+				if (rule.piercing.anus.weight === 0) {
+					slave.piercing.anus.weight = 0;
 					r += `<br>${slave.slaveName}'s asshole piercings have been removed.`;
 				} else {
-					slave.anusPiercing = rule.anusPiercing;
+					slave.piercing.anus.weight = rule.piercing.anus.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s asshole has been pierced.`;
 				}
 			}
 		}
 
-		if (rule.lipsPiercing !== undefined && (rule.lipsPiercing !== null)) {
-			if (slave.lipsPiercing !== rule.lipsPiercing) {
-				if (rule.lipsPiercing === 0) {
-					slave.lipsPiercing = 0;
+		if (rule.piercing.lips.weight !== undefined && (rule.piercing.lips.weight !== null)) {
+			if (slave.piercing.lips.weight !== rule.piercing.lips.weight) {
+				if (rule.piercing.lips.weight === 0) {
+					slave.piercing.lips.weight = 0;
 					r += `<br>${slave.slaveName}'s lip piercings have been removed.`;
 				} else {
-					slave.lipsPiercing = rule.lipsPiercing;
+					slave.piercing.lips.weight = rule.piercing.lips.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s lips have been pierced.`;
 				}
 			}
 		}
 
-		if (rule.tonguePiercing !== undefined && (rule.tonguePiercing !== null)) {
-			if (slave.tonguePiercing !== rule.tonguePiercing) {
-				if (rule.tonguePiercing === 0) {
-					slave.tonguePiercing = 0;
+		if (rule.piercing.tongue.weight !== undefined && (rule.piercing.tongue.weight !== null)) {
+			if (slave.piercing.tongue.weight !== rule.piercing.tongue.weight) {
+				if (rule.piercing.tongue.weight === 0) {
+					slave.piercing.tongue.weight = 0;
 					r += `<br>${slave.slaveName}'s tongue piercings have been removed.`;
 				} else {
-					slave.tonguePiercing = rule.tonguePiercing;
+					slave.piercing.tongue.weight = rule.piercing.tongue.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s tongue has been pierced.`;
 				}
 			}
 		}
 
-		if (rule.earPiercing !== undefined && (rule.earPiercing !== null)) {
-			if (slave.earPiercing !== rule.earPiercing) {
-				if (rule.earPiercing === 0) {
-					slave.earPiercing = 0;
+		if (rule.piercing.ear.weight !== undefined && (rule.piercing.ear.weight !== null)) {
+			if (slave.piercing.ear.weight !== rule.piercing.ear.weight) {
+				if (rule.piercing.ear.weight === 0) {
+					slave.piercing.ear.weight = 0;
 					r += `<br>${slave.slaveName}'s ear piercings have been removed.`;
 				} else {
-					slave.earPiercing = rule.earPiercing;
+					slave.piercing.ear.weight = rule.piercing.ear.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s ears have been pierced.`;
 				}
 			}
 		}
 
-		if (rule.nosePiercing !== undefined && (rule.nosePiercing !== null)) {
-			if (slave.nosePiercing !== rule.nosePiercing) {
-				if (rule.nosePiercing === 0) {
-					slave.nosePiercing = 0;
+		if (rule.piercing.nose.weight !== undefined && (rule.piercing.nose.weight !== null)) {
+			if (slave.piercing.nose.weight !== rule.piercing.nose.weight) {
+				if (rule.piercing.nose.weight === 0) {
+					slave.piercing.nose.weight = 0;
 					r += `<br>${slave.slaveName}'s nose piercing has been removed.`;
 				} else {
-					slave.nosePiercing = rule.nosePiercing;
+					slave.piercing.nose.weight = rule.piercing.nose.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s nose has been pierced.`;
 				}
 			}
 		}
 
-		if (rule.eyebrowPiercing !== undefined && (rule.eyebrowPiercing !== null)) {
-			if (slave.eyebrowPiercing !== rule.eyebrowPiercing) {
-				if (rule.eyebrowPiercing === 0) {
-					slave.eyebrowPiercing = 0;
+		if (rule.piercing.eyebrow.weight !== undefined && (rule.piercing.eyebrow.weight !== null)) {
+			if (slave.piercing.eyebrow.weight !== rule.piercing.eyebrow.weight) {
+				if (rule.piercing.eyebrow.weight === 0) {
+					slave.piercing.eyebrow.weight = 0;
 					r += `<br>${slave.slaveName}'s eyebrow piercings have been removed.`;
 				} else {
-					slave.eyebrowPiercing = rule.eyebrowPiercing;
+					slave.piercing.eyebrow.weight = rule.piercing.eyebrow.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s eyebrows have been pierced.`;
 				}
 			}
 		}
 
-		if (rule.navelPiercing !== undefined && (rule.navelPiercing !== null)) {
-			if (slave.navelPiercing !== rule.navelPiercing) {
-				if (rule.navelPiercing === 0) {
-					slave.navelPiercing = 0;
+		if (rule.piercing.navel.weight !== undefined && (rule.piercing.navel.weight !== null)) {
+			if (slave.piercing.navel.weight !== rule.piercing.navel.weight) {
+				if (rule.piercing.navel.weight === 0) {
+					slave.piercing.navel.weight = 0;
 					r += `<br>${slave.slaveName}'s navel piercing have been removed.`;
 				} else {
-					slave.navelPiercing = rule.navelPiercing;
+					slave.piercing.navel.weight = rule.piercing.navel.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName}'s navel has been pierced.`;
 				}
 			}
 		}
 
-		if (rule.corsetPiercing !== undefined && (rule.corsetPiercing !== null)) {
-			if (slave.corsetPiercing !== rule.corsetPiercing) {
-				if (rule.corsetPiercing === 0) {
-					slave.corsetPiercing = 0;
+		if (rule.piercing.corset.weight !== undefined && (rule.piercing.corset.weight !== null)) {
+			if (slave.piercing.corset.weight !== rule.piercing.corset.weight) {
+				if (rule.piercing.corset.weight === 0) {
+					slave.piercing.corset.weight = 0;
 					r += `<br>${slave.slaveName}'s corset piercings have been removed.`;
 				} else {
-					slave.corsetPiercing = rule.corsetPiercing;
+					slave.piercing.corset.weight = rule.piercing.corset.weight;
 					cashX(forceNeg(V.modCost), "slaveMod", slave);
 					r += `<br>${slave.slaveName} has been given a set of corset piercings.`;
 				}
 			}
 		}
+
+		for (const p in slave.piercing) {
+			if (slave.piercing[p].weight) {
+				if (rule.piercing[p].desc !== undefined && (rule.piercing[p].desc !== null)) {
+					if (slave.piercing[p].desc !== rule.piercing[p].desc) {
+						if (rule.piercing[p].desc === "") {
+							r += `<br>${slave.slaveName}'s ${p} piercings will use the default design.`;
+						} else {
+							r += `<br>${slave.slaveName}'s ${p} piercings have been updated to a different design.`;
+						}
+						slave.piercing[p].desc = rule.piercing[p].desc;
+					}
+				}
+			}
+		}
 	}
 
 	/**
@@ -2688,8 +2713,8 @@ globalThis.DefaultRules = (function() {
 	 */
 	function ProcessSmartPiercings(slave, rule) {
 		const hasSmartVibe = dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator";
-		const smartThing = (slave.clitPiercing === 3) ? "smart piercing" : "smart vibrator";
-		if (slave.clitPiercing === 3 || hasSmartVibe) {
+		const smartThing = (slave.piercing.genitals.smart) ? "smart piercing" : "smart vibrator";
+		if (slave.piercing.genitals.smart || hasSmartVibe) {
 			if (rule.clitSetting !== undefined && rule.clitSetting !== null) {
 				let fetish = rule.clitSetting;
 				if (fetish === "random") {
diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js
index de83cb13652..c104ba3f5a9 100644
--- a/src/js/SlaveState.js
+++ b/src/js/SlaveState.js
@@ -409,6 +409,84 @@ App.Entity.scarState = class {
 	}
 };
 
+App.Entity.piercingState = class {
+	constructor() {
+		/** @type {FC.PiercingType} */
+		this.weight = 0;
+		/**
+		 * String describing piercing.  Leave empty to use default description.
+		 * @type {string}
+		 */
+		this.desc = "";
+	}
+};
+
+App.Entity.genitalPiercingState = class extends App.Entity.piercingState {
+	constructor() {
+		super();
+		/** @type {boolean} */
+		this.smart = false;
+	}
+};
+
+
+App.Entity.piercingStateRA = class {
+	constructor() {
+		/** @type {FC.PiercingType} */
+		this.weight = null;
+		/**
+		 * String describing piercing.  Leave empty to use default description.
+		 * @type {string}
+		 */
+		this.desc = null;
+	}
+};
+
+App.Entity.genitalPiercingStateRA = class extends App.Entity.piercingStateRA {
+	constructor() {
+		super();
+		/** @type {boolean} */
+		this.smart = null;
+	}
+};
+
+
+App.Entity.completePiercingState = class {
+	constructor() {
+		this.ear = new App.Entity.piercingState();
+		this.nose = new App.Entity.piercingState();
+		this.eyebrow = new App.Entity.piercingState();
+		this.lips = new App.Entity.piercingState();
+		this.tongue = new App.Entity.piercingState();
+		this.nipple = new App.Entity.piercingState();
+		this.areola = new App.Entity.piercingState();
+		this.navel = new App.Entity.piercingState();
+		this.corset = new App.Entity.piercingState();
+		this.genitals = new App.Entity.genitalPiercingState();
+		this.vagina = new App.Entity.piercingState();
+		this.dick = new App.Entity.piercingState();
+		this.anus = new App.Entity.piercingState();
+	}
+};
+
+App.Entity.completePiercingStateRA = class {
+	constructor() {
+		this.ear = new App.Entity.piercingStateRA();
+		this.nose = new App.Entity.piercingStateRA();
+		this.eyebrow = new App.Entity.piercingStateRA();
+		this.lips = new App.Entity.piercingStateRA();
+		this.tongue = new App.Entity.piercingStateRA();
+		this.nipple = new App.Entity.piercingStateRA();
+		this.areola = new App.Entity.piercingStateRA();
+		this.navel = new App.Entity.piercingStateRA();
+		this.corset = new App.Entity.piercingStateRA();
+		this.genitals = new App.Entity.genitalPiercingStateRA();
+		this.vagina = new App.Entity.piercingStateRA();
+		this.dick = new App.Entity.piercingStateRA();
+		this.anus = new App.Entity.piercingStateRA();
+	}
+};
+
 /**
  * To ensure that all new limbs contain expected attributes
  */
@@ -855,9 +933,6 @@ App.Entity.SlaveState = class SlaveState {
 		 * * -96-: absurd
 		 */
 		this.waist = 0;
-		/** series of rings up the back that can be tied together. 0: no, 1: yes
-		 * @type {FC.Bool} */
-		this.corsetPiercing = 0;
 		/**
 		 * What level of prosthetic interface she has installed
 		 * * 0: no interface
@@ -1005,21 +1080,12 @@ App.Entity.SlaveState = class SlaveState {
 		 * @type {FC.NippleShape}
 		 */
 		this.nipples = "cute";
-		/**
-		 * nipple are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavily */
-		this.nipplesPiercing = 0;
 		/** what accessory, if any, or on her nipples */
 		this.nipplesAccessory = "none";
 		/** slave areolae
 		 *
 		 * 0: normal; 1: large; 2: unusually wide; 3: huge, 4: massive */
 		this.areolae = 0;
-		/** edge of areolae are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavy */
-		this.areolaePiercing = 0;
 		/** slave areolae shape ("heart"; "star"; "circle") */
 		this.areolaeShape = "circle";
 		/**
@@ -1176,11 +1242,6 @@ App.Entity.SlaveState = class SlaveState {
 		 * @see lips
 		 */
 		this.lipsImplant = 0;
-		/**
-		 * lips pierced
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.lipsPiercing = 0;
 		/**
 		 * lip tattoo
 		 *
@@ -1215,11 +1276,6 @@ App.Entity.SlaveState = class SlaveState {
 		 * @type {FC.TeethType}
 		 */
 		this.teeth = "normal";
-		/**
-		 * has tongue piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.tonguePiercing = 0;
 		/**
 		 * vagina type
 		 * * -1: no vagina
@@ -1235,10 +1291,6 @@ App.Entity.SlaveState = class SlaveState {
 		 *
 		 * 0: dry; 1: wet; 2: soaking wet */
 		this.vaginaLube = 0;
-		/** has vagina piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.vaginaPiercing = 0;
 		/**
 		 * vagina tattoo
 		 *
@@ -1399,15 +1451,6 @@ App.Entity.SlaveState = class SlaveState {
 		 * * 5: like a massive penis
 		 */
 		this.clit = 0;
-		/**
-		 * is clit pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * * 3: smart
-		 * @type {FC.ClitoralPiercingType}
-		 */
-		this.clitPiercing = 0;
 		/**
 		 * smart piercing setting
 		 * * "off"
@@ -1458,14 +1501,6 @@ App.Entity.SlaveState = class SlaveState {
 		this.dick = 0;
 		/** used to calculate size of area around anus. */
 		this.analArea = 1;
-		/**
-		 * is dick pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * @type {FC.PiercingType}
-		 */
-		this.dickPiercing = 0;
 		/**
 		 * dick tattoo
 		 *
@@ -1521,10 +1556,6 @@ App.Entity.SlaveState = class SlaveState {
 		 * @type {FC.Bool}
 		 * 0: no; 1: yes */
 		this.ovaries = 0;
-		/** has anus piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.anusPiercing = 0;
 		/**
 		 * anus tattoo
 		 *
@@ -1572,25 +1603,9 @@ App.Entity.SlaveState = class SlaveState {
 		this.nails = 0;
 		/**
 		 * brand
-		 *
 		 * @type {Object.<string, string>} */
 		this.brand = {};
-		/** has pierced ears
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.earPiercing = 0;
-		/** has pierced nose
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.nosePiercing = 0;
-		/** has eyebrow piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.eyebrowPiercing = 0;
-		/** has navel piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.navelPiercing = 0;
+		this.piercing = new App.Entity.completePiercingState();
 		/**
 		 * shoulder tattoo
 		 *
@@ -2450,7 +2465,7 @@ App.Entity.SlaveState = class SlaveState {
 		 * Sub-object:
 		 * the body part in question, such as back or left hand
 		 * the key of that part is the type of scar they can have and the value is how serious it is, from 0 up
-		 * @type {Object.<string, Object>} */
+		 * @type {Object.<string, Partial<App.Entity.scarState>>} */
 		this.scar = {};
 		/**
 		 * In a eugenics society, this slave is a designated breeder.
diff --git a/src/js/economyJS.js b/src/js/economyJS.js
index c11f3b051b7..6cd3ecfc7b5 100644
--- a/src/js/economyJS.js
+++ b/src/js/economyJS.js
@@ -233,6 +233,79 @@ globalThis.CategoryAssociatedGroup = Object.freeze({
 	]
 });
 
+globalThis.CategoryAssociatedGroupRep = Object.freeze({
+	PENTHOUSE: [
+		'fucktoy',
+		'publicServant',
+		'gloryhole',
+		'concubine',
+		'headGirl',
+		'bodyguard',
+		'recruiter'
+	],
+	ARCADE: [
+		'arcade',
+		'gloryholeArcade',
+	],
+	BROTHEL: [
+		'brothel'
+	],
+	CLUB: [
+		'club',
+		'publicServantClub',
+		'clubAds'
+	],
+	PIT: [
+		'pit'
+	],
+	SERVANTSQUARTERS: [
+		'servantsQuarters'
+	],
+	SPA: [
+		'spa'
+	],
+	FARMYARD: [
+		'shows'
+	],
+	SLAVES: [
+		'slavesViewOfPC',
+		'prestigiousSlave',
+		'porn',
+		'slaveTransfer',
+		'babyTransfer',
+		'birth',
+		'retirement',
+		'vignette',
+		'fuckdolls'
+	],
+	POLICIES: [
+		'capEx',
+		'subsidiesAndBarriers',
+		'futureSocieties',
+		'food'
+	],
+	EDICTS: [
+		'edicts'
+	],
+	PERSONALFINANCE: [
+		'personalBusiness',
+		'PCappearance',
+		'PCactions',
+		'PCRelationships',
+		'SlaveRelationships',
+		'event'
+	],
+	SECURITY: [
+		'securityExpansion',
+		'specialForces',
+		'war',
+		'peacekeepers'
+	],
+	WASTE: [
+		'multiplier'
+	]
+})
+
 globalThis.calculateCosts = (function() {
 	return {
 		predict: predictCost,
diff --git a/src/js/findSlave.js b/src/js/findSlave.js
index 4780514d6e0..4c8c602e040 100644
--- a/src/js/findSlave.js
+++ b/src/js/findSlave.js
@@ -1,7 +1,9 @@
 App.UI.findSlave = function() {
 	const node = new DocumentFragment();
 
-	App.UI.DOM.appendNewElement("p", node, `After spending a minute trying to remember some details about one of your slaves, you sit down behind your desk and tell ${assistant.name} that you need to locate a particular slave's records.`);
+	// App.UI.DOM.appendNewElement("h1", node, `Find slave`);
+
+	App.UI.DOM.appendNewElement("p", node, `After spending a minute trying to remember some details about one of your slaves, you sit down behind your desk and tell ${V.assistant.name} that you need to locate a particular slave's records.`);
 
 	App.UI.DOM.appendNewElement("p", node, `"Certainly, ${properMaster()}. What can you tell me about them?"`);
 
diff --git a/src/js/modification.js b/src/js/modification.js
index 60c1c43724a..5dff40616f2 100644
--- a/src/js/modification.js
+++ b/src/js/modification.js
@@ -2,7 +2,7 @@
  * Basic application of scar
  * @param {App.Entity.SlaveState} slave
  * @param {string} scar
- * @param {string} design
+ * @param {keyof App.Entity.scarState} design
  * @param {number} [weight]
  */
 App.Medicine.Modification.addScar = function(slave, scar, design, weight) {
@@ -27,7 +27,7 @@ App.Medicine.Modification.addScar = function(slave, scar, design, weight) {
  * Basic application of scar
  * @param {App.Entity.SlaveState} slave
  * @param {string} scar
- * @param {string} design
+ * @param {keyof App.Entity.scarState} design
  */
 App.Medicine.Modification.removeScar = function(slave, scar, design) {
 	/*
@@ -103,7 +103,7 @@ App.Medicine.Modification.addScourged = function(slave, weight) {
  * Scars a slave over a large section of their body.
  * @param {App.Entity.SlaveState} slave
  * @param {string} location full, upper, lower, left or right
- * @param {string} type whip, burn, surgical, generic
+ * @param {keyof App.Entity.scarState} type whip, burn, surgical, generic
  * @param {number} weight
  */
 App.Medicine.Modification.addBulkScars = function(slave, location, type, weight) {
@@ -280,6 +280,10 @@ App.Medicine.Modification.setPiercing = function(slave, location, weight) {
 		if (slave.sexualFlaw === "hates anal" && weight > 0) {
 			r.push(`${He} has trouble thinking of ${his} asshole as a sexy, fuckable hole, so ${his} new piercings will be therapeutic. The constant tickling back there should force ${him} past ${his} hang-ups.`);
 		}
+	} else if (location === "genitals") {
+		if (weight === 0) {
+			slave.piercing.genitals.smart = false;
+		}
 	}
 
 	if (slave.genes === "XY" && slave.attrXY <= 35 && ["ear", "eyebrow", "lips", "navel", "nose"].includes(location)) {
@@ -308,7 +312,7 @@ App.Medicine.Modification.setPiercing = function(slave, location, weight) {
 		}
 	}
 
-	slave[`${location}Piercing`] = weight;
+	slave.piercing[location].weight = weight;
 	return r.join(" ");
 };
 
diff --git a/src/js/relationshipChecks.js b/src/js/relationshipChecks.js
index 56eaf1f964d..e48adae77cc 100644
--- a/src/js/relationshipChecks.js
+++ b/src/js/relationshipChecks.js
@@ -68,11 +68,12 @@ globalThis.PCrelationshipTerm = function(id) {
  * even though it's not going to have any mechanical impact on the scene.
  * @param {FC.HumanState} context
  * @param {FC.HumanState} actor
- * @param {boolean|string} [asLink=false] - when true, instead of using the slave's first name, use their full name with a (SC Markup) link to the slave description dialog. when "DOM", generate a DOM link and return a DocumentFragment.
- * @param {boolean} [insertComma=false] - when true, if a relationship is found, it will be separated from the actor's name by a comma ("her father, Dave" instead of "her father Dave")
+ * @param {boolean|'DOM'} [asLink] When true, instead of using the slave's first name, use their full name with a (SC Markup) link to the slave description dialog. when "DOM", generate a DOM link and return a DocumentFragment.
+ * @param {boolean} [insertComma] When true, if a relationship is found, it will be separated from the actor's name by a comma ("her father, Dave" instead of "her father Dave")
+ * @param {boolean} [capitalize] When true, capitalizes the first letter of the intro. Use if called at the beginning of a sentence.
  * @returns {string|DocumentFragment}
  */
-globalThis.contextualIntro = function(context, actor, asLink = false, insertComma = false) {
+globalThis.contextualIntro = function(context, actor, asLink = false, insertComma = false, capitalize = false) {
 	let r = ``;
 	const preamble = (context === V.PC) ? "your" : getPronouns(context).possessive;
 
@@ -92,7 +93,7 @@ globalThis.contextualIntro = function(context, actor, asLink = false, insertComm
 	terms = terms.concat(relativeTerms(context, actor));
 
 	if (terms.length > 0) {
-		r = preamble + " " + toSentence(terms);
+		r = (capitalize ? capFirstChar(preamble) : preamble) + " " + toSentence(terms);
 	}
 
 	if (r !== ``) {
diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index 5b9bc86fb06..aa70b9bbc69 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -237,6 +237,7 @@ App.RA.newRule = function() {
 			chastityAnus: null,
 			chastityPenis: null,
 			virginAccessory: null,
+			vaginaLube: null,
 			aVirginAccessory: null,
 			vaginalAccessory: null,
 			aVirginDickAccessory: null,
@@ -262,20 +263,7 @@ App.RA.newRule = function() {
 			markings: null,
 			pubicHColor: null,
 			pubicHStyle: null,
-			nipplesPiercing: null,
-			areolaePiercing: null,
-			clitPiercing: null,
-			vaginaLube: null,
-			vaginaPiercing: null,
-			dickPiercing: null,
-			anusPiercing: null,
-			lipsPiercing: null,
-			tonguePiercing: null,
-			earPiercing: null,
-			nosePiercing: null,
-			eyebrowPiercing: null,
-			navelPiercing: null,
-			corsetPiercing: null,
+			piercing: new App.Entity.completePiercingStateRA(),
 			boobsTat: null,
 			buttTat: null,
 			vaginaTat: null,
@@ -316,7 +304,6 @@ App.RA.newRule = function() {
 			// eslint-disable-next-line camelcase
 			hyper_drugs: 0,
 			aphrodisiacs: null,
-			autoSurgery: 0,
 			autoBrand: 0,
 			pornFeed: null,
 			pornFameSpending: null,
@@ -513,7 +500,6 @@ globalThis.initRules = function() {
 	rule.condition.function = "between";
 	rule.condition.data.attribute = "devotion";
 	rule.condition.data.value = [20, null];
-	rule.set.removalAssignment = "rest";
 
 	V.defaultRules = [rule];
 	V.rulesToApplyOnce = {};
diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js
index 501603b0b10..cbe9553726e 100644
--- a/src/js/rulesAssistantOptions.js
+++ b/src/js/rulesAssistantOptions.js
@@ -259,7 +259,7 @@ App.RA.options = (function() {
 		}
 	}
 
-	let _blockCallback=Symbol("Block Callback");
+	let _blockCallback = Symbol("Block Callback");
 	// list of clickable elements
 	// has a short explanation (the prefix) and a value display
 	// value display can optionally be an editable text input field
@@ -315,21 +315,21 @@ App.RA.options = (function() {
 			this.propagateChange();
 		}
 		trySetValue(what) {
-			if(what == null && this._allowNullValue) {
+			if (what == null && this._allowNullValue) {
 				this.setValue(what);
 				return;
 			}
 			const selected = this.children.filter(listItem => _.isEqual(listItem.data, what));
-			if(selected != null && selected.length === 1) {
+			if (selected != null && selected.length === 1) {
 				this.selectItem(selected[0]);
-			} else if(this._allowNullValue) {
+			} else if (this._allowNullValue) {
 				this.setValue(null);
 			}
 		}
 		setValue(what) {
-			if(what == null && !this._allowNullValue) { what = ""; }
+			if (what == null && !this._allowNullValue) { what = ""; }
 			this.realValue = what;
-			if(this[_blockCallback]) { return; }
+			if (this[_blockCallback]) { return; }
 			try {
 				this[_blockCallback] = true;
 				this.setTextValue(what);
@@ -370,7 +370,7 @@ App.RA.options = (function() {
 		updateSelected() {
 			const dataValue = this.getData();
 			let selected;
-			if(dataValue == null) {
+			if (dataValue == null) {
 				selected = this.children.filter(listItem => listItem.data == null);
 			} else {
 				selected = this.children.filter(listItem => this.dataEqual(listItem.data, dataValue));
@@ -379,8 +379,8 @@ App.RA.options = (function() {
 			if (selected.length === 1) {
 				const listItem = selected[0];
 				listItem.select(false);
-				if(this.selectedItem != null
-				&& !_.isEqual(this.selectedItem, listItem)) {
+				if (this.selectedItem != null
+					&& !_.isEqual(this.selectedItem, listItem)) {
 					this.selectedItem.deselect();
 				}
 				this.selectedItem = listItem;
@@ -429,7 +429,7 @@ App.RA.options = (function() {
 			if (this.selected) { return false; }
 			this.selected = true;
 			this.element.classList.add("selected");
-			if(notify) { this.parent.selectItem(this); }
+			if (notify) { this.parent.selectItem(this); }
 			return true;
 		}
 
@@ -656,14 +656,14 @@ App.RA.options = (function() {
 			res.onkeypress = (e) => {
 				if (returnP(e)) { this.inputEdited(); }
 			};
-			$(res).click(()=>res.setAttribute("placeholder", ""));
+			$(res).click(() => res.setAttribute("placeholder", ""));
 			return res;
 		}
 		setValue(what) {
 			super.setValue(what);
 			this.value.setAttribute("placeholder", what == null
-												 ? `(${capFirstChar(noDefaultSetting.text)})`
-												 : '');
+				? `(${capFirstChar(noDefaultSetting.text)})`
+				: '');
 		}
 
 		getTextData() {
@@ -767,7 +767,7 @@ App.RA.options = (function() {
 			this.numEditor = document.createElement("input");
 			this.numEditor.type = "number";
 			this.numEditor.min = min;
-			this.numEditor.max= max;
+			this.numEditor.max = max;
 			this.numEditor.classList.add("rajs-value"); //
 			this.numEditor.onchange = () => {
 				this.inputEdited();
@@ -996,7 +996,7 @@ App.RA.options = (function() {
 			super(label);
 			this.parent = parent;
 			this.labelElement_.className = "ra-sub-label";
-			pairs.forEach(item => this.appendChild(Array.isArray(item) ? new ListItem( ...item) : new ListItem(item)));
+			pairs.forEach(item => this.appendChild(Array.isArray(item) ? new ListItem(...item) : new ListItem(item)));
 		}
 
 		render() {
@@ -1175,14 +1175,18 @@ App.RA.options = (function() {
 		}
 
 		render(element) {
+			const div = document.createElement("div");
 			const greeting = App.UI.DOM.makeElement("p", null, "scene-intro");
+
+			// App.UI.DOM.appendNewElement("h1", div, `Rules Assistant`);
 			App.UI.DOM.appendNewElement("div", greeting, `${properTitle()}, I will review your slaves and make changes that will have a beneficial effect. Apologies, ${properTitle()}, but this function is... not fully complete. It may have some serious limitations. Please use the '${noDefaultSetting.text}' option to identify areas I should not address.`);
 			App.UI.DOM.appendNewElement("div", greeting, `For things like breast, butt, lip, dick, and ball injections, you need to only set the growth targets in Physical Regimen and I'll try to figure out how to best achieve them. You probably won't need a separate rule for each of them, or have to worry about ending the injections.`);
 			App.UI.DOM.appendNewElement("div", greeting, `Please note that surgeries will only be applied to slaves that are in the penthouse, and will not be applied until the end of the week.  Surgery outcomes are included in a slave's individual report, instead of with the other effects of the RA.`);
 			const summary = App.UI.DOM.appendNewElement("div", greeting, `You can always see an overview of all of your rules in the `);
 			summary.append(App.UI.DOM.passageLink("summary view", "Rules Assistant Summary"));
 			summary.append(`.`);
-			element.appendChild(greeting);
+			div.append(greeting);
+			element.append(div);
 			return element;
 		}
 	}
@@ -1419,7 +1423,7 @@ App.RA.options = (function() {
 			});
 			elem.appendChild(textarea);
 
-			if(RuleHasError(current_rule)) {
+			if (RuleHasError(current_rule)) {
 				const errorMessage = document.createElement("div");
 				$(errorMessage).addClass("yellow");
 				errorMessage.innerText = "WARNING: There are errors in this condition. Please ensure the syntax is correct and equality is either '==' or '===', not '='";
@@ -1509,7 +1513,7 @@ App.RA.options = (function() {
 				"intelligence": "From moronic to brilliant: [-100, 100]",
 				"accent": "No accent: 0, Nice accent: 1, Bad accent: 2, Can't speak language: 3 and above",
 				"waist": "Masculine waist: (95, ∞), Ugly waist: (40, 95], Unattractive waist: (10, 40], Average waist: [-10, 10], Feminine waist: [-40, -10), Wasp waist: [-95, -40), Absurdly narrow: (-∞, -95)",
-			} [attribute] || " ");
+			}[attribute] || " ");
 		}
 	}
 
@@ -1864,18 +1868,32 @@ App.RA.options = (function() {
 		constructor(tabButtons) {
 			super("bodyMod", "Body Mod", tabButtons);
 			this.appendChild(new EarPiercingList());
+			this.appendChild(new EarPiercingString());
 			this.appendChild(new NosePiercingList());
+			this.appendChild(new NosePiercingString());
 			this.appendChild(new EyebrowPiercingList());
+			this.appendChild(new EyebrowPiercingString());
 			this.appendChild(new NavelPiercingList());
+			this.appendChild(new NavelPiercingString());
 			this.appendChild(new NipplePiercingList());
+			this.appendChild(new NipplePiercingString());
 			this.appendChild(new AreolaPiercingList());
+			this.appendChild(new AreolaPiercingString());
 			this.appendChild(new LipPiercingList());
+			this.appendChild(new LipPiercingString());
 			this.appendChild(new TonguePiercingList());
+			this.appendChild(new TonguePiercingString());
 			this.appendChild(new ClitPiercingList());
+			this.appendChild(new ClitPiercingString());
+			this.appendChild(new ClitSmartPiercingList());
 			this.appendChild(new LabiaPiercingList());
+			this.appendChild(new LabiaPiercingString());
 			this.appendChild(new ShaftPiercingList());
+			this.appendChild(new ShaftPiercingString());
 			this.appendChild(new PerineumPiercingList());
+			this.appendChild(new PerineumPiercingString());
 			this.appendChild(new CorsetPiercingList());
+			this.appendChild(new CorsetPiercingString());
 
 			this.appendChild(new AutoBrandingList());
 			this.appendChild(new BrandingLocationList());
@@ -1993,18 +2011,18 @@ App.RA.options = (function() {
 
 	class MaskList extends ListSelector {
 		constructor() {
-			const pairs = [["No mask", "none"]].concat(isItemAccessible.array(App.Data.slaveWear.faceAccessory ));
+			const pairs = [["No mask", "none"]].concat(isItemAccessible.array(App.Data.slaveWear.faceAccessory));
 			super("Mask", pairs);
-			this.setValue(current_rule.set.faceAccessory );
+			this.setValue(current_rule.set.faceAccessory);
 			this.onchange = (value) => current_rule.set.faceAccessory = value;
 		}
 	}
 
 	class GagList extends ListSelector {
 		constructor() {
-			const pairs = [["No gag", "none"]].concat(isItemAccessible.array(App.Data.mouthAccessory ));
+			const pairs = [["No gag", "none"]].concat(isItemAccessible.array(App.Data.mouthAccessory));
 			super("Gag", pairs);
-			this.setValue(current_rule.set.mouthAccessory );
+			this.setValue(current_rule.set.mouthAccessory);
 			this.onchange = (value) => current_rule.set.mouthAccessory = value;
 		}
 	}
@@ -2680,9 +2698,9 @@ App.RA.options = (function() {
 				["healthy", App.RA.makeRange(-10, 10)],
 				["nicely plush", App.RA.makeRange(11, 30)],
 				[hdp ? "quite curvy" : "chubby", App.RA.makeRange(31, 95)],
-				[hdp ? "extremely curvy": "overweight", App.RA.makeRange(96, 130)],
-				[hdp ? "amazingly curvy": "very overweight", App.RA.makeRange(131, 160)],
-				[hdp ? "spectacularly curvy": "extremely overweight", App.RA.makeRange(161, 190)],
+				[hdp ? "extremely curvy" : "overweight", App.RA.makeRange(96, 130)],
+				[hdp ? "amazingly curvy" : "very overweight", App.RA.makeRange(131, 160)],
+				[hdp ? "spectacularly curvy" : "extremely overweight", App.RA.makeRange(161, 190)],
 				[hdp ? "perfectly curvy" : "dangerously overweight", App.RA.makeRange(191, 200)]
 			];
 			super("Weight", pairs, true, -100, 200);
@@ -2731,7 +2749,7 @@ App.RA.options = (function() {
 	}
 
 	const dietAddedText = function(value) {
-		switch(value) {
+		switch (value) {
 			case 0:
 				return "None";
 			case 1:
@@ -2763,7 +2781,7 @@ App.RA.options = (function() {
 			};
 		}
 		setTextValue(what) {
-			if(what.cum == null && what.milk == null) {
+			if (what.cum == null && what.milk == null) {
 				super.setTextValue(capFirstChar(noDefaultSetting.text));
 			} else {
 				super.setTextValue(`Cum: ${dietAddedText(what.cum)}, Milk: ${dietAddedText(what.milk)}`);
@@ -3325,55 +3343,86 @@ App.RA.options = (function() {
 		}
 	}
 
-	function piercingTypes(smartEnabled = false) {
-		let res = [
+	function piercingTypes() {
+		return [
 			["none", 0],
 			["light", 1],
 			["heavy", 2]
 		];
-		if (smartEnabled) {
-			res.push(["Smart (expensive)", 3]);
-		}
-		return res;
 	}
 
 	class EarPiercingList extends ListSelector {
 		constructor() {
 			super("Ear piercings", piercingTypes());
-			this.setValue(current_rule.set.earPiercing);
-			this.onchange = (value) => current_rule.set.earPiercing = value;
+			this.setValue(current_rule.set.piercing.ear.weight);
+			this.onchange = (value) => current_rule.set.piercing.ear.weight = value;
 		}
 	}
 
+	class EarPiercingString extends StringEditor {
+		constructor() {
+			super("Ear description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.ear.desc);
+			this.onchange = (value) => current_rule.set.piercing.ear.desc = value;
+		}
+	}
 	class NosePiercingList extends ListSelector {
 		constructor() {
 			super("Nasal piercings", piercingTypes());
-			this.setValue(current_rule.set.nosePiercing);
-			this.onchange = (value) => current_rule.set.nosePiercing = value;
+			this.setValue(current_rule.set.piercing.nose.weight);
+			this.onchange = (value) => current_rule.set.piercing.nose.weight = value;
+		}
+	}
+	class NosePiercingString extends StringEditor {
+		constructor() {
+			super("Nasal description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.nose.desc);
+			this.onchange = (value) => current_rule.set.piercing.nose.desc = value;
 		}
 	}
 
 	class EyebrowPiercingList extends ListSelector {
 		constructor() {
 			super("Eyebrow piercings", piercingTypes());
-			this.setValue(current_rule.set.eyebrowPiercing);
-			this.onchange = (value) => current_rule.set.eyebrowPiercing = value;
+			this.setValue(current_rule.set.piercing.eyebrow.weight);
+			this.onchange = (value) => current_rule.set.piercing.eyebrow.weight = value;
+		}
+	}
+	class EyebrowPiercingString extends StringEditor {
+		constructor() {
+			super("Eyebrow description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.eyebrow.desc);
+			this.onchange = (value) => current_rule.set.piercing.eyebrow.desc = value;
 		}
 	}
 
 	class NavelPiercingList extends ListSelector {
 		constructor() {
 			super("Navel piercings", piercingTypes());
-			this.setValue(current_rule.set.navelPiercing);
-			this.onchange = (value) => current_rule.set.navelPiercing = value;
+			this.setValue(current_rule.set.piercing.navel.weight);
+			this.onchange = (value) => current_rule.set.piercing.navel.weight = value;
+		}
+	}
+	class NavelPiercingString extends StringEditor {
+		constructor() {
+			super("Navel description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.navel.desc);
+			this.onchange = (value) => current_rule.set.piercing.navel.desc = value;
 		}
 	}
 
 	class NipplePiercingList extends ListSelector {
 		constructor() {
 			super("Nipple piercings", piercingTypes());
-			this.setValue(current_rule.set.nipplesPiercing);
-			this.onchange = (value) => current_rule.set.nipplesPiercing = value;
+			this.setValue(current_rule.set.piercing.nipple.weight);
+			this.onchange = (value) => current_rule.set.piercing.nipple.weight = value;
+		}
+	}
+	class NipplePiercingString extends StringEditor {
+		constructor() {
+			super("Nipple description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.nipple.desc);
+			this.onchange = (value) => current_rule.set.piercing.nipple.desc = value;
 		}
 	}
 
@@ -3384,56 +3433,116 @@ App.RA.options = (function() {
 				["studded", 1]
 			];
 			super("Areola studs", pairs, true);
-			this.setValue(current_rule.set.areolaePiercing);
-			this.onchange = (value) => current_rule.set.areolaePiercing = value;
+			this.setValue(current_rule.set.piercing.areola.desc);
+			this.onchange = (value) => current_rule.set.piercing.areola.desc = value;
+		}
+	}
+	class AreolaPiercingString extends StringEditor {
+		constructor() {
+			super("Areola description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.areola.desc);
+			this.onchange = (value) => current_rule.set.piercing.areola.desc = value;
 		}
 	}
 
 	class LipPiercingList extends ListSelector {
 		constructor() {
 			super("Lip piercings", piercingTypes());
-			this.setValue(current_rule.set.lipsPiercing);
-			this.onchange = (value) => current_rule.set.lipsPiercing = value;
+			this.setValue(current_rule.set.piercing.lips.weight);
+			this.onchange = (value) => current_rule.set.piercing.lips.weight = value;
+		}
+	}
+	class LipPiercingString extends StringEditor {
+		constructor() {
+			super("Lip description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.lips.desc);
+			this.onchange = (value) => current_rule.set.piercing.lips.desc = value;
 		}
 	}
 
 	class TonguePiercingList extends ListSelector {
 		constructor() {
 			super("Tongue piercing", piercingTypes());
-			this.setValue(current_rule.set.tonguePiercing);
-			this.onchange = (value) => current_rule.set.tonguePiercing = value;
+			this.setValue(current_rule.set.piercing.tongue.weight);
+			this.onchange = (value) => current_rule.set.piercing.tongue.weight = value;
+		}
+	}
+	class TonguePiercingString extends StringEditor {
+		constructor() {
+			super("Tongue description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.tongue.desc);
+			this.onchange = (value) => current_rule.set.piercing.tongue.desc = value;
 		}
 	}
-
 	class ClitPiercingList extends ListSelector {
 		constructor() {
-			super("Clit piercing", piercingTypes(true));
-			this.setValue(current_rule.set.clitPiercing);
-			this.onchange = (value) => current_rule.set.clitPiercing = value;
+			super("Clit piercing", piercingTypes());
+			this.setValue(current_rule.set.piercing.genitals.weight);
+			this.onchange = (value) => current_rule.set.piercing.genitals.weight = value;
+		}
+	}
+	class ClitPiercingString extends StringEditor {
+		constructor() {
+			super("Clit description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.genitals.desc);
+			this.onchange = (value) => current_rule.set.piercing.genitals.desc = value;
+		}
+	}
+	class ClitSmartPiercingList extends ListSelector {
+		constructor() {
+			const pairs = [
+				["none", false],
+				["installed", true]
+			];
+			super("Clit piercing smart capability", pairs, true);
+			this.setValue(current_rule.set.piercing.genitals.smart);
+			this.onchange = (value) => current_rule.set.piercing.genitals.smart = value;
 		}
 	}
 
 	class LabiaPiercingList extends ListSelector {
 		constructor() {
 			super("Pussylips piercings", piercingTypes());
-			this.setValue(current_rule.set.vaginaPiercing);
-			this.onchange = (value) => current_rule.set.vaginaPiercing = value;
+			this.setValue(current_rule.set.piercing.vagina.weight);
+			this.onchange = (value) => current_rule.set.piercing.vagina.weight = value;
 		}
 	}
 
+	class LabiaPiercingString extends StringEditor {
+		constructor() {
+			super("Pussylips description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.vagina.desc);
+			this.onchange = (value) => current_rule.set.piercing.vagina.desc = value;
+		}
+	}
 	class ShaftPiercingList extends ListSelector {
 		constructor() {
 			super("Shaft piercings", piercingTypes());
-			this.setValue(current_rule.set.dickPiercing);
-			this.onchange = (value) => current_rule.set.dickPiercing = value;
+			this.setValue(current_rule.set.piercing.dick.weight);
+			this.onchange = (value) => current_rule.set.piercing.dick.weight = value;
+		}
+	}
+	class ShaftPiercingString extends StringEditor {
+		constructor() {
+			super("Shaft description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.dick.desc);
+			this.onchange = (value) => current_rule.set.piercing.dick.desc = value;
 		}
 	}
 
 	class PerineumPiercingList extends ListSelector {
 		constructor() {
 			super("Perianal piercings", piercingTypes());
-			this.setValue(current_rule.set.anusPiercing);
-			this.onchange = (value) => current_rule.set.anusPiercing = value;
+			this.setValue(current_rule.set.piercing.anus.weight);
+			this.onchange = (value) => current_rule.set.piercing.anus.weight = value;
+		}
+	}
+
+	class PerineumPiercingString extends StringEditor {
+		constructor() {
+			super("Perianal description", [["Default", ""]]);
+			this.setValue(current_rule.set.piercing.anus.desc);
+			this.onchange = (value) => current_rule.set.piercing.anus.desc = value;
 		}
 	}
 
@@ -3444,8 +3553,16 @@ App.RA.options = (function() {
 				["applied", 1]
 			];
 			super("Corset piercings", pairs, true);
-			this.setValue(current_rule.set.corsetPiercing);
-			this.onchange = (value) => current_rule.set.corsetPiercing = value;
+			this.setValue(current_rule.set.piercing.corset.weight);
+			this.onchange = (value) => current_rule.set.piercing.corset.weight = value;
+		}
+	}
+
+	class CorsetPiercingString extends StringEditor {
+		constructor() {
+			super("Corset description", [["Default", ""]], true);
+			this.setValue(current_rule.set.piercing.corset.desc);
+			this.onchange = (value) => current_rule.set.piercing.corset.desc = value;
 		}
 	}
 
@@ -4116,9 +4233,9 @@ App.RA.options = (function() {
 		}
 	}
 
-	class PitAssignmentList extends ListSelector{
+	class PitAssignmentList extends ListSelector {
 		constructor() {
-			const items =[["remove from pit", 0], ["assign to pit", 1]];
+			const items = [["remove from pit", 0], ["assign to pit", 1]];
 			super("Pit assignment", items);
 			this.setValue(current_rule.set.pitRules);
 			this.onchange = (value) => current_rule.set.pitRules = value;
@@ -4147,7 +4264,7 @@ App.RA.options = (function() {
 
 	class LabelRemoveList extends StringEditor {
 		constructor() {
-			super("Remove custom label(s) (separate by '|')", [], true, true);
+			super("Default label(s) (separate by '|')", [], true, true);
 			this.setValue(current_rule.set.removeLabel);
 			this.onchange = (value) => current_rule.set.removeLabel = value;
 		}
diff --git a/src/js/rulesAssistantSummary.js b/src/js/rulesAssistantSummary.js
index d67a754b6a8..bf16c4c2b28 100644
--- a/src/js/rulesAssistantSummary.js
+++ b/src/js/rulesAssistantSummary.js
@@ -1,10 +1,11 @@
 App.RA.summary = function() {
-	const el = App.UI.DOM.makeElement("div", null, "scroll");
-	App.UI.DOM.appendNewElement("div", el, `Here you can see an overview of all of your rules at the same time.`, "scene-intro");
-	App.UI.DOM.appendNewElement("div", el, `Rules further to the right will always take priority, but some rules may not apply to all slaves.`, "scene-intro");
-
-	el.append(makeTable());
-	return el;
+	const frag = new DocumentFragment();
+	// App.UI.DOM.appendNewElement("h1", frag, `Rules Assistant Summary`);
+	App.UI.DOM.appendNewElement("div", frag, `Here you can see an overview of all of your rules at the same time.`, "scene-intro");
+	App.UI.DOM.appendNewElement("div", frag, `Rules further to the right will always take priority, but some rules may not apply to all slaves.`, "scene-intro");
+	setTimeout(() => $("#passage-rules-assistant-summary").css("overflow", "auto"), Engine.minDomActionDelay);
+	frag.append(makeTable());
+	return frag;
 	/**
 	 * Creates a table to summarize RA
 	 * @returns {HTMLTableElement}
diff --git a/src/js/slaveCostJS.js b/src/js/slaveCostJS.js
index 8003662e2ca..87ec1f54bd1 100644
--- a/src/js/slaveCostJS.js
+++ b/src/js/slaveCostJS.js
@@ -1808,17 +1808,17 @@ globalThis.FResultArray = (function() {
 			return;
 		}
 
-		adjustFResult(`Oral potential: Tongue piercing, skill, and arcology oral weight`, (6 + slave.tonguePiercing) * (V.oralUseWeight / uses) * (slave.skill.oral / 30));
+		adjustFResult(`Oral potential: Tongue piercing, skill, and arcology oral weight`, (6 + slave.piercing.tongue.weight) * (V.oralUseWeight / uses) * (slave.skill.oral / 30));
 		if (slave.sexualFlaw === "cum addict") {
 			adjustFResult(`Oral potential: Cum Addict, skill, and arcology oral weight`, (V.oralUseWeight / uses) * (slave.skill.oral / 30));
 		}
 		if (canDoVaginal(slave) || (slave.vagina > -1 && forSale)) {
-			adjustFResult(`Vaginal potential: skill, and arcology vaginal weight`, (6 + slave.vaginaPiercing) * (V.vaginalUseWeight / uses) * (slave.skill.vaginal / 30));
+			adjustFResult(`Vaginal potential: skill, and arcology vaginal weight`, (6 + slave.piercing.vagina.weight) * (V.vaginalUseWeight / uses) * (slave.skill.vaginal / 30));
 			adjustFResult(`Vaginal potential: Vagina stretched level`, (3 - slave.vagina));
 			adjustFResult(`Vaginal: Lube`, slave.vaginaLube);
 		}
 		if (canDoAnal(slave) || forSale) {
-			adjustFResult(`Anal potential: skill, and arcology anal weight`, (6 + slave.anusPiercing) * (V.analUseWeight / uses) * (slave.skill.anal / 30));
+			adjustFResult(`Anal potential: skill, and arcology anal weight`, (6 + slave.piercing.anus.weight) * (V.analUseWeight / uses) * (slave.skill.anal / 30));
 			adjustFResult(`Anus potential: Anus stretched level`, (3 - slave.anus));
 			if (slave.sexualFlaw === "anal addict") {
 				adjustFResult(`Anal potential: Anal Addict, skill, and arcology anal weight`, (V.analUseWeight / uses) * (slave.skill.anal / 30));
@@ -1949,7 +1949,7 @@ globalThis.FResultArray = (function() {
 	 * @param {App.Entity.SlaveState} slave
 	 */
 	function calcSexAttributes(slave) {
-		if (slave.clitPiercing > 2) {
+		if (slave.piercing.genitals.smart) {
 			adjustFResult(`Piercings: Clit`, 1);
 		}
 		if (slave.tail === "sex") {
diff --git a/src/js/slaveSummaryHelpers.js b/src/js/slaveSummaryHelpers.js
index 00b68a44578..88aea2f5fe9 100644
--- a/src/js/slaveSummaryHelpers.js
+++ b/src/js/slaveSummaryHelpers.js
@@ -465,7 +465,7 @@ App.UI.SlaveSummaryImpl = function() {
 		function smartFetishStr(slave, spData) {
 			/** @type {string} */
 			let value;
-			if (slave.clitPiercing === 3) {
+			if (slave.piercing.genitals.smart) {
 				value = spData.system.piercing;
 			} else if (slave.dickAccessory === "smart bullet vibrator") {
 				value = spData.system.bullet;
@@ -808,7 +808,7 @@ App.UI.SlaveSummaryImpl = function() {
 		 */
 		function long_mods(slave, c) {
 			const modScore = SlaveStatsChecker.modScore(slave);
-			if (slave.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+			if (slave.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 				return;
 			}
 			if (modScore.total > 15 || (modScore.piercing > 8 && modScore.tat > 5)) {
@@ -984,7 +984,7 @@ App.UI.SlaveSummaryImpl = function() {
 		 */
 		function short_mods(slave, c) {
 			const modScore = SlaveStatsChecker.modScore(slave);
-			if (slave.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+			if (slave.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 				return;
 			} else if (modScore.total > 15 || (modScore.piercing > 8 && modScore.tat > 5)) {
 				makeSpan(c, "Mods++");
diff --git a/src/js/slaveSummaryWidgets.js b/src/js/slaveSummaryWidgets.js
index f052b8a9d67..cf9c80df66a 100644
--- a/src/js/slaveSummaryWidgets.js
+++ b/src/js/slaveSummaryWidgets.js
@@ -206,7 +206,7 @@ App.UI.SlaveSummaryRenderers = function() {
 				makeSpan(c, "Barr", styles);
 			} else if (slave.pubertyXX === 0 && (slave.ovaries === 1 || slave.mpreg === 1)) {
 				makeSpan(c, "Prepub", styles);
-			} else if (slave.ovaryAge >= 47 && (slave.ovaries === 1 || slave.mpreg === 1)) {
+			} else if (slave.ovaryAge >= 47 && slave.preg <= 0 && (slave.ovaries === 1 || slave.mpreg === 1)) {
 				makeSpan(c, "Meno", styles);
 			} else if (slave.pregWeek < 0) {
 				makeSpan(c, "Postpartum", styles);
@@ -298,7 +298,7 @@ App.UI.SlaveSummaryRenderers = function() {
 					b.attraction(slave, c);
 				}
 			}
-			if (slave.clitPiercing === 3 || dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator") {
+			if (slave.piercing.genitals.smart || dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator") {
 				b.smart_piercing(slave, c);
 			}
 			b.behavior_flaw(slave, c);
@@ -527,7 +527,7 @@ App.UI.SlaveSummaryRenderers = function() {
 				makeSpan(c, "Barren.", styles);
 			} else if (slave.pubertyXX === 0 && (slave.ovaries === 1 || slave.mpreg === 1)) {
 				makeSpan(c, "Not ovulating yet.", styles);
-			} else if (slave.ovaryAge >= 47 && (slave.ovaries === 1 || slave.mpreg === 1)) {
+			} else if (slave.ovaryAge >= 47 && slave.preg <= 0 && (slave.ovaries === 1 || slave.mpreg === 1)) {
 				makeSpan(c, "Menopausal.", styles);
 			} else if (slave.pregWeek < 0) {
 				makeSpan(c, "Postpartum.", styles);
@@ -692,7 +692,7 @@ App.UI.SlaveSummaryRenderers = function() {
 					b.attraction(slave, c);
 				}
 			}
-			if (slave.clitPiercing === 3 || dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator") {
+			if (slave.piercing.genitals.smart || dildoVibeLevel(slave) > 1 || slave.dickAccessory === "smart bullet vibrator") {
 				b.smart_piercing(slave, c);
 			}
 			b.behavior_flaw(slave, c);
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index c190246501d..779d45f12c6 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -51,7 +51,7 @@ globalThis.SlaveStatsChecker = (function() {
 		if (V.disableLisping === 1 || !canTalk(slave)) {
 			return false;
 		}
-		return (slave.lips > 70 || (slave.lipsPiercing + slave.tonguePiercing > 2) || slave.teeth === "gapped");
+		return (slave.lips > 70 || (slave.piercing.lips.weight + slave.piercing.tongue.weight > 2) || slave.teeth === "gapped");
 	}
 
 	/** call as SlaveStatsChecker.modScore()
@@ -80,47 +80,13 @@ globalThis.SlaveStatsChecker = (function() {
 	function piercingScore(slave) {
 		let score = 0;
 
-		if (slave.earPiercing > 0) {
-			score += slave.earPiercing * 0.75 - 0.5;
-		}
-		if (slave.nosePiercing > 0) {
-			score += slave.nosePiercing * 0.75 - 0.5;
-		}
-		if (slave.eyebrowPiercing > 0) {
-			score += slave.eyebrowPiercing * 0.75 - 0.5;
-		}
-		if (slave.navelPiercing > 0) {
-			score += slave.navelPiercing * 0.75 - 0.5;
-		}
-		if (slave.corsetPiercing > 0) {
-			score += slave.corsetPiercing * 0.75 + 0.5;
-		}
-		if (slave.nipplesPiercing > 0) {
-			score += slave.nipplesPiercing * 0.75 - 0.25;
-		}
-		if (slave.areolaePiercing > 0) {
-			score += slave.areolaePiercing * 0.75 + 0.5;
-		}
-		if (slave.lipsPiercing > 0) {
-			score += slave.lipsPiercing * 0.75 - 0.25;
-		}
-		if (slave.tonguePiercing > 0) {
-			score += slave.tonguePiercing * 0.75 - 0.25;
-		}
-		if (slave.clitPiercing === 3) /* smart piercing */ {
-			score += 1.25;
-		} else if (slave.clitPiercing > 0) {
-			score += slave.clitPiercing * 0.75 - 0.25;
-		}
-
-		if (slave.vaginaPiercing > 0) {
-			score += slave.vaginaPiercing * 0.75 - 0.25;
-		}
-		if (slave.dickPiercing > 0) {
-			score += slave.dickPiercing * 0.75 - 0.25;
-		}
-		if (slave.anusPiercing > 0) {
-			score += slave.anusPiercing * 0.75 - 0.25;
+		for (const piercing in slave.piercing) {
+			const impact = (["lips", "tongue", "nipple", "genitals", "vagina", "dick", "anus"].includes(piercing)) ? 0.25 : 0.5; // Piercings in sexual areas count more for piercing score.
+			if (piercing === "genitals" && slave.piercing.genitals.smart) {
+				score += 1.25;
+			} else if (slave.piercing[piercing].weight > 0) {
+				score += slave.piercing[piercing].weight * 0.75 - impact;
+			}
 		}
 
 		return score;
@@ -250,7 +216,7 @@ globalThis.SlaveStatsChecker = (function() {
 		const brands = brandScore(slave);
 		const scars = scarScore(slave);
 
-		return (!isModded(slave) && slave.corsetPiercing === 0 && piercings < 3 && tattoos < 2 && brands < 2 && scars <= 1);
+		return (!isModded(slave) && slave.piercing.corset.weight === 0 && piercings < 3 && tattoos < 2 && brands < 2 && scars <= 1);
 	}
 }());
 
diff --git a/src/js/underperformingSlaves.js b/src/js/underperformingSlaves.js
index e84136ca125..108896f970f 100644
--- a/src/js/underperformingSlaves.js
+++ b/src/js/underperformingSlaves.js
@@ -59,6 +59,7 @@ App.Underperformers.expensive = function() {
 
 App.Underperformers.passage = function() {
 	const node = new DocumentFragment();
+	// App.UI.DOM.appendNewElement("h1", node, `Underperforming Slaves`);
 	const r = [];
 	r.push(App.UI.DOM.makeElement("div", `${properMaster()}, while many of your slaves work hard to earn ¤ each week, some succeed more than others. As a trader in slaves, you may appreciate the opportunity that comes when a particularly valuable slave didn't earn very much last week. Or perhaps you just want the chance to tweak these problem slaves and train them to be better? The choice is yours.`));
 	if (V.slaveCostFactor > 1.1) {
diff --git a/src/js/utilsMisc.js b/src/js/utilsMisc.js
index f07b24d9c21..d5622be61a1 100644
--- a/src/js/utilsMisc.js
+++ b/src/js/utilsMisc.js
@@ -188,7 +188,7 @@ App.Utils.translate = function(englishWord) {
 App.Utils.totalNetWorth = function() {
 	const arcology = V.arcologies[0];
 	const assistant = V.assistant.power;
-	const menialMult = menialSlaveCost() * V.menialDemandFactor;
+	const menialPrice = menialSlaveCost();
 	let total = 0;
 
 	total += V.cash;
@@ -197,11 +197,11 @@ App.Utils.totalNetWorth = function() {
 		total += slaveCost(slave);
 	}
 
-	total += V.menials * menialMult;
-	total += V.menialBioreactors * menialMult;
-	total += V.bioreactorsXY * menialMult;
-	total += V.bioreactorsXX * menialMult;
-	total += V.bioreactorsHerm * menialMult;
+	total += V.menials * menialPrice;
+	total += V.menialBioreactors * menialPrice;
+	total += V.bioreactorsXY * menialPrice;
+	total += V.bioreactorsXX * menialPrice;
+	total += V.bioreactorsHerm * menialPrice;
 
 	total += V.building.findCells(cell => !(cell instanceof App.Arcology.Cell.Filler) && cell.owner === 1).length * 1000 * Math.trunc(arcology.prosperity * (1 + (arcology.demandFactor / 100)));
 
diff --git a/src/js/vignettes.js b/src/js/vignettes.js
index 956303df3a6..2be7992805d 100644
--- a/src/js/vignettes.js
+++ b/src/js/vignettes.js
@@ -1099,13 +1099,13 @@ globalThis.GetVignette = function(slave) {
 				effect: 1,
 			});
 		}
-		if (slave.lipsPiercing > 0) {
+		if (slave.piercing.lips.weight > 0) {
 			vignettes.push({
 				text: `${he} was highly recommended by a customer who liked the feeling of ${his} lip piercings on his cock,`,
 				type: "cash",
 				effect: 1,
 			});
-			if (slave.lipsPiercing > 1) {
+			if (slave.piercing.lips.weight > 1) {
 				vignettes.push({
 					text: `a customer's pubic hairs got snagged in ${his} lip piercings,`,
 					type: "cash",
@@ -3115,13 +3115,13 @@ globalThis.GetVignette = function(slave) {
 				effect: 1,
 			});
 		}
-		if (slave.lipsPiercing > 0) {
+		if (slave.piercing.lips.weight > 0) {
 			vignettes.push({
 				text: `${he} was highly recommended by a citizen who liked the feeling of ${his} lip piercings on his cock,`,
 				type: "rep",
 				effect: 1,
 			});
-			if (slave.lipsPiercing > 1) {
+			if (slave.piercing.lips.weight > 1) {
 				vignettes.push({
 					text: `a citizen's pubic hairs got snagged in ${his} lip piercings,`,
 					type: "rep",
diff --git a/src/markets/specificMarkets/householdLiquidator.js b/src/markets/specificMarkets/householdLiquidator.js
index bf14e7b98d8..60d371c28f4 100644
--- a/src/markets/specificMarkets/householdLiquidator.js
+++ b/src/markets/specificMarkets/householdLiquidator.js
@@ -91,7 +91,7 @@ App.Markets["Household Liquidator"] = function() {
 			"div",
 			el,
 			App.UI.DOM.link(
-				`Buy their slave contract`,
+				`Buy their slave contracts`,
 				() => {
 					V.market.newSlaves = newSlaves;
 					V.market.newSlaves.forEach((s) => cashX(forceNeg(totalCost / V.market.newSlaves.length), "slaveTransfer", s));
diff --git a/src/markets/specificMarkets/prestigiousSlave.js b/src/markets/specificMarkets/prestigiousSlave.js
index a6a65f429ee..6bc015545ed 100644
--- a/src/markets/specificMarkets/prestigiousSlave.js
+++ b/src/markets/specificMarkets/prestigiousSlave.js
@@ -68,11 +68,11 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 2;
 				slave.vagina = 2;
 				slave.weight = 0;
-				slave.clitPiercing = 1;
-				slave.tonguePiercing = 1;
-				slave.nipplesPiercing = 1;
-				slave.nosePiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.tongue.weight = 1;
+				slave.piercing.nipple.weight = 1;
+				slave.piercing.nose.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.vaginal = 100;
 				slave.skill.oral = 100;
 				slave.skill.anal = 100;
@@ -108,9 +108,9 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 1;
 				slave.vagina = 1;
 				slave.weight = 0;
-				slave.clitPiercing = 1;
-				slave.nipplesPiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.nipple.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.vaginal = 35;
 				slave.skill.oral = 35;
 				slave.skill.anal = 15;
@@ -139,10 +139,10 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 1;
 				slave.vagina = 1;
 				slave.weight = 0;
-				slave.earPiercing = 1;
-				slave.eyebrowPiercing = random(0, 1);
-				slave.nosePiercing = random(0, 1);
-				slave.navelPiercing = random(0, 1);
+				slave.piercing.ear.weight = 1;
+				slave.piercing.eyebrow.weight = random(0, 1);
+				slave.piercing.nose.weight = random(0, 1);
+				slave.piercing.navel.weight = random(0, 1);
 				slave.skill.vaginal = 15;
 				slave.skill.oral = 15;
 				slave.skill.anal = 0;
@@ -171,7 +171,7 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 1;
 				slave.vagina = 1;
 				slave.weight = 0;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.vaginal = 15;
 				slave.skill.oral = 15;
 				slave.skill.anal = 0;
@@ -229,16 +229,16 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 3;
 				slave.vagina = 3;
 				slave.weight = 0;
-				slave.clitPiercing = 2;
-				slave.tonguePiercing = 2;
-				slave.nipplesPiercing = 2;
-				slave.nosePiercing = 2;
-				slave.lipsPiercing = 2;
-				slave.vaginaPiercing = 2;
-				slave.anusPiercing = 2;
-				slave.navelPiercing = 2;
-				slave.eyebrowPiercing = 2;
-				slave.earPiercing = 2;
+				slave.piercing.genitals.weight = 2;
+				slave.piercing.tongue.weight = 2;
+				slave.piercing.nipple.weight = 2;
+				slave.piercing.nose.weight = 2;
+				slave.piercing.lips.weight = 2;
+				slave.piercing.vagina.weight = 2;
+				slave.piercing.anus.weight = 2;
+				slave.piercing.navel.weight = 2;
+				slave.piercing.eyebrow.weight = 2;
+				slave.piercing.ear.weight = 2;
 				slave.skill.vaginal = 100;
 				slave.skill.oral = 100;
 				slave.skill.anal = 100;
@@ -278,7 +278,7 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 1;
 				slave.vagina = 1;
 				slave.weight = 0;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.vaginal = 15;
 				slave.skill.oral = 15;
 				slave.skill.anal = 15;
@@ -379,17 +379,17 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 3;
 				slave.vagina = 3;
 				slave.weight = -20;
-				slave.nipplesPiercing = 2;
-				slave.clitPiercing = 2;
-				slave.vaginaPiercing = 2;
-				slave.dickPiercing = 2;
-				slave.anusPiercing = 2;
-				slave.lipsPiercing = 2;
-				slave.tonguePiercing = 2;
-				slave.earPiercing = 2;
-				slave.nosePiercing = 2;
-				slave.eyebrowPiercing = 2;
-				slave.navelPiercing = 2;
+				slave.piercing.nipple.weight = 2;
+				slave.piercing.genitals.weight = 2;
+				slave.piercing.vagina.weight = 2;
+				slave.piercing.dick.weight = 2;
+				slave.piercing.anus.weight = 2;
+				slave.piercing.lips.weight = 2;
+				slave.piercing.tongue.weight = 2;
+				slave.piercing.ear.weight = 2;
+				slave.piercing.nose.weight = 2;
+				slave.piercing.eyebrow.weight = 2;
+				slave.piercing.navel.weight = 2;
 				slave.boobsTat = "rude words";
 				slave.buttTat = "rude words";
 				slave.vaginaTat = "rude words";
@@ -429,7 +429,7 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.anus = 1;
 				slave.vagina = 1;
 				slave.weight = 20;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.vaginal = 15;
 				slave.skill.oral = 15;
 				slave.skill.anal = 1;
@@ -553,11 +553,11 @@ App.Markets["Prestigious Slave"] = function() {
 					slave.scrotum = slave.balls;
 				}
 				slave.weight = 0;
-				slave.clitPiercing = 1;
-				slave.tonguePiercing = 1;
-				slave.nipplesPiercing = 1;
-				slave.nosePiercing = 1;
-				slave.earPiercing = 1;
+				slave.piercing.genitals.weight = 1;
+				slave.piercing.tongue.weight = 1;
+				slave.piercing.nipple.weight = 1;
+				slave.piercing.nose.weight = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.oral = 100;
 				slave.skill.anal = 100;
 				slave.skill.whoring = 15;
@@ -583,7 +583,7 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.trust = random(-45, -25);
 				setHealth(slave, jsRandom(60, 80), 0, 0, 0, jsRandom(10, 30));
 				slave.weight = 0;
-				slave.clitPiercing = 1;
+				slave.piercing.genitals.weight = 1;
 				slave.skill.oral = 15;
 				slave.skill.anal = 0;
 				slave.skill.whoring = 15;
@@ -647,7 +647,7 @@ App.Markets["Prestigious Slave"] = function() {
 				setHealth(slave, jsRandom(-20, 20), 0, 0, 0, jsRandom(10, 30));
 				slave.anus = 2;
 				slave.weight = 0;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.oral = 100;
 				slave.skill.anal = 0;
 				slave.skill.whoring = 15;
@@ -712,16 +712,16 @@ App.Markets["Prestigious Slave"] = function() {
 				}
 				slave.balls = 0;
 				slave.weight = 0;
-				slave.clitPiercing = 2;
-				slave.tonguePiercing = 2;
-				slave.nipplesPiercing = 2;
-				slave.nosePiercing = 2;
-				slave.lipsPiercing = 2;
-				slave.vaginaPiercing = 2;
-				slave.anusPiercing = 2;
-				slave.navelPiercing = 2;
-				slave.eyebrowPiercing = 2;
-				slave.earPiercing = 2;
+				slave.piercing.genitals.weight = 2;
+				slave.piercing.tongue.weight = 2;
+				slave.piercing.nipple.weight = 2;
+				slave.piercing.nose.weight = 2;
+				slave.piercing.lips.weight = 2;
+				slave.piercing.vagina.weight = 2;
+				slave.piercing.anus.weight = 2;
+				slave.piercing.navel.weight = 2;
+				slave.piercing.eyebrow.weight = 2;
+				slave.piercing.ear.weight = 2;
 				slave.skill.oral = 100;
 				slave.skill.anal = 100;
 				slave.skill.whoring = 100;
@@ -759,7 +759,7 @@ App.Markets["Prestigious Slave"] = function() {
 				setHealth(slave, jsRandom(-80, -40), 0, 0, 0, jsRandom(30, 70));
 				slave.anus = 1;
 				slave.weight = 0;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.oral = 15;
 				slave.skill.anal = 15;
 				slave.skill.whoring = 0;
@@ -845,17 +845,17 @@ App.Markets["Prestigious Slave"] = function() {
 				setHealth(slave, jsRandom(-80, -60), undefined, undefined, undefined, jsRandom(40, 90));
 				slave.anus = 3;
 				slave.weight = -20;
-				slave.nipplesPiercing = 2;
-				slave.clitPiercing = 2;
-				slave.vaginaPiercing = 2;
-				slave.dickPiercing = 2;
-				slave.anusPiercing = 2;
-				slave.lipsPiercing = 2;
-				slave.tonguePiercing = 2;
-				slave.earPiercing = 2;
-				slave.nosePiercing = 2;
-				slave.eyebrowPiercing = 2;
-				slave.navelPiercing = 2;
+				slave.piercing.nipple.weight = 2;
+				slave.piercing.genitals.weight = 2;
+				slave.piercing.vagina.weight = 2;
+				slave.piercing.dick.weight = 2;
+				slave.piercing.anus.weight = 2;
+				slave.piercing.lips.weight = 2;
+				slave.piercing.tongue.weight = 2;
+				slave.piercing.ear.weight = 2;
+				slave.piercing.nose.weight = 2;
+				slave.piercing.eyebrow.weight = 2;
+				slave.piercing.navel.weight = 2;
 				slave.boobsTat = "rude words";
 				slave.buttTat = "rude words";
 				slave.vaginaTat = "rude words";
@@ -895,7 +895,7 @@ App.Markets["Prestigious Slave"] = function() {
 				setHealth(slave, jsRandom(-45, -25), 0, 0, 0, jsRandom(20, 60));
 				slave.anus = 2;
 				slave.weight = 20;
-				slave.earPiercing = 1;
+				slave.piercing.ear.weight = 1;
 				slave.skill.oral = 30;
 				slave.skill.anal = 1;
 				slave.skill.whoring = 5;
diff --git a/src/markets/specificMarkets/slaveShelter.js b/src/markets/specificMarkets/slaveShelter.js
index a577b8e6f61..792da858761 100644
--- a/src/markets/specificMarkets/slaveShelter.js
+++ b/src/markets/specificMarkets/slaveShelter.js
@@ -15,9 +15,7 @@ App.Markets["Slave Shelter"] = function() {
 
 		App.UI.DOM.appendNewElement("span", el, r.join(" "));
 
-		if ((V.shelterSlaveGeneratedWeek || 0) < V.week) {
-			V.shelterSlaveGeneratedWeek = V.week;
-
+		if (V.shelterSlave === 0) {
 			const possibleOrigins = [];
 			possibleOrigins.push("broken");
 			if (V.seeExtreme === 1) {
diff --git a/src/markets/theMarket/buySlaves.js b/src/markets/theMarket/buySlaves.js
index 4672eec2ead..7c8be3b43e6 100644
--- a/src/markets/theMarket/buySlaves.js
+++ b/src/markets/theMarket/buySlaves.js
@@ -8,7 +8,7 @@ App.UI.buySlaves = function() {
 	const minCost = minimumSlaveCost();
 	let linkArray;
 
-	App.UI.DOM.appendNewElement("h2", el, "The Market");
+	App.UI.DOM.appendNewElement("h1", el, "The Market");
 	App.UI.DOM.appendNewElement("p", el, `There are many different organizations to purchase slaves from, but many of them are selective about their customers and will only sell to you if you are reputable. `, `note`);
 
 	if (V.slaveCostFactor > 1.1) {
diff --git a/src/markets/theMarket/marketData.js b/src/markets/theMarket/marketData.js
index 90a1330b65f..fb53bf18d6d 100644
--- a/src/markets/theMarket/marketData.js
+++ b/src/markets/theMarket/marketData.js
@@ -272,7 +272,7 @@ App.Data.Markets = {
 		{
 			title: "Acquire other slaveowners' stock",
 			marketType: "Special Slave",
-			note: "Variable and expensive",
+			note: "Variable and expensive.",
 			encyclopedia: "Pre-Owned Slaves",
 			bulkAvailable: false,
 			get requirements() { return (V.rep > 14000) ? true : `You are not reputable enough to acquire other slaveowners' stock.`; }
diff --git a/src/markets/theMarket/tradeMenials.js b/src/markets/theMarket/tradeMenials.js
index dce3d4dba5e..aebf1ed0993 100644
--- a/src/markets/theMarket/tradeMenials.js
+++ b/src/markets/theMarket/tradeMenials.js
@@ -59,7 +59,7 @@ App.UI.tradeMenials = function(menialWorkersOnly) {
 		}
 		if (V.deltaDemand !== 0) {
 			if (V.demandTimer - V.elapsedDemandTimer < 3) {
-				App.UI.DOM.appendNewElement("span", div, ` but it might change soon`);
+				App.UI.DOM.appendNewElement("span", div, ` but it might change soon.`);
 			}
 		}
 		if (V.cheatMode && V.cheatModeM) {
@@ -116,7 +116,7 @@ App.UI.tradeMenials = function(menialWorkersOnly) {
 		}
 		if (V.deltaSupply !== 0) {
 			if (V.supplyTimer - V.elapsedDemandTimer < 3) {
-				App.UI.DOM.appendNewElement("span", div, ` but it might change soon`);
+				App.UI.DOM.appendNewElement("span", div, ` but it might change soon.`);
 			}
 		}
 
diff --git a/src/neighbor/neighborInteract.js b/src/neighbor/neighborInteract.js
index a03f70b4213..8f2b6ae0b64 100644
--- a/src/neighbor/neighborInteract.js
+++ b/src/neighbor/neighborInteract.js
@@ -1,6 +1,8 @@
 App.Neighbor.Interact = function() {
 	const node = new DocumentFragment();
 
+	App.UI.DOM.appendNewElement("h1", node, `Diplomacy`);
+
 	if (V.cheatMode === 1) {
 		App.UI.DOM.appendNewElement("div", node,
 			App.UI.DOM.passageLink("Cheat Edit Neighboring Arcologies", "Neighbor Arcology Cheat"),
diff --git a/src/npc/children/ChildState.js b/src/npc/children/ChildState.js
index 41b0fdab666..0c74279d58d 100644
--- a/src/npc/children/ChildState.js
+++ b/src/npc/children/ChildState.js
@@ -333,9 +333,7 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * * -96-: absurd
 		 */
 		this.waist = 0;
-		/** Series of rings up the back that can be tied together. 0: no, 1: yes
-		 * @type {FC.Bool} */
-		this.corsetPiercing = 0;
+		this.piercing = new App.Entity.completePiercingState();
 		/**
 		 * What level of prosthetic interface she has installed
 		 * * 0: no interface
@@ -494,21 +492,12 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * @type {FC.NippleShape}
 		 */
 		this.nipples = "cute";
-		/**
-		 * nipple are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavily */
-		this.nipplesPiercing = 0;
 		/** What accessory, if any, or on her nipples */
 		this.nipplesAccessory = "none";
 		/** Slave areolae
 		 *
 		 * 0: normal; 1: large; 2: unusually wide; 3: huge, 4: massive */
 		this.areolae = 0;
-		/** Edge of areolae are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavy */
-		this.areolaePiercing = 0;
 		/** Slave areolae shape ("heart"; "star"; "circle") */
 		this.areolaeShape = "circle";
 		/**
@@ -665,11 +654,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * @see lips
 		 */
 		this.lipsImplant = 0;
-		/**
-		 * lips pierced
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.lipsPiercing = 0;
 		/**
 		 * lip tattoo
 		 *
@@ -701,11 +685,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * @type {FC.TeethType}
 		 */
 		this.teeth = "normal";
-		/**
-		 * has tongue piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.tonguePiercing = 0;
 		/**
 		 * vagina type
 		 * * -1: no vagina
@@ -721,10 +700,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 *
 		 * 0: dry; 1: wet; 2: soaking wet */
 		this.vaginaLube = 0;
-		/** Has vagina piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.vaginaPiercing = 0;
 		/**
 		 * vagina tattoo
 		 *
@@ -882,15 +857,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * * 5: like a massive penis
 		 */
 		this.clit = 0;
-		/**
-		 * is clit pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * * 3: smart
-		 * @type {FC.ClitoralPiercingType}
-		 */
-		this.clitPiercing = 0;
 		/**
 		 * smart piercing setting
 		 * * "off"
@@ -941,14 +907,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		this.dick = 0;
 		/** Used to calculate size of area around anus. */
 		this.analArea = 1;
-		/**
-		 * is dick pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * @type {FC.PiercingType}
-		 */
-		this.dickPiercing = 0;
 		/**
 		 * dick tattoo
 		 *
@@ -1004,10 +962,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * @type {FC.Bool}
 		 * 0: no; 1: yes */
 		this.ovaries = 0;
-		/** Has anus piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.anusPiercing = 0;
 		/**
 		 * anus tattoo
 		 *
@@ -1057,22 +1011,6 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		 * brand
 		 * @type {Object.<string, string>} */
 		this.brand = {};
-		/** Has pierced ears
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.earPiercing = 0;
-		/** Has pierced nose
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.nosePiercing = 0;
-		/** Has eyebrow piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.eyebrowPiercing = 0;
-		/** Has navel piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.navelPiercing = 0;
 		/**
 		 * shoulder tattoo
 		 *
diff --git a/src/npc/children/childSummary.js b/src/npc/children/childSummary.js
index 6b7bc261c51..e73b5bdaed9 100644
--- a/src/npc/children/childSummary.js
+++ b/src/npc/children/childSummary.js
@@ -192,7 +192,7 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 					shortAttraction(child);
 				}
 			}
-			if (child.clitPiercing === 3) {
+			if (child.piercing.genitals.smart) {
 				shortSmartFetish(child);
 				shortSmartAttraction(child);
 			}
@@ -209,7 +209,7 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 					longAttraction(child);
 				}
 			}
-			if (child.clitPiercing === 3) {
+			if (child.piercing.genitals.smart) {
 				longSmartFetish(child);
 				longSmartAttraction(child);
 			}
@@ -2266,7 +2266,7 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 	//  */
 	// function shortMods(child) {
 	// 	const modScore = SlaveStatsChecker.modScore(child);
-	// 	if (child.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+	// 	if (child.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 	// 		return;
 	// 	} else if (modScore.total > 15 || (modScore.piercing > 8 && modScore.tat > 5)) {
 	// 		r += `Mods++`;
@@ -2594,7 +2594,7 @@ App.Facilities.Nursery.ChildSummary = function(child) {
 	//  */
 	// function longMods(child) {
 	// 	const modScore = SlaveStatsChecker.modScore(child);
-	// 	if (child.corsetPiercing === 0 && modScore.piercing < 3 && modScore.tat < 2) {
+	// 	if (child.piercing.corset.weight === 0 && modScore.piercing < 3 && modScore.tat < 2) {
 	// 		return;
 	// 	} else if (modScore.total > 15 || (modScore.piercing > 8 && modScore.tat > 5)) {
 	// 		r += `Extensive body mods. `;
diff --git a/src/npc/children/longChildDescription.js b/src/npc/children/longChildDescription.js
index 979ab7cb6fd..c36b61100cc 100644
--- a/src/npc/children/longChildDescription.js
+++ b/src/npc/children/longChildDescription.js
@@ -4013,15 +4013,15 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 			let r = ``;
 
 			if (child.vagina > -1) {
-				if (child.anusPiercing === 1) {
+				if (child.piercing.anus.weight === 1) {
 					r += `${He} has a simple piercing between ${his} pussy and ${his} asshole. `;
-				} else if (child.anusPiercing === 2) {
+				} else if (child.piercing.anus.weight === 2) {
 					r += `${He} has a big ring between ${his} pussy and ${his} asshole and studs in all around ${his} anus. `;
 				}
 			} else {
-				if (child.anusPiercing === 1) {
+				if (child.piercing.anus.weight === 1) {
 					r += `${He} has a simple perianal piercing between the base of ${his} dick and ${his} girly butthole. `;
-				} else if (child.anusPiercing === 2) {
+				} else if (child.piercing.anus.weight === 2) {
 					r += `${He} has a big ring between the base of ${his} dick and ${his} girly butthole, which has studs all around it. `;
 				}
 			}
@@ -4033,29 +4033,24 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 
 		function clit(child) {
 			let r = ``;
-
-			switch (child.clitPiercing) {
-				case 3:
-					if (child.vagina > -1) {
-						r += `${He} has a smart piercing in ${his} clit. `;
-					} else {
-						r += `${He} has a smart frenulum piercing. `;
-					}
-					break;
-				case 2:
-					if (child.vagina > -1) {
-						r += `${He} has a big ring in ${his} clit. `;
-					} else {
-						r += `${He} has a big ring in ${his} dickhead. `;
-					}
-					break;
-				case 1:
-					if (child.vagina > -1) {
-						r += `${He} has a simple clitoral stud. `;
-					} else {
-						r += `${He} has a simple dickhead stud. `;
-					}
-					break;
+			if (child.piercing.genitals.smart) {
+				if (child.vagina > -1) {
+					r += `${He} has a smart piercing in ${his} clit. `;
+				} else {
+					r += `${He} has a smart frenulum piercing. `;
+				}
+			} else if (child.piercing.genitals.weight === 2) {
+				if (child.vagina > -1) {
+					r += `${He} has a big ring in ${his} clit. `;
+				} else {
+					r += `${He} has a big ring in ${his} dickhead. `;
+				}
+			} else if (child.piercing.genitals.weight === 1) {
+				if (child.vagina > -1) {
+					r += `${He} has a simple clitoral stud. `;
+				} else {
+					r += `${He} has a simple dickhead stud. `;
+				}
 			}
 
 			return r;
@@ -4066,7 +4061,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function corset(child) {
 			let r = ``;
 
-			if (child.corsetPiercing > 0) {
+			if (child.piercing.corset.weight > 0) {
 				r += `${He} has a corset piercing, a ladder of steel rings running up each side of ${his} back: `;
 				if (child.bellyAccessory === "a corset" || child.bellyAccessory === "an extreme corset") {
 					r += `these are looped through special lugs in the back of ${his} actual corset, making it almost a part of ${his} body. `;
@@ -4117,22 +4112,22 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 			let r = ``;
 
 			if (child.dick !== 0) {
-				if (child.dickPiercing === 1) {
+				if (child.piercing.dick.weight === 1) {
 					r += `${He} has a row of studs down ${his} shaft. `;
-				} else if (child.dickPiercing === 2) {
+				} else if (child.piercing.dick.weight === 2) {
 					r += `${He} has a row of heavy rings down ${his} shaft. `;
 				}
 
 				if (child.scrotum !== 0) {
-					if (child.dickPiercing === 1) {
+					if (child.piercing.dick.weight === 1) {
 						r += `${He} has a couple of studs in ${his} ballsack. `;
-					} else if (child.dickPiercing === 2) {
+					} else if (child.piercing.dick.weight === 2) {
 						r += `${He} has a row of rings down the center of ${his} ballsack, all the way from the base of ${his} shaft to ${his} perineum. `;
 					}
 				} else {
-					if (child.dickPiercing === 1) {
+					if (child.piercing.dick.weight === 1) {
 						r += `${He} has a couple of studs beneath the base of ${his} dick. `;
-					} else if (child.dickPiercing === 2) {
+					} else if (child.piercing.dick.weight === 2) {
 						r += `${He} has a row of rings all the way from the base of ${his} shaft to ${his} perineum. `;
 					}
 				}
@@ -4146,8 +4141,8 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function ears(child) {
 			let r = ``;
 
-			if (child.earPiercing > 0) {
-				if (child.earPiercing === 1) {
+			if (child.piercing.ear.weight > 0) {
+				if (child.piercing.ear.weight === 1) {
 					r += `${His} earlobes are conventionally pierced. `;
 				} else {
 					r += `${His} ears are heavily pierced, with multiple lobe piercings and a row of helix piercings. `;
@@ -4181,9 +4176,9 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function eyebrows(child) {
 			let r = ``;
 
-			if (child.eyebrowPiercing === 1) {
+			if (child.piercing.eyebrow.weight === 1) {
 				r += `${He} has a simple stud in one eyebrow. `;
-			} else if (child.eyebrowPiercing === 2) {
+			} else if (child.piercing.eyebrow.weight === 2) {
 				r += `${He} has multiple eyebrow rings. `;
 			}
 
@@ -4195,9 +4190,9 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function lips(child) {
 			let r = ``;
 
-			if (child.lipsPiercing === 1) {
+			if (child.piercing.lips.weight === 1) {
 				r += `${He} has a simple lip piercing. `;
-			} else if (child.lipsPiercing === 2) {
+			} else if (child.piercing.lips.weight === 2) {
 				r += `${His} lips are heavily pierced. `;
 			}
 
@@ -4210,9 +4205,9 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 			let r = ``;
 			let nipColor = nippleColor(child);
 
-			if (child.nipplesPiercing === 1) {
+			if (child.piercing.nipple.weight === 1) {
 				r += `${His} ${nipColor} nipples have a simple piercing, which keeps them a little harder than they would normally be. `;
-			} else if (child.nipplesPiercing === 2) {
+			} else if (child.piercing.nipple.weight === 2) {
 				r += `${His} ${nipColor} nipples are heavily pierced with several rings and studs, and there is a chain between them. `;
 				if (child.boobShape === "saggy" && child.boobs > 2500) {
 					r += `It's been shortened to take advantage of the way ${his} tits sag, and holds ${his} ${nipColor} nipples almost together, producing cleavage that runs from ${his} ${nipColor} nipples all the way up to ${his} sternum. `;
@@ -4220,7 +4215,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 					r += `The constant tugging keeps ${his} ${nipColor} nipples erect. `;
 				}
 
-				if (child.nipplesPiercing > 0) {
+				if (child.piercing.nipple.weight > 0) {
 					switch (child.clothes) {
 						case "a schoolgirl outfit":
 							if (child.boobs <= 2500) {
@@ -4242,9 +4237,9 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function nose(child) {
 			let r = ``;
 
-			if (child.nosePiercing === 1) {
+			if (child.piercing.nose.weight === 1) {
 				r += `${He} has simple studs in ${his} nose. `;
-			} else if (child.nosePiercing === 2) {
+			} else if (child.piercing.nose.weight === 2) {
 				r += `${He} has nasal studs and a large septum ring. `;
 			}
 
@@ -4256,12 +4251,12 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function tongue(child) {
 			let r = ``;
 
-			if (child.tonguePiercing === 1) {
+			if (child.piercing.tongue.weight === 1) {
 				r += `${His} tongue bears a single stud, so oral sex with ${him} is a bit more fun. `;
-			} else if (child.tonguePiercing === 2) {
+			} else if (child.piercing.tongue.weight === 2) {
 				r += `${His} tongue bears a row of studs, offering thorough stimulation to anyone ${he} blows. `;
 			}
-			if (canTalk(child) && child.lips <= 70 && child.lipsPiercing === 2) {
+			if (canTalk(child) && child.lips <= 70 && child.piercing.lips.weight === 2) {
 				r += `${He} can barely enunciate past ${his} piercings; '${getWrittenTitle(child)}' comes out as '${master(child)}.' `;
 			}
 
@@ -4273,9 +4268,9 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		function vagina(child) {
 			let r = ``;
 
-			if (child.vaginaPiercing > 0) {
+			if (child.piercing.vagina.weight > 0) {
 				r += `${He} has a `;
-				if (child.vaginaPiercing) {
+				if (child.piercing.vagina.weight) {
 					r += `simple row of studs `;
 				} else {
 					r += `row of big rings `;
@@ -7719,7 +7714,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 		r += `${child.counter.pitKills} slaves have died by ${his} hand in pit fights. `;
 	}
 
-	if (child.corsetPiercing > 0) {
+	if (child.piercing.corset.weight > 0) {
 		r += piercings.corset(child);
 	}
 
diff --git a/src/npc/databases/cheatmodeDatabase.js b/src/npc/databases/cheatmodeDatabase.js
index d1342b0a785..b71e75dd408 100644
--- a/src/npc/databases/cheatmodeDatabase.js
+++ b/src/npc/databases/cheatmodeDatabase.js
@@ -43,7 +43,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anus = 1;
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
+	cheatSlave.piercing.ear.weight = 1;
 	cheatSlave.skill.oral = 100;
 	cheatSlave.skill.anal = 100;
 	cheatSlave.skill.whoring = 100;
@@ -116,7 +116,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anus = 2;
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
+	cheatSlave.piercing.ear.weight = 1;
 	cheatSlave.skill.oral = 100;
 	cheatSlave.skill.anal = 100;
 	cheatSlave.skill.whoring = 100;
@@ -172,7 +172,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.boobs = 1600;
 	cheatSlave.boobsImplant = 600;
 	cheatSlave.boobsImplantType = "normal";
-	cheatSlave.nipplesPiercing = 1;
+	cheatSlave.piercing.nipple.weight = 1;
 	cheatSlave.areolae = 1;
 	cheatSlave.butt = 6;
 	cheatSlave.buttImplant = 2;
@@ -184,7 +184,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anus = 1;
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
+	cheatSlave.piercing.ear.weight = 1;
 	cheatSlave.skill.oral = 35;
 	cheatSlave.skill.anal = 35;
 	cheatSlave.skill.whoring = 35;
@@ -253,8 +253,8 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anusTat = "bovine patterns";
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
-	cheatSlave.nosePiercing = 2;
+	cheatSlave.piercing.ear.weight = 1;
+	cheatSlave.piercing.nose.weight = 2;
 	cheatSlave.shouldersTat = "bovine patterns";
 	cheatSlave.armsTat = "bovine patterns";
 	cheatSlave.legsTat = "bovine patterns";
@@ -315,7 +315,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anus = 2;
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
+	cheatSlave.piercing.ear.weight = 1;
 	cheatSlave.skill.anal = 35;
 	cheatSlave.skill.combat = 1;
 	cheatSlave.energy = 65;
@@ -384,8 +384,8 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.anusTat = "bovine patterns";
 	cheatSlave.makeup = 1;
 	cheatSlave.nails = 1;
-	cheatSlave.earPiercing = 1;
-	cheatSlave.nosePiercing = 2;
+	cheatSlave.piercing.ear.weight = 1;
+	cheatSlave.piercing.nose.weight = 2;
 	cheatSlave.shouldersTat = "bovine patterns";
 	cheatSlave.armsTat = "bovine patterns";
 	cheatSlave.legsTat = "bovine patterns";
diff --git a/src/npc/databases/dSlavesDatabase.js b/src/npc/databases/dSlavesDatabase.js
index ad54ecb0f19..57d725ec95e 100644
--- a/src/npc/databases/dSlavesDatabase.js
+++ b/src/npc/databases/dSlavesDatabase.js
@@ -1,6 +1,6 @@
 /* eslint-disable camelcase */
 /**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.D = [
 	// start 900000
@@ -158,18 +158,16 @@ App.Data.HeroSlaves.D = [
 		buttTat: "tribal patterns",
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
-		nosePiercing: 1,
 		skill: {
 			vaginal: 35,
 			oral: 35,
 			anal: 35
 		},
 		clothes: "uncomfortable straps",
-		attrXY: 40
+		attrXY: 40,
+		piercing: {vagina: {weight: 1}, ear: {weight: 1}, nose: {weight: 1}}
 	},
 	/* Tat should be lower back, "Wears a leather collar, a Scarab clitoris g-string, Tortoise shell leather harness, and a pair of black thigh high boots"*/
 	/* Corrected piercings -BoneyM*/
@@ -198,7 +196,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		nosePiercing: 2,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -206,7 +203,8 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXY: 40,
 		fetish: "submissive",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nose: {weight: 2}}
 	},
 	/* Corrected piercings, added origin -BoneyM*/
 	{
@@ -298,18 +296,15 @@ App.Data.HeroSlaves.D = [
 		boobs: 1400,
 		boobsImplant: 800,
 		boobsImplantType: "normal",
-		nipplesPiercing: 2,
 		boobsTat: "degradation",
 		butt: 6,
 		buttImplant: 3,
 		buttImplantType: "normal",
 		buttTat: "degradation",
 		lips: 35,
-		lipsPiercing: 2,
 		lipsTat: "degradation",
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		vaginaTat: "degradation",
 		anus: 1,
 		ovaries: 1,
@@ -327,6 +322,7 @@ App.Data.HeroSlaves.D = [
 		fetish: "humiliation",
 		fetishKnown: 1,
 		behavioralFlaw: "arrogant",
+		piercing: {nipple: {weight: 2}, lips: {weight: 2}, vagina: {weight: 1}},
 		custom: {tattoo: "$He has several 'tribal' style tattoos on $his arms from before $his enslavement."},
 		career: "a slaver"
 	},
@@ -398,11 +394,9 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "neat",
 		boobs: 300,
-		nipplesPiercing: 1,
 		butt: 3,
 		vagina: 3,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		vaginaTat: "degradation",
 		anus: 3,
 		ovaries: 1,
@@ -412,7 +406,8 @@ App.Data.HeroSlaves.D = [
 			anal: 100
 		},
 		attrXY: 40,
-		hips: 2
+		hips: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 1}}
 	},
 	{
 		ID: 900012,
@@ -436,7 +431,6 @@ App.Data.HeroSlaves.D = [
 		hLength: 30,
 		hStyle: "neat",
 		boobs: 300,
-		nipplesPiercing: 1,
 		butt: 1,
 		vagina: 1,
 		vaginaLube: 1,
@@ -453,7 +447,8 @@ App.Data.HeroSlaves.D = [
 		intelligenceImplant: 30,
 		attrXX: 80,
 		attrXY: 40,
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}}
 	},
 	/* corrected eyes, changed skin to 'freckled', tweaked height downward, added pseudophallus clit, added origin -BoneyM*/
 	/* corrected skin to fair?, changed markings to 'freckled' Bane70 */
@@ -478,8 +473,6 @@ App.Data.HeroSlaves.D = [
 		butt: 2,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "submissive",
 		ovaries: 1,
 		skill: {
 			vaginal: 15,
@@ -487,7 +480,9 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXY: 40,
 		fetishKnown: 1,
-		career: "a slave"
+		career: "a slave",
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "submissive"
 	},
 	/* Added origin, tweaked skills, added smart piercing set to submissive, removed buttslut -BoneyM*/
 	{
@@ -802,13 +797,11 @@ App.Data.HeroSlaves.D = [
 		boobs: 650,
 		boobsImplant: 600,
 		boobsImplantType: "normal",
-		nipplesPiercing: 1,
 		butt: 2,
 		buttTat: "tribal patterns",
 		face: -15,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		anus: 1,
 		analArea: 1,
 		ovaries: 1,
@@ -822,7 +815,8 @@ App.Data.HeroSlaves.D = [
 		intelligence: 20,
 		intelligenceImplant: 30,
 		attrXY: 40,
-		sexualFlaw: "hates penetration"
+		sexualFlaw: "hates penetration",
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}}
 	},
 	/* fighter*/
 	/* Tweaked face down, added 'hates penetration' and combat skill -BoneyM*/
@@ -843,14 +837,11 @@ App.Data.HeroSlaves.D = [
 		origSkin: "white",
 		hLength: 10,
 		boobs: 650,
-		nipplesPiercing: 2,
 		boobsTat: "tribal patterns",
 		butt: 3,
 		buttTat: "tribal patterns",
-		lipsPiercing: 2,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		vaginaTat: "tribal patterns",
 		anus: 1,
 		ovaries: 1,
@@ -860,7 +851,8 @@ App.Data.HeroSlaves.D = [
 			anal: 100
 		},
 		intelligence: 10,
-		attrXY: 40
+		attrXY: 40,
+		piercing: {nipple: {weight: 2}, lips: {weight: 2}, vagina: {weight: 1}}
 	},
 	/* Tweaked devotion up, added arrogant -BoneyM*/
 	{
@@ -1068,19 +1060,16 @@ App.Data.HeroSlaves.D = [
 		hLength: 10,
 		hStyle: "afro",
 		boobs: 1000,
-		nipplesPiercing: 2,
 		butt: 4,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		clit: 3,
-		clitPiercing: 1,
 		anus: 3,
 		ovaries: 1,
 		clothes: "attractive lingerie",
 		attrXY: 40,
 		fetishKnown: 1,
-		navelPiercing: 1
+		piercing: {nipple: {weight: 2}, vagina: {weight: 2}, navel: {weight: 1}, genitals: {weight: 1}}
 	},
 	/* big clit*/
 	/* Added big clit, increased nipple piercing, added clit piercing -BoneyM*/
@@ -1143,7 +1132,6 @@ App.Data.HeroSlaves.D = [
 		lipsTat: "permanent makeup",
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		anus: 1,
 		ovaries: 1,
 		skill: {
@@ -1151,6 +1139,7 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {vagina: {weight: 1}},
 		custom: {tattoo: "$He has a barcode tattooed on $his abdomen, and 'cut here' lines on $his arms and legs."},
 		sexualFlaw: "self hating"
 	},
@@ -1242,10 +1231,7 @@ App.Data.HeroSlaves.D = [
 		boobs: 650,
 		boobsImplant: 600,
 		boobsImplantType: "normal",
-		nipplesPiercing: 1,
 		butt: 5,
-		lipsPiercing: 1,
-		tonguePiercing: 1,
 		vagina: 1,
 		vaginaLube: 1,
 		anus: 1,
@@ -1260,6 +1246,7 @@ App.Data.HeroSlaves.D = [
 		attrXX: 80,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 1}, tongue: {weight: 1}},
 		custom: {tattoo: "$He has 'Charity' tattooed in cursive across the back of $his neck."}
 	},
 	/* Changed $him to Arabic, corrected tattoo syntax, added entertain skill -BoneyM*/
@@ -1287,9 +1274,7 @@ App.Data.HeroSlaves.D = [
 		butt: 3,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 3,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			oral: 15,
 			whoring: 15,
@@ -1300,6 +1285,8 @@ App.Data.HeroSlaves.D = [
 		attrXX: 80,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "submissive",
 		custom: {tattoo: "$He has a barcode of $his identifying information tattooed on $his left shoulder."},
 		career: "a slaver"
 	},
@@ -1367,8 +1354,6 @@ App.Data.HeroSlaves.D = [
 		hStyle: "neat",
 		boobs: 400,
 		butt: 2,
-		lipsPiercing: 1,
-		tonguePiercing: 1,
 		vagina: 1,
 		vaginaLube: 1,
 		ovaries: 1,
@@ -1378,7 +1363,8 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXY: 40,
 		fetish: "submissive",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {lips: {weight: 1}, tongue: {weight: 1}}
 	},
 	/* likes toys*/
 	/* Reduced weight, changed eyes, added nail polish -BoneyM*/
@@ -1646,19 +1632,13 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "cornrows",
 		boobs: 800,
-		nipplesPiercing: 1,
 		butt: 4,
 		lips: 35,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		clit: 1,
-		clitPiercing: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 2,
-		nosePiercing: 1,
-		eyebrowPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -1673,8 +1653,7 @@ App.Data.HeroSlaves.D = [
 		areolae: 2,
 		nipples: "huge",
 		voice: 1,
-		navelPiercing: 1,
-		tonguePiercing: 1
+		piercing: {nipple: {weight: 1}, tongue: {weight: 1}, vagina: {weight: 1}, ear: {weight: 2}, nose: {weight: 1}, eyebrow: {weight: 1}, navel: {weight: 1}, genitals: {weight: 1}}
 	},
 	/* big clit*/
 	/* Changed eyes to hazel, increased clit, added a lot of piercings, changed fetish to nympho, fixed customDesc syntax -BoneyM*/
@@ -1697,14 +1676,11 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "luxurious",
 		boobs: 800,
-		nipplesPiercing: 1,
 		butt: 4,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		anus: 2,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 100,
 			oral: 100,
@@ -1716,6 +1692,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "humiliation",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, ear: {weight: 1}},
 		custom: {desc: "$He has the air of a princess."}
 	},
 	/* Changed eyes to blue, added origin, pierced ears, fixed customDesc syntax -BoneyM*/
@@ -1735,14 +1712,9 @@ App.Data.HeroSlaves.D = [
 		hLength: 10,
 		underArmHStyle: "bald",
 		boobs: 300,
-		nipplesPiercing: 1,
 		butt: 3,
-		lipsPiercing: 2,
-		tonguePiercing: 2,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
-		clitPiercing: 1,
 		anus: 2,
 		ovaries: 1,
 		skill: {
@@ -1757,6 +1729,7 @@ App.Data.HeroSlaves.D = [
 		energy: 100,
 		attrXY: 100,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 2}, tongue: {weight: 2}, vagina: {weight: 1}, genitals: {weight: 1}},
 		custom: {
 			desc: "$He has a scar on the back of $his head, concealed by $his hair."
 		},
@@ -1851,7 +1824,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 35,
@@ -1861,6 +1833,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "cumslut",
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}},
 		custom: {
 			desc: "$He is friendly, clever, and quick."
 		},
@@ -1973,7 +1946,6 @@ App.Data.HeroSlaves.D = [
 		vagina: 1,
 		vaginaLube: 1,
 		anus: 2,
-		nosePiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -1981,7 +1953,8 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXX: 80,
 		attrXY: 40,
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nose: {weight: 1}}
 	},
 	/* Added nose piercing, reduced height, changed fetish to bisexual -BoneyM*/
 	{
@@ -2010,7 +1983,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 100
@@ -2021,6 +1993,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "buttslut",
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}},
 		custom: {
 			desc: "$He has fetishes for wedgies, spanking and herms."
 		},
@@ -2109,11 +2082,9 @@ App.Data.HeroSlaves.D = [
 		devotion: 60,
 		hStyle: "neat",
 		boobs: 500,
-		nipplesPiercing: 1,
 		butt: 3,
 		vagina: 2,
 		vaginaLube: 1,
-		clitPiercing: 1,
 		anus: 2,
 		ovaries: 1,
 		skill: {
@@ -2123,7 +2094,8 @@ App.Data.HeroSlaves.D = [
 		},
 		clothes: "attractive lingerie",
 		attrXY: 40,
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, genitals: {weight: 1}}
 	},
 	/* Couldn't find this slave in the thread or the submission page on the blog -BoneyM*/
 	{
@@ -2190,11 +2162,8 @@ App.Data.HeroSlaves.D = [
 		butt: 3,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 2,
-		nosePiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 35,
@@ -2205,6 +2174,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "bitchy",
+		piercing: {ear: {weight: 2}, nose: {weight: 1}, genitals: {weight: 1}},
 		custom: {desc: "$He has piercings along $his collarbones and corset piercings with red ribbons down $his lower back and thighs."},
 		height: 168
 	},
@@ -2228,16 +2198,12 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "neat",
 		boobs: 500,
-		nipplesPiercing: 1,
 		butt: 3,
 		lips: 35,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
-		clitPiercing: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -2247,6 +2213,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "arrogant",
+		piercing: {nipple: {weight: 1}, vagina: {weight: 1}, ear: {weight: 1}, genitals: {weight: 1}},
 		custom: {desc: "$He is extremely claustrophobic."}
 	},
 	/* claustrophobia, pride*/
@@ -2286,7 +2253,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -2298,6 +2264,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "bitchy",
+		piercing: {ear: {weight: 1}},
 		custom: {
 			tattoo: "$He has a pair of full sleeve tattoos.",
 			desc: "$He has many scars, and is skilled with plants."
@@ -2323,13 +2290,10 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "neat",
 		boobs: 300,
-		nipplesPiercing: 1,
 		butt: 1,
 		face: 60,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "off",
 		anus: 2,
 		ovaries: 1,
 		skill: {
@@ -2341,6 +2305,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "submissive",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "off",
 		custom: {
 			tattoo: "$He has 'Use Backdoor' tattooed above $his vagina and, in tribal tattoos, 'Anal Slut' on $his back.",
 			desc: "$He wears a dog collar with lights that indicate $his arousal and was bought wearing a vaginal chastity belt."
@@ -2371,7 +2337,6 @@ App.Data.HeroSlaves.D = [
 		boobs: 1200,
 		boobsImplant: 800,
 		boobsImplantType: "fillable",
-		nipplesPiercing: 2,
 		lactation: 1,
 		lactationDuration: 2,
 		butt: 6,
@@ -2381,14 +2346,10 @@ App.Data.HeroSlaves.D = [
 		faceImplant: 15,
 		lips: 35,
 		lipsImplant: 10,
-		lipsPiercing: 1,
-		tonguePiercing: 1,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 2,
 		skill: {
 			vaginal: 35,
 			oral: 35,
@@ -2396,11 +2357,11 @@ App.Data.HeroSlaves.D = [
 		},
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 2}, lips: {weight: 1}, tongue: {weight: 1}, ear: {weight: 2}, navel: {weight: 1}, genitals: {weight: 1}},
 		custom: {
 			tattoo: "$He has many girly tattoos.",
 			desc: "$He loves hair play."
-		},
-		navelPiercing: 1
+		}
 	},
 	/* Reduced weight, increased face and face implant, added piercings, corrected tattoo and customDesc syntax -BoneyM*/
 	{
@@ -2458,18 +2419,15 @@ App.Data.HeroSlaves.D = [
 		boobs: 300,
 		butt: 5,
 		lips: 35,
-		lipsPiercing: 1,
-		tonguePiercing: 1,
 		vaginaLube: 1,
 		ovaries: 1,
-		earPiercing: 1,
-		eyebrowPiercing: 1,
 		skill: {
 			oral: 35
 		},
 		intelligence: -60,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {lips: {weight: 1}, tongue: {weight: 1}, ear: {weight: 1}, eyebrow: {weight: 1}},
 		custom: {desc: "$He has a heart shaped face and many scars."},
 		faceShape: "cute",
 		hips: 3,
@@ -2528,14 +2486,13 @@ App.Data.HeroSlaves.D = [
 		hStyle: "neat",
 		boobs: 500,
 		nipples: "inverted",
-		nipplesPiercing: 1,
 		butt: 3,
-		clitPiercing: 1,
 		ovaries: 1,
 		clothes: "attractive lingerie",
 		intelligence: 30,
 		intelligenceImplant: 30,
-		attrXY: 40
+		attrXY: 40,
+		piercing: {nipple: {weight: 1}, genitals: {weight: 1}}
 	},
 	/* love*/
 	/* Added origin, removed it from customDesc. Increased health.*/
@@ -2563,7 +2520,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 35,
 			oral: 35,
@@ -2572,6 +2528,7 @@ App.Data.HeroSlaves.D = [
 		energy: 100,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}},
 		custom: {desc: "$He is trim and fit."}
 	},
 	/* genki*/
@@ -2629,17 +2586,16 @@ App.Data.HeroSlaves.D = [
 		hLength: 60,
 		hStyle: "neat",
 		boobs: 1400,
-		nipplesPiercing: 1,
 		butt: 4,
 		vagina: 1,
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		nosePiercing: 1,
 		attrXY: 40,
 		behavioralFlaw: "arrogant",
 		fetishKnown: 1,
-		sexualFlaw: "hates penetration"
+		sexualFlaw: "hates penetration",
+		piercing: {nipple: {weight: 1}, nose: {weight: 1}}
 	},
 	/* hates sex*/
 	/* Corrected hair color, added piercings, added 'hates penetration' -BoneyM*/
@@ -2711,11 +2667,8 @@ App.Data.HeroSlaves.D = [
 		hStyle: "neat",
 		pubicHStyle: "neat",
 		boobs: 300,
-		nipplesPiercing: 1,
 		butt: 3,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "oral",
 		anus: 2,
 		ovaries: 1,
 		skill: {
@@ -2727,6 +2680,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "cumslut",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "oral",
 		custom: {desc: "$He is fit and athletic."},
 		behavioralFlaw: "arrogant",
 		hips: 1
@@ -2845,7 +2800,6 @@ App.Data.HeroSlaves.D = [
 		vaginaLube: 1,
 		anus: 1,
 		ovaries: 1,
-		earPiercing: 1,
 		skill: {
 			vaginal: 35,
 			oral: 35,
@@ -2859,6 +2813,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "arrogant",
+		piercing: {ear: {weight: 1}},
 		custom: {
 			tattoo: "$He has a fine, intricate vine-like tattoo around $his right ankle."
 		},
@@ -2959,16 +2914,15 @@ App.Data.HeroSlaves.D = [
 		hStyle: "neat",
 		waist: -55,
 		boobs: 700,
-		nipplesPiercing: 1,
 		butt: 2,
 		face: 55,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "all",
 		ovaries: 1,
 		anusTat: "bleached",
 		attrXY: 40,
-		fetish: "pregnancy"
+		fetish: "pregnancy",
+		piercing: {nipple: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "all"
 	},
 	{
 		ID: 900078,
@@ -2989,10 +2943,8 @@ App.Data.HeroSlaves.D = [
 		hLength: 5,
 		hStyle: "a poor emulation of a military cut",
 		boobs: 250,
-		nipplesPiercing: 1,
 		butt: 5,
 		buttTat: "tribal patterns",
-		lipsPiercing: 1,
 		lipsTat: "tribal patterns",
 		vagina: 1,
 		vaginaLube: 1,
@@ -3001,10 +2953,6 @@ App.Data.HeroSlaves.D = [
 		anus: 1,
 		ovaries: 1,
 		anusTat: "tribal patterns",
-		earPiercing: 1,
-		nosePiercing: 1,
-		eyebrowPiercing: 1,
-		navelPiercing: 1,
 		shouldersTat: "tribal patterns",
 		armsTat: "tribal patterns",
 		legsTat: "tribal patterns",
@@ -3025,6 +2973,7 @@ App.Data.HeroSlaves.D = [
 		attrXX: 80,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 1}, ear: {weight: 1}, nose: {weight: 1}, eyebrow: {weight: 1}, navel: {weight: 1}},
 		custom: {
 			desc: "Amongst the scars that decorate $his body, one in the shape of a heart can be made out on the top of $his right hand."
 		},
@@ -3070,12 +3019,9 @@ App.Data.HeroSlaves.D = [
 		pubicHStyle: "bushy",
 		waist: -55,
 		boobs: 400,
-		nipplesPiercing: 1,
 		butt: 4,
 		face: 15,
 		faceImplant: 65,
-		lipsPiercing: 1,
-		tonguePiercing: 1,
 		vagina: 1,
 		vaginaLube: 1,
 		anus: 1,
@@ -3083,9 +3029,6 @@ App.Data.HeroSlaves.D = [
 		anusTat: "bleached",
 		makeup: 2,
 		nails: 1,
-		earPiercing: 1,
-		nosePiercing: 1,
-		eyebrowPiercing: 1,
 		skill: {
 			whoring: 15,
 			entertainment: 15,
@@ -3098,6 +3041,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "boobs",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 1}, tongue: {weight: 1}, ear: {weight: 1}, nose: {weight: 1}, eyebrow: {weight: 1}},
 		eye: {
 			origColor: "white",
 			left: {
@@ -3134,8 +3078,6 @@ App.Data.HeroSlaves.D = [
 		face: 55,
 		lips: 35,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "submissive",
 		ovaries: 1,
 		skill: {
 			oral: 100
@@ -3145,6 +3087,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "submissive",
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "submissive",
 		custom: {tattoo: "$His name is tattooed in flowing cursive script across $his upper back. "}
 	},
 	{
@@ -3171,8 +3115,6 @@ App.Data.HeroSlaves.D = [
 		vagina: 2,
 		vaginaLube: 1,
 		clit: 1,
-		clitPiercing: 3,
-		clitSetting: "anal",
 		boobs: 650,
 		boobsImplant: 200,
 		boobsImplantType: "normal",
@@ -3182,11 +3124,9 @@ App.Data.HeroSlaves.D = [
 		faceImplant: 65,
 		anus: 1,
 		ovaries: 1,
-		anusPiercing: 2,
 		anusTat: "bleached",
 		makeup: 2,
 		nails: 2,
-		earPiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15
@@ -3199,6 +3139,8 @@ App.Data.HeroSlaves.D = [
 		fetish: "buttslut",
 		fetishKnown: 1,
 		markings: "freckles",
+		piercing: {anus: {weight: 2}, ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "anal",
 		custom: {
 			desc: "$His pale skin is lightly freckled, and $his nipples are dark tan. $He used to be sexually repressed, and used to hate anal sex."
 		},
@@ -3234,18 +3176,13 @@ App.Data.HeroSlaves.D = [
 		pubicHStyle: "in a strip",
 		waist: -55,
 		boobs: 1450,
-		nipplesPiercing: 2,
 		butt: 5,
 		lips: 55,
 		vagina: 2,
 		vaginaLube: 1,
-		clit: 2,
-		clitPiercing: 2,
-		clitSetting: "women",
 		anus: 2,
 		ovaries: 1,
 		anusTat: "bleached",
-		earPiercing: 1,
 		skill: {
 			vaginal: 100,
 			oral: 100,
@@ -3260,6 +3197,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "arrogant",
+		piercing: {nipple: {weight: 2}, ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "women",
 		custom: {
 			tattoo: "$He has tattoo of cobra wrapping around $his neck, which head with wide open maw and inflated hood tattooed right at $his throat.",
 			desc: "$He has a streak of ritual scars resembling some very complex snake skin pattern running down $his spine from nape to tail-bone."
@@ -3290,8 +3229,6 @@ App.Data.HeroSlaves.D = [
 		butt: 4,
 		vagina: 2,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "all",
 		anus: 2,
 		ovaries: 1,
 		skill: {
@@ -3308,6 +3245,8 @@ App.Data.HeroSlaves.D = [
 		energy: 100,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "all",
 		custom: {
 			tattoo: "$He has a small, grinning harlequin tattoo on $his inner thigh.",
 			desc: "In place of $his left hand's pinkie finger is a large pink scar that crosses the entire back of $his hand."
@@ -3402,21 +3341,15 @@ App.Data.HeroSlaves.D = [
 		hStyle: "disheveled",
 		waist: -55,
 		boobs: 500,
-		nipplesPiercing: 1,
 		butt: 3,
-		lipsPiercing: 1,
 		vagina: 1,
 		vaginaLube: 1,
-		clitPiercing: 1,
 		clitSetting: "anal",
 		anus: 1,
 		ovaries: 1,
 		anusTat: "bleached",
 		makeup: 2,
 		nails: 2,
-		earPiercing: 2,
-		nosePiercing: 1,
-		navelPiercing: 1,
 		skill: {
 			vaginal: 100,
 			oral: 100,
@@ -3429,8 +3362,9 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "buttslut",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 1}, ear: {weight: 2}, nose: {weight: 1}, navel: {weight: 1}, genitals: {weight: 1}},
 		custom: {
-			tattoo: "$He has been heavily tattooed, with $his chest, thighs}, and both arms covered in various punk-style pieces. The biggest and most impressive piece is the large logo of a legendary late 20th century punk band."
+			tattoo: "$He has been heavily tattooed, with $his chest, thighs, and both arms covered in various punk-style pieces. The biggest and most impressive piece is the large logo of a legendary late 20th century punk band."
 		},
 	},
 	{
@@ -3454,14 +3388,11 @@ App.Data.HeroSlaves.D = [
 		boobs: 3550,
 		boobsImplant: 3000,
 		boobsImplantType: "advanced fillable",
-		nipplesPiercing: 1,
 		areolae: 3,
 		boobsTat: "degradation",
 		butt: 2,
 		face: 15,
-		lipsPiercing: 2,
 		lipsTat: "degradation",
-		tonguePiercing: 2,
 		vaginaLube: 1,
 		anus: 2,
 		ovaries: 1,
@@ -3475,7 +3406,8 @@ App.Data.HeroSlaves.D = [
 		shoes: "heels",
 		attrXY: 40,
 		fetish: "cumslut",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 2}, tongue: {weight: 2}}
 	},
 	{
 		ID: 900087,
@@ -3495,8 +3427,6 @@ App.Data.HeroSlaves.D = [
 		vagina: 1,
 		vaginaLube: 1,
 		clit: 1,
-		clitPiercing: 3,
-		clitSetting: "humiliation",
 		anus: 1,
 		skill: {
 			vaginal: 100,
@@ -3511,6 +3441,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "humiliation",
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "humiliation",
 		custom: {desc: "$He is an enthusiastic high school graduate, eager to make $his teacher proud by becoming the greatest slave known to any owner."},
 		career: "a student"
 	},
@@ -3548,7 +3480,6 @@ App.Data.HeroSlaves.D = [
 		bellyAccessory: "a corset",
 		ovaries: 1,
 		anusTat: "flowers",
-		earPiercing: 1,
 		stampTat: "scenes",
 		skill: {
 			vaginal: 15,
@@ -3563,6 +3494,7 @@ App.Data.HeroSlaves.D = [
 		fetishKnown: 1,
 		behavioralFlaw: "hates men",
 		sexualFlaw: "crude",
+		piercing: {ear: {weight: 1}},
 		custom: {desc: "$He absolutely detests men."},
 		career: "a principal"
 	},
@@ -3590,7 +3522,6 @@ App.Data.HeroSlaves.D = [
 		butt: 3,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		preg: 27,
 		pregType: 1,
 		pregWeek: 27,
@@ -3604,7 +3535,6 @@ App.Data.HeroSlaves.D = [
 		anus: 3,
 		ovaries: 1,
 		brand: {"right buttock": "SLAVE"},
-		earPiercing: 1,
 		skill: {
 			vaginal: 100,
 			oral: 100,
@@ -3619,7 +3549,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishKnown: 1,
 		face: 0,
-		intelligence: 0
+		intelligence: 0,
+		piercing: {vagina: {weight: 1}, ear: {weight: 1}}
 	},
 	{
 		ID: 900090,
@@ -3642,15 +3573,10 @@ App.Data.HeroSlaves.D = [
 		butt: 5,
 		vagina: 3,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
-		clitPiercing: 3,
-		clitSetting: "vanilla",
 		anus: 3,
 		ovaries: 1,
-		anusPiercing: 1,
 		makeup: 1,
 		brand: {"right buttock": "SLAVE"},
-		earPiercing: 1,
 		skill: {
 			vaginal: 100,
 			oral: 100,
@@ -3664,6 +3590,8 @@ App.Data.HeroSlaves.D = [
 		intelligenceImplant: 30,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {vagina: {weight: 2}, anus: {weight: 1}, ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "vanilla",
 		custom: {
 			tattoo: "$His nickname, 'Horsepussy,' is tattooed on $his forehead.",
 			desc: "$His pussy has been extensively surgically altered. $His labia are large and puffy, sticking out nearly an inch from $his crotch. $His cunt is exquisitely pink at the center, but $his large labia are dark at the edges, almost black.",
@@ -3687,8 +3615,6 @@ App.Data.HeroSlaves.D = [
 		butt: 1,
 		face: 15,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "submissive",
 		analArea: 1,
 		ovaries: 1,
 		skill: {
@@ -3702,6 +3628,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "submissive",
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "submissive",
 		custom: {
 			tattoo: "$He has a tattoo of falling cherry petals on $his back, starting at $his shoulder blades, down to $his butt.",
 			desc: "$He has a small scar on the back of $his right hand. $He was injured while participating in the finals of a national kendo tournament, and decided to keep the scar to remind $him of $his achievements."
@@ -3733,8 +3661,6 @@ App.Data.HeroSlaves.D = [
 		vagina: 1,
 		vaginaLube: 1,
 		clit: 1,
-		clitPiercing: 3,
-		clitSetting: "all",
 		anus: 2,
 		skill: {
 			vaginal: 100,
@@ -3752,6 +3678,8 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetishStrength: 100,
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "all",
 		custom: {desc: "$He was once a skilled police investigator. Even at $his age, $his long, enticing legs are proof that $he still retains $his natural strength and beauty."},
 		career: "a police detective"
 	},
@@ -3778,8 +3706,6 @@ App.Data.HeroSlaves.D = [
 		face: 55,
 		lips: 35,
 		vaginaLube: 1,
-		clitPiercing: 3,
-		clitSetting: "oral",
 		ovaries: 1,
 		anusTat: "bleached",
 		skill: {
@@ -3814,6 +3740,8 @@ App.Data.HeroSlaves.D = [
 			hColor: "white",
 			skin: "extremely pale"
 		},
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "oral",
 		custom: {
 			tattoo: "$His entire body is tattooed with a detailed map of $his arteries which, combined with $his albinism, gives $him a quasi-translucent quality.",
 			desc: "$His eyes are unsettling; though $his irises are a pale grey color, in some lights the whole eye takes on a red cast."
@@ -3879,17 +3807,14 @@ App.Data.HeroSlaves.D = [
 		boobs: 650,
 		boobsImplant: 200,
 		boobsImplantType: "normal",
-		nipplesPiercing: 2,
 		butt: 3,
 		buttImplant: 1,
 		buttImplantType: "normal",
 		face: 55,
 		faceImplant: 15,
 		lips: 35,
-		tonguePiercing: 1,
 		vagina: 3,
 		vaginaLube: 1,
-		clitPiercing: 1,
 		anus: 3,
 		ovaries: 1,
 		brand: {"right buttock": "your initials"},
@@ -3908,7 +3833,8 @@ App.Data.HeroSlaves.D = [
 		intelligenceImplant: 30,
 		energy: 100,
 		attrXY: 40,
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {nipple: {weight: 2}, tongue: {weight: 1}, genitals: {weight: 1}}
 	},
 	{
 		ID: 900096,
@@ -3953,7 +3879,6 @@ App.Data.HeroSlaves.D = [
 		anus: 1,
 		ovaries: 1,
 		anusTat: "bovine patterns",
-		earPiercing: 1,
 		shouldersTat: "bovine patterns",
 		armsTat: "bovine patterns",
 		legsTat: "bovine patterns",
@@ -3980,6 +3905,7 @@ App.Data.HeroSlaves.D = [
 		attrXY: 40,
 		fetish: "boobs",
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}},
 		custom: {
 			desc: "$He is quite sweaty, often soaking though any clothing $he is wearing."
 		},
@@ -4001,29 +3927,18 @@ App.Data.HeroSlaves.D = [
 		hStyle: "shaved",
 		pubicHStyle: "bushy",
 		boobs: 600,
-		nipplesPiercing: 1,
 		boobsTat: "tribal patterns",
 		butt: 2,
 		buttTat: "tribal patterns",
 		face: 55,
 		faceImplant: 15,
 		lips: 35,
-		lipsPiercing: 1,
 		lipsTat: "tribal patterns",
-		tonguePiercing: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 1,
 		vaginaTat: "tribal patterns",
 		preg: -2,
-		clitPiercing: 3,
-		clitSetting: "all",
 		ovaries: 1,
-		anusPiercing: 1,
 		anusTat: "bleached",
-		earPiercing: 1,
-		nosePiercing: 1,
-		eyebrowPiercing: 1,
-		navelPiercing: 1,
 		shouldersTat: "tribal patterns",
 		armsTat: "tribal patterns",
 		legsTat: "tribal patterns",
@@ -4051,6 +3966,8 @@ App.Data.HeroSlaves.D = [
 		energy: 100,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, lips: {weight: 1}, tongue: {weight: 1}, vagina: {weight: 1}, anus: {weight: 1}, ear: {weight: 1}, nose: {weight: 1}, eyebrow: {weight: 1}, navel: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "all",
 		custom: {
 			tattoo: "$He has a barcode tattooed on the top of $his head.",
 			desc: "$His skin is unnaturally perfect, totally without blemishes. $He radiates unnatural health and resilience."
@@ -4081,7 +3998,7 @@ App.Data.HeroSlaves.D = [
 ];
 /* Removed eye color customDesc -BoneyM*/
 /**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.Dextreme = [
 	{
@@ -4225,7 +4142,6 @@ App.Data.HeroSlaves.Dextreme = [
 		boobs: 6260,
 		boobsImplant: 4200,
 		boobsImplantType: "string",
-		nipplesPiercing: 2,
 		areolae: 3,
 		boobsTat: "flowers",
 		lactation: 2,
@@ -4238,12 +4154,9 @@ App.Data.HeroSlaves.Dextreme = [
 		faceImplant: 15,
 		lips: 55,
 		lipsImplant: 10,
-		lipsPiercing: 2,
 		lipsTat: "flowers",
-		tonguePiercing: 2,
 		vagina: 3,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		vaginaTat: "flowers",
 		preg: 37,
 		pregType: 1,
@@ -4255,17 +4168,10 @@ App.Data.HeroSlaves.Dextreme = [
 			births: 2,
 			birthsTotal: 2
 		},
-		clitPiercing: 3,
-		clitSetting: "boobs",
 		anus: 2,
 		ovaries: 1,
-		anusPiercing: 2,
 		anusTat: "flowers",
 		makeup: 3,
-		earPiercing: 2,
-		nosePiercing: 2,
-		eyebrowPiercing: 2,
-		navelPiercing: 2,
 		shouldersTat: "advertisements",
 		stampTat: "flowers",
 		skill: {
@@ -4283,6 +4189,8 @@ App.Data.HeroSlaves.Dextreme = [
 		attrXY: 40,
 		fetish: "boobs",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 2}, lips: {weight: 2}, tongue: {weight: 2}, vagina: {weight: 2}, anus: {weight: 2}, ear: {weight: 2}, nose: {weight: 2}, eyebrow: {weight: 2}, navel: {weight: 2}, genitals: {weight: 2, smart: true}},
+		clitSetting: "boobs",
 		removedLimbs: [1, 1, 1, 1]
 	},
 	{
@@ -4312,8 +4220,6 @@ App.Data.HeroSlaves.Dextreme = [
 		vagina: 2,
 		vaginaLube: 1,
 		bellyAccessory: "an extreme corset",
-		clitPiercing: 3,
-		clitSetting: "submissive",
 		anus: 2,
 		ovaries: 1,
 		stampTat: "degradation",
@@ -4331,6 +4237,8 @@ App.Data.HeroSlaves.Dextreme = [
 		attrXY: 40,
 		fetish: "submissive",
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "submissive",
 		custom: {tattoo: "$His left butt cheek is tattooed with a small shield bearing the words 'Daughter of Liberty' with a large red 'not' symbol added over it."}
 	},
 	{
@@ -4477,11 +4385,8 @@ App.Data.HeroSlaves.Dextreme = [
 		buttImplantType: "normal",
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
-		clitPiercing: 1,
 		anus: 2,
 		anusTat: "tribal patterns",
-		nosePiercing: 1,
 		skill: {
 			vaginal: 15,
 			oral: 15,
@@ -4491,7 +4396,8 @@ App.Data.HeroSlaves.Dextreme = [
 		attrXY: 40,
 		attrKnown: 0,
 		fetish: "mindbroken",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {vagina: {weight: 2}, nose: {weight: 1}, genitals: {weight: 1}}
 	},
 	/* mindbroken*/
 	/* Tweaked smart piercing setting, corrected piercings -BoneyM*/
@@ -4650,7 +4556,6 @@ App.Data.HeroSlaves.Dextreme = [
 		butt: 2,
 		face: 100,
 		lips: 25,
-		earPiercing: 1,
 		skill: {
 			oral: 15,
 			entertainment: 100
@@ -4660,6 +4565,7 @@ App.Data.HeroSlaves.Dextreme = [
 		fetish: "boobs",
 		fetishStrength: 70,
 		behavioralFlaw: "arrogant",
+		piercing: {ear: {weight: 1}},
 		custom: {desc: "$He has an identical twin sister named Kennerly, from whom $he hates to be parted. They're from the former United States."},
 		mother: -9999,
 		father: -9998
@@ -4695,8 +4601,6 @@ App.Data.HeroSlaves.Dextreme = [
 		butt: 2,
 		face: 100,
 		lips: 15,
-		earPiercing: 1,
-		navelPiercing: 1,
 		skill: {
 			oral: 15,
 			entertainment: 100
@@ -4706,6 +4610,7 @@ App.Data.HeroSlaves.Dextreme = [
 		fetish: "boobs",
 		fetishStrength: 70,
 		behavioralFlaw: "arrogant",
+		piercing: {ear: {weight: 1}, navel: {weight: 1}},
 		custom: {desc: "$He has an identical twin sister named Camille, from whom $he hates to be parted. They're from the former United States."},
 		mother: -9999,
 		father: -9998
diff --git a/src/npc/databases/ddSlavesDatabase.js b/src/npc/databases/ddSlavesDatabase.js
index b0a33c8f6d3..0e213158b6d 100644
--- a/src/npc/databases/ddSlavesDatabase.js
+++ b/src/npc/databases/ddSlavesDatabase.js
@@ -1,25 +1,7 @@
 /* eslint-disable camelcase */
 
 /**
- * @typedef {object} missingProperties
- * @property {any} health
- * @property {any} skill
- * @property {any} custom
- * @property {any} eye
- * @property {any} counter
- * @property {any} leg
- * @property {any} geneticQuirks
- * @property {any} rules
- * @property {Array<0|1>} removedLimbs //limbs to be removed
- */
-
-/**
- * @typedef {object} partialSlaveState
- * @type {App.Entity.SlaveState & missingProperties}
- */
-
-/**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.DD = [
 	{
@@ -212,13 +194,10 @@ App.Data.HeroSlaves.DD = [
 		boobs: 1000,
 		boobsImplant: 600,
 		boobsImplantType: "normal",
-		nipplesPiercing: 1,
 		lips: 55,
 		lipsImplant: 10,
 		vagina: -1,
 		preg: -2,
-		clitPiercing: 3,
-		clitSetting: "anal",
 		dick: 5,
 		anus: 2,
 		prostate: 1,
@@ -230,6 +209,8 @@ App.Data.HeroSlaves.DD = [
 		attrXX: 40,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "anal",
 		brand: {"left testicle": "a brand of a former master"},
 		stampTat: "$He has a fairly generic tramp stamp.",
 		career: "a gang leader"
@@ -509,7 +490,6 @@ App.Data.HeroSlaves.DD = [
 		boobs: 1000,
 		boobsImplant: 600,
 		boobsImplantType: "normal",
-		nipplesPiercing: 2,
 		lactation: 1,
 		lactationDuration: 2,
 		butt: 5,
@@ -517,7 +497,6 @@ App.Data.HeroSlaves.DD = [
 		buttImplantType: "normal",
 		lips: 35,
 		lipsImplant: 10,
-		lipsPiercing: 1,
 		vagina: 1,
 		preg: -2,
 		dick: 5,
@@ -533,7 +512,7 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetishKnown: 1,
 		custom: {tattoo: "$He has many girly tattoos.", desc: "$He likes hair play."},
-		navelPiercing: 1
+		piercing: {nipple: {weight: 2}, lips: {weight: 1}, navel: {weight: 1}}
 	},
 	{
 		ID: 800014,
@@ -556,7 +535,6 @@ App.Data.HeroSlaves.DD = [
 		hStyle: "braided",
 		hLength: 60,
 		boobs: 1800,
-		nipplesPiercing: 1,
 		shoulders: -1,
 		waist: -20,
 		hips: 1,
@@ -576,6 +554,7 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetish: "submissive",
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 1}},
 		custom: {desc: "$He has a slim and perfectly feminine frame except for $his big feet and ears. $He's very intelligent and well learned."}
 	},
 	{
@@ -791,13 +770,10 @@ App.Data.HeroSlaves.DD = [
 		preg: -2,
 		dick: 5,
 		anus: 2,
-		dickPiercing: 1,
 		prostate: 1,
 		balls: 2,
 		scrotum: 2,
 		anusTat: "bleached",
-		earPiercing: 1,
-		navelPiercing: 1,
 		skill: {anal: 100, combat: 1},
 		addict: 50,
 		intelligence: 20,
@@ -807,7 +783,8 @@ App.Data.HeroSlaves.DD = [
 		fetish: "buttslut",
 		fetishKnown: 1,
 		behavioralFlaw: "odd",
-		custom: {desc: "$He has a large police badge made of polished silver pinned right to the skin with several barbell piercings just above $his left nipple. $He wears two pairs of handcuffs as bracelets (one pair on each wrist); the handcuff keyholes are welded, so they cannot be unlocked and removed in any normal way."},
+		piercing: {dick: {weight: 1}, ear: {weight: 1}, navel: {weight: 1}, areola: {weight: 2, desc:  "$He has a large police badge made of polished silver pinned right to the skin with several barbell piercings just above $his left nipple."}},
+		custom: {desc: "$He wears two pairs of handcuffs as bracelets (one pair on each wrist); the handcuff keyholes are welded, so they cannot be unlocked and removed in any normal way."},
 		career: "a security guard"
 	},
 	{
@@ -839,7 +816,6 @@ App.Data.HeroSlaves.DD = [
 		anusTat: "flowers",
 		makeup: 1,
 		nails: 1,
-		earPiercing: 1,
 		shouldersTat: "tribal patterns",
 		armsTat: "rude words",
 		stampTat: "rude words",
@@ -852,6 +828,7 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetish: "buttslut",
 		fetishKnown: 1,
+		piercing: {ear: {weight: 1}},
 		custom: {desc: "A palm sized ring adorns the end of $his braid, perfect for grabbing and pulling during any occasion."}
 	},
 	{
@@ -873,7 +850,6 @@ App.Data.HeroSlaves.DD = [
 		boobs: 9200,
 		boobsImplant: 6000,
 		boobsImplantType: "advanced fillable",
-		nipplesPiercing: 2,
 		boobsTat: "bovine patterns",
 		lactation: 2,
 		lactationDuration: 2,
@@ -886,28 +862,19 @@ App.Data.HeroSlaves.DD = [
 		faceImplant: 65,
 		lips: 55,
 		lipsImplant: 2,
-		lipsPiercing: 2,
 		lipsTat: "bovine patterns",
-		tonguePiercing: 2,
 		vagina: 2,
-		vaginaPiercing: 2,
 		vaginaTat: "bovine patterns",
 		preg: -2,
-		clitPiercing: 3,
 		anus: 2,
 		dick: 5,
 		prostate: 1,
 		balls: 3,
 		scrotum: 2,
-		anusPiercing: 2,
 		anusTat: "bovine patterns",
 		makeup: 2,
 		nails: 2,
 		brand: {"right buttock": "SLUT"},
-		earPiercing: 2,
-		nosePiercing: 2,
-		eyebrowPiercing: 2,
-		navelPiercing: 2,
 		shouldersTat: "bovine patterns",
 		armsTat: "bovine patterns",
 		legsTat: "bovine patterns",
@@ -926,6 +893,8 @@ App.Data.HeroSlaves.DD = [
 		attrXX: 40,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {nipple: {weight: 2}, lips: {weight: 2}, tongue: {weight: 2}, vagina: {weight: 2}, anus: {weight: 2}, ear: {weight: 2}, nose: {weight: 2}, eyebrow: {weight: 2}, navel: {weight: 2}, genitals: {weight: 2, smart: true}},
+		clitSetting: "boobs",
 		custom: {
 			tattoo: "$He has tattoos of teasing, enticing messages begging others to come taste $his addictive milk.",
 			desc: "$His musky milky aura drives men and women around $him giggly and dumb with lust."
@@ -953,7 +922,6 @@ App.Data.HeroSlaves.DD = [
 		hStyle: "ponytail",
 		pubicHStyle: "bushy",
 		boobs: 650,
-		nipplesPiercing: 1,
 		areolae: 2,
 		lactation: 2,
 		lactationDuration: 2,
@@ -961,15 +929,12 @@ App.Data.HeroSlaves.DD = [
 		lips: 35,
 		vagina: -1,
 		preg: -2,
-		clitPiercing: 3,
 		dick: 4,
 		prostate: 1,
 		balls: 5,
 		scrotum: 4,
-		anusPiercing: 1,
 		makeup: 1,
 		nails: 1,
-		earPiercing: 1,
 		skill: {entertainment: 35},
 		clothes: "cutoffs and a t-shirt",
 		collar: "pretty jewelry",
@@ -980,6 +945,8 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "odd",
+		piercing: {nipple: {weight: 1}, anus: {weight: 1}, ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "off",
 		custom: {
 			tattoo: "$He has a blood red, faux brand tattoo on $his left ass cheek.",
 			desc: "$He has a nearly faded pockmark on the skin above $his left eyebrow, the last reminder of $his awkward past."
@@ -1016,17 +983,14 @@ App.Data.HeroSlaves.DD = [
 		faceImplant: 65,
 		vagina: -1,
 		preg: -2,
-		clitPiercing: 3,
 		anus: 1,
 		dick: 5,
 		dickTat: "flowers",
 		prostate: 1,
 		balls: 2,
 		scrotum: 2,
-		anusPiercing: 1,
 		anusTat: "flowers",
 		brand: {"back": "your initials"},
-		earPiercing: 1,
 		skill: {oral: 15, anal: 15, entertainment: 15},
 		clothes: "a comfortable bodysuit",
 		collar: "pretty jewelry",
@@ -1034,6 +998,8 @@ App.Data.HeroSlaves.DD = [
 		intelligence: -30,
 		attrXX: 40,
 		attrXY: 40,
+		piercing: {anus: {weight: 1}, ear: {weight: 1}, genitals: {weight: 2, smart: true}},
+		clitSetting: "off",
 		custom: {
 			tattoo: "$He has tattooed petals trailing from the nape of $his neck down $his back, ending between $his butt cheeks.",
 			desc: "$His red pubic hair is waxed into the shape of a heart. $He has bright blue eyeshadow on $his bottom lids."
@@ -1071,8 +1037,6 @@ App.Data.HeroSlaves.DD = [
 		scrotum: 2,
 		makeup: 1,
 		nails: 1,
-		earPiercing: 1,
-		navelPiercing: 1,
 		skill: {oral: 15},
 		collar: "pretty jewelry",
 		shoes: "heels",
@@ -1080,6 +1044,7 @@ App.Data.HeroSlaves.DD = [
 		intelligenceImplant: 30,
 		attrXX: 40,
 		attrXY: 40,
+		piercing: {ear: {weight: 1}, navel: {weight: 1}},
 		career: "a spy"
 	},
 	{
@@ -1117,7 +1082,6 @@ App.Data.HeroSlaves.DD = [
 		faceImplant: 15,
 		lips: 35,
 		lipsTat: "permanent makeup",
-		tonguePiercing: 1,
 		vagina: -1,
 		preg: -2,
 		anus: 1,
@@ -1127,7 +1091,6 @@ App.Data.HeroSlaves.DD = [
 		scrotum: 4,
 		anusTat: "bleached",
 		nails: 3,
-		earPiercing: 1,
 		legsTat: "flowers",
 		stampTat: "flowers",
 		skill: {oral: 100, anal: 100, whoring: 100},
@@ -1141,6 +1104,7 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetishKnown: 1,
 		behavioralFlaw: "arrogant",
+		piercing: {tongue: {weight: 1}, ear: {weight: 1}},
 		custom: {
 			tattoo: "$He has two neon-blue butterflies tattooed on $his right temple and one more right above $his right eyebrow; a bright blue, luminescent tattoo of an oriental dragon is intertwining with floral tattoos on $his right leg.",
 			desc: "$He is almost never seen without $his long, thin, lavishly decorated smoking pipe, either holding it in hand, or carrying it tucked in $his chignon."
@@ -1181,7 +1145,6 @@ App.Data.HeroSlaves.DD = [
 		scrotum: 2,
 		makeup: 1,
 		nails: 1,
-		earPiercing: 1,
 		skill: {oral: 15},
 		clothes: "a slutty maid outfit",
 		shoes: "heels",
@@ -1189,7 +1152,8 @@ App.Data.HeroSlaves.DD = [
 		attrXX: 40,
 		attrXY: 40,
 		fetish: "submissive",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {ear: {weight: 1}}
 	},
 	{
 		ID: 800028,
@@ -1219,7 +1183,6 @@ App.Data.HeroSlaves.DD = [
 		face: 55,
 		lips: 35,
 		preg: -2,
-		clitPiercing: 3,
 		dick: 4,
 		prostate: 1,
 		balls: 4,
@@ -1244,6 +1207,8 @@ App.Data.HeroSlaves.DD = [
 		attrXX: 40,
 		attrXY: 40,
 		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "off",
 		custom: {desc: "$He has the style of Gothic royalty, and the demeanor to match."}
 	},
 	{
@@ -1281,8 +1246,6 @@ App.Data.HeroSlaves.DD = [
 		faceImplant: 65,
 		lips: 35,
 		vagina: 1,
-		clitPiercing: 3,
-		clitSetting: "humiliation",
 		anus: 1,
 		dick: 5,
 		prostate: 1,
@@ -1305,7 +1268,9 @@ App.Data.HeroSlaves.DD = [
 		attrXX: 40,
 		attrXY: 40,
 		fetish: "humiliation",
-		fetishKnown: 1
+		fetishKnown: 1,
+		piercing: {genitals: {weight: 2, smart: true}},
+		clitSetting: "humiliation"
 	},
 	{
 		ID: 800030,
@@ -1401,7 +1366,6 @@ App.Data.HeroSlaves.DD = [
 		boobs: 1100,
 		boobsImplant: 400,
 		boobsImplantType: "normal",
-		nipplesPiercing: 1,
 		areolae: 1,
 		butt: 4,
 		buttImplant: 2,
@@ -1417,8 +1381,6 @@ App.Data.HeroSlaves.DD = [
 		anusTat: "bleached",
 		makeup: 3,
 		nails: 1,
-		earPiercing: 1,
-		navelPiercing: 1,
 		legsTat: "degradation",
 		stampTat: "degradation",
 		skill: {
@@ -1437,6 +1399,7 @@ App.Data.HeroSlaves.DD = [
 		attrXY: 40,
 		fetish: "humiliation",
 		behavioralFlaw: "arrogant",
+		piercing: {nipple: {weight: 1}, ear: {weight: 1}, navel: {weight: 1}},
 		custom: {
 			tattoo: "$He has a tattoo down $his left arm, which reads 'Once a tall, muscular, handsome man with a big dick and big balls.'",
 			desc: "Since becoming a slave $he has been turned into a little bimbo."
@@ -1445,7 +1408,7 @@ App.Data.HeroSlaves.DD = [
 ];
 
 /**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.DDextreme = [
 	{
@@ -1603,7 +1566,6 @@ App.Data.HeroSlaves.DDextreme = [
 		hStyle: "shaved",
 		waist: -55,
 		boobs: 100,
-		nipplesPiercing: 1,
 		butt: 1,
 		face: 15,
 		vagina: -1,
@@ -1613,16 +1575,14 @@ App.Data.HeroSlaves.DDextreme = [
 		balls: 3,
 		scrotum: 3,
 		anusTat: "bleached",
-		earPiercing: 1,
-		nosePiercing: 1,
-		navelPiercing: 1,
 		skill: {combat: 1},
 		intelligence: -40,
 		intelligenceImplant: 30,
 		attrXX: 40,
 		attrXY: 40,
 		behavioralFlaw: "bitchy",
-		career: "a soldier"
+		career: "a soldier",
+		piercing: {nipple: {weight: 1}, ear: {weight: 1}, nose: {weight: 1}, navel: {weight: 1}}
 	},
 
 	/* dickskilled*/
@@ -1658,14 +1618,11 @@ App.Data.HeroSlaves.DDextreme = [
 		vagina: -1,
 		vaginaTat: "bovine patterns",
 		preg: -3,
-		clitPiercing: 3,
-		clitSetting: "boobs",
 		anus: 2,
 		dick: 1,
 		dickTat: "bovine patterns",
 		prostate: 1,
 		anusTat: "bovine patterns",
-		nosePiercing: 2,
 		shouldersTat: "bovine patterns",
 		armsTat: "bovine patterns",
 		legsTat: "bovine patterns",
@@ -1677,6 +1634,8 @@ App.Data.HeroSlaves.DDextreme = [
 		fetish: "boobs",
 		fetishKnown: 1,
 		voice: 0,
+		piercing: {nose: {weight: 2}, genitals: {weight: 2, smart: true}},
+		clitSetting: "boobs",
 		custom: {desc: "Though $his vocal cords have been altered to keep $him from speaking, $he is still capable of the occasional moo."}
 	},
 	{
diff --git a/src/npc/databases/dfSlavesDatabase.js b/src/npc/databases/dfSlavesDatabase.js
index 8f7bda7f28c..0cc8d4f8cbc 100644
--- a/src/npc/databases/dfSlavesDatabase.js
+++ b/src/npc/databases/dfSlavesDatabase.js
@@ -1,7 +1,7 @@
 /* eslint-disable camelcase */
 
 /**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.DF = [
 	{
@@ -23,12 +23,10 @@ App.Data.HeroSlaves.DF = [
 		hLength: 60,
 		pubicHStyle: "waxed",
 		boobs: 500,
-		nipplesPiercing: 1,
 		butt: 3,
 		lips: 35,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		ovaries: 1,
 		skill: {vaginal: 35},
@@ -37,7 +35,7 @@ App.Data.HeroSlaves.DF = [
 		fetishKnown: 1,
 		lipsTat: "Two cherries are tattooed on $his left cheek.",
 		buttTat: "Two cherries are tattooed on $his right butt cheek.",
-		clitPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 		counter: {birthsTotal: 1}
 	},
 	/* vag implant, vibe nips*/
@@ -65,7 +63,6 @@ App.Data.HeroSlaves.DF = [
 		boobs: 1000,
 		boobsImplant: 400,
 		boobsImplantType: "normal",
-		nipplesPiercing: 1,
 		butt: 5,
 		buttImplant: 2,
 		buttImplantType: "normal",
@@ -73,7 +70,6 @@ App.Data.HeroSlaves.DF = [
 		lipsImplant: 10,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 2,
 		ovaries: 1,
@@ -83,7 +79,7 @@ App.Data.HeroSlaves.DF = [
 		fetishKnown: 1,
 		lipsTat: "Strawberries are tattooed on $his left cheek.",
 		buttTat: "Strawberries are tattooed on $his right buttock.",
-		clitPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 		counter: {birthsTotal: 2}
 	},
 	/* vibe nips, muscles*/
@@ -110,13 +106,11 @@ App.Data.HeroSlaves.DF = [
 		boobs: 1800,
 		boobsImplant: 800,
 		boobsImplantType: "fillable",
-		nipplesPiercing: 1,
 		butt: 4,
 		lips: 35,
 		lipsImplant: 10,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 2,
 		ovaries: 1,
@@ -127,8 +121,7 @@ App.Data.HeroSlaves.DF = [
 		lipsTat: "Watermelons are tattooed on $his face.",
 		buttTat: "Watermelons are tattooed on $his buttocks.",
 		teeth: "removable",
-		clitPiercing: 2,
-		lipsPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}, lips: {weight: 2}},
 		counter: {birthsTotal: 1}
 	},
 	/* vibe nips, saliva implant*/
@@ -153,14 +146,12 @@ App.Data.HeroSlaves.DF = [
 		hStyle: "in curly pigtails",
 		pubicHStyle: "waxed",
 		boobs: 650,
-		nipplesPiercing: 1,
 		butt: 8,
 		buttImplant: 4,
 		buttImplantType: "fillable",
 		lips: 35,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 3,
 		ovaries: 1,
@@ -170,8 +161,7 @@ App.Data.HeroSlaves.DF = [
 		fetishKnown: 1,
 		lipsTat: "Carambolas — starfruits — are tattooed on $his face.",
 		buttTat: "Carambolas — starfruits — are tattooed on $his buttocks.",
-		clitPiercing: 2,
-		tonguePiercing: 1,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}, tongue: {weight: 1}},
 		clothes: "no clothing",
 		collar: "bell collar",
 		heels: 1
@@ -191,12 +181,10 @@ App.Data.HeroSlaves.DF = [
 		pubicHColor: "black",
 		origSkin: "brown",
 		boobs: 400,
-		nipplesPiercing: 1,
 		butt: 5,
 		lips: 35,
 		vagina: 2,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 2,
 		ovaries: 1,
@@ -207,7 +195,7 @@ App.Data.HeroSlaves.DF = [
 		lipsTat: "Bananas are tattooed on $his face.",
 		buttTat: "Bananas are tattooed on $his buttocks.",
 		teeth: "removable",
-		clitPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 		hips: 1,
 		labia: 2,
 		clit: 1,
@@ -238,11 +226,9 @@ App.Data.HeroSlaves.DF = [
 		hStyle: "neat",
 		pubicHStyle: "waxed",
 		boobs: 650,
-		nipplesPiercing: 1,
 		butt: 4,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 1,
 		ovaries: 1,
@@ -254,7 +240,7 @@ App.Data.HeroSlaves.DF = [
 		buttTat: "Green grapes are tattooed on $his buttocks.",
 		mother: -9995,
 		father: -9994,
-		clitPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 		intelligence: -60
 	},
 	/* vibe nips, implant link to sister*/
@@ -277,11 +263,9 @@ App.Data.HeroSlaves.DF = [
 		hStyle: "neat",
 		pubicHStyle: "waxed",
 		boobs: 650,
-		nipplesPiercing: 1,
 		butt: 4,
 		vagina: 1,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 1,
 		ovaries: 1,
@@ -293,7 +277,7 @@ App.Data.HeroSlaves.DF = [
 		buttTat: "Purple grapes are tattooed on $his buttocks.",
 		mother: -9995,
 		father: -9994,
-		clitPiercing: 2,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 		intelligence: -60
 	},
 	/* vibe nips, implant link to sister */
@@ -317,13 +301,11 @@ App.Data.HeroSlaves.DF = [
 		hStyle: "neat",
 		pubicHStyle: "waxed",
 		boobs: 500,
-		nipplesPiercing: 1,
 		butt: 3,
 		lips: 55,
 		lipsTat: "permanent makeup",
 		vagina: 3,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		ovaries: 1,
 		skill: {vaginal: 15, oral: 35},
@@ -335,13 +317,13 @@ App.Data.HeroSlaves.DF = [
 		custom: {tattoo: "Cored apples are tattooed on $his face."},
 		buttTat: "Cored apples are tattooed on $his buttocks.",
 		intelligence: -60,
-		clitPiercing: 2
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}},
 	},
 	/* vibe nips, stupid, sensitive, no masturbation implant*/
 ];
 
 /**
- * @type {Partial<partialSlaveState>[]}
+ * @type {FC.SlaveTemplate[]}
  */
 App.Data.HeroSlaves.DFextreme = [
 	{
@@ -364,12 +346,10 @@ App.Data.HeroSlaves.DFextreme = [
 		hStyle: "wavy",
 		pubicHStyle: "waxed",
 		boobs: 400,
-		nipplesPiercing: 1,
 		butt: 2,
 		lips: 35,
 		vagina: 5,
 		vaginaLube: 1,
-		vaginaPiercing: 2,
 		preg: -2,
 		anus: 2,
 		ovaries: 1,
@@ -379,9 +359,7 @@ App.Data.HeroSlaves.DFextreme = [
 		fetishKnown: 1,
 		lipsTat: "Cored plums are tattooed on $his face.",
 		buttTat: "Cored plums are tattooed on $his buttocks.",
-		custom: {desc: "$He has massive C-clamp piercings in $his back that allow $him to act as furniture, and a truly enormous vagina."},
-		clitPiercing: 2,
-		corsetPiercing: 1,
+		piercing: {nipple: {weight: 1}, vagina: {weight: 2}, genitals: {weight: 2}, corset: {weight: 1, desc:  "$He has massive C-clamp piercings in $his back that allow $him to act as furniture"}},
 		sexualFlaw: "self hating",
 		clothes: "no clothing",
 		vaginalAccessory: "long, huge dildo"
diff --git a/src/npc/descriptions/belly/belly.js b/src/npc/descriptions/belly/belly.js
index 3c2b1570963..0b58d08ffc6 100644
--- a/src/npc/descriptions/belly/belly.js
+++ b/src/npc/descriptions/belly/belly.js
@@ -14033,9 +14033,9 @@ App.Desc.belly = function(slave, {market, eventDescription} = {}) {
 						break;
 				}
 				if (V.showBodyMods === 1) {
-					if (slave.navelPiercing === 1) {
+					if (slave.piercing.navel.weight === 1) {
 						r.push(`${His} fake navel bears a simple stud.`);
-					} else if (slave.navelPiercing === 2) {
+					} else if (slave.piercing.navel.weight === 2) {
 						r.push(`${His} fake navel is pierced with a big ring.`);
 						if (slave.clothes === "slutty jewelry") {
 							r.push(`It has a length of gilded chain dangling from it.`);
@@ -14046,14 +14046,14 @@ App.Desc.belly = function(slave, {market, eventDescription} = {}) {
 				}
 			} else {
 				if (V.showBodyMods === 1) {
-					if (slave.navelPiercing === 1) {
+					if (slave.piercing.navel.weight === 1) {
 						r.push(`${His} navel bears a simple`);
 						if (slave.weight > 130) {
 							r.push(`stud, though it has since vanished into ${his} soft folds.`);
 						} else {
 							r.push(`stud.`);
 						}
-					} else if (slave.navelPiercing === 2) {
+					} else if (slave.piercing.navel.weight === 2) {
 						r.push(`${His} navel is pierced with a big`);
 						if (slave.weight > 130) {
 							r.push(`ring that just managed to extend out of the fat roll covering ${his} navel.`);
@@ -14261,11 +14261,11 @@ App.Desc.belly = function(slave, {market, eventDescription} = {}) {
 				}
 			}
 		} else {
-			if (slave.navelPiercing > 0 && V.showBodyMods === 1) {
+			if (slave.piercing.navel.weight > 0 && V.showBodyMods === 1) {
 				if (slave.belly >= 10000) {
-					if (slave.navelPiercing === 1) {
+					if (slave.piercing.navel.weight === 1) {
 						r.push(`${His} popped navel bears a simple stud.`);
-					} else if (slave.navelPiercing === 2) {
+					} else if (slave.piercing.navel.weight === 2) {
 						r.push(`${His} popped navel is pierced with a big ring.`);
 					}
 					r.push(`It's eye-catching, since most of ${his} piercings are hidden by the suit.`);
diff --git a/src/npc/descriptions/boobs/boobs.js b/src/npc/descriptions/boobs/boobs.js
index 895add8e5f5..536ae50142e 100644
--- a/src/npc/descriptions/boobs/boobs.js
+++ b/src/npc/descriptions/boobs/boobs.js
@@ -530,13 +530,6 @@ App.Desc.boobs = function() {
 						r += `${slave.slaveName}'s scalemail bikini top covers everything, while still flaunting it.`;
 					}
 					break;
-				case "striped panties":
-					if (slave.boobs < 300) {
-						r += `${slave.slaveName}'s ${adjNoun} is completely bare.`;
-					} else {
-						r += `${slave.slaveName}'s ${adjNoun} are completely bare.`;
-					}
-					break;
 				case "clubslut netting":
 					r += `${slave.slaveName}'s `;
 					if (slave.boobs > 12000) {
@@ -1156,7 +1149,12 @@ App.Desc.boobs = function() {
 				case "panties":
 				case "jeans":
 				case "sport shorts":
-					r += `${slave.slaveName}'s ${adjNoun} are completely bare.`;
+				case "striped panties":
+					if (slave.boobs < 300) {
+						r += `${slave.slaveName}'s ${adjNoun} is completely bare.`;
+					} else {
+						r += `${slave.slaveName}'s ${adjNoun} are completely bare.`;
+					}
 					break;
 				case "a tank-top":
 				case "a tank-top and panties":
@@ -1710,7 +1708,7 @@ App.Desc.nipples = function(slave, {market, eventDescription} = {}) {
 					r += 'tiny little nubs.';
 					break;
 				case "flat":
-					if (slave.nipplesPiercing !== 0) {
+					if (slave.piercing.nipple.weight !== 0) {
 						r += "pulled flat from the constant tug of oversized implants. They are held back by piercings, preventing them from blending into the areolae.";
 					} else {
 						r += "pulled flat from the constant tug of oversized implants: when soft, they blend in with the areolae.";
@@ -1720,14 +1718,14 @@ App.Desc.nipples = function(slave, {market, eventDescription} = {}) {
 					r += 'puffy, the soft flesh around each swelling outward to a promontory.';
 					break;
 				case "partially inverted":
-					if (slave.nipplesPiercing !== 0) {
+					if (slave.piercing.nipple.weight !== 0) {
 						r += "partially inverted, or would be if they weren't pierced. The metal is holding them protruded, causing some discomfort.";
 					} else {
 						r += "partially inverted: when soft, they rest flush with the front of the breast.";
 					}
 					break;
 				case "inverted":
-					if (slave.nipplesPiercing !== 0) {
+					if (slave.piercing.nipple.weight !== 0) {
 						r += "inverted, or would be if they weren't pierced. The metal is holding them protruded, to the slave's considerable discomfort.";
 					} else {
 						r += "inverted: they are completely swallowed by the surrounding breastflesh.";
@@ -1848,7 +1846,7 @@ App.Desc.areola = function(slave, {market, eventDescription} = {}) {
 	let r = [];
 	if (slave.fuckdoll === 0) {
 		if (V.showBodyMods === 1) { // this seems wrong
-			if (slave.areolaePiercing === 0) {
+			if (slave.piercing.areola.weight === 0) {
 				switch (slave.areolae) {
 					case 1:
 						r.push(`${His} areolae form large, lovely circles of ${nipColor} skin around each nipple.`);
@@ -1882,7 +1880,7 @@ App.Desc.areola = function(slave, {market, eventDescription} = {}) {
 					}
 				}
 			} /* else {
-				r.push(this.areolaePiercing(slave, pronouns));
+				r.push(this.piercing.areola.weight(slave, pronouns));
 			}*/
 		}
 		if (V.showClothing === 1 && !market) {
diff --git a/src/npc/descriptions/boobs/piercing.js b/src/npc/descriptions/boobs/piercing.js
index 42352651a96..480e6e08590 100644
--- a/src/npc/descriptions/boobs/piercing.js
+++ b/src/npc/descriptions/boobs/piercing.js
@@ -2,12 +2,12 @@
  * @param {App.Entity.SlaveState} slave
  * @returns {string}
  */
-App.Desc.areolaePiercing = function(slave) {
+App.Desc.areolaPiercing = function(slave) {
 	const {his, He, His} = getPronouns(slave);
 	const nipColor = nippleColor(slave);
 	let r = [];
 	if (slave.fuckdoll === 0) {
-		if (slave.areolaePiercing > 0) {
+		if (slave.piercing.areola.weight > 0) {
 			switch (slave.areolae) {
 				case 1:
 					r.push(`${His} areolae form large, lovely circles of ${nipColor} skin around each nipple.`);
diff --git a/src/npc/descriptions/crotch/dick.js b/src/npc/descriptions/crotch/dick.js
index effc7a4ae5e..d8755e2343a 100644
--- a/src/npc/descriptions/crotch/dick.js
+++ b/src/npc/descriptions/crotch/dick.js
@@ -664,9 +664,9 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 				} else if ((slave.fetish === "submissive") && (slave.fetishStrength > 60) && (slave.fetishKnown === 1)) {
 					r.push(`Judging by how hard ${he}`);
 					if (slave.prostate > 1) {
-						r.push(`and the constant flow of precum leaking from the tip of ${his} dick,`);
+						r.push(`is and the constant flow of precum leaking from the tip of ${his} dick,`);
 					} else if (slave.prostate > 0) {
-						r.push(`and the little bead of precum forming at the tip of ${his} dick,`);
+						r.push(`is and the little bead of precum forming at the tip of ${his} dick,`);
 					} else {
 						r.push(`is,`);
 					}
diff --git a/src/npc/descriptions/describePiercings.js b/src/npc/descriptions/describePiercings.js
index d5d27e471cf..695d8823c90 100644
--- a/src/npc/descriptions/describePiercings.js
+++ b/src/npc/descriptions/describePiercings.js
@@ -11,12 +11,14 @@ App.Desc.piercing = function(slave, surface) {
 	} = getPronouns(slave);
 	if (V.showBodyMods !== 1) {
 		return;
+	} else if (slave.piercing[surface] && slave.piercing[surface].desc) {
+		return `${pronounsForSlaveProp(slave, slave.piercing[surface].desc)}.`;
 	}
 	switch (surface) {
 		case "ear": {
-			if (slave.earPiercing > 0) {
+			if (slave.piercing.ear.weight > 0) {
 				const clothing = App.Data.clothes.get(slave.clothes);
-				if (slave.earPiercing === 1) {
+				if (slave.piercing.ear.weight === 1) {
 					r.push(`${His} earlobes are conventionally pierced.`);
 				} else {
 					r.push(`${His} ears are heavily pierced, with multiple lobe piercings and a row of helix piercings.`);
@@ -201,60 +203,58 @@ App.Desc.piercing = function(slave, surface) {
 			break;
 		}
 		case "nose": {
-			if (slave.nosePiercing === 1) {
+			if (slave.piercing.nose.weight === 1) {
 				r.push(`${He} has simple studs in ${his} nose.`);
-			} else if (slave.nosePiercing === 2) {
+			} else if (slave.piercing.nose.weight === 2) {
 				r.push(`${He} has nasal studs and a large septum ring.`);
-				if (slave.clothes === "slutty jewelry" && slave.earPiercing > 0) {
+				if (slave.clothes === "slutty jewelry" && slave.piercing.ear.weight > 0) {
 					r.push(`${His} bangles include a light chain from ${his} nose ring to ${his} ear piercings on one side.`);
 				}
 			}
 			break;
 		}
 		case "eyebrow": {
-			if (slave.eyebrowPiercing === 1) {
+			if (slave.piercing.eyebrow.weight === 1) {
 				r.push(`${He} has a simple stud in one eyebrow.`);
-			} else if (slave.eyebrowPiercing === 2) {
+			} else if (slave.piercing.eyebrow.weight === 2) {
 				r.push(`${He} has multiple eyebrow rings.`);
 			}
 			break;
 		}
 		case "lips": {
-			if (slave.lipsPiercing === 1) {
+			if (slave.piercing.lips.weight === 1) {
 				r.push(`${He} has a simple lip piercing.`);
-			} else if (slave.lipsPiercing === 2) {
+			} else if (slave.piercing.lips.weight === 2) {
 				r.push(`${His} lips are heavily pierced.`);
 			}
 			break;
 		}
 		case "tongue": {
-			if (slave.tonguePiercing === 1) {
+			if (slave.piercing.tongue.weight === 1) {
 				r.push(`${His} tongue bears a single stud, so oral sex with ${him} is a bit more fun.`);
-			} else if (slave.tonguePiercing === 2) {
+			} else if (slave.piercing.tongue.weight === 2) {
 				r.push(`${His} tongue bears a row of studs, offering thorough stimulation to anyone ${he} blows.`);
 			}
-			if (slave.tonguePiercing && SlaveStatsChecker.checkForLisp(slave)) {
+			if (slave.piercing.tongue.weight && SlaveStatsChecker.checkForLisp(slave)) {
 				r.push(`The piercings make ${his} lisp more pronounced.`);
 			}
 			break;
 		}
 		case "nipple": {
-			if (slave.fuckdoll > 0) {
-				if (slave.nipplesPiercing > 0) {
+			if (slave.piercing.nipple.weight > 0) {
+				if (slave.fuckdoll > 0) {
 					r.push(`${His} nipple piercings help secure the suit material to ${his} breasts.`);
-				}
-			} else {
-				if (slave.nipplesPiercing === 1) {
-					r.push(`${His} ${nippleColor(slave)} nipples have a simple piercing, which keeps them a little harder than they would normally be.`);
-				} else if (slave.nipplesPiercing === 2) {
-					r.push(`${His} ${nippleColor(slave)} nipples are heavily pierced with several rings and studs, and there is a chain between them.`);
-					if (slave.boobShape === "saggy" && slave.boobs > 2500) {
-						r.push(`It's been shortened to take advantage of the way ${his} tits sag, and holds ${his} ${nippleColor(slave)} nipples almost together, producing cleavage that runs from ${his} ${nippleColor(slave)} nipples all the way up to ${his} sternum.`);
-					} else {
-						r.push(`The constant tugging keeps ${his} ${nippleColor(slave)} nipples erect.`);
+				} else {
+					if (slave.piercing.nipple.weight === 1) {
+						r.push(`${His} ${nippleColor(slave)} nipples have a simple piercing, which keeps them a little harder than they would normally be.`);
+					} else if (slave.piercing.nipple.weight === 2) {
+						r.push(`${His} ${nippleColor(slave)} nipples are heavily pierced with several rings and studs, and there is a chain between them.`);
+						if (slave.boobShape === "saggy" && slave.boobs > 2500) {
+							r.push(`It's been shortened to take advantage of the way ${his} tits sag, and holds ${his} ${nippleColor(slave)} nipples almost together, producing cleavage that runs from ${his} ${nippleColor(slave)} nipples all the way up to ${his} sternum.`);
+						} else {
+							r.push(`The constant tugging keeps ${his} ${nippleColor(slave)} nipples erect.`);
+						}
 					}
-				}
-				if (slave.nipplesPiercing > 0) {
 					switch (slave.clothes) {
 						case "kitty lingerie":
 							r.push(`The piercings slightly distort the shape of ${his} lacy bra's cleavage window.`);
@@ -339,16 +339,16 @@ App.Desc.piercing = function(slave, surface) {
 
 			break;
 		}
-		case "areolae": {
-			r.push(App.Desc.areolaePiercing(slave));
+		case "areola": {
+			r.push(App.Desc.areolaPiercing(slave));
 			break;
 		}
 		case "navel": {
 			if (slave.fuckdoll === 0) {
 				if (App.Data.misc.fakeBellies.includes(slave.bellyAccessory)) {
-					if (slave.navelPiercing === 1) {
+					if (slave.piercing.navel.weight === 1) {
 						r.push(`${His} fake navel bears a simple stud.`);
-					} else if (slave.navelPiercing === 2) {
+					} else if (slave.piercing.navel.weight === 2) {
 						r.push(`${His} fake navel is pierced with a big ring.`);
 						if (slave.clothes === "slutty jewelry") {
 							r.push(`It has a length of gilded chain dangling from it.`);
@@ -357,9 +357,9 @@ App.Desc.piercing = function(slave, surface) {
 						}
 					}
 				} else {
-					if (slave.navelPiercing === 1) {
+					if (slave.piercing.navel.weight === 1) {
 						r.push(`${His} navel bears a simple stud.`);
-					} else if (slave.navelPiercing === 2) {
+					} else if (slave.piercing.navel.weight === 2) {
 						r.push(`${His} navel is pierced with a big ring.`);
 						if (slave.clothes === "slutty jewelry") {
 							r.push(`It has a length of gilded chain dangling from it.`);
@@ -369,11 +369,11 @@ App.Desc.piercing = function(slave, surface) {
 					}
 				}
 			} else {
-				if (slave.navelPiercing > 0) {
+				if (slave.piercing.navel.weight > 0) {
 					if (slave.belly >= 10000) {
-						if (slave.navelPiercing === 1) {
+						if (slave.piercing.navel.weight === 1) {
 							r.push(`${His} popped navel bears a simple stud.`);
-						} else if (slave.navelPiercing === 2) {
+						} else if (slave.piercing.navel.weight === 2) {
 							r.push(`${His} popped navel is pierced with a big ring.`);
 						}
 						r.push(`It's eye-catching, since most of ${his} piercings are hidden by the suit.`);
@@ -384,73 +384,84 @@ App.Desc.piercing = function(slave, surface) {
 			}
 			break;
 		}
-		case "clit": {
-			if (slave.clitPiercing === 1 && slave.vagina !== -1) {
-				r.push(`${He} has a simple clitoral stud.`);
-			} else if (slave.clitPiercing === 2 && slave.vagina !== -1) {
-				r.push(`${He} has a big ring in ${his} clit.`);
-				if (slave.clothes === "slutty jewelry") {
-					r.push(`Since ${he}'s wearing slutty bangles ${he} has a short length of light chain dangling from ${his} clit ring; it constantly stimulates ${his} pussylips.`);
+		case "clit":
+		case "genitals": {
+			if (slave.dick > 0) {
+				if (slave.piercing.genitals.weight === 1) {
+					r.push(`${He} has a simple dickhead stud.`);
+				} else if (slave.piercing.genitals.weight === 2) {
+					r.push(`${He} has a big ring in ${his} dickhead.`);
+					if (slave.clothes === "slutty jewelry") {
+						r.push(`Since ${he}'s wearing slutty bangles ${he} has a short length of light chain dangling from ${his} dickhead piercing; as ${he} moves it tugs lightly at ${his} cock.`);
+					}
 				}
-			} else if (slave.clitPiercing === 3 && slave.vagina !== -1 && slave.dick === 0) {
-				r.push(`${He} has a smart piercing in ${his} clit.`);
-			} else if (slave.clitPiercing === 1) {
-				r.push(`${He} has a simple dickhead stud.`);
-			} else if (slave.clitPiercing === 2) {
-				r.push(`${He} has a big ring in ${his} dickhead.`);
-				if (slave.clothes === "slutty jewelry") {
-					r.push(`Since ${he}'s wearing slutty bangles ${he} has a short length of light chain dangling from ${his} dickhead piercing; as ${he} moves it tugs lightly at ${his} cock.`);
+			} else if (slave.vagina === -1) { // God help us, nulls.
+				if (slave.piercing.genitals.weight === 1) {
+					r.push(`${He} has a simple stud in the smooth ${slave.skin} skin above ${his} urethra.`);
+				} else if (slave.piercing.genitals.weight === 2) {
+					r.push(`${He} has a big ring in the smooth ${slave.skin} skin above ${his} urethra.`);
+					if (slave.clothes === "slutty jewelry") {
+						r.push(`Since ${he}'s wearing slutty bangles ${he} has a short length of light chain dangling from the ring; it constantly stimulates what remains of ${his} sexual nerves.`);
+					}
 				}
-			} else if (slave.clitPiercing === 3) {
-				r.push(`${He} has a smart frenulum piercing.`);
+			} else {
+				if (slave.piercing.genitals.weight === 1) {
+					r.push(`${He} has a simple clitoral stud.`);
+				} else if (slave.piercing.genitals.weight === 2) {
+					r.push(`${He} has a big ring in ${his} clit.`);
+					if (slave.clothes === "slutty jewelry") {
+						r.push(`Since ${he}'s wearing slutty bangles ${he} has a short length of light chain dangling from ${his} clit ring; it constantly stimulates ${his} pussylips.`);
+					}
+				}
+			}
+
+			if (slave.piercing.genitals.smart) {
+				r.push(`It is upgraded with smart vibe technology.`);
 			}
+
 			if (slave.fuckdoll > 0) {
 				r.push(`It anchors the suit's material.`);
 			}
 			break;
 		}
 		case "vagina": {
-			if (slave.vagina !== -1) {
-				if (slave.vaginaPiercing > 0) {
-					r.push(`${He} has a`);
-					if (slave.vaginaPiercing === 1) {
-						r.push(`simple row of studs`);
-					} else {
-						r.push(`row of big rings`);
-					}
-					r.push(`down ${his}`);
-					if (slave.fuckdoll > 0) {
-						r.push(`labia, which are looped into the edge of the suit's material as it stops around ${his} vulva.`);
-					} else {
-						r.push(`labia.`);
-					}
+			if (slave.piercing.vagina.weight > 0) {
+				r.push(`${He} has a`);
+				if (slave.piercing.vagina.weight === 1) {
+					r.push(`simple row of studs`);
+				} else {
+					r.push(`row of big rings`);
+				}
+				r.push(`down ${his}`);
+				if (slave.fuckdoll > 0) {
+					r.push(`labia, which are looped into the edge of the suit's material as it stops around ${his} vulva.`);
+				} else {
+					r.push(`labia.`);
 				}
 			}
 			break;
 		}
 		case "dick": {
-			if (slave.dick !== 0) {
-				if (slave.dickPiercing === 1) {
-					r.push(`${He} has a row of studs down ${his} shaft.`);
-				} else if (slave.dickPiercing === 2) {
-					r.push(`${He} has a row of heavy rings down ${his} shaft.`);
+			if (slave.piercing.dick.weight === 1) {
+				r.push(`${He} has a row of studs down ${his} shaft.`);
+			} else if (slave.piercing.dick.weight === 2) {
+				r.push(`${He} has a row of heavy rings down ${his} shaft.`);
+			}
+			if (slave.scrotum !== 0) {
+				if (slave.piercing.dick.weight === 1) {
+					r.push(`${He} has a couple of studs in ${his} ballsack.`);
+				} else if (slave.piercing.dick.weight === 2) {
+					r.push(`${He} has a row of rings down the center of ${his} ballsack, all the way from the base of ${his} shaft to ${his} perineum.`);
 				}
-				if (slave.scrotum !== 0) {
-					if (slave.dickPiercing === 1) {
-						r.push(`${He} has a couple of studs in ${his} ballsack.`);
-					} else if (slave.dickPiercing === 2) {
-						r.push(`${He} has a row of rings down the center of ${his} ballsack, all the way from the base of ${his} shaft to ${his} perineum.`);
-					}
-				} else {
-					if (slave.dickPiercing === 1) {
-						r.push(`${He} has a couple of studs beneath the base of ${his} dick.`);
-					} else if (slave.dickPiercing === 2) {
-						r.push(`${He} has a row of rings all the way from the base of ${his} shaft to ${his} perineum.`);
-					}
+			} else {
+				if (slave.piercing.dick.weight === 1) {
+					r.push(`${He} has a couple of studs beneath the base of ${his} dick.`);
+				} else if (slave.piercing.dick.weight === 2) {
+					r.push(`${He} has a row of rings all the way from the base of ${his} shaft to ${his} perineum.`);
 				}
 			}
 			if (slave.fuckdoll > 0) {
-				if (slave.dickPiercing > 0) {
+				if (slave.piercing.dick.weight > 0) {
 					r.push(`Every one of them runs through the suit's material, securing it to the Fuckdoll's member.`);
 				}
 			}
@@ -458,7 +469,7 @@ App.Desc.piercing = function(slave, surface) {
 		}
 		case "anus": {
 			if (slave.vagina > -1) {
-				if (slave.anusPiercing === 1) {
+				if (slave.piercing.anus.weight === 1) {
 					r.push(`${He} has a simple piercing between ${his} pussy and ${his}`);
 					if (slave.fuckdoll > 0) {
 						r.push(`asshole which helps keep the strip of material`);
@@ -471,7 +482,7 @@ App.Desc.piercing = function(slave, surface) {
 					} else {
 						r.push(`asshole.`);
 					}
-				} else if (slave.anusPiercing === 2) {
+				} else if (slave.piercing.anus.weight === 2) {
 					r.push(`${He} has a big ring between ${his} pussy and ${his} asshole,`);
 					if (slave.fuckdoll > 0) {
 						r.push(`which helps keep the strip of material`);
@@ -485,7 +496,7 @@ App.Desc.piercing = function(slave, surface) {
 					r.push(`and studs all around ${his} anus.`);
 				}
 			} else {
-				if (slave.anusPiercing === 1) {
+				if (slave.piercing.anus.weight === 1) {
 					r.push(`${He} has a simple perianal piercing between the base of ${his} dick and ${his} girly`);
 					if (slave.fuckdoll > 0) {
 						r.push(`butthole which helps keep the strip of material`);
@@ -498,14 +509,14 @@ App.Desc.piercing = function(slave, surface) {
 					} else {
 						r.push(`butthole.`);
 					}
-				} else if (slave.anusPiercing === 2) {
+				} else if (slave.piercing.anus.weight === 2) {
 					r.push(`${He} has a big ring between the base of ${his} dick and ${his} girly butthole, which has studs all around it.`);
 				}
 			}
 			break;
 		}
 		case "corset": { // non anatomical
-			if (slave.corsetPiercing > 0) {
+			if (slave.piercing.corset.weight > 0) {
 				if (slave.fuckdoll === 0) {
 					r.push(`${He} has a corset piercing, a ladder of steel rings running up each side of ${his} back:`);
 					if (slave.bellyAccessory === "a corset" || slave.bellyAccessory === "an extreme corset") {
@@ -784,8 +795,8 @@ App.Desc.piercing = function(slave, surface) {
 			break;
 		}
 		case "chastity": { // non anatomical
-			if (slave.clitPiercing > 0
-				&& slave.nipplesPiercing > 0
+			if (slave.piercing.genitals.weight > 0
+				&& slave.piercing.nipple.weight > 0
 				&& !(slave.chastityPenis)
 				&& slave.dick > 4
 				&& slave.boobs > 1000
diff --git a/src/npc/descriptions/face.js b/src/npc/descriptions/face.js
index a1078e24ec0..054322c1f2e 100644
--- a/src/npc/descriptions/face.js
+++ b/src/npc/descriptions/face.js
@@ -5,7 +5,7 @@
 App.Desc.face = function(slave) {
 	const r = [];
 	const {
-		he, him, his, He, His
+		he, him, his, He, His, girl,
 	} = getPronouns(slave);
 
 	r.push(`${His} <span class="pink">face is`);
@@ -59,7 +59,7 @@ App.Desc.face = function(slave) {
 			} else if (slave.face <= 95) {
 				r.push(`beautiful, yet somehow also approachably cute.`);
 			} else {
-				r.push(`an impossibly perfect combination of beauty and girl-next-door cuteness.`);
+				r.push(`an impossibly perfect combination of beauty and ${girl}-next-door cuteness.`);
 			}
 			break;
 		case "sensual":
diff --git a/src/npc/descriptions/longSlave.js b/src/npc/descriptions/longSlave.js
index 6562ff3e3a2..f162f5db997 100644
--- a/src/npc/descriptions/longSlave.js
+++ b/src/npc/descriptions/longSlave.js
@@ -516,7 +516,7 @@ App.Desc.longSlave = function(slave, {market = 0, eventDescription = false, pris
 
 	if (V.showBodyMods === 1) {
 		if (slave.fuckdoll > 0) {
-			if (slave.earPiercing + slave.eyebrowPiercing + slave.nosePiercing > 0) {
+			if (slave.piercing.ear.weight + slave.piercing.eyebrow.weight + slave.piercing.nose.weight > 0) {
 				r.push(`The piercings on ${his} head run through ${his} suit, helping secure the material to ${his} head.`);
 			}
 		} else {
diff --git a/src/npc/descriptions/upperBack.js b/src/npc/descriptions/upperBack.js
index d1c810d4445..07332e0c5ab 100644
--- a/src/npc/descriptions/upperBack.js
+++ b/src/npc/descriptions/upperBack.js
@@ -36,7 +36,7 @@ App.Desc.upperBack = function(slave) {
 	} else if (slave.appendages === "falcon") {
 		r.push(`${he} has a pair of large, ${slave.appendagesColor} wings${slave.appendagesEffect === "none" ? `` : ` that have ${slave.appendagesEffect} on them`}. They're made of advanced synthetic alloys. The wings enable fast aerial movement, swiping at targets with its razor sharp edges and can be used to block projectiles.`);
 	} else if (slave.appendages === "arachnid") {
-		r.push(`${he} has a set of eight, ${slave.appendagesColor} and deadly spider legs${slave.appendagesEffect === "none" ? `` : ` that have ${slave.appendagesEffect} on them`}. The legs are made of an advanced synthetic alloy. Being extremely durable in addition to very light, allows extention to thrice their original length. An built-in AI helps with combat, 3-dimensional maneuvering and appendage coordination.`);
+		r.push(`${he} has a set of eight ${slave.appendagesColor} deadly spider legs. The legs are made of an advanced synthetic alloy. Being extremely durable in addition to very light, allows extension to thrice their original length. An built-in AI helps with combat, 3-dimensional maneuvering and appendage coordination.`);
 	} else if (slave.appendages === "kraken") {
 		r.push(`${he} has a set of eight, ${slave.appendagesColor} tentacles${slave.appendagesEffect === "none" ? `` : ` that have ${slave.appendagesEffect} on them`}. The tentacles are made of an advanced synthetic alloy. Being extremely durable in addition to very light, allows the tentacles to extend to thrice their original length. An built-in AI helps with combat, 3-dimensional maneuvering and appendage coordination.`);
 	} else if (slave.appendages === "sex") {
diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js
index d4d9417c87e..ef71c518860 100644
--- a/src/npc/generate/generateGenetics.js
+++ b/src/npc/generate/generateGenetics.js
@@ -1212,20 +1212,14 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 		child.boobs = 0;
 		child.butt = 0;
 		child.chem = 990;
-		child.areolaePiercing = 0;
-		child.corsetPiercing = 0;
+		child.piercing = new App.Entity.completePiercingState();
 		child.boobsImplant = 0;
 		child.boobsImplantType = "none";
-		child.nipplesPiercing = 0;
-		child.areolaePiercing = 0;
 		child.lactation = 0;
 		child.hipsImplant = 0;
 		child.buttImplant = 0;
 		child.buttImplantType = "none";
 		child.lipsImplant = 0;
-		child.lipsPiercing = 0;
-		child.tonguePiercing = 0;
-		child.vaginaPiercing = 0;
 		child.preg = 0;
 		child.pregType = 0;
 		child.pregKnown = 0;
@@ -1234,16 +1228,10 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 		child.bellyFluid = 0;
 		child.bellyImplant = -1;
 		child.cervixImplant = 0;
-		child.clitPiercing = 0;
-		child.dickPiercing = 0;
 		child.makeup = 0;
 		child.nails = 0;
-		child.earPiercing = 0;
-		child.nosePiercing = 0;
-		child.eyebrowPiercing = 0;
 		child.stampTat = 0;
 		child.bellyTat = 0;
-		child.anusPiercing = 0;
 		child.anusTat = 0;
 		child.shouldersTat = 0;
 		child.armsTat = 0;
@@ -1271,7 +1259,6 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 			child.tankBaby = 3;
 		}
 		child.intelligenceImplant = 0;
-		child.navelPiercing = 0;
 	}
 
 	child.inbreedingCoeff = genes.inbreedingCoeff;
diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js
index 27c64f2b01b..4f6aa8ed612 100644
--- a/src/npc/generate/generateMarketSlave.js
+++ b/src/npc/generate/generateMarketSlave.js
@@ -803,15 +803,16 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 				slave.bellyTat = 0;
 				slave.abortionTat = 0;
 				slave.birthsTat = 0;
-				slave.corsetPiercing = 0;
-				slave.nipplesPiercing = 0;
-				slave.areolaePiercing = 0;
-				slave.lipsPiercing = 0;
-				slave.tonguePiercing = 0;
-				slave.vaginaPiercing = 0;
-				slave.clitPiercing = 0;
-				slave.dickPiercing = 0;
-				slave.anusPiercing = 0;
+				slave.piercing.corset.weight = 0;
+				slave.piercing.nipple.weight = 0;
+				slave.piercing.areola.weight = 0;
+				slave.piercing.lips.weight = 0;
+				slave.piercing.tongue.weight = 0;
+				slave.piercing.vagina.weight = 0;
+				slave.piercing.genitals.weight = 0;
+				slave.piercing.genitals.smart = false;
+				slave.piercing.dick.weight = 0;
+				slave.piercing.anus.weight = 0;
 			} else if (neighbor.FSTransformationFetishist > 80) {
 				r += `They vary in terms of what size their implants are, not whether they have them. `;
 				slave.chem += jsRandom(10, 100);
@@ -2301,7 +2302,8 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			slave.dick = 0;
 			slave.balls = 0;
 			slave.preg = 0;
-			slave.clitPiercing = 0;
+			slave.piercing.genitals.weight = 0;
+			slave.piercing.genitals.smart = false;
 			slave.eyebrowHStyle = "bald";
 			slave.underArmHStyle = "bald";
 			slave.pubicHStyle = "bald";
diff --git a/src/npc/generate/generateNewSlaveJS.js b/src/npc/generate/generateNewSlaveJS.js
index 9a3c477f74a..7ce7bc3833a 100644
--- a/src/npc/generate/generateNewSlaveJS.js
+++ b/src/npc/generate/generateNewSlaveJS.js
@@ -1098,13 +1098,13 @@ globalThis.GenerateNewSlave = (function() {
 
 	function generateXXMods() {
 		if (passage() !== "Starting Girls") {
-			slave.earPiercing = jsEither([0, 1]);
-			slave.nosePiercing = jsEither([0, 0, 0, 1]);
-			slave.eyebrowPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.clitPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.lipsPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.navelPiercing = jsEither([0, 0, 0, 1]);
-			slave.nipplesPiercing = jsEither([0, 0, 0, 0, 1]);
+			slave.piercing.ear.weight = jsEither([0, 1]);
+			slave.piercing.nose.weight = jsEither([0, 0, 0, 1]);
+			slave.piercing.eyebrow.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.genitals.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.lips.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.navel.weight = jsEither([0, 0, 0, 1]);
+			slave.piercing.nipple.weight = jsEither([0, 0, 0, 0, 1]);
 		}
 		if (slave.anus !== 0 && Math.random() < 0.25) {
 			slave.anusTat = "bleached";
@@ -1113,13 +1113,13 @@ globalThis.GenerateNewSlave = (function() {
 
 	function generateXYMods() {
 		if (passage() !== "Starting Girls") {
-			slave.earPiercing = jsEither([0, 0, 0, 1]);
-			slave.nosePiercing = jsEither([0, 0, 0, 0, 1]);
-			slave.eyebrowPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.clitPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.lipsPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-			slave.navelPiercing = jsEither([0, 0, 0, 0, 1]);
-			slave.nipplesPiercing = jsEither([0, 0, 0, 0, 1]);
+			slave.piercing.ear.weight = jsEither([0, 0, 0, 1]);
+			slave.piercing.nose.weight = jsEither([0, 0, 0, 0, 1]);
+			slave.piercing.eyebrow.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.genitals.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.lips.weight = jsEither([0, 0, 0, 0, 0, 1]);
+			slave.piercing.navel.weight = jsEither([0, 0, 0, 0, 1]);
+			slave.piercing.nipple.weight = jsEither([0, 0, 0, 0, 1]);
 		}
 		if (slave.anus !== 0 && Math.random() < 0.25) {
 			slave.anusTat = "bleached";
diff --git a/src/npc/generate/generateRelatedSlave.js b/src/npc/generate/generateRelatedSlave.js
index 8cf3aa77cfe..b9c84451094 100644
--- a/src/npc/generate/generateRelatedSlave.js
+++ b/src/npc/generate/generateRelatedSlave.js
@@ -542,14 +542,14 @@ globalThis.generateRelatedSlave = (function() {
 		slave.hormoneBalance -= (slave.hormoneBalance - 10) * 2;
 
 		// regenerate piercings (would be nice to just call generateXXMods here)
-		slave.earPiercing = jsEither([0, 1]);
-		slave.nosePiercing = jsEither([0, 0, 0, 1]);
-		slave.eyebrowPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.clitPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.dickPiercing = 0;
-		slave.lipsPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.navelPiercing = jsEither([0, 0, 0, 1]);
-		slave.nipplesPiercing = jsEither([0, 0, 0, 0, 1]);
+		slave.piercing.ear.weight = jsEither([0, 1]);
+		slave.piercing.nose.weight = jsEither([0, 0, 0, 1]);
+		slave.piercing.eyebrow.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.genitals.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.dick.weight = 0;
+		slave.piercing.lips.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.navel.weight = jsEither([0, 0, 0, 1]);
+		slave.piercing.nipple.weight = jsEither([0, 0, 0, 0, 1]);
 	}
 
 	/**
@@ -602,13 +602,13 @@ globalThis.generateRelatedSlave = (function() {
 		slave.hormoneBalance -= (slave.hormoneBalance - 10) * 2;
 
 		// regenerate piercings (would be nice to just call generateXYMods here)
-		slave.earPiercing = jsEither([0, 0, 0, 1]);
-		slave.nosePiercing = jsEither([0, 0, 0, 0, 1]);
-		slave.eyebrowPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.clitPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.lipsPiercing = jsEither([0, 0, 0, 0, 0, 1]);
-		slave.navelPiercing = jsEither([0, 0, 0, 0, 1]);
-		slave.nipplesPiercing = jsEither([0, 0, 0, 0, 1]);
+		slave.piercing.ear.weight = jsEither([0, 0, 0, 1]);
+		slave.piercing.nose.weight = jsEither([0, 0, 0, 0, 1]);
+		slave.piercing.eyebrow.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.genitals.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.lips.weight = jsEither([0, 0, 0, 0, 0, 1]);
+		slave.piercing.navel.weight = jsEither([0, 0, 0, 0, 1]);
+		slave.piercing.nipple.weight = jsEither([0, 0, 0, 0, 1]);
 	}
 
 	return generateRelative;
diff --git a/src/npc/generate/lawCompliance.js b/src/npc/generate/lawCompliance.js
index 64cc2396c7e..1177cec825c 100644
--- a/src/npc/generate/lawCompliance.js
+++ b/src/npc/generate/lawCompliance.js
@@ -345,18 +345,19 @@ App.Desc.lawCompliance = function(slave, market = 0) {
 	}
 
 	function FSBodyPuristSMR() {
-		slave.nipplesPiercing = 0;
-		slave.areolaePiercing = 0;
-		slave.lipsPiercing = 0;
-		slave.vaginaPiercing = 0;
-		slave.dickPiercing = 0;
-		slave.clitPiercing = 0;
-		slave.anusPiercing = 0;
-		slave.corsetPiercing = 0;
-		slave.earPiercing = 0;
-		slave.eyebrowPiercing = 0;
-		slave.nosePiercing = 0;
-		slave.navelPiercing = 0;
+		slave.piercing.nipple.weight = 0;
+		slave.piercing.areola.weight = 0;
+		slave.piercing.lips.weight = 0;
+		slave.piercing.vagina.weight = 0;
+		slave.piercing.dick.weight = 0;
+		slave.piercing.genitals.weight = 0;
+		slave.piercing.genitals.smart = false;
+		slave.piercing.anus.weight = 0;
+		slave.piercing.corset.weight = 0;
+		slave.piercing.ear.weight = 0;
+		slave.piercing.eyebrow.weight = 0;
+		slave.piercing.nose.weight = 0;
+		slave.piercing.navel.weight = 0;
 		slave.lipsTat = 0;
 		slave.buttTat = 0;
 		slave.anusTat = 0;
diff --git a/src/npc/generate/newSlaveIntro.js b/src/npc/generate/newSlaveIntro.js
index 025f764bd7f..659eb02459f 100644
--- a/src/npc/generate/newSlaveIntro.js
+++ b/src/npc/generate/newSlaveIntro.js
@@ -257,7 +257,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 			slave.skill.vaginal = 0;
 		}
 
-		if (slave.nipplesPiercing > 0) {
+		if (slave.piercing.nipple.weight > 0) {
 			if (slave.nipples === "partially inverted" || slave.nipples === "flat") {
 				slave.nipples = "cute";
 			} else if (slave.nipples === "inverted") {
@@ -924,9 +924,6 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 						result: function(slave) {
 							const r = [];
 							r.push(`The former knight stands in front of you, glaring down as you casually announce that you'll be branding ${his} ${brandTarget} to mark ${him} as property. ${He}'s an absolutely enormous mass of corded muscle, all of it on naked display, and the furious glint in ${his} eyes makes it look like ${he}'s thinking about snapping you in two at any moment. As the captive man tries ${his} best to silently intimidate you, you laugh, once, and bring your face up close to ${his}, making it disturbingly clear that ${his} muscle and strength is no use anymore. Escorted by your drones, you bring the ex-Knight to the body modification studio, strap ${him} down, and take your time to heat up the brand before bringing it to ${his} virgin flesh with a sudden ferocity that makes the huge man scream in agony. As ${he} writhes and thrashes under the straps, ${he} gets his first taste of <span class="gold">genuine pain,</span> and ${he} <span class="mediumorchid">hates you</span> even more than ${he} did before as ${his} <span class="health dec">wound</span> heals.`);
-							if (canDoAnal(slave)) {
-								r.push(VCheck.Anal(slave, 1));
-							}
 							applyBrand();
 							return r.join(" ");
 						},
@@ -1013,7 +1010,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 						linkName: `Allow ${him} to stuff ${himself}`,
 						result: function(slave) {
 							const r = [];
-							r.push(`You point ${him} toward the nearest slave food dispenser and tell ${him} to drink as much as ${he} likes. ${He} <span class="hotpink">eagerly complies,</span> quickly bloating ${his} long-deprived belly; between the psychoactive effects of slave food, the sudden end of ${his} long fast, and the look of <span class="mediumaquamarine">slightly spaced-out contentment</span> on ${his} face as ${he} rubs ${his} sated belly, you have a feeling that you're witnessing the beginning of an <span class="red">overeating habit</span>.`);
+							r.push(`You point ${him} toward the nearest slave food dispenser and tell ${him} to drink as much as ${he} likes. ${He} <span class="hotpink">eagerly complies,</span> quickly bloating ${his} long-deprived belly; between the psychoactive effects of slave food, the sudden end of ${his} long fast, and the look of <span class="mediumaquamarine">slightly spaced-out contentment</span> on ${his} face as ${he} rubs ${his} sated belly, you have a feeling that you're witnessing the beginning of an <span class="red">overeating habit.</span>`);
 							slave.devotion += 10;
 							slave.trust += 10;
 							if (slave.behavioralQuirk === "fitness") {
@@ -1384,13 +1381,14 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.butt -= slave.buttImplant;
 							slave.buttImplant = 0;
 							slave.buttImplantType = "none";
-							slave.lipsPiercing = 0;
-							slave.tonguePiercing = 0;
-							slave.nosePiercing = 0;
-							slave.eyebrowPiercing = 0;
-							slave.navelPiercing = 0;
-							slave.nipplesPiercing = 0;
-							slave.clitPiercing = 0;
+							slave.piercing.lips.weight = 0;
+							slave.piercing.tongue.weight = 0;
+							slave.piercing.nose.weight = 0;
+							slave.piercing.eyebrow.weight = 0;
+							slave.piercing.navel.weight = 0;
+							slave.piercing.nipple.weight = 0;
+							slave.piercing.genitals.weight = 0;
+							slave.piercing.genitals.smart = false;
 							slave.hStyle = "neat";
 							slave.custom.tattoo = " ";
 							return r.join(" ");
@@ -2015,7 +2013,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 					linkName: `Give ${him} a smart clitoral piercing`,
 					result: function(slave) {
 						cashX(forceNeg(V.SPcost), "slaveMod", slave);
-						slave.clitPiercing = 3;
+						slave.piercing.genitals.smart = true;
+						slave.piercing.genitals.weight = 2;
 						return `You take ${him} to the body modification studio, strap ${him} down, pierce ${his} clit, and insert what appears to be a large stainless steel barbell piercing. It actually contains a device that can vibrate to give ${him} sexual stimulation or create subtle pain to suppress pleasure. It is connected wirelessly to the arcology, which can be given instructions to encourage or discourage sexual pleasure in specific situations. You run a quick test. On the oral setting, as soon as ${he} kneels in front of your crotch, ${he} gasps as the stimulation starts. On the anal setting, ${he} whimpers when you run a finger across ${his} asshole.`;
 					},
 					note: `This option costs ${cashFormat(V.SPcost)}`
@@ -2027,7 +2026,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 						const r = [];
 						cashX(forceNeg(V.SPcost), "slaveMod", slave);
 						r.push(`You take ${him} to the body modification studio, strap ${him} down, pierce ${his} frenulum, and insert what appears to be a large stainless steel barbell piercing. It actually contains a device that can vibrate to give ${him} sexual stimulation or create subtle pain to suppress pleasure. It is connected wirelessly to the arcology, which can be given instructions to encourage or discourage sexual pleasure in specific situations. You run a quick test. On the oral setting, as soon as ${he} kneels in front of your crotch, ${he} gasps as the stimulation starts. On the anal setting, ${he} whimpers and gets rock hard when you run a finger across ${his} asshole.`);
-						slave.clitPiercing = 3;
+						slave.piercing.genitals.smart = true;
+						slave.piercing.genitals.weight = 2;
 						return r.join(" ");
 					},
 					note: `This option costs ${cashFormat(V.SPcost)}`
diff --git a/src/npc/interaction/fAnus.js b/src/npc/interaction/fAnus.js
index b86b5b128fe..67e1ab34158 100644
--- a/src/npc/interaction/fAnus.js
+++ b/src/npc/interaction/fAnus.js
@@ -55,9 +55,9 @@ App.Interact.fAnus = function(slave) {
 		}
 	}
 
-	if (slave.anusPiercing > 1) {
+	if (slave.piercing.anus.weight > 1) {
 		r.push(`The ring of stud piercings around ${his} anus should massage you delightfully as you sodomize ${him}.`);
-	} else if (slave.anusPiercing === 1) {
+	} else if (slave.piercing.anus.weight === 1) {
 		r.push(`${His} perineum piercing has a big ring in it, which you should be able to feel when you hilt yourself in ${his} ass.`);
 	}
 
diff --git a/src/npc/interaction/fBeg.js b/src/npc/interaction/fBeg.js
index ef815f9e505..aca72060a4f 100644
--- a/src/npc/interaction/fBeg.js
+++ b/src/npc/interaction/fBeg.js
@@ -75,7 +75,7 @@ App.Interact.fBeg = function(slave) {
 		switch (slave.fetish) {
 			case "submissive":
 				r.push(`As ${he} begins to strip you grab ${him} without warning and begin to tear off ${his} clothes. Your slave expected you to allow ${him} to obey your command, and so ${he} is initially taken aback by the sudden force but ${his} submissive nature keeps ${him} from resisting. ${He} is such a submissive slut that you feel obligation to push ${his} status even further. You bind ${his} arms tightly behind ${his} back in a leather monoglove, lacing it tighter until ${his} elbows are touching. ${He} gives a soft whimper, but you both know that this is for your benefit and not a protest.`);
-				if (slave.nipplesPiercing >= 1) {
+				if (slave.piercing.nipple.weight >= 1) {
 					r.push(`You then retrieve heavy bells and attach them to ${his} nipple rings.`);
 				} else {
 					r.push(`You reach into your pocket and retrieve two weighted and belled nipple clamps, attaching them tightly to your slave's delicate nipples.`);
@@ -201,9 +201,9 @@ App.Interact.fBeg = function(slave) {
 				r.push(`declares`);
 			}
 			r.push(`angrily that slavery is wrong and ${he} will not bow. You look at your assistant who silently summons two other, more obedient slaves from their duties.`);
-			if (slave.nipplesPiercing > 1) {
+			if (slave.piercing.nipple.weight > 1) {
 				r.push(`You reach out and grab ${him} by ${his} nipple chain, pulling ${him} in harshly. ${He} yelps in pain, but knows better than to pull away.`);
-			} else if (slave.nosePiercing > 1) {
+			} else if (slave.piercing.nose.weight > 1) {
 				r.push(`You reach out and grab ${him} by ${his} nose ring, pulling ${him} in harshly. ${He} yelps in pain, but knows better than to pull away.`);
 			} else {
 				r.push(`You reach out and grab ${him} firmly by the collar.`);
@@ -537,9 +537,9 @@ App.Interact.fBeg = function(slave) {
 		} else {
 			if (slave.fetishKnown === 1 && slave.fetishStrength > 60) {
 				r.push(`and ${he} bows ${his} head in total submission.`);
-				if (slave.nipplesPiercing > 0) {
+				if (slave.piercing.nipple.weight > 0) {
 					r.push(`The armbinder thrusts ${his} tits out nicely, and ${his} nipple rings are pulled tight by the weighted bells weighing them down.`);
-				} else if (slave.nipplesPiercing > 1) {
+				} else if (slave.piercing.nipple.weight > 1) {
 					r.push(`The armbinder thrusts ${his} tits out nicely, and ensures that ${his} nipple chains are pulled tight by the angle of ${his} shoulders. The bells on ${his} nipple piercings jungle sweetly as ${he} breathes.`);
 				} else {
 					r.push(`The armbinder thrusts ${his} tits out nicely and ${his} nipples are now red from the clamps pressing down hard on ${his} sensitive flesh. Every painful shudder makes the bells jungle ever so sweetly.`);
diff --git a/src/npc/interaction/fBoobs.js b/src/npc/interaction/fBoobs.js
index 019482829b1..2bd57c1e643 100644
--- a/src/npc/interaction/fBoobs.js
+++ b/src/npc/interaction/fBoobs.js
@@ -49,9 +49,9 @@ App.Interact.fBoobs = function(slave) {
 		r.push(`${His} puffy nipples beg to be sucked.`);
 	} else if (slave.nipples === "flat") {
 		r.push(`${His} nipples are stretched nearly flat by ${his} implants, reducing them to two lewd little buttons.`);
-	} else if (slave.nipples === "partially inverted" && slave.nipplesPiercing === 0) {
+	} else if (slave.nipples === "partially inverted" && slave.piercing.nipple.weight === 0) {
 		r.push(`${His} partially inverted nipples should protrude at the slightest stimulation.`);
-	} else if (slave.nipples === "inverted" && slave.nipplesPiercing === 0) {
+	} else if (slave.nipples === "inverted" && slave.piercing.nipple.weight === 0) {
 		r.push(`${His} inverted nipples form lewd little creases across ${his} areolae.`);
 	} else if (slave.nipples === "fuckable") {
 		if (slave.lactation) {
@@ -61,11 +61,11 @@ App.Interact.fBoobs = function(slave) {
 		}
 	}
 
-	if (slave.nipplesPiercing > 1 && !hasAnyLegs(slave)) {
+	if (slave.piercing.nipple.weight > 1 && !hasAnyLegs(slave)) {
 		r.push(`You carry ${him} over, playing with the chain between ${his} nipples.`);
-	} else if (slave.nipplesPiercing > 1) {
+	} else if (slave.piercing.nipple.weight > 1) {
 		r.push(`You pull ${him} over by the chain between ${his} nipples.`);
-	} else if (slave.nipplesPiercing === 1) {
+	} else if (slave.piercing.nipple.weight === 1) {
 		r.push(`${His} nipple piercings glint enticingly.`);
 	}
 
diff --git a/src/npc/interaction/fButt.js b/src/npc/interaction/fButt.js
index fd4c97964d9..61ab016c5c6 100644
--- a/src/npc/interaction/fButt.js
+++ b/src/npc/interaction/fButt.js
@@ -41,21 +41,21 @@ App.Interact.fButt = function(slave) {
 		}
 	}
 
-	if (slave.vaginaPiercing > 1) {
+	if (slave.piercing.vagina.weight > 1) {
 		r.push(`${His} pierced lips and clit have ${him} nice and wet.`);
 		if (slave.dick !== 0) {
 			r.push(`Metal glints all up and down ${his} cock.`);
 		}
-	} else if (slave.vaginaPiercing === 1) {
+	} else if (slave.piercing.vagina.weight === 1) {
 		r.push(`${His} pierced clit has ${his} nice and moist.`);
 		if (slave.dick !== 0) {
 			r.push(`Metal glints at the head of ${his} cock.`);
 		}
 	}
 
-	if (slave.anusPiercing > 1) {
+	if (slave.piercing.anus.weight > 1) {
 		r.push(`The ring of stud piercings around ${his} anus should massage you delightfully as you sodomize ${him}.`);
-	} else if (slave.anusPiercing === 1) {
+	} else if (slave.piercing.anus.weight === 1) {
 		r.push(`${His} perineum piercing has a big ring in it, which you should be able to feel when you hilt yourself in ${his} ass.`);
 	}
 
diff --git a/src/npc/interaction/fCaress.js b/src/npc/interaction/fCaress.js
index 33bfd7550d1..94346cfae82 100644
--- a/src/npc/interaction/fCaress.js
+++ b/src/npc/interaction/fCaress.js
@@ -111,7 +111,7 @@ App.Interact.fCaress = function(slave) {
 	if (slave.lipsTat !== 0) {
 		r.push(`Your fingers trace ${his} facial tattoos, slowly picking out the patterns against ${his} ${slave.skin} skin.`);
 	}
-	if (slave.lipsPiercing+slave.tonguePiercing > 2) {
+	if (slave.piercing.lips.weight+slave.piercing.tongue.weight > 2) {
 		r.push(`You touch each of ${his} facial piercings, one by one, feeling the hard metal contrast with ${his} pliant flesh.`);
 	}
 	r.push(`Then, you gently tilt ${his}`);
diff --git a/src/npc/interaction/fDance.js b/src/npc/interaction/fDance.js
index 0ebe24ee3d4..e12588a5af8 100644
--- a/src/npc/interaction/fDance.js
+++ b/src/npc/interaction/fDance.js
@@ -245,9 +245,9 @@ App.Interact.fDance = function(slave) {
 						r.push(`${his} neck tie`);
 						break;
 					case "ancient Egyptian":
-						if (slave.nosePiercing === 2) {
+						if (slave.piercing.nose.weight === 2) {
 							r.push(`${his} nose ring.`);
-						} else if (slave.nipplesPiercing === 2) {
+						} else if (slave.piercing.nipple.weight === 2) {
 							r.push(`${his} nipple chain.`);
 						} else {
 							r.push(`${his} wesekh.`);
@@ -258,9 +258,9 @@ App.Interact.fDance = function(slave) {
 						r.push(`${his} retirement counter`);
 						break;
 					case "default":
-						if (slave.nosePiercing === 2) {
+						if (slave.piercing.nose.weight === 2) {
 							r.push(`${his} nose ring`);
-						} else if (slave.nipplesPiercing === 2) {
+						} else if (slave.piercing.nipple.weight === 2) {
 							r.push(`${his} nipple chain`);
 						} else {
 							r.push(`a collar that is placed on ${his} neck for the occasion, and`);
@@ -286,9 +286,9 @@ App.Interact.fDance = function(slave) {
 			} else if (slave.faceAccessory !== "none") {
 				switch (slave.faceAccessory) {
 					case "porcelain mask":
-						if (slave.nosePiercing === 2) {
+						if (slave.piercing.nose.weight === 2) {
 							r.push(`${his} nose ring`);
-						} else if (slave.nipplesPiercing === 2) {
+						} else if (slave.piercing.nipple.weight === 2) {
 							r.push(`${his} nipple chain`);
 						} else {
 							r.push(`a collar that is placed around ${his} neck`);
@@ -310,18 +310,18 @@ App.Interact.fDance = function(slave) {
 					r.push(`making breathing even more difficult;`);
 					break;
 				case "ancient Egyptian":
-					if (slave.nosePiercing === 2) {
+					if (slave.piercing.nose.weight === 2) {
 						r.push(`tugging at ${his} nose ring;`);
-					} else if (slave.nipplesPiercing === 2) {
+					} else if (slave.piercing.nipple.weight === 2) {
 						r.push(`threatening to tear themselves from ${his} sensitive flesh;`);
 					} else {
 						r.push(`tugging at ${his} throat;`);
 					}
 					break;
 				case "default":
-					if (slave.nosePiercing === 2) {
+					if (slave.piercing.nose.weight === 2) {
 						r.push(`tugging at ${his} nose ring;`);
-					} else if (slave.nipplesPiercing === 2) {
+					} else if (slave.piercing.nipple.weight === 2) {
 						r.push(`threatening to tear themselves from ${his} sensitive flesh;`);
 					} else {
 						r.push(`choking ${him};`);
@@ -1930,9 +1930,9 @@ App.Interact.fDance = function(slave) {
 			}
 		} else {
 			r.push(`${He} looks at you angrily, refusing to obey. You are forced to get up from your chair and retrieve ${his} leash, dragging ${him} back by ${his}`);
-			if (slave.nosePiercing === 2) {
+			if (slave.piercing.nose.weight === 2) {
 				r.push(`nose ring.`);
-			} else if (slave.nipplesPiercing === 2) {
+			} else if (slave.piercing.nipple.weight === 2) {
 				r.push(`nipples.`);
 			} else {
 				r.push(`collar.`);
diff --git a/src/npc/interaction/fDick.js b/src/npc/interaction/fDick.js
index aabba388b57..fffb022fd15 100644
--- a/src/npc/interaction/fDick.js
+++ b/src/npc/interaction/fDick.js
@@ -99,9 +99,9 @@ App.Interact.fDick = function(slave) {
 			r.push(`ass`);
 		}
 		r.push(`with ${his}`);
-		if (slave.vaginaPiercing > 1 && slave.dick !== 0) {
+		if (slave.piercing.vagina.weight > 1 && slave.dick !== 0) {
 			r.push(`pierced cock-head.`);
-		} else if (slave.vaginaPiercing === 1 && slave.dick !== 0) {
+		} else if (slave.piercing.vagina.weight === 1 && slave.dick !== 0) {
 			r.push(`pierced cock.`);
 		} else {
 			r.push(`cock.`);
@@ -279,9 +279,9 @@ App.Interact.fDick = function(slave) {
 			r.push(`ass`);
 		}
 		r.push(`with`);
-		if (slave.vaginaPiercing > 1 && slave.dick !== 0) {
+		if (slave.piercing.vagina.weight > 1 && slave.dick !== 0) {
 			r.push(`${his} pierced cock-head.`);
-		} else if (slave.vaginaPiercing === 1 && slave.dick !== 0) {
+		} else if (slave.piercing.vagina.weight === 1 && slave.dick !== 0) {
 			r.push(`${his} pierced cock`);
 		} else {
 			r.push(`${his} cock`);
diff --git a/src/npc/interaction/fFeelings.js b/src/npc/interaction/fFeelings.js
index 883ac05791e..b0cd4581432 100644
--- a/src/npc/interaction/fFeelings.js
+++ b/src/npc/interaction/fFeelings.js
@@ -1627,7 +1627,7 @@ App.Interact.feelings = function(slave) {
 						}
 					} else if (slave.toyHole !== "dick") {
 						if (slave.energy > 95 && V.PC.dick !== 0) {
-							r.push(Spoken(slave, `I love how taking your cock is my only job, and I love having your other toys to have sex too.`));
+							r.push(Spoken(slave, `I love how taking your cock is my only job, and I love having your other toys to have sex with too.`));
 						} else {
 							r.push(Spoken(slave, `It's nice being your ${girl}.`));
 						}
diff --git a/src/npc/interaction/fKiss.js b/src/npc/interaction/fKiss.js
index 451396c5067..7c79d741b8f 100644
--- a/src/npc/interaction/fKiss.js
+++ b/src/npc/interaction/fKiss.js
@@ -161,7 +161,7 @@ App.Interact.fKiss = function(slave) {
 	if (slave.lipsTat !== 0) {
 		r.push(`Your fingers trace ${his} facial tattoos, slowly picking out the patterns against ${his} ${slave.skin} skin.`);
 	}
-	if (slave.lipsPiercing + slave.tonguePiercing > 2) {
+	if (slave.piercing.lips.weight + slave.piercing.tongue.weight > 2) {
 		r.push(`You touch each of ${his} facial piercings, one by one, feeling the hard metal contrast with ${his} pliant flesh.`);
 	}
 	r.push(`Then, you gently raise ${his}`);
diff --git a/src/npc/interaction/fLips.js b/src/npc/interaction/fLips.js
index d90063293fe..d01ce9b6e51 100644
--- a/src/npc/interaction/fLips.js
+++ b/src/npc/interaction/fLips.js
@@ -80,9 +80,9 @@ App.Interact.fLips = function(slave) {
 		r.push(`The tattoos on ${his} face are asking for it, after all.`);
 	}
 
-	if (slave.lipsPiercing + slave.tonguePiercing > 2) {
+	if (slave.piercing.lips.weight + slave.piercing.tongue.weight > 2) {
 		r.push(`The stimulation from ${his} many oral piercings should be great.`);
-	} else if (slave.lipsPiercing + slave.tonguePiercing > 0) {
+	} else if (slave.piercing.lips.weight + slave.piercing.tongue.weight > 0) {
 		r.push(`The sensation of ${his} oral piercings should be quite nice.`);
 	}
 
diff --git a/src/npc/interaction/fPCImpreg.js b/src/npc/interaction/fPCImpreg.js
index a707bbfe153..0a730d4e925 100644
--- a/src/npc/interaction/fPCImpreg.js
+++ b/src/npc/interaction/fPCImpreg.js
@@ -95,10 +95,10 @@ App.Interact.fPCImpreg = function(slave) {
 			}
 		}
 
-		if (slave.vaginaPiercing > 0) {
-			if (slave.vaginaPiercing > 1) {
+		if (slave.piercing.vagina.weight > 0) {
+			if (slave.piercing.vagina.weight > 1) {
 				text.push(`${His} pierced lips and clit have ${him} nice and wet.`);
-			} else if (slave.vaginaPiercing === 1) {
+			} else if (slave.piercing.vagina.weight === 1) {
 				text.push(`${His} pierced clit has ${him} nice and moist.`);
 			}
 		}
diff --git a/src/npc/interaction/fVagina.js b/src/npc/interaction/fVagina.js
index 36ea4920134..3d5228f948d 100644
--- a/src/npc/interaction/fVagina.js
+++ b/src/npc/interaction/fVagina.js
@@ -79,14 +79,14 @@ App.Interact.fVagina = function(slave) {
 		}
 	}
 
-	if (slave.vaginaPiercing > 1) {
+	if (slave.piercing.vagina.weight > 1) {
 		if (slave.vagina !== -1) {
 			r.push(`${His} pierced lips and clit have ${him} nice and wet.`);
 		}
 		if (slave.dick !== 0) {
 			r.push(`Metal glints all up and down ${his} cock.`);
 		}
-	} else if (slave.vaginaPiercing === 1) {
+	} else if (slave.piercing.vagina.weight === 1) {
 		if (slave.vagina !== -1) {
 			r.push(`${His} pierced clit has ${him} nice and moist.`);
 		}
@@ -113,32 +113,37 @@ App.Interact.fVagina = function(slave) {
 	if (canMove(slave) && slave.fetish !== "mindbroken") {
 		r.push(`You decide to fuck ${him}`);
 		if (fPosition <= 20) {
-			r.push(`in the missionary position.`);
+			r.push(`in the missionary position`);
 			if (slave.bellyPreg >= 600000) {
-				r.push(`A position that will be a challenge due to ${his} immense pregnancy.`);
+				r.push(r.pop() + `, a position that will be a challenge due to ${his} immense pregnancy.`);
 			} else if (slave.belly >= 600000) {
-				r.push(`A position that will be a challenge due to ${his} immense stomach.`);
+				r.push(r.pop() + `, a position that will be a challenge due to ${his} immense stomach.`);
 			} else if (slave.bellyPreg >= 300000) {
-				r.push(`A position that will be difficult due to ${his} massive pregnancy.`);
+				r.push(r.pop() + `, a position that will be difficult due to ${his} massive pregnancy.`);
 			} else if (slave.belly >= 300000) {
-				r.push(`A position that will be difficult due to ${his} massive stomach.`);
+				r.push(r.pop() + `, a position that will be difficult due to ${his} massive stomach.`);
 			} else if (slave.belly+V.PC.belly >= 20000 && slave.belly >= 1500 && V.PC.belly >= 1500) {
-				r.push(`A position that will be difficult with the combined size of your rounded middles.`);
+				r.push(r.pop() + `, a position that will be difficult with the combined size of your rounded middles.`);
+			} else {
+				r.push(r.pop() + `.`);
 			}
 			r.push(`You tell ${him} to lie down on the couch next to your desk.`);
 		} else if (fPosition <= 40) {
-			r.push(`in the cowgirl position. You lie on the couch beside your desk and tell ${him} to straddle you, facing towards you.`);
+			r.push(`in the cowgirl position`);
 			if (slave.bellyPreg >= 600000) {
-				r.push(`A position that will smother you with ${his} immense pregnancy.`);
+				r.push(r.pop() + `, a position that will smother you with ${his} immense pregnancy.`);
 			} else if (slave.belly >= 600000) {
-				r.push(`A position that will smother you with ${his} immense stomach.`);
+				r.push(r.pop() + `, a position that will smother you with ${his} immense stomach.`);
 			} else if (slave.bellyPreg >= 300000) {
-				r.push(`A position that will allow you to tease ${his} massive pregnancy as you fuck ${him}.`);
+				r.push(r.pop() + `, a position that will allow you to tease ${his} massive pregnancy as you fuck ${him}.`);
 			} else if (slave.belly >= 300000) {
-				r.push(`A position that will allow you to tease ${his} massive belly as you fuck ${him}.`);
+				r.push(r.pop() + `, a position that will allow you to tease ${his} massive belly as you fuck ${him}.`);
 			} else if (slave.belly+V.PC.belly >= 20000 && slave.belly >= 1500 && V.PC.belly >= 1500) {
-				r.push(`A position that will be awkward with the combined size of your rounded middles.`);
+				r.push(r.pop() + `, a position that will be awkward with the combined size of your rounded middles.`);
+			} else {
+				r.push(r.pop() + `.`);
 			}
+			r.push(`You lie on the couch beside your desk and tell ${him} to straddle you, facing towards you.`);
 		} else if (fPosition <= 60) {
 			r.push(`doggy-style. You tell ${him} to get on the couch beside your desk on ${his}`);
 			if (hasAnyArms(slave)) {
@@ -164,22 +169,25 @@ App.Interact.fVagina = function(slave) {
 				r.push(`${His} back will make a good rest for your gravid middle.`);
 			}
 		} else if (fPosition <= 80) {
-			r.push(`in the reverse cowgirl position. You lie on the couch beside your desk and tell ${him} to straddle you facing away from you.`);
+			r.push(`in the reverse cowgirl position`);
 			if (slave.bellyPreg >= 600000) {
-				r.push(`A position that will much more comfortable for ${his} immense pregnancy and won't crush you under its mass.`);
+				r.push(r.pop() + `, a position that will much more comfortable for ${his} immense pregnancy and won't crush you under its mass.`);
 			} else if (slave.belly >= 600000) {
-				r.push(`A position that will much more comfortable for ${his} immense belly and won't crush you under its mass.`);
+				r.push(r.pop() + `, a position that will much more comfortable for ${his} immense belly and won't crush you under its mass.`);
 			} else if (slave.bellyPreg >= 300000) {
-				r.push(`A position that will much more comfortable for ${his} massive pregnancy.`);
+				r.push(r.pop() + `, a position that will much more comfortable for ${his} massive pregnancy.`);
 			} else if (slave.belly >= 300000) {
-				r.push(`A position that will much more comfortable for ${his} massive belly.`);
+				r.push(r.pop() + `, a position that will much more comfortable for ${his} massive belly.`);
+			} else {
+				r.push(r.pop() + `.`);
 			}
+			r.push(`You lie on the couch beside your desk and tell ${him} to straddle you facing away from you.`);
 		} else {
 			r.push(`in the wheelbarrow position. You tell ${him} to get on the couch beside your desk, stand next to ${him} and lift ${his} legs up into the air.`);
 			if (slave.bellyPreg >= 600000) {
-				r.push(`${His} pregnancy is so immense it reaches the floor even as you hold ${him} saving you the trouble of bearing its weight.`);
+				r.push(`${His} pregnancy is so immense it reaches the floor even as you hold ${him}, saving you the trouble of bearing its weight.`);
 			} else if (slave.belly >= 600000) {
-				r.push(`${His} belly is so immense it reaches the floor even as you hold ${him} saving you the trouble of bearing its weight.`);
+				r.push(`${His} belly is so immense it reaches the floor even as you hold ${him}, saving you the trouble of bearing its weight.`);
 			} else if (slave.bellyPreg >= 300000) {
 				r.push(`You hope you don't strain something supporting ${his} massive pregnancy.`);
 			} else if (slave.belly >= 300000) {
diff --git a/src/npc/interaction/fondleBoobs.js b/src/npc/interaction/fondleBoobs.js
index c2678308d92..937cf63247e 100644
--- a/src/npc/interaction/fondleBoobs.js
+++ b/src/npc/interaction/fondleBoobs.js
@@ -39,9 +39,9 @@ App.Interact.fondleBoobs = function(slave) {
 		r.push(`${His} puffy nipples beg to be sucked.`);
 	} else if (slave.nipples === "flat") {
 		r.push(`${His} nipples form lewd little circles amid ${his} areolae.`);
-	} else if (slave.nipples === "partially inverted" && slave.nipplesPiercing === 0) {
+	} else if (slave.nipples === "partially inverted" && slave.piercing.nipple.weight === 0) {
 		r.push(`${His} partially inverted nipples should protrude at the slightest stimulation.`);
-	} else if (slave.nipples === "inverted" && slave.nipplesPiercing === 0) {
+	} else if (slave.nipples === "inverted" && slave.piercing.nipple.weight === 0) {
 		r.push(`${His} inverted nipples form lewd little creases across ${his} areolae.`);
 	} else if (slave.nipples === "fuckable") {
 		if (slave.lactation) {
@@ -57,11 +57,11 @@ App.Interact.fondleBoobs = function(slave) {
 		r.push(`The tattoos on ${his} breasts certainly draw attention to ${his} nipples.`);
 	}
 
-	if (slave.nipplesPiercing > 1 && !hasAnyLegs(slave)) {
+	if (slave.piercing.nipple.weight > 1 && !hasAnyLegs(slave)) {
 		r.push(`You play with the chain between ${his} nipples.`);
-	} else if (slave.nipplesPiercing > 1) {
+	} else if (slave.piercing.nipple.weight > 1) {
 		r.push(`You pull ${him} over by the chain between ${his} nipples.`);
-	} else if (slave.nipplesPiercing === 1) {
+	} else if (slave.piercing.nipple.weight === 1) {
 		r.push(`${His} nipple piercings glint enticingly.`);
 	}
 
diff --git a/src/npc/interaction/fondleDick.js b/src/npc/interaction/fondleDick.js
index ca650c236e9..1fbe9cacf30 100644
--- a/src/npc/interaction/fondleDick.js
+++ b/src/npc/interaction/fondleDick.js
@@ -65,9 +65,9 @@ App.Interact.fondleDick = function(slave) {
 	}
 
 	if (slave.dick !== 0) {
-		if (slave.vaginaPiercing > 1) {
+		if (slave.piercing.vagina.weight > 1) {
 			r.push(`Metal glints all up and down ${his} cock.`);
-		} else if (slave.vaginaPiercing === 1) {
+		} else if (slave.piercing.vagina.weight === 1) {
 			r.push(`Metal glints at the head of ${his} cock.`);
 		}
 	}
diff --git a/src/npc/interaction/fondleVagina.js b/src/npc/interaction/fondleVagina.js
index 5f822c2d909..ef2ce2ed2de 100644
--- a/src/npc/interaction/fondleVagina.js
+++ b/src/npc/interaction/fondleVagina.js
@@ -85,9 +85,9 @@ App.Interact.fondleVagina = function(slave) {
 		}
 	}
 
-	if (slave.vaginaPiercing > 1 && slave.clitPiercing > 0) {
+	if (slave.piercing.vagina.weight > 1 && slave.piercing.genitals.weight > 0) {
 		r.push(`${His} pierced lips and clit have ${his} nice and wet.`);
-	} else if (slave.clitPiercing > 0) {
+	} else if (slave.piercing.genitals.weight > 0) {
 		r.push(`${His} pierced clit has ${him} nice and moist.`);
 	}
 
diff --git a/src/npc/interaction/passage/fSlaveSlaveAss.js b/src/npc/interaction/passage/fSlaveSlaveAss.js
index 637d3adbcd4..2215b946ad5 100644
--- a/src/npc/interaction/passage/fSlaveSlaveAss.js
+++ b/src/npc/interaction/passage/fSlaveSlaveAss.js
@@ -432,7 +432,7 @@ App.Interact.fSlaveSlaveAss = function(slave) {
 			}
 			r.push(`to ${his} horror and resentment, while ${rapist.slaveName} is sleeping next to ${him} in a state of obvious satiation and bliss.`);
 		} else if (slave.devotion <= 20 || rapist.devotion <= 20) {
-			r.push(`You order ${slave.slaveName} onto the couch and tell ${rapist.slaveName} to get on with it. They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a non-verbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice rapist.slaveName's looking a little more longingly at ${slave.slaveName}.`);
+			r.push(`You order ${slave.slaveName} onto the couch and tell ${rapist.slaveName} to get on with it. They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a non-verbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice ${rapist.slaveName} is looking a little more longingly at ${slave.slaveName}.`);
 		} else if (slave.devotion <= 50 || rapist.devotion <= 50) {
 			r.push(`You order ${slave.slaveName} and ${rapist.slaveName} to get on with it. They fuck mechanically at first, gazing with roiling emotions into each others' eyes. Eventually, they begin to enjoy the intimacy of the act, finding the shared pleasure between them comforting. They finish and resume life as slaves, the light of this intimacy diminishing, softening with rapist.slaveName's dick and dripping away with the contents of ${slave.slaveName}'s cum-filled asshole.`);
 		} else {
diff --git a/src/npc/interaction/passage/fSlaveSlaveDick.js b/src/npc/interaction/passage/fSlaveSlaveDick.js
index 982f157d321..c853c580443 100644
--- a/src/npc/interaction/passage/fSlaveSlaveDick.js
+++ b/src/npc/interaction/passage/fSlaveSlaveDick.js
@@ -1011,7 +1011,7 @@ App.Interact.fSlaveSlaveDick = function(slave) {
 				}
 			}/* closes losing virginity */
 
-			r.push(`${He2} rides the helpless ${slave.slaveName} through several ejaculating orgasms. In the short breaks between them, ${he2} teases ${his} pussy. By the end of the session ${rapist.slaveName}'s cunt is dripping cum, to ${his2} obvious satiation and bliss. ${slave.slaveName} is lying next to ${him2} on the bed in a state of fatigue, the entire experience having thoroughly exhausted ${him}.`);
+			r.push(`${He2} rides the helpless ${slave.slaveName} through several ejaculating orgasms. ${slave.vagina > -1 ? `In the short breaks between them, ${he2} teases ${his} pussy. ` : ``}By the end of the session ${rapist.slaveName}'s cunt is dripping cum, to ${his2} obvious satiation and bliss. ${slave.slaveName} is lying next to ${him2} on the bed in a state of fatigue, the entire experience having thoroughly exhausted ${him}.`);
 			seX(slave, "penetrative", rapist, "vaginal", 3);
 		} else if (slave.devotion <= 20 || rapist.devotion <= 20) {
 			r.push(`You toss ${slave.slaveName} onto the bed and tell ${rapist.slaveName} to get on with it.`);
@@ -1076,7 +1076,7 @@ App.Interact.fSlaveSlaveDick = function(slave) {
 					}
 				}
 			}/* closes losing virginity */
-			r.push(`They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a nonverbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice ${rapist.slaveName}'s looking a little more longingly at ${slave.slaveName}.`);
+			r.push(`They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a nonverbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice ${rapist.slaveName} is looking a little more longingly at ${slave.slaveName}.`);
 		} else if (slave.devotion <= 50 || rapist.devotion <= 50) {
 			r.push(`You order ${slave.slaveName} and ${rapist.slaveName} to get on with it.`);
 			if (rapist.vagina === 0) { /* losing virginity */
diff --git a/src/npc/interaction/passage/fSlaveSlaveVag.js b/src/npc/interaction/passage/fSlaveSlaveVag.js
index aa12e30bc46..3d97db7d6b7 100644
--- a/src/npc/interaction/passage/fSlaveSlaveVag.js
+++ b/src/npc/interaction/passage/fSlaveSlaveVag.js
@@ -440,7 +440,7 @@ App.Interact.fSlaveSlaveVag = function(slave) {
 			}
 			r.push(`to ${his} horror and resentment, while ${rapist.slaveName} is sleeping next to ${him} in a state of obvious satiation and bliss.`);
 		} else if (slave.devotion <= 20 || rapist.devotion <= 20) {
-			r.push(`You order ${slave.slaveName} onto the couch and tell ${rapist.slaveName} to get on with it. They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a non-verbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice ${rapist.slaveName}'s looking a little more longingly at ${slave.slaveName}.`);
+			r.push(`You order ${slave.slaveName} onto the couch and tell ${rapist.slaveName} to get on with it. They fuck mechanically, gazing with roiling emotions into each others' eyes. They do seem to come to some sort of a non-verbal understanding on the necessity of getting it done, and there is no real unhappiness in either of them when they finish and disentangle themselves. As they clean themselves and exit, you notice ${rapist.slaveName} is looking a little more longingly at ${slave.slaveName}.`);
 		} else if (slave.devotion <= 50 || rapist.devotion <= 50) {
 			r.push(`You order ${slave.slaveName} and ${rapist.slaveName} to get on with it. They fuck mechanically at first, gazing with roiling emotions into each others' eyes. Eventually, they begin to enjoy the intimacy of the act, finding the shared pleasure between them comforting. They finish and resume life as slaves, the light of this intimacy diminishing, softening with ${rapist.slaveName}'s dick and dripping away with the contents of ${slave.slaveName}'s cum-filled pussy.`);
 		} else {
diff --git a/src/npc/startingGirls/startingGirls.js b/src/npc/startingGirls/startingGirls.js
index 015bb2520e8..282b30ed888 100644
--- a/src/npc/startingGirls/startingGirls.js
+++ b/src/npc/startingGirls/startingGirls.js
@@ -785,7 +785,7 @@ App.StartingGirls.physical = function(slave, cheat = false) {
 						""
 					);
 					if (cheat ) {
-						if (slave.PLimb > 0 && slave.PLimb < 3) {
+						if (slave.PLimb.isBetween(0, 3)) {
 							option.addValueList([
 								["Simple prosthetic", 2],
 								["Advanced: Sex", 3],
@@ -793,7 +793,7 @@ App.StartingGirls.physical = function(slave, cheat = false) {
 								["Advanced: Combat", 5],
 							]);
 						}
-						if (slave.PLimb > 1 && slave.PLimb < 3) {
+						if (slave.PLimb.isBetween(1, 3)) {
 							option.addValue("Cybernetic", 6);
 						}
 						if (slave.PLimb === 3) {
@@ -1253,7 +1253,7 @@ App.StartingGirls.lower = function(slave, cheat = false) {
 	if (cheat) {
 		options.addOption("Butt implant type", "buttImplantType", slave)
 			.addValueList([
-				["None", "None"],
+				["None", "none"],
 				["Normal", "normal"],
 				["String", "string"],
 				["Fillable", "fillable"],
diff --git a/src/npc/surgery/bodySwap/bodySwap.js b/src/npc/surgery/bodySwap/bodySwap.js
index 6dc71526e3b..3d64769a492 100644
--- a/src/npc/surgery/bodySwap/bodySwap.js
+++ b/src/npc/surgery/bodySwap/bodySwap.js
@@ -41,7 +41,6 @@ globalThis.bodySwap = function(soul, body, fromGenepool) {
 	soul.hStyle = body.hStyle;
 	soul.pubicHStyle = body.pubicHStyle;
 	soul.waist = body.waist;
-	soul.corsetPiercing = body.corsetPiercing;
 	soul.arm = body.arm;
 	soul.leg = body.leg;
 	soul.PLimb = body.PLimb;
@@ -56,10 +55,8 @@ globalThis.bodySwap = function(soul, body, fromGenepool) {
 	soul.boobsImplantType = body.boobsImplantType;
 	soul.boobShape = body.boobShape;
 	soul.nipples = body.nipples;
-	soul.nipplesPiercing = body.nipplesPiercing;
 	soul.nipplesAccessory = body.nipplesAccessory;
 	soul.areolae = body.areolae;
-	soul.areolaePiercing = body.areolaePiercing;
 	soul.areolaeShape = body.areolaeShape;
 	soul.boobsTat = body.boobsTat;
 	soul.lactation = body.lactation;
@@ -78,13 +75,10 @@ globalThis.bodySwap = function(soul, body, fromGenepool) {
 	soul.faceShape = body.faceShape;
 	soul.lips = body.lips;
 	soul.lipsImplant = body.lipsImplant;
-	soul.lipsPiercing = body.lipsPiercing;
 	soul.lipsTat = body.lipsTat;
 	soul.teeth = body.teeth;
-	soul.tonguePiercing = body.tonguePiercing;
 	soul.vagina = body.vagina;
 	soul.vaginaLube = body.vaginaLube;
-	soul.vaginaPiercing = body.vaginaPiercing;
 	soul.vaginaTat = body.vaginaTat;
 	soul.fertKnown = body.fertKnown;
 	soul.fertPeak = body.fertPeak;
@@ -94,23 +88,17 @@ globalThis.bodySwap = function(soul, body, fromGenepool) {
 	soul.broodmotherCountDown = body.broodmotherCountDown;
 	soul.labia = body.labia;
 	soul.clit = body.clit;
-	soul.clitPiercing = body.clitPiercing;
 	soul.dick = body.dick;
 	soul.foreskin = body.foreskin;
 	soul.anus = body.anus;
 	soul.analArea = body.analArea;
-	soul.dickPiercing = body.dickPiercing;
 	soul.dickTat = body.dickTat;
 	soul.prostate = body.prostate;
 	soul.balls = body.balls;
 	soul.scrotum = body.scrotum;
 	soul.ovaries = body.ovaries;
-	soul.anusPiercing = body.anusPiercing;
 	soul.anusTat = body.anusTat;
 	soul.brand = body.brand;
-	soul.nosePiercing = body.nosePiercing;
-	soul.eyebrowPiercing = body.eyebrowPiercing;
-	soul.navelPiercing = body.navelPiercing;
 	soul.shouldersTat = body.shouldersTat;
 	soul.armsTat = body.armsTat;
 	soul.legsTat = body.legsTat;
@@ -173,7 +161,7 @@ globalThis.bodySwap = function(soul, body, fromGenepool) {
 		soul.minorInjury = body.minorInjury;
 		soul.eyewear = body.eyewear;
 		soul.earwear = body.earwear;
-		soul.earPiercing = body.earPiercing;
+		soul.piercing = body.piercing;
 		soul.armAccessory = body.armAccessory;
 		soul.legAccessory = body.legAccessory;
 		soul.bellyAccessory = body.bellyAccessory;
diff --git a/src/npc/surgery/bodySwap/bodySwapReaction.js b/src/npc/surgery/bodySwap/bodySwapReaction.js
index a9f0e9c0fe9..aca16292ce8 100644
--- a/src/npc/surgery/bodySwap/bodySwapReaction.js
+++ b/src/npc/surgery/bodySwap/bodySwapReaction.js
@@ -186,9 +186,9 @@ globalThis.bodySwapReaction = function(body, soul) {
 			r.push(`${His} hand roams over ${his} face searching for changes.`);
 
 			if (
-				(body.earPiercing !== 0 && soul.earPiercing === 0) ||
-				(body.eyebrowPiercing !== 0 && soul.eyebrowPiercing === 0) ||
-				(body.nosePiercing !== 0 && soul.nosePiercing === 0)
+				(body.piercing.ear.weight !== 0 && soul.piercing.ear.weight === 0) ||
+				(body.piercing.eyebrow.weight !== 0 && soul.piercing.eyebrow.weight === 0) ||
+				(body.piercing.nose.weight !== 0 && soul.piercing.nose.weight === 0)
 			) {
 				r.push(`${He} finds several new piercings adorning ${his} face.`);
 			}
@@ -251,7 +251,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					r.push(`finding them familiar enough.`);
 				}
 			}
-			if (body.lipsPiercing !== 0 && soul.lipsPiercing === 0) {
+			if (body.piercing.lips.weight !== 0 && soul.piercing.lips.weight === 0) {
 				r.push(`${He} flexes ${his} lips and notices the telltale clicking of a piercing against ${his} teeth.`);
 			}
 			if (body.teeth === "removable" && soul.teeth !== "removable") { /* no teeth */
@@ -260,7 +260,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					r.push(`${He} <span class="mediumorchid">glowers</span> at them, knowing full well they'll be back in ${his} mouth shortly.`);
 					body.devotion -= 2;
 				}
-			} else if (body.teeth !== "removable" && body.tonguePiercing > 0 && soul.tonguePiercing === 0) { /* (if tongue pierced+has teeth) */
+			} else if (body.teeth !== "removable" && body.piercing.tongue.weight > 0 && soul.piercing.tongue.weight === 0) { /* (if tongue pierced+has teeth) */
 				r.push(`You can vaguely hear ${him} rattling ${his} tongue piercing against ${his} teeth.`);
 			}
 			if (
@@ -716,7 +716,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					}
 				}
 			}
-			if (body.areolaePiercing !== 0 && soul.areolaePiercing === 0) {
+			if (body.piercing.areola.weight !== 0 && soul.piercing.areola.weight === 0) {
 				r.push(`${He} bumps into the piercings in ${his} areolae, brushing ${his} fingers against them and toying with them for a moment.`);
 			}
 
@@ -782,7 +782,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 						break;
 					case "partially inverted":
 						r.push(`${He} quivers a little as ${he}`);
-						if (body.nipplesPiercing !== 0) {
+						if (body.piercing.nipple.weight !== 0) {
 							r.push(`tugs on the piercings, pulling <span class="lime">partially inverted nipples</span> out.`);
 						} else {
 							r.push(`teases the <span class="lime">little exposed nipples</span> sticking out of ${his} breasts.`);
@@ -790,7 +790,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 						break;
 					case "inverted":
 						r.push(`${He} quivers a little as ${he}`);
-						if (body.nipplesPiercing !== 0) {
+						if (body.piercing.nipple.weight !== 0) {
 							r.push(`tugs on the piercings, forcing ${his} <span class="lime">inverted nipples</span> completely out.`);
 						} else {
 							r.push(`accidentally pops one of ${his} <span class="lime">inverted nipples</span> out.`);
@@ -799,7 +799,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					default:
 						r.push(`They can only be called normal, though ${he} can still call them cute.`);
 				}
-				if (body.nipplesPiercing !== 0 && soul.nipplesPiercing === 0 && body.nipples !== "inverted" && body.nipples !== "partially inverted") {
+				if (body.piercing.nipple.weight !== 0 && soul.piercing.nipple.weight === 0 && body.nipples !== "inverted" && body.nipples !== "partially inverted") {
 					r.push(`${He} also finds they are pierced, and takes a moment to pull at one, shivering at the tingles the action sends through ${his} chest.`);
 				}
 			}
@@ -1543,7 +1543,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 			} else {
 				r.push(`stomach, though ${he} finds little out of the ordinary${(weightChange === 1) ? `; other than the obvious, of course` : ``}.`);
 			}
-			if (body.navelPiercing !== 0 && soul.navelPiercing === 0) {
+			if (body.piercing.navel.weight !== 0 && soul.piercing.navel.weight === 0) {
 				r.push(`${He} now has a piercing in ${his} navel; ${he} rolls ${his} tummy${(body.belly >= 15000) ? `, a feat in and of itself` : ``}, fascinated by ${his} new hardware grazing ${his} stomach to the motion.`);
 			}
 
@@ -1572,7 +1572,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 			}
 
 			/* corset piercing */
-			if (body.corsetPiercing !== 0 && soul.corsetPiercing === 0) {
+			if (body.piercing.corset.weight !== 0 && soul.piercing.corset.weight === 0) {
 				r.push(`An odd feeling on ${his} back draws ${his} attention. ${He} discovers a series of rings running down ${his} spine and, flexing ${his} back muscles, shudders at the sensation.`);
 			}
 
@@ -1746,7 +1746,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 				}
 				cockChanged = 1;
 			}
-			if (body.dickPiercing !== 0 && soul.dickPiercing === 0) {
+			if (body.piercing.dick.weight !== 0 && soul.piercing.dick.weight === 0) {
 				r.push(`There was no missing the piercing in ${his} dick as well.`);
 				cockChanged = 1;
 			}
@@ -1865,10 +1865,10 @@ globalThis.bodySwapReaction = function(body, soul) {
 					r.push(`After a bit of toying, ${he}'s satisfied with ${his} new organ.`);
 				}
 			}
-			if (body.clitPiercing > 0 && soul.clitPiercing === 0 && body.dick === 0) {
+			if (body.piercing.genitals.weight > 0 && soul.piercing.genitals.weight === 0 && body.dick === 0) {
 				r.push(`${He} also briefly felt something metallic near ${his} clit. ${He} frowns for a moment, before reaching down to ${his} nether region to peel back ${his} folds to feel a new, hard spot that wasn't there before. As ${he} pulls at it, ${his} face and body contort in pleasure at the sensation.`);
 			}
-			if (body.vaginaPiercing !== 0 && soul.vaginaPiercing === 0) {
+			if (body.piercing.vagina.weight !== 0 && soul.piercing.vagina.weight === 0) {
 				r.push(`${He} also now has piercings in ${his} vagina, a ring around ${his} labia, creating`);
 				if (canSee(body)) {
 					r.push(`a halo of sparkles that ${he} couldn't help but marvel at.`);
@@ -2001,7 +2001,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					body.devotion -= 3;
 				}
 			}
-			if (body.anusPiercing !== 0 && soul.anusPiercing === 0) {
+			if (body.piercing.anus.weight !== 0 && soul.piercing.anus.weight === 0) {
 				r.push(`As ${he} moves, ${he} feels something odd in ${his} butt. With a hesitant finger, ${he} traces ${his} anus and finds something that will take some getting used to; a new anal piercing.`);
 			}
 
@@ -2494,7 +2494,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					}
 				}
 			}
-			if (body.areolaePiercing !== 0 && soul.areolaePiercing === 0) {
+			if (body.piercing.areola.weight !== 0 && soul.piercing.areola.weight === 0) {
 				if (body.fetish !== "mindbroken" && body.boobs >= 10000) {
 					r.push(`${He} can just barely catch the glimmer of the piercings adorning ${his} areolae.`);
 				} else if (body.fetish === "mindbroken" && body.boobs >= 10000) {
@@ -2563,7 +2563,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					default:
 						r.push(`They can only be called normal, though ${he} can still call them cute.`);
 				}
-				if (body.nipplesPiercing !== 0 && soul.nipplesPiercing === 0) {
+				if (body.piercing.nipple.weight !== 0 && soul.piercing.nipple.weight === 0) {
 					r.push(`${He} also notices they are pierced, judging by how ${his} eyes follow the movement of the piercings.`);
 				}
 			}
@@ -2728,7 +2728,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					r.push(`finding them familiar enough.`);
 				}
 			}
-			if (body.lipsPiercing !== 0 && soul.lipsPiercing === 0) {
+			if (body.piercing.lips.weight !== 0 && soul.piercing.lips.weight === 0) {
 				r.push(`${He} touches the tip of ${his} tongue to ${his} new piercing.`);
 			}
 			if (body.teeth === "removable" && soul.teeth !== "removable") { /* no teeth */
@@ -2737,7 +2737,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					r.push(`${He} <span class="mediumorchid">glowers</span> at them, knowing full well they'll be back in ${his} mouth shortly.`);
 					body.devotion -= 2;
 				}
-			} else if (body.teeth !== "removable" && body.tonguePiercing > 0 && soul.tonguePiercing === 0) { /* (if tongue pierced+has teeth) */
+			} else if (body.teeth !== "removable" && body.piercing.tongue.weight > 0 && soul.piercing.tongue.weight === 0) { /* (if tongue pierced+has teeth) */
 				r.push(`You can vaguely hear ${him} rattling ${his} tongue piercing against ${his} teeth as ${he} takes in ${his} appearance.`);
 			}
 			if (
@@ -2773,9 +2773,9 @@ globalThis.bodySwapReaction = function(body, soul) {
 				}
 			}
 			if (
-				(body.earPiercing !== 0 && soul.earPiercing === 0) ||
-				(body.eyebrowPiercing !== 0 && soul.eyebrowPiercing === 0) ||
-				(body.nosePiercing !== 0 && soul.nosePiercing === 0)
+				(body.piercing.ear.weight !== 0 && soul.piercing.ear.weight === 0) ||
+				(body.piercing.eyebrow.weight !== 0 && soul.piercing.eyebrow.weight === 0) ||
+				(body.piercing.nose.weight !== 0 && soul.piercing.nose.weight === 0)
 			) {
 				r.push(`On top of that, several new piercings glint upon ${his} face.`);
 			}
@@ -3296,7 +3296,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 			} else {
 				r.push(`stomach, though ${he} finds little out of the ordinary${(weightChange === 1) ? `; other than the obvious, of course` : ``}.`);
 			}
-			if (body.navelPiercing !== 0 && soul.navelPiercing === 0) {
+			if (body.piercing.navel.weight !== 0 && soul.piercing.navel.weight === 0) {
 				r.push(`${He} now has a piercing in ${his} navel; ${he} rolls ${his} tummy${(body.belly >= 15000) ? `, a feat in and of itself` : ``}, fascinated by ${his} new hardware grazing ${his} stomach to the motion.`);
 			}
 
@@ -3436,7 +3436,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 						}
 					}
 				}
-				if (body.anusPiercing !== 0 && soul.anusPiercing === 0) {
+				if (body.piercing.anus.weight !== 0 && soul.piercing.anus.weight === 0) {
 					r.push(`As ${he} moved, ${he} felt something odd in ${his} butt. ${He} can only speculate that ${he} has a new addition down there.`);
 				}
 			}
@@ -3455,7 +3455,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 				}
 				if (body.fetish !== "mindbroken") {
 					r.push(`${He} shifts ${his} weight so that ${he} falls onto ${his} back`);
-					if (body.corsetPiercing !== 0 && soul.corsetPiercing === 0) {
+					if (body.piercing.corset.weight !== 0 && soul.piercing.corset.weight === 0) {
 						r.push(`and recoils as ${he} lands on something unfamiliar and hard. ${His} mind races as to what it could be, before the realization sets in that ${he} now has a corset piercing up ${his} back. Once ${he} gets used to the feeling, ${he} leans to ${his} side to finally get a view around ${his} body.`);
 					} else {
 						r.push(`and leans to ${his} side to finally see what's under ${his} body.`);
@@ -3624,7 +3624,7 @@ globalThis.bodySwapReaction = function(body, soul) {
 					}
 					cockChanged = 1;
 				}
-				if (body.dickPiercing !== 0 && soul.dickPiercing === 0) {
+				if (body.piercing.dick.weight !== 0 && soul.piercing.dick.weight === 0) {
 					r.push(`There was no missing the piercing in ${his} dick as well.`);
 					cockChanged = 1;
 				}
@@ -3749,10 +3749,10 @@ globalThis.bodySwapReaction = function(body, soul) {
 						} else {
 							r.push(`After a bit of flexing, ${he}'s satisfied with ${his} new organ.`);
 						}
-						if (body.clitPiercing > 0 && soul.clitPiercing === 0 && body.dick === 0) {
+						if (body.piercing.genitals.weight > 0 && soul.piercing.genitals.weight === 0 && body.dick === 0) {
 							r.push(`${He} also noticed a glimmer ${his} clit.`);
 						}
-						if (body.vaginaPiercing !== 0 && soul.vaginaPiercing === 0) {
+						if (body.piercing.vagina.weight !== 0 && soul.piercing.vagina.weight === 0) {
 							r.push(`${He} also now has piercings in ${his} vagina, a ring around ${his} labia, creating a halo of sparkles that ${he} couldn't help but marvel at.`);
 						}
 					}
diff --git a/src/npc/surgery/surgery.js b/src/npc/surgery/surgery.js
index 9b412cae006..3c5519f2ae2 100644
--- a/src/npc/surgery/surgery.js
+++ b/src/npc/surgery/surgery.js
@@ -542,21 +542,21 @@ globalThis.surgeryAmp = function(slave, part, cheat = false) {
 			delete slave.brand["left ear"];
 			slave.earShape = "none";
 			slave.earT = "none";
-			slave.earPiercing = 0;
+			slave.piercing.ear.weight = 0;
 			surgeryDamage(slave, 10, cheat);
 			break;
 		case "right ear":
 			delete slave.brand["right ear"];
 			slave.earShape = "none";
 			slave.earT = "none";
-			slave.earPiercing = 0;
+			slave.piercing.ear.weight = 0;
 			surgeryDamage(slave, 10, cheat);
 			break;
 		case "dick":
 			slave.dick = 0;
 			slave.foreskin = 0;
 			slave.skill.vaginal = 0;
-			slave.dickPiercing = 0;
+			slave.piercing.dick.weight = 0;
 			slave.dickTat = 0;
 			slave.dickAccessory = "none";
 			slave.chastityPenis = 0;
diff --git a/src/npc/surgery/surgeryDegradation.js b/src/npc/surgery/surgeryDegradation.js
index 9a18eff12ef..392ca3083b8 100644
--- a/src/npc/surgery/surgeryDegradation.js
+++ b/src/npc/surgery/surgeryDegradation.js
@@ -18,7 +18,8 @@ App.UI.SlaveInteract.surgeryDegradation = function(slave) {
 	// TODO: do this during apply
 	if (slave.dick === 0) {
 		if (slave.vagina === -1) {
-			slave.clitPiercing = 0;
+			slave.piercing.genitals.weight = 0;
+			slave.piercing.genitals.smart = false;
 		}
 		if (slave.drugs === "penis enhancement" || slave.drugs === "hyper penis enhancement" || slave.drugs === "breast redistributors") {
 			slave.drugs = "no drugs";
diff --git a/src/personalAssistant/assistantOptions.js b/src/personalAssistant/assistantOptions.js
index 946a370fd9f..9c8be5465dc 100644
--- a/src/personalAssistant/assistantOptions.js
+++ b/src/personalAssistant/assistantOptions.js
@@ -1,6 +1,8 @@
 App.UI.personalAssistantOptions = function() {
 	const node = new DocumentFragment();
 
+	// App.UI.DOM.appendNewElement("h1", node, `Personal Assistant`);
+
 	assistant.object();
 
 	App.Events.drawEventArt(node, "assistant");
diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js
index 8557f486d25..8094f227fb5 100644
--- a/src/player/js/PlayerState.js
+++ b/src/player/js/PlayerState.js
@@ -514,9 +514,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * * -96-: absurd
 		 */
 		this.waist = 0;
-		/** series of rings up the back that can be tied together. 0: no, 1: yes
-		 * @type {FC.Bool} */
-		this.corsetPiercing = 0;
 		/**
 		 * What level of prosthetic interface you have installed
 		 * * 0: no interface
@@ -664,21 +661,12 @@ App.Entity.PlayerState = class PlayerState {
 		 * @type {FC.NippleShape}
 		 */
 		this.nipples = "cute";
-		/**
-		 * nipple are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavily */
-		this.nipplesPiercing = 0;
 		/** what accessory, if any, are on your nipples */
 		this.nipplesAccessory = "none";
 		/** slave areolae
 		 *
 		 * 0: normal; 1: large; 2: unusually wide; 3: huge, 4: massive */
 		this.areolae = 0;
-		/** edge of areolae are pierced
-		 * @type {FC.PiercingType}
-		 * 0: none; 1: yes; 2: heavy */
-		this.areolaePiercing = 0;
 		/** your areolae shape ("heart"; "star"; "circle") */
 		this.areolaeShape = "circle";
 		/**
@@ -834,11 +822,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * @see lips
 		 */
 		this.lipsImplant = 0;
-		/**
-		 * lips pierced
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.lipsPiercing = 0;
 		/**
 		 * lip tattoo
 		 *
@@ -870,11 +853,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * @type {FC.TeethType}
 		 */
 		this.teeth = "normal";
-		/**
-		 * have tongue piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.tonguePiercing = 0;
 		/**
 		 * vagina type
 		 * * -1: no vagina
@@ -895,10 +873,6 @@ App.Entity.PlayerState = class PlayerState {
 		 *
 		 * 0: dry; 1: wet; 2: soaking wet */
 		this.vaginaLube = 0;
-		/** have vagina piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.vaginaPiercing = 0;
 		/**
 		 * vagina tattoo
 		 *
@@ -1069,15 +1043,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * * 5: like a massive penis
 		 */
 		this.clit = 0;
-		/**
-		 * is clit pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * * 3: smart
-		 * @type {FC.ClitoralPiercingType}
-		 */
-		this.clitPiercing = 0;
 		/** 0: circumcised; 1+:uncut, also affects foreskin size */
 		this.foreskin = 0;
 		/**
@@ -1107,14 +1072,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * * 11+: hypertrophied
 		 */
 		this.dick = 4;
-		/**
-		 * is dick pierced
-		 * * 0: no
-		 * * 1: yes
-		 * * 2: heavy
-		 * @type {FC.PiercingType}
-		 */
-		this.dickPiercing = 0;
 		/**
 		 * dick tattoo
 		 *
@@ -1175,10 +1132,6 @@ App.Entity.PlayerState = class PlayerState {
 		 * @type {FC.Bool}
 		 * 0: no; 1: yes */
 		this.ovaries = 0;
-		/** has anus piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.anusPiercing = 0;
 		/**
 		 * anus tattoo
 		 *
@@ -1229,22 +1182,7 @@ App.Entity.PlayerState = class PlayerState {
 		 *
 		 * @type {Object.<string, string>} */
 		this.brand = {};
-		/** has pierced ears
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.earPiercing = 0;
-		/** has pierced nose
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.nosePiercing = 0;
-		/** has eyebrow piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.eyebrowPiercing = 0;
-		/** has navel piercing
-		 * @type {FC.PiercingType}
-		 * 0: no; 1: yes; 2: heavy */
-		this.navelPiercing = 0;
+		this.piercing = new App.Entity.completePiercingState();
 		/**
 		 * shoulder tattoo
 		 *
@@ -2041,9 +1979,9 @@ App.Entity.PlayerState = class PlayerState {
 	 */
 	static makeSkeleton() {
 		return {
-			arm: {left: {}, right: {}},
-			leg: {left: {}, right: {}},
-			eye: {left: {}, right: {}},
+			arm: { left: {}, right: {} },
+			leg: { left: {}, right: {} },
+			eye: { left: {}, right: {} },
 			readyProsthetics: [], // yes, not an object, but needed for hero slaves
 			counter: {},
 			brand: {},
diff --git a/src/player/personalAttentionSelect.js b/src/player/personalAttentionSelect.js
index 7cec8edf7a2..a1b132c6755 100644
--- a/src/player/personalAttentionSelect.js
+++ b/src/player/personalAttentionSelect.js
@@ -45,7 +45,7 @@ App.UI.Player.personalAttention = function() {
 
 			if (V.personalAttention.length > 1) {
 				V.personalAttention[1].trainingRegimen = V.personalAttention[1].trainingRegimen
-					|| getRegimen(getSlave(V.personalAttention[0].ID));
+					|| getRegimen(getSlave(V.personalAttention[1].ID));
 			}
 
 			text.push(`training <span class="slave-name">${SlaveFullName(getSlave(V.personalAttention[0].ID))}</span> to <span class="bold">${V.personalAttention[0].trainingRegimen}${V.personalAttention.length > 1? `</span> and <span class="slave-name">${SlaveFullName(getSlave(V.personalAttention[1].ID))}</span> to <span class="bold">${V.personalAttention[1].trainingRegimen}` : ``}.</span>`);
@@ -964,30 +964,28 @@ App.UI.Player.personalAttention = function() {
 	 * @returns {string}
 	 */
 	function getRegimen(slave, regimen = null) {
-		const {his} = getPronouns(slave);
-
 		if (!regimen) {
 			if (slave.health.condition < -20) {
-				return `look after ${his} health`;
+				return `look after her health`;
 			} else if (slave.behavioralFlaw !== "none") {
 				if (slave.devotion < -20) {
-					return `fix ${his} behavioral flaw`;
+					return `fix her behavioral flaw`;
 				} else {
-					return `soften ${his} behavioral flaw`;
+					return `soften her behavioral flaw`;
 				}
 			} else if (slave.sexualFlaw !== "none") {
 				if (slave.devotion < -20) {
-					return `fix ${his} sexual flaw`;
+					return `fix her sexual flaw`;
 				} else {
-					return `soften ${his} sexual flaw`;
+					return `soften her sexual flaw`;
 				}
 			} else if (!slave.fetishKnown) {
-				return `explore ${his} sexuality`;
+				return `explore her sexuality`;
 			} else if (slave.devotion <= 20 && slave.trust >= -20) {
-				return `break ${his} will`;
+				return `break her will`;
 			}
 		}
 
-		return `build ${his} devotion`;
+		return `build her devotion`;
 	}
 };
diff --git a/src/pregmod/FCTV/FCTVshows.js b/src/pregmod/FCTV/FCTVshows.js
index d7833dbf562..bd04001b8bb 100644
--- a/src/pregmod/FCTV/FCTVshows.js
+++ b/src/pregmod/FCTV/FCTVshows.js
@@ -542,7 +542,7 @@ App.Data.FCTV.channels = {
 						r.push(`survive`);
 					}
 					r.push(`the 10 day sentence!"</p>`);
-					r.push(`<p>Jules smiles. "That's exactly right Master McMahon, she's going to be`);
+					r.push(`<p>Jules smiles. "That's exactly right, Master McMahon, she's going to be`);
 					if (V.seeExtreme === 0) {
 						r.push(`<i>hugged until she smiles</i>.`);
 					} else {
diff --git a/src/pregmod/theBlackMarket.js b/src/pregmod/theBlackMarket.js
index ccbfa9d5591..55e1c1c9fe4 100644
--- a/src/pregmod/theBlackMarket.js
+++ b/src/pregmod/theBlackMarket.js
@@ -1,6 +1,8 @@
 App.UI.theBlackMarket = function() {
 	const node = new DocumentFragment();
 
+	// App.UI.DOM.appendNewElement("h1", node, `The Black Market`);
+
 	const {
 		He,
 		he, his
@@ -163,7 +165,7 @@ App.UI.theBlackMarket = function() {
 									},
 									[],
 									"",
-									`${cashFormat(growthCash)}.`
+									`Costs ${cashFormat(growthCash)}`
 								));
 							} else {
 								r.push(`You cannot afford the asking price of <span class="cash dec">${(cashFormat(growthCash))}</span> for extremely powerful growth drug formulas. "Why'd you even come here if you didn't have the credits to buy anything?"`);
@@ -191,7 +193,7 @@ App.UI.theBlackMarket = function() {
 									},
 									[],
 									"",
-									`${cashFormat(reverseGrowthCash)}.`
+									`Costs ${cashFormat(reverseGrowthCash)}`
 								));
 							} else {
 								r.push(`You cannot afford the asking price of <span class="cash dec">${cashFormat(reverseGrowthCash)}</span> for growth reversing drug formulas. "`);
@@ -229,7 +231,7 @@ App.UI.theBlackMarket = function() {
 									},
 									[],
 									"",
-									`${cashFormat(beautyCreamCash)}.`
+									`Costs ${cashFormat(beautyCreamCash)}`
 								));
 							} else {
 								r.push(`You cannot afford the asking price of <span class="cash dec">${cashFormat(beautyCreamCash)}</span> for extremely effective anti-aging beauty creams. "${(V.PC.visualAge > 40) ? `Those wrinkles don't look that bad on you, so don't worry about not being able to afford this` : `Just tell them they look young, and, well, don't give them any mirrors. Probably should keep your money troubles from them, too`}."`);
@@ -528,7 +530,7 @@ App.UI.theBlackMarket = function() {
 									},
 									[],
 									"",
-									`${(cashFormat(slushFund))}.`
+									`Costs ${(cashFormat(slushFund))}`
 								));
 							} else {
 								r.push(`You cannot afford the asking price of <span class="cash dec">${(cashFormat(slushFund))}</span> for elasticity increasing injections.`);
-- 
GitLab