code:
App.Data.NewGamePlus = (function() {
	const NGPOffset = 1200000;

	function ngpSlaveID(id, preserveSpecial=false) {
		const minID = preserveSpecial ? -20 : -1;
		if (id > 0) {
			id += NGPOffset;
		} else if (V.freshPC === 1 && id === -1) {
			id = -NGPOffset;
		} else if (id < minID) {
			id -= NGPOffset;
		}
		return id;
	}

	function slaveIDOrZero(id) {
		if (id > 0 && !getSlave(id)) {
			return 0;
		}
		return id;
	}

	function PCInit() {
		if (V.freshPC === 0) {
			cashX(V.ngpParams.prosperity, "personalBusiness");
			const oldCash = V.cash;
			V.cash = 0;
			V.cashLastWeek = 0;
			cashX((Math.clamp(1000*Math.trunc(oldCash/100000), 5000, 1000000)), "personalBusiness");
			if (V.retainCareer === 0) {
				V.PC.career = "arcology owner";
				V.PC.skill.trading = 100;
				V.PC.skill.warfare = 100;
				V.PC.skill.hacking = 100;
				V.PC.skill.slaving = 100;
				V.PC.skill.engineering = 100;
				V.PC.skill.medicine = 100;
			}
			V.PC.mother = ngpSlaveID(V.PC.mother);
			V.PC.father = ngpSlaveID(V.PC.father);
			V.PC.pregSource = slaveIDOrZero(ngpSlaveID(V.PC.pregSource, true));
			for (let fetus of V.PC.womb) {
				fetus.fatherID = ngpSlaveID(fetus.fatherID, true);
				fetus.genetics.father = ngpSlaveID(fetus.genetics.father, true);
				fetus.genetics.mother = ngpSlaveID(fetus.genetics.mother, true);
			}
		} else {
			V.PC = basePlayer();
			WombInit(V.PC);
			V.cheater = 0;
			V.cash = 0;
			cashX(10000, "personalBusiness");
		}
	}

	function slaveLoopInit() {
		/**
		 * @param {Readonly<{[key: string]: Partial<FC.GenePoolRecord>}>} [genePool={}]
		 * @returns {Readonly<{[key: string]: Partial<FC.GenePoolRecord>}>}
		 */
		const ngUpdateGenePool = function(genePool = {}) {
			/** @type {FC.HumanID[]} */
			const transferredSlaveIds = getSlaves()
				.filter(s => s.ID >= NGPOffset)
				.map(s => s.ID - NGPOffset);
			/** @type {{[key: string]: Partial<FC.GenePoolRecord>}} */
			const newGP = {};
			for (const ID in genePool) {
				if (transferredSlaveIds.includes(ID)) {
					const record = _.cloneDeep(genePool[ID]);
					record.ID += NGPOffset;
					record.mother = ngpSlaveID(record.mother);
					record.father = ngpSlaveID(record.father);
					record.cloneID = ngpSlaveID(record.cloneID);
					newGP[String(record.ID)] = record;
				}
			}
			if (V.freshPC === 0) {
				newGP[String(-1)] = _.cloneDeep(genePool[String(-1)]);
			}
			return newGP;
		};

		/**
		 * @param {Record<FC.HumanID, FC.MissingParentRecord>} missingTable
		 * @returns {Record<FC.HumanID, FC.MissingParentRecord>}
		 */
		const ngUpdateMissingTable = function(missingTable) {
			const newTable = {};
			let needed = [];

			(getSlaves())
				.forEach(s => ([s.pregSource + NGPOffset, s.mother + NGPOffset, s.father + NGPOffset]
					.filter(i => (i in missingTable))
					.forEach(i => {
						if (needed.indexOf(i) === -1) {
							needed.push(i);
						}
					})));
			(getSlaves()).forEach(s => (s.womb
				.forEach(f => ([f.fatherID, f.genetics.father, f.genetics.mother]
					.filter(i => (i in missingTable))
					.forEach(i => {
						if (needed.indexOf(i) === -1) {
							needed.push(i);
						}
					})))));

			while (needed.length > 0) {
				let i = needed.shift();
				let s = missingTable[i];
				newTable[i - NGPOffset] = s;
				s.ID -= NGPOffset;
				if (s.mother in missingTable) {
					s.mother -= NGPOffset;
					if (!(s.mother in newTable) && needed.indexOf(s.mother + NGPOffset) === -1) {
						needed.push(s.mother + NGPOffset);
					}
				}
				if (s.father in missingTable) {
					s.father -= NGPOffset;
					if (!(s.father in newTable) && needed.indexOf(s.father + NGPOffset) === -1) {
						needed.push(s.father + NGPOffset);
					}
				}
			}

			return newTable;
		};

		const ngUpdatePartners = function(slave) {
			const partners = [...slave.partners]
				.map(k => ngpSlaveID(k, true));

			return new Set(partners);
		};

		let oldMissingParentID = Math.min(-10000, ...Object.keys(V.missingTable)) - 1;
		getSlaves().filter(s => (s.assignment !== Job.IMPORTED)).forEach(s => {
			V.missingTable[oldMissingParentID] = missingTableRecordFromHumanState(s, oldMissingParentID);
			Object.values(V.missingTable).forEach(so => {
				if (so.mother === s.ID) {
					so.mother = oldMissingParentID;
				}
				if (so.father === s.ID) {
					so.father = oldMissingParentID;
				}
			});
			[].concat(...getSlaves().values()).concat([V.PC]).forEach(so => {
				if (so.mother === s.ID) {
					so.mother = oldMissingParentID;
				}
				if (so.father === s.ID) {
					so.father = oldMissingParentID;
				}
				if (so.assignment === Job.IMPORTED || so.ID === -1) {
					WombChangeID(so, s.ID, oldMissingParentID);
				}
			});
			oldMissingParentID--;
		});

		getSlaves().forEach((s, ID, map) => {
			if (s.assignment !== Job.IMPORTED) {
				map.delete(ID);
			}
		});

		for (let slave of getSlaves().values()) {
			slave.ID += NGPOffset;
			slave.assignment = Job.REST;
			if (V.freshPC === 1) { // check whether to reset weekAcquired same way we check whether to change father of fetus
				// She's the same number of weeks pregnant, with the same baby, so to the extent this is "really" happening,
				// the new PC must have acquired her this week.
				slave.weekAcquired = 0;
			} else {
				// V.week is getting reset to 0, new weekAcquired is relative to the new V.week
				slave.weekAcquired -= V.week;
			}
			slave.newGamePlus = 1;
			slave.mother = ngpSlaveID(slave.mother);
			slave.father = ngpSlaveID(slave.father);
			slave.canRecruit = 0;
			slave.breedingMark = 0;
			if (typeof V.ngpParams.nationality === 'string') {
				slave.nationality = V.ngpParams.nationality;
			}
			slave.relationshipTarget = ngpSlaveID(slave.relationshipTarget);
			slave.cloneID = ngpSlaveID(slave.cloneID);
			slave.pregSource = ngpSlaveID(slave.pregSource, true);
			for (let fetus of slave.womb) {
				fetus.fatherID = ngpSlaveID(fetus.fatherID, true);
				fetus.genetics.father = ngpSlaveID(fetus.genetics.father, true);
				fetus.genetics.mother = ngpSlaveID(fetus.genetics.mother, true);
			}
			slave.rivalry = 0;
			slave.rivalryTarget = 0;
			slave.subTarget = 0;
			slave.drugs = "no drugs";
			slave.porn.spending = 0;
			slave.rules.living = "spare";
			slave.diet = "healthy";
			slave.pregControl = "none";
		}
		for (let slave of getSlaves().values()) {
			slave.pregSource = slaveIDOrZero(slave.pregSource);
			slave.cloneID = slaveIDOrZero(slave.cloneID);
			slave.relationshipTarget = slaveIDOrZero(slave.relationshipTarget);
		}
		// replace the slave pool map so that the keys are correct
		const newPool = new Map();
		getSlaves().forEach((s) => { newPool.set(s.ID, s); });
		V.slaves = newPool;
		// @ts-expect-error gene pool is protected. This is one of the few times that it should be written to
		V.genePool = ngUpdateGenePool(V.genePool);
		V.missingTable = ngUpdateMissingTable(V.missingTable);
		let validRelationship = (s) => (s.relationshipTarget !== 0 && getSlave(s.relationshipTarget).relationshipTarget === s.ID);
		for (let slave of getSlaves().values()) {
			if ((slave.relationship < 0 && V.freshPC === 1) || (slave.relationship > 0 && !validRelationship(slave))) {
				slave.relationship = 0;
				slave.relationshipTarget = 0;
			}
			slave.counter.milk = 0;
			slave.counter.cum = 0;
			slave.counter.births = 0;
			slave.counter.mammary = 0;
			slave.counter.penetrative = 0;
			slave.counter.oral = 0;
			slave.counter.anal = 0;
			slave.counter.vaginal = 0;
			slave.counter.events = 0;
			slave.partners = ngUpdatePartners(slave);
			slave.lifetimeCashExpenses = 0;
			slave.lifetimeCashIncome = 0;
			slave.lastWeeksCashIncome = 0;
			slave.lifetimeRepExpenses = 0;
			slave.lifetimeRepIncome = 0;
			slave.lastWeeksRepExpenses = 0;
			slave.lastWeeksRepIncome = 0;
		}
	}

	function updateMods() {
		V.mods.food.amount = 0;
		V.mods.food.lastWeek = 0;
		V.mods.food.market = false;
		V.mods.food.rations = 0;
		V.mods.food.total = 0;
		V.mods.food.warned = false;
	}

	function doNGPSetup() {
		slaveLoopInit();
		PCInit();
		resetFamilyCounters();
		updateMods();
		V.ngpParams = {};
	}

	return doNGPSetup;
})();


code:
// cSpell:words divs

/**
 * Need to know how to apply a patch? Go to the line with `====== How to apply a patch ======`.
 * Need to create a patch for a new feature? Then keep reading.
 * Need to create a patch to make an old save load correctly? Then keep reading and also read the contents of `====== How to create a legacy patch ======`.
 *
 * Each patch should exist in its own file in `/src/data/patches/releases/`.
 * The naming scheme is: `[releaseID]_[some name that describes what this patch does].js`.
 * With the exception of the underdash the naming scheme is the same as the rest of FC's files.
 *
 * Each patch file should have a single call to `App.Patch.register()` with a `App.Patch.Utils.PatchRecord` object as the only argument.
 * See {@link App.Patch.register} and {@link App.Patch.Utils.PatchRecord}
 *
 * Each function defined by `App.Patch.Utils.PatchRecord` is optional, only use the ones you need.
 * The definitions of each function and what it is used for can be found below starting on the line with `====== Functions and their use ======`.
 * The `releaseID` and `descriptionOfChanges` properties listed in `App.Patch.Utils.PatchRecord` are not optional.
 * 'releaseID` should be `App.Version.release` + 1 and should be the same number as in the patches filename.
 * `App.Version.release` is defined on line ~13 of `/src/002-config/fc-version.js`
 * There can only be one patch for each `releaseID`.
 * `descriptionOfChanges` should be a string that describes what was changed to cause this patch to be needed.
 *
 * There are some helpful functions located in `/src/data/dataUtils.js` and under {@link App.Utils}.
 * You should use {@link App.Patch.log}() to report what you are doing in each patch function.
 *
 * ====== Patch functions and their use ======
 *
 * `gameVariables` is for anything on the save variable (`V`) that isn't covered by another function.
 * @see V
 * `humanState` is for anything that needs to be modified for any object that is based off `App.Entity.HumanState`.
 * @see App.Entity.HumanState
 * `slaveState` is for anything that needs to be modified for any object that is based off `App.Entity.SlaveState`.
 * @see App.Entity.SlaveState
 * `tankSlaveState` is for anything that needs to be modified for any object that is based off `App.Entity.TankSlaveState`.
 * @see App.Entity.TankSlaveState
 * `playerState` is for anything that needs to be modified for any object that is based off `App.Entity.PlayerState`.
 * @see App.Entity.PlayerState
 *
 * `fetus` is for anything that needs to be modified for any object (babies in the womb) that is based off `App.Entity.Fetus`.
 * @see App.Entity.Fetus
 * `infantState` is for anything that needs to be modified for any object that is based off `App.Entity.InfantState`.
 * @see App.Entity.InfantState
 * `childState` is for anything that needs to be modified for any object that is based off `App.Entity.ChildState`.
 * @see App.Entity.ChildState
 *
 * ====== How to create a legacy patch ======
 *
 * Legacy patches are mostly the same as normal patches except for a few differences.
 *
 * Legacy patches should never assume that a property exists, likewise they should never assume that a property doesn't exist.
 * The [Nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing)
 * And [Optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)
 * are both helpful in this regard.
 * So is `App.Utils.objectExistsAndHasKeys()` when working with simple/flat objects.
 * @see App.Utils.objectExistsAndHasKeys
 *
 * The naming scheme for legacy patches is: `legacy_[save's releaseID].js`.
 * The releaseID of a legacy patch should be the save's releaseID +1.
 *
 * If a legacy patch already exists for the save's releaseID, but the save still won't load.
 * Then add the code needed to make the save load to the bottom of the existing patch.
 * Make sure not to modify the existing code in the patch as that code is what was required to get other peoples saves to load
 *
 * The first legacy patch that has been written is located at `/src/data/patches/releases/legacy_1055.js` and can serve as a guide.
 *
 * ====== How to apply a patch ======
 *
 * If you need to apply it to everything (loading an old save for example) then call `App.Patch.applyAll()`.
 * @see App.Patch.applyAll
 *
 * If you only need to patch a specific data structure then you should also do data verification.
 * Refer to the verification instructions at the top of `/src/data/verification/zVerify.js`
 * for the correct data verification function(s). Data verification does patching as needed.
 */

// TODO:@franklygeorge add a way to force apply a list of patch versions and types in order
// TODO:@franklygeorge move the "Open All Reports" code from App.EndWeek.slaveAssignmentReport to App.UI.DOM and then utilize it in the patch system

/**
 * registers a patch to the database
 * @param {App.Patch.Utils.PatchRecord} patchRecord
 */
App.Patch.register = (patchRecord) => {
	if (patchRecord.releaseID === 2000) {
		throw new Error("releaseID 2000 cannot be used, skip it and use 2001 instead");
	} else if (Object.keys(App.Patch.Patches).includes(String(patchRecord.releaseID))) {
		throw new Error(`There can be only one patch for each releaseID and a patch already exists for releaseID ${patchRecord.releaseID}.`);
	} else if (patchRecord.releaseID > App.Version.release) {
		throw new Error(`Patch exists for release ${patchRecord.releaseID}, but App.Version.release === ${App.Version.release}. Did you forget to increment the release in 'src/002-config/fc-version.js'?`);
	} else if (patchRecord.descriptionOfChanges.trim() === "") {
		console.warn(`patchRecord for releaseID ${patchRecord.releaseID} is missing its description`);
	}
	App.Patch.Patches[patchRecord.releaseID] = patchRecord;
};

/**
 * Visually displays a message and also prints it to the console
 * @param {string} message
 * @param {"info"|"warn"|"error"} type
 */
App.Patch.log = (message, type="info") => {
	const locator = `Patch ${App.Patch.Utils.current.patch}["${App.Patch.Utils.current.type}"](${App.Patch.Utils.current.identifier})`;
	const eTemplate = `<span class="error">${locator}: ${message}</span>`;
	const wTemplate = `<span class="orange">${locator}: ${message}</span>`;
	const iTemplate = `<span>${locator}: ${message}</span>`;
	const div = App.UI.DOM.makeElement("div");
	if (type === "info") {
		// console.log(message);
		div.innerHTML = iTemplate;
	} else if (type === "error") {
		// console.error(message);
		div.innerHTML += eTemplate;
	} else if (type === "warn") {
		// console.warn(message);
		div.innerHTML += wTemplate;
	}
	App.Patch.Utils.current.div.append(div);
};

/**
 * Applies all available patches in order.
 * Skipping patches that have releaseID's that are less than the current releaseID
 * Updates the releaseID to match the last patch applied
 * @returns {DocumentFragment} a document fragment with the results of the patching
 */
App.Patch.applyAll = () => {
	// create a loading screen
	App.Patch.Utils.loadingScreen.start();

	// create our document fragment and our main divs
	const frag = document.createDocumentFragment();
	const head = App.UI.DOM.appendNewElement("div", frag);
	head.id = "patch-header";
	const cDiv = App.UI.DOM.appendNewElement("div", frag);
	cDiv.id = "patch-content";

	// get all available patches in reverse order so that when we call .pop we will get the smallest patch version
	let patchVersions = Object.keys(App.Patch.Patches).sort((a, b)=> +b - +a);

	// make sure a patch exists for App.Version.release
	if (Number(patchVersions[0]) < App.Version.release) {
		App.Patch.Utils.loadingScreen.end();
		throw new Error(`No patch exists for releaseID ${App.Version.release}! Did you make a patch? Instructions are in '/src/data/patches/patch.js'.`);
	}

	// remove all unneeded patch versions from the array
	patchVersions = patchVersions.filter((patchID) => { return Number(patchID) > V.releaseID; });
	// get the amount of the patches we are going to apply for later use
	const patchCount = patchVersions.length;

	// We use setTimeout here to give the App.Patch.applyAll() function time to return frag and SugarCube the time to change passages
	// The execution flow skips this setTimeout call temporarily
	setTimeout((() => {
		// get the elements we created earlier
		let f = document.getElementById("patch-content");
		let header = document.getElementById("patch-header");
		// this element was created by the App.Patch.Utils.loadingScreen.start() call
		let message = document.getElementById("patch-message");

		let verificationStart;

		/** This is called by App.Verify.everything() when it is done */
		const finalize = () => {
			if (getProp(V, "reportVerificationChanges", 0) === 0) {
				App.Patch.Utils.current.div.append(App.UI.DOM.makeElement('div', "Change detection was skipped because it is disabled"));
			}

			// report the time taken and the amount of content added to current div
			const verificationTime = (new Date().getTime() - verificationStart).toLocaleString();
			const divLength = App.Patch.Utils.current.div.childNodes.length;

			f.append(App.UI.DOM.accordion(
				`Cleanup and Verification (${divLength}) (${verificationTime}ms)`,
				App.Patch.Utils.current.div,
				(divLength === 0 || getProp(V, "useAccordion", 1) > 0)
			));

			// handle App.Verify.Utils.verificationError
			if (App.Verify.Utils.verificationError) {
				header.innerHTML += `<span class="error">Verification failed!</span>`;
				console.error("Verification failed!");
				State.restore(); // restore the state to before patching
			} else {
				if (patchCount !== 0) {
					header.innerHTML += `<span class="green">${patchCount} patches applied! You are on release ${V.releaseID}</span>`;
				} else {
					header.innerHTML += `<span class="green">No patches needed to be applied! You are on release ${V.releaseID}</span>`;
				}
				App.UI.DOM.appendNewElement("h3", f, "Done!");
				console.log("Done!");
			}

			header.innerHTML += `<br><span>See below for details</span><hr>`;

			// update the sidebar to remove any potential errors that were cause by being on an outdated save
			App.Utils.scheduleSidebarRefresh();

			// remove the loading screen so the user can see the results
			App.Patch.Utils.loadingScreen.end();

			App.Patch.Utils.current.div = undefined;
			// this is where the execution actually stops for the patching system
		};

		/**
		 * This function is called later in the code.
		 * It does verification and final cleanup after the patching is done
		 * @returns {undefined}
		 */
		const verifyAndCleanup = () => {
			// make a new div
			App.Patch.Utils.current.div = App.UI.DOM.makeElement("div");

			// Cleanup
			console.log(`Cleanup`);

			V.NaNArray = findNaN(); // reset NaNArray
			App.UI.SlaveSummary.settingsChanged(); // let slave summary know that settings may have changed

			// verification
			console.log(`Verification`);

			App.Verify.Utils.verificationError = false;
			try {
				verificationStart = new Date().getTime();
				// does the actual verification
				App.Verify.everything(App.Patch.Utils.current.div, finalize);
			} catch (e) {
				header.innerHTML += `<span class="error">Verification failed!</span>`;
				console.error("Verification failed!");
				App.Patch.Utils.current.div.append(App.UI.DOM.formatException(e));
				State.restore(); // restore the state to before patching
				header.innerHTML += `<br><span>See below for details</span><hr>`;
				// close the loading screen so that the user can see the error
				App.Patch.Utils.loadingScreen.end();
				return;
			}
		};

		const patchingStart = new Date().getTime();
		let i;

		/**
		 * This function is called later in the code.
		 * It applies a single patch.
		 * If there are more patches to apply it calls itself, if not then it calls verifyAndCleanup().
		 * @returns {undefined}
		 */
		const applyPatch = () => {
			const patchID = Number(patchVersions.pop());

			/** @type {{identifier: string, actor: FC.HumanState, div: HTMLDivElement}[]} */
			const wombs = [];

			const patchStart = new Date().getTime();

			const writePatchDiv = () => {
				// report the time taken and the amount of content added to current div
				const patchTime = (new Date().getTime() - patchStart).toLocaleString();
				const divLength = App.Patch.Utils.current.div.childNodes.length;

				f.append(App.UI.DOM.accordion(
					`Patch ${patchID} (${divLength}) (${patchTime}ms)`,
					App.Patch.Utils.current.div,
					(divLength === 0 || getProp(V, "useAccordion", 1) > 0)
				));
			};

			// patch
			try {
				// make a new div
				App.Patch.Utils.current.div = App.UI.DOM.makeElement("div");

				// Pre patch; This should always be the first patch
				App.Patch.Utils.gameVariables("pre", App.Patch.Utils.current.div, patchID);

				// PlayerState
				App.Patch.Utils.playerState("PC", V.PC, "PC", App.Patch.Utils.current.div, patchID);
				wombs.push({identifier: `V.PC`, actor: V.PC, div: App.Patch.Utils.current.div});

				// SlaveState
				for (const [ID, slave] of getSlaves(true)) {
					App.Patch.Utils.slaveState(
						`getSlave(${ID})`, slave, "main slave pool", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getSlave(${ID})`, actor: slave, div: App.Patch.Utils.current.div});
				}

				const hostage = V.detached?.hostage?.actor ?? getProp(V, "hostage");
				if (hostage) {
					App.Patch.Utils.slaveState(
						`getHostage().actor`, hostage, "detached hostage", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getHostage().actor`, actor: hostage, div: App.Patch.Utils.current.div});
				}

				const hostageWife = V.detached?.hostage?.wife ?? getProp(V, "hostageWife");
				if (hostageWife) {
					App.Patch.Utils.slaveState(
						`getHostage().wife`, hostageWife, "detached hostage wife", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getHostage().wife`, actor: hostageWife, div: App.Patch.Utils.current.div});
				}

				const boomerang = V.detached?.boomerang?.actor ?? getProp(V, "boomerangSlave");
				if (boomerang) {
					App.Patch.Utils.slaveState(
						`getBoomerang().actor`, boomerang, "detached boomerang",
						App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getBoomerang().actor`, actor: boomerang, div: App.Patch.Utils.current.div});
				}

				const shelterSlave = V.detached?.shelter?.actor ?? getProp(V, "shelterSlave");
				if (shelterSlave) {
					App.Patch.Utils.slaveState(
						`getShelterSlave().actor`, shelterSlave, "detached shelter",
						App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getShelterSlave().actor`, actor: shelterSlave, div: App.Patch.Utils.current.div});
				}

				const traitor = V.detached?.traitor?.actor ?? getProp(V, "traitor");
				if (traitor) {
					App.Patch.Utils.slaveState(
						`getTraitor().actor`, traitor, "detached traitor", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getTraitor().actor`, actor: traitor, div: App.Patch.Utils.current.div});
				}

				// TankSlaveState
				const tankSlaves = getTankSlaves(true);
				for (const [ID, tankSlave] of tankSlaves) {
					App.Patch.Utils.tankSlaveState(
						`getTankSlave(${ID})`, tankSlave, App.Patch.Utils.current.div, patchID
					);
					wombs.push({
						identifier: `getTankSlave(${ID})`,
						actor: tankSlave,
						div: App.Patch.Utils.current.div
					});
				}

				// InfantState
				const infants = getInfants(true);
				for (const [ID, infant] of infants) {
					App.Patch.Utils.infantState(
						`getInfant(${ID})`, infant, "infant slave pool", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `getInfant(${ID})`, actor: infant, div: App.Patch.Utils.current.div}); // shouldn't be needed, but InfantStates are HumanStates so might as well make sure it is right
				}

				// ChildState
				// TODO:@franklygeorge this is waiting on FC.ChildState to be implemented
				const children = [];
				for (i in children) {
					App.Patch.Utils.childState(
						// @ts-ignore
						`children[${i}]`, children[i], "children", App.Patch.Utils.current.div, patchID
					);
					wombs.push({identifier: `children[${i}]`, actor: children[i], div: App.Patch.Utils.current.div});
				}

				// Wombs/Fetuses; This should always be below all the HumanState patches
				wombs.forEach((womb) => {
					App.Patch.Utils.patchWomb(womb.identifier, womb.actor, womb.div, patchID);
				});

				// CustomOrderSlave
				if (V.customSlave) {
					App.Patch.Utils.customSlaveOrder(
						"V.customSlave", V.customSlave, App.Patch.Utils.current.div, patchID
					);
				}
				if (V.huskSlave) {
					App.Patch.Utils.customSlaveOrder(
						"V.huskSlave", V.huskSlave, App.Patch.Utils.current.div, patchID
					);
				}

				// Post patch; This should always be the last patch
				App.Patch.Utils.gameVariables("post", App.Patch.Utils.current.div, patchID);
			} catch (e) {
				header.innerHTML += `<span class="error">Patching Failed when applying patch ${App.Patch.Utils.current.patch}["${App.Patch.Utils.current.type}"] to ${App.Patch.Utils.current.identifier}!</span>`;
				App.Patch.Utils.current.div.append(App.UI.DOM.formatException(e));
				State.restore(); // restore the state to before patching
				header.innerHTML += `<br><span>See below for details</span><hr>`;
				// close the loading screen so that the user can see the error
				App.Patch.Utils.loadingScreen.end();
				writePatchDiv(); // write out the current patch div so the error can be read
				return;
			}

			writePatchDiv();

			// continue
			if (patchVersions.length !== 0) {
				// let the user know what we are doing, by changing the loading screen message
				message.innerHTML = `Applying Patch ${patchVersions.last()}...`;
				// give the DOM time to update and then call applyPatch() again
				setTimeout(applyPatch, 0);
			} else {
				const patchingTime = (new Date().getTime() - patchingStart).toLocaleString();
				f.append(App.UI.DOM.accordion(
					`Patching results (${patchCount} patches) (${patchingTime}ms)`,
					App.UI.DOM.makeElement('div', `Patching completed successfully, applying ${patchCount} patches in ${patchingTime}ms`),
					true,
				));
				// let the user know what we are doing, by changing the loading screen message
				message.innerHTML = `Cleaning up and verifying...`;
				// give the DOM time to update and then call verifyAndCleanup()
				setTimeout(verifyAndCleanup, 0);
			}
		};

		// start the patching
		if (patchVersions.length !== 0) {
			// let the user know what we are doing, by changing the loading screen message
			message.innerHTML = `Applying Patch ${patchVersions.last()}...`;
			// give the DOM time to update and then call applyPatch()
			setTimeout(applyPatch, 0);
		} else {
			// we didn't have any patches to apply but we still run verification
			App.UI.DOM.appendNewElement('div', f, `No patches needed to be applied`);
			// let the user know what we are doing, by changing the loading screen message
			message.innerHTML = `Cleaning up and verifying...`;
			// give the DOM time to update and then call verifyAndCleanup()
			setTimeout(verifyAndCleanup, 0);
		}
	}), 0);

	// return the empty document
	// the first setTimeout above will execute soon after the passage change happens
	return frag;
};

repo_name: Nithhogg/fc

license: mit


code:
/**
 * Adds release ID to the given object if it is missing
 * @param {object} obj
 */
App.Patch.Utils.ensureReleaseID = (obj) => {
	if (!('releaseID' in obj)) {
		obj.releaseID = 0;
	}
};

/**
 * patches the given object using the given patchType and returns it.
 * if no object is given then it does patching on V and returns nothing.
 * throws an error on failure.
 * @param {App.Patch.Utils.PatchType} patchType
 * @param {number} patchUpTo the releaseID to patch to
 * @param {string} identifier a string that helps identify where an object came from
 * @param {HTMLDivElement} [div=undefined] an optional div to provide visual information
 * @param {object|undefined} [obj] the object to be patched, this object will not be modified
 * @param {App.Patch.Utils.HumanStateLocation|FC.HumanState|"pre"|"post"|"V.customSlave"|"V.huskSlave"|undefined} [extra] location, mother, customSlaveOrder location, or undefined
 */
App.Patch.Utils.patch = (patchType, patchUpTo, identifier, div=undefined, obj, extra) => {
	const DEBUG = false;
	const isV = (obj === undefined);
	if (isV && !["pre", "post"].includes(patchType)) {
		throw new Error(`patchType '${patchType}' cannot be used without an object`);
	} else if (!isV && ["pre", "post"].includes(patchType)) {
		throw new Error(`patchType '${patchType}' can only be used with V`);
	}

	obj = isV ? V : obj;
	div = div ?? App.UI.DOM.makeElement("div");

	App.Patch.Utils.current.div = div;
	App.Patch.Utils.current.identifier = identifier ?? ((typeof extra === "string" ? extra : "no identifier provided"));

	if (patchType === "playerState" && !extra) { extra = "PC"; }

	if (DEBUG) {
		console.log(`\\/ \\/ \\/ Patching of '${patchType}' started for '${identifier}'  \\/ \\/ \\/`);
	}
	const patchVersions = Object.keys(App.Patch.Patches).sort().filter((version) => {
		return (Number(version) <= patchUpTo && Number(version) > obj.releaseID);
	});

	/** @type {number} */
	let patchID;

	for (const ID in patchVersions) {
		try {
			patchID = Number(patchVersions[ID]);
			App.Patch.Utils.current.patch = patchID;
			if (obj.releaseID >= patchID) { continue; }

			// eslint-disable-next-line dot-notation
			const tools = App.Patch.Patches[patchID]["tools"];

			// apply the patch
			if (isV) {
				if (App.Patch.Patches[patchID][patchType]) {
					App.Patch.Utils.current.type = patchType;
					// @ts-ignore expects 3 arguments, even thought that is wrong
					App.Patch.Patches[patchID][patchType](div, tools);
				}
			} else if (extra) {
				if (App.Patch.Patches[patchID].humanState && ["slaveState", "tankSlaveState", "playerState", "childState", "infantState"].includes(patchType)) {
					App.Patch.Utils.current.type = "humanState";
					// @ts-ignore hush now
					App.Patch.Patches[patchID].humanState(div, obj, extra, tools);
				}
				if (App.Patch.Patches[patchID].slaveState && ["tankSlaveState", "childState", "infantState"].includes(patchType)) {
					App.Patch.Utils.current.type = "slaveState";
					// @ts-ignore dear children
					App.Patch.Patches[patchID].slaveState(div, obj, extra, tools);
				}
				if (App.Patch.Patches[patchID][patchType]) {
					App.Patch.Utils.current.type = patchType;
					// @ts-ignore for life is this way
					App.Patch.Patches[patchID][patchType](div, obj, extra, tools);
				}
			} else {
				if (["slaveState", "tankSlaveState", "playerState", "childState", "infantState"].includes(patchType)) {
					throw new Error(`App.Patch.Utils.patch called with patchType '${patchType}', but without location being specified!`);
				}
				if (App.Patch.Patches[patchID][patchType]) {
					App.Patch.Utils.current.type = patchType;
					App.Patch.Patches[patchID][patchType](div, obj, undefined, tools);
				}
			}
			if (patchType !== "pre") {
				obj.releaseID = Number(patchID);
			}
			if (patchType === "post" && V.releaseID === App.Version.release) {
				// bump the save's versions
				V.ver = App.Version.base;
				V.pmodVer = App.Version.pmod;
				V.commitHash = App.Version.commitHash;
			}
		} catch (e) {
			console.error(`/\\ /\\ /\\ Patching of '${patchType}' failed for '${identifier}' when applying patch for releaseID ${patchID} /\\ /\\ /\\`, e);
			throw e;
		}
	}
	if (DEBUG) {
		console.log(`/\\ /\\ /\\ Patching of '${patchType}' finished for '${identifier}' /\\ /\\ /\\`);
	}
};

/**
 * Patches fetuses in wombs if they exist
 * @param {string} identifier a string that helps identify where an actor came from
 * @param {FC.HumanState} actor
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.patchWomb = (identifier, actor, div, patchUpTo=App.Version.release) => {
	if ('womb' in actor && Array.isArray(actor.womb)) {
		for (let f in actor.womb) {
			App.Patch.Utils.ensureReleaseID(actor.womb[f]);
			if (actor.womb[f].releaseID >= patchUpTo) { continue; }
			// patch
			App.Patch.Utils.fetus(`${identifier}.womb[${f}]`, actor.womb[f], actor, div, patchUpTo);
		}
	}
};

/**
 * Patch FC.GameVariables (V). Do not call directly, call `App.Verify.gameVariables()` instead
 * @see App.Verify.gameVariables
 * @param {"pre"|"post"} type
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.gameVariables = (type, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(V);
	if (V.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch(type, patchUpTo, "V", div, undefined);
	if (V.releaseID !== App.Version.release) { return; }
	// add nonexistant properties to V from `App.Data.defaultGameStateVariables` and `App.Data.resetOnNGPlus`
	App.Utils.assignMissingDefaults(V, App.Data.defaultGameStateVariables, App.Data.resetOnNGPlus);
};

/**
 * Patch FC.PlayerState objects. Do not call directly, call `App.Verify.playerState()` instead
 * @see App.Verify.playerState
 * @param {string} identifier a string that can be used to locate the given actor (likely "PC" in this case)
 * @param {FC.PlayerState} actor
 * @param {App.Patch.Utils.HumanStateLocation} [location="PC"]
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.playerState = (identifier, actor, location="PC", div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("playerState", patchUpTo, identifier, div, actor, location);
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(actor, basePlayer());
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * @param {FC.SlaveState} actor
 * @returns {FC.SlaveState}
 */
App.Patch.Utils.slaveTemplate = (actor) => {
	/** @type {"XX"|"XY"} */
	let sex = "XX";
	if (actor.genes && ["XX", "XY"].includes(actor.genes)) {
		sex = /** @type {"XX"|"XY"} */ (actor.genes);
	}
	return GenerateNewSlave(
		sex,
		{
			minAge: actor.visualAge,
			maxAge: actor.visualAge,
			nationality: actor.nationality,
			race: actor.race,
			disableDisability: 1,
		}
	);
};

/**
 * Patch FC.SlaveState objects. Do not call directly, call `App.Verify.slaveState()` instead
 * @see App.Verify.slaveState
 * @param {string} identifier a string that can be used to locate the given actor
 * @param {FC.SlaveState} actor
 * @param {App.Patch.Utils.HumanStateLocation} location
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.slaveState = (identifier, actor, location, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("slaveState", patchUpTo, identifier, div, actor, location);
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(actor, App.Patch.Utils.slaveTemplate(actor));
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * Patch FC.TankSlaveState objects. Do not call directly, call `App.Verify.tankSlaveState()` instead
 * @see App.Verify.tankSlaveState
 * @param {string} identifier a string that can be used to locate the given actor
 * @param {FC.TankSlaveState} actor
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.tankSlaveState = (identifier, actor, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("tankSlaveState", patchUpTo, identifier, div, actor, "tank slave pool");
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(
		actor,
		App.Patch.Utils.slaveTemplate(actor),
		App.Entity.TankSlaveState.toTank(App.Patch.Utils.slaveTemplate(actor))
	);
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * @param {FC.ChildState} actor
 * @returns {FC.ChildState}
 */
App.Patch.Utils.childTemplate = (actor) => {
	return new App.Entity.ChildState(); // TODO: use generator when/if it exists
};

/**
 * Patch FC.ChildState objects. Do not call directly, call `App.Verify.childState()` instead
 * @see App.Verify.childState
 * @param {string} identifier a string that can be used to locate the given actor
 * @param {FC.ChildState} actor
 * @param {App.Patch.Utils.HumanStateLocation} location
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.childState = (identifier, actor, location, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("childState", patchUpTo, identifier, div, actor, location);
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(actor, App.Patch.Utils.childTemplate(actor));
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * @param {FC.InfantState} actor
 * @returns {FC.InfantState}
 */
App.Patch.Utils.infantTemplate = (actor) => {
	return new App.Entity.InfantState(); // TODO: use generator when/if it exists
};

/**
 * Patch FC.InfantState objects. Do not call directly, call `App.Verify.infantState()` instead
 * @see App.Verify.infantState
 * @param {string} identifier a string that can be used to locate the given actor
 * @param {FC.InfantState} actor
 * @param {App.Patch.Utils.HumanStateLocation} [location="infant slave pool"]
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.infantState = (identifier, actor, location="infant slave pool", div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("infantState", patchUpTo, identifier, div, actor, location);
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(actor, App.Patch.Utils.infantTemplate(actor));
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * @param {FC.Fetus} actor
 * @param {FC.HumanState} mother
 * @returns {FC.Fetus}
 */
App.Patch.Utils.fetusTemplate = (actor, mother) => {
	return new App.Entity.Fetus(
		actor.age,
		actor.fatherID,
		mother,
	);
};

/**
 * Patch FC.Fetus objects. Do not call directly, call `App.Verify.fetus()` instead
 * @see App.Verify.fetus
 * @param {string} identifier a string that can be used to locate the given actor
 * @param {FC.Fetus} actor
 * @param {FC.HumanState} mother
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.fetus = (identifier, actor, mother, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(actor);
	if (actor.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("fetus", patchUpTo, identifier, div, actor, mother);
	if (actor.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(actor, App.Patch.Utils.fetusTemplate(actor, mother));
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

/**
 * Patch FC.CustomOrderSlave objects. Do not call directly, call `App.Verify.customSlaveOrder()` instead
 * @see App.Verify.customSlaveOrder
 * @param {"V.customSlave"|"V.huskSlave"} location
 * @param {FC.CustomSlaveOrder} order
 * @param {HTMLDivElement} [div]
 * @param {number} [patchUpTo=App.Version.release] the releaseID to patch to
 */
App.Patch.Utils.customSlaveOrder = (location, order, div, patchUpTo=App.Version.release) => {
	App.Patch.Utils.ensureReleaseID(order);
	if (order.releaseID >= patchUpTo) { return; }
	// patch
	App.Patch.Utils.patch("customSlaveOrder", patchUpTo, location, div, order, location);
	if (order.releaseID !== App.Version.release) { return; }
	// add missing props
	App.Utils.assignMissingDefaults(order, new App.Entity.CustomSlaveOrder());
	// TODO:@franklygeorge report extra properties if patch debugging is enabled
};

App.Patch.Utils.current = {
	/** @type {number} */
	patch: 0,
	/** @type {HTMLDivElement} */
	div: undefined,
	/** @type {string} */
	identifier: "",
	/** @type {App.Patch.Utils.PatchType|"humanState"} */
	type: undefined,
};

/**
 * @typedef {"pre"|"post"|"slaveState"|"tankSlaveState"|"playerState"|"fetus"|"infantState"|"childState"|"customSlaveOrder"} App.Patch.Utils.PatchType
 */

/**
 * @typedef {"PC"|"main slave pool"|"tank slave pool"|"infant slave pool"|"gene pool"|"detached hostage"|"detached hostage wife"|"detached boomerang"|"detached traitor"|"detached shelter"|"none"} App.Patch.Utils.HumanStateLocation
 */

/**
 * This and App.Verify.Utils.InstructionSet should have the same keys
 * With the exception of the `humanState`, `pre`, and `post` keys which should be missing from `App.Patch.Utils.PatchRecord`
 * and the `gameVariables` key which should be missing from here.
 * @see App.Verify.Utils.InstructionSet
 *
 * @typedef {object} App.Patch.Utils.PatchRecord
 * @property {number} releaseID
 * @property {string} descriptionOfChanges
 *
 * @property {object} [tools] this object is for shared functions
 *
 * @property {(div: HTMLDivElement, tools: object) => void} [pre] used to modify the V object before any other patch is ran
 * @property {(div: HTMLDivElement, tools: object) => void} [post] used to modify the V object after all the other patches have ran
 *
 * @property {(div: HTMLDivElement, human: FC.HumanState, location: App.Patch.Utils.HumanStateLocation, tools: object) => FC.HumanState} [humanState]
 * @property {(div: HTMLDivElement, slave: FC.SlaveState, location: App.Patch.Utils.HumanStateLocation, tools: object) => FC.SlaveState} [slaveState]
 * @property {(div: HTMLDivElement, tank: FC.TankSlaveState, tools: object) => FC.TankSlaveState} [tankSlaveState]
 * @property {(div: HTMLDivElement, player: FC.PlayerState, location: App.Patch.Utils.HumanStateLocation, tools: object) => FC.PlayerState} [playerState]
 *
 * @property {(div: HTMLDivElement, fetus: FC.Fetus, mother: FC.HumanState, tools: object) => FC.Fetus} [fetus]
 * @property {(div: HTMLDivElement, infant: FC.InfantState, tools: object) => FC.InfantState} [infantState]
 * @property {(div: HTMLDivElement, child: FC.ChildState, tools: object) => FC.ChildState} [childState]
 * @property {(div: HTMLDivElement, order: FC.CustomSlaveOrder, location: "V.customSlave"|"V.huskSlave", tools: object) => FC.CustomSlaveOrder} [customSlaveOrder]
 */

// put on a loading screen
// this was copied from endWeekAnim.js and modified
App.Patch.Utils.loadingScreen = (function() {
	let loadLockID = -1;
	let timeoutTime = 1000; // 1 second is plenty as this will never fire while the DOM is busy. So it will only fire after the loading screen is closed or an error has stopped execution
	let timeout;
	/** @type {HTMLDivElement} */
	let infoDiv = null;

	// Create an observer instance.
	const observer = new MutationObserver(function(mutations) {
		startTimeout();
	});

	function makeInfoDiv() {
		infoDiv = document.createElement("div");
		infoDiv.className = "endweek-titleblock";
		const title = document.createElement("div");
		title.className = "endweek-maintitle";
		title.innerHTML = "Applying patches...";
		infoDiv.append(title);
		const sub = document.createElement("div");
		sub.className = "endweek-subtitle";
		sub.id = "patch-message";
		infoDiv.append(sub);

		observer.observe(title, {
			childList:     true,
		});
		observer.observe(sub, {
			childList:     true,
		});
	}

	/**
	 * @param {boolean} dueToTimeout If true then the reason we are adding the link is due to timing out
	 */
	function makeHideLink(dueToTimeout = false) {
		if (infoDiv === null) { return; }
		const link = document.createElement("a");
		link.id = "hide-patch-screen";
		link.innerHTML = dueToTimeout ? "Something may have gone wrong. Click here to continue" : "Hide this screen";
		link.addEventListener("click", () => {
			App.Patch.Utils.loadingScreen.end();
		});
		infoDiv.append(link);
	}

	function stopTimeout() {
		if (timeout) {
			clearTimeout(timeout);
		}
	}

	function startTimeout() {
		stopTimeout();
		const link = document.getElementById("hide-patch-screen");
		if (link && !V.debugMode) {
			link.remove();
		}
		timeout = setTimeout(() => { makeHideLink(true); }, timeoutTime);
	}

	function start() {
		if (loadLockID === -1) {
			makeInfoDiv();
			if (V.debugMode) {
				makeHideLink();
			}
			$("#init-screen").append(infoDiv);
			loadLockID = LoadScreen.lock();
			startTimeout();
		}
	}

	function end() {
		if (loadLockID !== -1) {
			setTimeout(() => {
				LoadScreen.unlock(loadLockID);
				observer.disconnect();
				stopTimeout();
				infoDiv.remove();
				infoDiv = null;
				loadLockID = -1;
			}, 0);
		}
	}

	return {
		start,
		end
	};
})();


code:
App.Patch.register({
	releaseID: 1257,
	descriptionOfChanges: "The patching system was implemented in this release",
	infantState: (div, actor) => {
		// InfantStates has extended SlaveStates for a while, but there exists no BC to add missing SlaveState props.
		// This has been fine since we haven't been sending them though shared SlaveState/HumanState BC.
		// Now we are sending them so they need to be valid SlaveState/HumanState objects.
		// So we just add any missing props from the InfantState to actor.
		// But we want to add the props that exist in this moment since this patch runs before legacy BC
		// and InfantState may change in the future.
		App.Patch.log("Adding missing properties to InfantState");
		App.Utils.assignMissingDefaults(
			actor,
			{
				"releaseID": 1257,
				"slaveName": "blank",
				"slaveSurname": 0,
				"birthName": "blank",
				"birthSurname": 0,
				"genes": "XX",
				"pronoun": 0,
				"natural": {
					"height": 170,
					"boobs": 500,
					"artSeed": 25132346125674
				},
				"origin": "",
				"career": "a slave",
				"ID": 0,
				"prestige": 0,
				"prestigeDesc": 0,
				"father": 0,
				"mother": 0,
				"daughters": 0,
				"sisters": 0,
				"training": 0,
				"birthWeek": 19,
				"actualAge": 18,
				"visualAge": 18,
				"physicalAge": 18,
				"ovaryAge": 18,
				"ageImplant": 0,
				"health": {
					"condition": 0,
					"shortDamage": 0,
					"longDamage": 0,
					"illness": 0,
					"tired": 0,
					"health": 0
				},
				"minorInjury": 0,
				"weight": 0,
				"muscles": 0,
				"height": 170,
				"heightImplant": 0,
				"nationality": "slave",
				"race": "white",
				"origRace": "white",
				"markings": "none",
				"eye": {
					"left": {
						"type": 1,
						"vision": 2,
						"iris": "brown",
						"pupil": "circular",
						"sclera": "white"
					},
					"right": {
						"type": 1,
						"vision": 2,
						"iris": "brown",
						"pupil": "circular",
						"sclera": "white"
					},
					"origColor": "brown"
				},
				"eyewear": "none",
				"hears": 0,
				"earwear": "none",
				"earImplant": 0,
				"earShape": "normal",
				"earT": "none",
				"earTNatural": 0,
				"earTColor": "hairless",
				"earTEffectColor": "none",
				"earTEffect": "none",
				"smells": 0,
				"tastes": 0,
				"horn": "none",
				"hornColor": "none",
				"tail": "none",
				"PTail": 0,
				"tailShape": "none",
				"tailColor": "none",
				"tailEffectColor": "none",
				"tailEffect": "none",
				"appendages": "none",
				"PBack": 0,
				"wingsShape": "none",
				"appendagesColor": "none",
				"appendagesEffectColor": "none",
				"appendagesEffect": "none",
				"patternColor": "black",
				"origHColor": "brown",
				"hColor": "brown",
				"hEffectColor": "none",
				"hEffect": "none",
				"pubicHColor": "brown",
				"underArmHColor": "brown",
				"eyebrowHColor": "brown",
				"origSkin": "light",
				"skin": "light",
				"hLength": 60,
				"eyebrowFullness": "natural",
				"hStyle": "neat",
				"pubicHStyle": "neat",
				"underArmHStyle": "neat",
				"eyebrowHStyle": "natural",
				"waist": 0,
				"PLimb": 0,
				"leg": {
					"left": {
						"type": 1,
						"scar": {},
						"brand": {}
					},
					"right": {
						"type": 1,
						"scar": {},
						"brand": {}
					}
				},
				"arm": {
					"left": {
						"type": 1,
						"scar": {},
						"brand": {}
					},
					"right": {
						"type": 1,
						"scar": {},
						"brand": {}
					}
				},
				"heels": 0,
				"voice": 2,
				"voiceImplant": 0,
				"electrolarynx": 0,
				"accent": 0,
				"shoulders": 0,
				"shouldersImplant": 0,
				"boobs": 0,
				"boobsMilk": 0,
				"boobsImplant": 0,
				"boobsImplantType": "none",
				"boobShape": "normal",
				"nipples": "cute",
				"nipplesAccessory": "none",
				"areolae": 0,
				"areolaeShape": "circle",
				"boobsTat": 0,
				"lactation": 0,
				"lactationDuration": 0,
				"induceLactation": 0,
				"lactationAdaptation": 0,
				"hips": 0,
				"hipsImplant": 0,
				"butt": 0,
				"buttImplant": 0,
				"buttImplantType": "none",
				"buttTat": 0,
				"face": 0,
				"faceImplant": 0,
				"faceShape": "normal",
				"lips": 15,
				"lipsImplant": 0,
				"lipsTat": 0,
				"teeth": "normal",
				"vagina": 0,
				"vaginaLube": 0,
				"vaginaTat": 0,
				"preg": -1,
				"pregSource": 0,
				"pregType": 0,
				"pregMood": 0,
				"pregAdaptation": 50,
				"ovaImplant": 0,
				"wombImplant": "none",
				"fertKnown": 0,
				"fertPeak": 0,
				"broodmother": 0,
				"broodmotherFetuses": 0,
				"broodmotherOnHold": 0,
				"broodmotherCountDown": 0,
				"labor": 0,
				"pregNoticeDefault": "none",
				"pregNoticeBypass": false,
				"bellyAccessory": "none",
				"labia": 0,
				"clit": 0,
				"foreskin": 0,
				"anus": 0,
				"analArea": 1,
				"dick": 0,
				"dickTat": 0,
				"prostate": 0,
				"prostateImplant": 0,
				"balls": 0,
				"ballsImplant": 0,
				"scrotum": 0,
				"ovaries": 0,
				"anusTat": 0,
				"makeup": 0,
				"nails": 0,
				"brand": {},
				"piercing": {
					"ear": {
						"weight": 0,
						"desc": ""
					},
					"nose": {
						"weight": 0,
						"desc": ""
					},
					"eyebrow": {
						"weight": 0,
						"desc": ""
					},
					"lips": {
						"weight": 0,
						"desc": ""
					},
					"tongue": {
						"weight": 0,
						"desc": ""
					},
					"nipple": {
						"weight": 0,
						"desc": ""
					},
					"areola": {
						"weight": 0,
						"desc": ""
					},
					"navel": {
						"weight": 0,
						"desc": ""
					},
					"corset": {
						"weight": 0,
						"desc": ""
					},
					"genitals": {
						"weight": 0,
						"desc": "",
						"smart": false
					},
					"vagina": {
						"weight": 0,
						"desc": ""
					},
					"dick": {
						"weight": 0,
						"desc": ""
					},
					"anus": {
						"weight": 0,
						"desc": ""
					}
				},
				"shouldersTat": 0,
				"armsTat": 0,
				"legsTat": 0,
				"backTat": 0,
				"stampTat": 0,
				"diet": "healthy",
				"hormones": 0,
				"curatives": 0,
				"chem": 0,
				"aphrodisiacs": 0,
				"addict": 0,
				"devotion": 0,
				"clothes": "no clothing",
				"collar": "none",
				"faceAccessory": "none",
				"mouthAccessory": "none",
				"shoes": "none",
				"vaginalAccessory": "none",
				"vaginalAttachment": "none",
				"dickAccessory": "none",
				"chastityAnus": 0,
				"chastityPenis": 0,
				"chastityVagina": 0,
				"armAccessory": "none",
				"legAccessory": "none",
				"buttplug": "none",
				"buttplugAttachment": "none",
				"intelligence": 0,
				"intelligenceImplant": 0,
				"energy": 50,
				"need": 0,
				"partners": {},
				"attrXX": 0,
				"attrXY": 0,
				"attrKnown": 0,
				"fetish": "none",
				"fetishStrength": 70,
				"fetishKnown": 0,
				"preferredHole": 1,
				"behavioralFlaw": "none",
				"behavioralQuirk": "none",
				"sexualFlaw": "none",
				"sexualQuirk": "none",
				"geneticQuirks": {
					"macromastia": 0,
					"gigantomastia": 0,
					"potent": 0,
					"fertility": 0,
					"hyperFertility": 0,
					"superfetation": 0,
					"polyhydramnios": 0,
					"uterineHypersensitivity": 0,
					"galactorrhea": 0,
					"gigantism": 0,
					"dwarfism": 0,
					"neoteny": 0,
					"progeria": 0,
					"pFace": 0,
					"uFace": 0,
					"albinism": 0,
					"heterochromia": 0,
					"rearLipedema": 0,
					"wellHung": 0,
					"wGain": 0,
					"wLoss": 0,
					"androgyny": 0,
					"mGain": 0,
					"mLoss": 0,
					"twinning": 0,
					"girlsOnly": 0
				},
				"spermY": 50,
				"counter": {
					"milk": 0,
					"cum": 0,
					"birthsTotal": 0,
					"abortions": 0,
					"miscarriages": 0,
					"laborCount": 0,
					"slavesFathered": 0,
					"slavesKnockedUp": 0,
					"oral": 0,
					"vaginal": 0,
					"anal": 0,
					"mammary": 0,
					"penetrative": 0,
					"pitWins": 0,
					"pitLosses": 0,
					"reHymen": 0,
					"births": 0,
					"publicUse": 0,
					"pitKills": 0,
					"bestiality": 0,
					"PCChildrenFathered": 0,
					"PCKnockedUp": 0,
					"timesBred": 0,
					"PCChildrenBeared": 0,
					"events": 0
				},
				"skill": {
					"vaginal": 0,
					"penetrative": 0,
					"oral": 0,
					"anal": 0,
					"whoring": 0,
					"entertainment": 0,
					"combat": 0,
					"headGirl": 0,
					"recruiter": 0,
					"bodyguard": 0,
					"madam": 0,
					"DJ": 0,
					"nurse": 0,
					"teacher": 0,
					"attendant": 0,
					"matron": 0,
					"stewardess": 0,
					"milkmaid": 0,
					"farmer": 0,
					"wardeness": 0,
					"servant": 0,
					"entertainer": 0,
					"whore": 0
				},
				"rules": {
					"living": "spare",
					"rest": "restrictive",
					"mobility": "restrictive",
					"speech": "restrictive",
					"release": {
						"masturbation": 0,
						"partner": 1,
						"facilityLeader": 1,
						"family": 0,
						"slaves": 0,
						"master": 1
					},
					"relationship": "restrictive",
					"lactation": "none",
					"punishment": "situational",
					"reward": "situational"
				},
				"custom": {
					"tattoo": "",
					"label": "",
					"desc": "",
					"title": "",
					"name": "",
					"titleLisp": "",
					"image": null,
					"hairVector": 0,
					"aiAutoRegenExclude": 0,
					"aiImageIds": [],
					"aiDisplayImageIdx": -1,
					"aiPrompts": null,
					"aiPromptsOverwrite": false,
					"aiPose": null
				},
				"bellyTat": 0,
				"abortionTat": -1,
				"birthsTat": -1,
				"induce": 0,
				"mpreg": 0,
				"inflation": 0,
				"inflationType": "none",
				"inflationMethod": 0,
				"milkSource": 0,
				"cumSource": 0,
				"burst": 0,
				"pregKnown": 0,
				"pregWeek": 0,
				"belly": 0,
				"bellyPreg": 0,
				"bellyFluid": 0,
				"bellyImplant": -1,
				"bellySag": 0,
				"bellySagPreg": 0,
				"bellyPain": 0,
				"cervixImplant": 0,
				"cervixImplantTubing": 0,
				"cervixImplantTarget": "bellyImplant",
				"pubertyAgeXX": 13,
				"pubertyXX": 0,
				"pubertyAgeXY": 13,
				"pubertyXY": 0,
				"scar": {},
				"breedingMark": 0,
				"ballType": "human",
				"eggType": "human",
				"pregControl": "none",
				"ageAdjust": 0,
				"bald": 0,
				"bodySwap": 0,
				"origBodyOwner": "",
				"origBodyOwnerID": 0,
				"hormoneBalance": 0,
				"breastMesh": 0,
				"prematureBirth": 0,
				"premature": 0,
				"vasectomy": 0,
				"haircuts": 0,
				"tankBaby": 0,
				"clone": 0,
				"cloneID": 0,
				"geneMods": {
					"NCS": 0,
					"rapidCellGrowth": 0,
					"immortality": 0,
					"flavoring": 0,
					"aggressiveSperm": 0,
					"livestock": 0,
					"progenitor": 0
				},
				"milkFlavor": "none",
				"NCSyouthening": 0,
				"weightDirection": 0,
				"albinismOverride": null,
				"inbreedingCoeff": 0,
				"pregData": {
					"type": "human",
					"normalOvaMin": 1,
					"normalOvaMax": 1,
					"normalBirth": 40,
					"minLiveBirth": 32,
					"drugsEffect": 1,
					"fetusWeek": [
						0,
						9,
						20,
						20,
						40,
						52,
						64,
						80,
						384,
						99999
					],
					"fetusSize": [
						1,
						3,
						16,
						25.6,
						51,
						60,
						67.5,
						71.6,
						129.5,
						130
					],
					"fetusRate": [
						1,
						1,
						1,
						0.64,
						0.6513,
						0.6459,
						0.644,
						0.6393,
						0.58,
						0.51
					],
					"sizeType": 0
				},
				"trueVirgin": 0,
				"drugs": "no drugs",
				"weekAcquired": 0,
				"porn": {
					"feed": 0,
					"viewerCount": 0,
					"spending": 0,
					"prestige": 0,
					"prestigeDesc": 0,
					"fameType": "none",
					"focus": "none",
					"fame": {
						"neglectful": 0,
						"cumAddict": 0,
						"analAddict": 0,
						"attentionWhore": 0,
						"breastGrowth": 0,
						"abusive": 0,
						"malicious": 0,
						"selfHating": 0,
						"breeder": 0,
						"sub": 0,
						"cumSlut": 0,
						"anal": 0,
						"humiliation": 0,
						"boobs": 0,
						"dom": 0,
						"sadist": 0,
						"masochist": 0,
						"pregnancy": 0,
						"fuckdoll": 0,
						"rape": 0,
						"preggo": 0,
						"BBW": 0,
						"loli": 0,
						"gainer": 0,
						"stud": 0,
						"muscle": 0,
						"incest": 0,
						"fucker": 0,
						"clitFucker": 0,
						"deepThroat": 0,
						"struggleFuck": 0,
						"painal": 0,
						"tease": 0,
						"romantic": 0,
						"pervert": 0,
						"caring": 0,
						"unflinching": 0,
						"sizeQueen": 0,
						"general": 0
					}
				},
				"relationship": 0,
				"relationshipTarget": 0,
				"rivalry": 0,
				"rivalryTarget": 0,
				"subTarget": 0,
				"canRecruit": 0,
				"choosesOwnAssignment": 0,
				"assignment": "rest",
				"sentence": 0,
				"toyHole": "all her holes",
				"indenture": -1,
				"indentureRestrictions": 0,
				"trust": 0,
				"oldTrust": 0,
				"oldDevotion": 0,
				"clitSetting": "vanilla",
				"useRulesAssistant": 1,
				"dietCum": 0,
				"dietMilk": 0,
				"fuckdoll": 0,
				"choosesOwnClothes": 0,
				"sexAmount": 0,
				"sexQuality": 0,
				"rudeTitle": 0,
				"currentRules": [],
				"PCExclude": 0,
				"HGExclude": 0,
				"StudExclude": 0,
				"inseminationExclude": 0,
				"choosesOwnChastity": 0,
				"readyProsthetics": [],
				"onDiet": 0,
				"newGamePlus": 0,
				"overrideRace": 0,
				"overrideSkin": 0,
				"overrideEyeColor": 0,
				"overrideHColor": 0,
				"overridePubicHColor": 0,
				"overrideArmHColor": 0,
				"overrideBrowHColor": 0,
				"slaveCost": 0,
				"lifetimeCashExpenses": 0,
				"lifetimeCashIncome": 0,
				"lastWeeksCashIncome": 0,
				"lifetimeRepExpenses": 0,
				"lifetimeRepIncome": 0,
				"lastWeeksRepIncome": 0,
				"lastWeeksRepExpenses": 0,
				"whoreClass": 0,
				"growTime": 156
			}
		);
		return actor;
	},
	post: (div) => {
		// add nonexistant properties to V from a copy of `App.Data.defaultGameStateVariables` and `App.Data.resetOnNGPlus`
		// `App.Data.defaultGameStateVariables` starts on the line with `// App.Data.defaultGameStateVariables`
		// `App.Data.resetOnNGPlus` starts on the line with `// App.Data.resetOnNGPlus`
		App.Utils.assignMissingDefaults(
			V,
			// App.Data.defaultGameStateVariables
			{
				"nextButton": "Continue",
				"nextLink": "Alpha disclaimer",
				"storedLink": "",
				"ver": "",
				"pmodVer": "",
				"releaseID": 0,
				"slaveIndices": {},
				"genePool": [],
				"missingTable": {},
				"slaves": [],
				"PC": null,
				"freshPC": 0,
				"IsInPrimePC": 3,
				"IsPastPrimePC": 5000,
				"playerAging": 2,
				"slavePC": 0,
				"saveImported": 0,
				"customVariety": 0,
				"nationalities": {},
				"cheater": 0,
				"cash": 0,
				"cashLastWeek": 0,
				"taintedSaveFile": 0,
				"UI": {
					"slaveSummary": {
						"abbreviation": {
							"clothes": 2,
							"devotion": 2,
							"beauty": 2,
							"diet": 2,
							"drugs": 2,
							"genitalia": 2,
							"health": 2,
							"hormoneBalance": 2,
							"mental": 2,
							"nationality": 2,
							"origins": 2,
							"physicals": 2,
							"race": 2,
							"rules": 2,
							"rulesets": 2,
							"skills": 2
						}
					},
					"compressSocialEffects": 0
				},
				"market": null,
				"FSNamePref": 0,
				"HGFormality": 1,
				"HGSeverity": 0,
				"HGPiercings": 1,
				"abbreviateSidebar": 1,
				"adamPrinciple": 0,
				"allowFamilyTitles": 0,
				"allowMaleSlaveNames": false,
				"autosave": 1,
				"baseDifficulty": 3,
				"dangerousPregnancy": 0,
				"debugMode": 0,
				"debugModeCustomFunction": 0,
				"debugModeEventSelection": 0,
				"difficultySwitch": 0,
				"disableLisping": 0,
				"displayAssignments": 1,
				"expansionRequestsAllowed": 1,
				"extremeUnderage": 0,
				"formatNumbers": 1,
				"fucktoyInteractionsPosition": 1,
				"slaveInteractLongForm": false,
				"headGirlSoftensFlaws": 1,
				"headGirlTrainsFlaws": 1,
				"headGirlOverridesQuirks": 0,
				"headGirlTrainsHealth": 1,
				"headGirlTrainsObedience": 1,
				"headGirlTrainsParaphilias": 1,
				"headGirlTrainsSkills": 1,
				"imageChoice": 1,
				"inbreeding": 1,
				"lastBDayEvent": -1,
				"endweekSaveWarning": 1,
				"purchaseStyle": "link",
				"limitFamilies": 0,
				"makeDicks": 0,
				"modRequestsAllowed": 1,
				"neighboringArcologies": 3,
				"neighborDisplay": "list",
				"newDescriptions": 0,
				"newModelUI": 1,
				"ngpParams": {},
				"nicknamesAllowed": 1,
				"positionMainLinks": -1,
				"profiler": 0,
				"realRoyalties": 0,
				"retainCareer": 1,
				"rulesAssistantAuto": 0,
				"rulesAssistantMain": 1,
				"seeAge": 1,
				"seeArcology": 1,
				"seeAvatar": 1,
				"seeBestiality": 0,
				"seeCats": 0,
				"seeCircumcision": 1,
				"seeCustomImagesOnly": 0,
				"seeDesk": 1,
				"seeDetails": 1,
				"seeDicks": 25,
				"seeDicksAffectsPregnancy": 1,
				"seeRandomHair": 1,
				"seeExtreme": 0,
				"seeFaces": 1,
				"seeFCNN": 1,
				"seeHeight": 0,
				"seeHyperPreg": 0,
				"seeIllness": 1,
				"seeImages": 0,
				"seeIncest": 1,
				"seeMainFetishes": 0,
				"seeNationality": 1,
				"seePee": 1,
				"seePreg": 1,
				"seeRace": 1,
				"seeReportImages": 1,
				"seeStretching": 1,
				"seeSummaryImages": 1,
				"seeVectorArtHighlights": 1,
				"setSuperSampling": 2,
				"setZoomSpeed": 1,
				"setPanSpeed": 1,
				"setRotationSpeed": 1,
				"setDefaultView": 1,
				"setAutoFrame": 0,
				"setFaceCulling": true,
				"setTextureResolution": 1024,
				"setShadowMapping": true,
				"setSSAO": true,
				"setSSS": true,
				"setImageSize": 1.25,
				"set3QView": false,
				"seeAnimation": false,
				"animFPS": 12,
				"eventControl": {
					"RIEPerWeek": 1,
					"RIESkip": [],
					"RIERemaining": 0,
					"level": 0,
					"otherTrack": false,
					"events": []
				},
				"aiFaceDetailer": false,
				"aiApiUrl": "http://localhost:7860",
				"aiAutoGen": true,
				"aiAutoGenFrequency": 10,
				"aiUseRAForEvents": false,
				"aiCfgScale": 5,
				"aiTimeoutPerStep": 2.5,
				"aiCachingStrategy": "static",
				"aiCustomImagePrompts": 0,
				"aiCustomStyleNeg": "",
				"aiCustomStylePos": "",
				"aiDynamicCfgEnabled": false,
				"aiDynamicCfgMimic": 6,
				"aiDynamicCfgMinimum": 4,
				"aiLoraPack": true,
				"aiDisabledLoRAs": [],
				"aiNationality": 2,
				"aiGenderHint": 1,
				"aiOpenPose": false,
				"aiOpenPoseModel": "",
				"aiSamplingMethod": "DPM++ 2M SDE Karras",
				"aiSamplingSteps": 20,
				"aiSamplingStepsEvent": 20,
				"aiStyle": 1,
				"aiSchedulingMethod": "karras",
				"aiRestoreFaces": false,
				"aiUpscale": false,
				"aiUpscaleScale": 1.75,
				"aiUpscaler": "SwinIR_4x",
				"aiCheckpoint": "majicmixRealistic_v6.safetensors",
				"aiCustomWorkflow": "",
				"aiUserInterface": 0,
				"aiBaseModel": 0,
				"aiPrebuiltWorkflow": 0,
				"aiPonyTurbo": false,
				"aiPonyLoraStack": "{ \"Styles\\Concept Art DarkSide Style LoRA_Pony XL v6.safetensors\": 0.5, \"Styles\\Digital Art Style SDXL_LoRA_Pony Diffusion V6 XL.safetensors\": 0.2, \"Styles\\Photo 2 Style SDXL_LoRA_Pony Diffusion V6 XL.safetensors\": 0.2 }",
				"aiHeight": 768,
				"aiWidth": 512,
				"aiAgeFilter": true,
				"customClothesPrompts": {},
				"showAgeDetail": 1,
				"showAppraisal": 1,
				"showAssignToScenes": 1,
				"showBodyMods": 1,
				"showBoobCCs": 1,
				"showPotentialSizes": 1,
				"showClothing": 1,
				"showDickCMs": 1,
				"showDistantRelatives": 0,
				"showEWD": 1,
				"showEWM": 1,
				"showEconomicDetails": 0,
				"showHeightCMs": 1,
				"showImplantEffects": 1,
				"showInches": 1,
				"showMissingSlaves": false,
				"racialAttractivenessBonus": 1,
				"showMissingSlavesSD": false,
				"showNeighborDetails": 1,
				"showNumbers": 2,
				"showNumbersMax": 20,
				"showScores": 1,
				"showSexualHistory": 1,
				"showTipsFromEncy": 1,
				"showVignettes": 1,
				"slavePanelStyle": 1,
				"sortSlavesBy": "devotion",
				"sortSlavesMain": 1,
				"sortSlavesOrder": "descending",
				"summaryStats": 0,
				"surnameArcology": "",
				"surnameOrder": 0,
				"surnamePCOverride": 0,
				"surnameScheme": 0,
				"tabChoice": {
					"Main": "all"
				},
				"universalRulesAssignsSelfFacility": 0,
				"universalRulesBirthing": 0,
				"universalRulesCSec": 0,
				"universalRulesChildrenBecomeBreeders": 0,
				"universalRulesConsent": 0,
				"universalRulesFacilityWork": 1,
				"universalRulesImmobileSlavesMaintainMuscles": 0,
				"universalRulesImpregnation": "none",
				"universalRulesSuperfetationImpregnation": 0,
				"universalRulesNewSlavesRA": 1,
				"useAccordion": 1,
				"favSeparateReport": 0,
				"useFSNames": 1,
				"useSlaveListInPageJSNavigation": 0,
				"useSlaveSummaryOverviewTab": 0,
				"useSlaveSummaryTabs": 0,
				"useTabs": 0,
				"verboseDescriptions": 0,
				"verticalizeArcologyLinks": 0,
				"weightAffectsAssets": 1,
				"oversizedBoobShrinkage": 0,
				"maxErectionSizeOption": 0,
				"curativeSideEffects": 1,
				"disableLongDamage": 1,
				"findName": "",
				"findBackground": "",
				"findData": "",
				"underperformersCount": 7,
				"pedoMode": 0,
				"minimumSlaveAge": 16,
				"fertilityAge": 13,
				"potencyAge": 13,
				"AgePenalty": 1,
				"precociousPuberty": 0,
				"loliGrow": 0,
				"retirementAge": 45,
				"customRetirementAge": 45,
				"customMenialRetirementAge": 65,
				"idealAge": 18,
				"targetIdealAge": 18,
				"idealAgeAdoption": 0,
				"sortIncubatorList": "Unsorted",
				"AgeEffectOnTrainerPricingPC": 1,
				"AgeEffectOnTrainerEffectivenessPC": 1,
				"AgeTrainingUpperBoundPC": 14,
				"AgeTrainingLowerBoundPC": 12,
				"childSex": 0,
				"showClothingErection": true,
				"continent": "North America",
				"terrain": "rural",
				"language": "English",
				"AProsperityCapModified": 0,
				"secExpEnabled": 0,
				"customItem": {
					"buttplug": new Map([]),
					"vaginalAccessory": new Map([])
				},
				"pregnancyNotice": {
					"enabled": true,
					"accordionCollapsed": -1,
					"nextLockout": false,
					"renderFetus": true,
					"processedSlaves": []
				},
				"donatrix": 0,
				"receptrix": 0,
				"impregnatrix": 0,
				"transplantFetuses": [],
				"mods": {
					"food": {
						"enabled": false,
						"amount": 125000,
						"cost": 25,
						"lastWeek": 125000,
						"market": false,
						"deficit": 0,
						"overstocked": 0,
						"rate": {
							"slave": 8,
							"lower": 14.5,
							"middle": 16,
							"upper": 17.5,
							"top": 19
						},
						"rations": 0,
						"total": 0,
						"warned": false
					}
				}
			},
			// App.Data.resetOnNGPlus
			{
				"policies": {
					"retirement": {
						"sex": 0,
						"milk": 0,
						"cum": 0,
						"births": 0,
						"kills": 0,
						"fate": 0,
						"menial2Citizen": 0,
						"customAgePolicy": 0,
						"physicalAgePolicy": 0
					},
					"SMR": {
						"basicSMR": 1,
						"healthInspectionSMR": 0,
						"educationSMR": 0,
						"frigiditySMR": 0,
						"weightSMR": 0,
						"honestySMR": 0,
						"beauty": {
							"basicSMR": 0,
							"qualitySMR": 0
						},
						"height": {
							"basicSMR": 0,
							"advancedSMR": 0
						},
						"intelligence": {
							"basicSMR": 0,
							"qualitySMR": 0
						},
						"eugenics": {
							"faceSMR": 0,
							"heightSMR": 0,
							"intelligenceSMR": 0
						}
					},
					"childProtectionAct": 1,
					"idealAge": 0,
					"culturalOpenness": 0,
					"proRefugees": 0,
					"publicFuckdolls": 0,
					"proRecruitment": 0,
					"cash4Babies": 0,
					"regularParties": 0,
					"publicPA": 0,
					"coursingAssociation": 0,
					"raidingMercenaries": 0,
					"mixedMarriage": 0,
					"goodImageCampaign": 0,
					"alwaysSubsidizeRep": 0,
					"alwaysSubsidizeGrowth": 0,
					"immigrationCash": 0,
					"immigrationRep": 0,
					"enslavementCash": 0,
					"enslavementRep": 0,
					"cashForRep": 0,
					"oralAppeal": 0,
					"vaginalAppeal": 0,
					"analAppeal": 0,
					"sexualOpenness": 0,
					"bestialityOpenness": 0,
					"gumjobFetishism": 0,
					"gumjobFetishismSMR": 0
				},
				"FCTV": {
					"receiver": -1,
					"channel": {},
					"pcViewership": {
						"count": 0,
						"frequency": 4
					},
					"remote": 0,
					"weekEnabled": 0
				},
				"assistant": null,
				"targetArcology": {
					"fs": "New"
				},
				"plot": 1,
				"plotEventWeek": 0,
				"assignmentRecords": {},
				"marrying": [],
				"organs": [],
				"corp": {
					"Name": "Your corporation",
					"Announced": 0,
					"Incorporated": 0,
					"Market": 0,
					"Econ": 0,
					"CashDividend": 0,
					"Div": 0,
					"ExpandToken": 0,
					"Spec": 0,
					"SpecToken": 0,
					"SpecRaces": [],
					"disableOverhead": 0
				},
				"dividendTimer": 0,
				"dividendRatio": 0,
				"personalShares": 0,
				"publicShares": 0,
				"SF": {},
				"thisWeeksFSWares": 0,
				"thisWeeksIllegalWares": 0,
				"eventQueue": [],
				"eliteAuctioned": 0,
				"slavesSacrificedThisWeek": 0,
				"mercenariesTitle": "",
				"FSReminder": 0,
				"facility": {},
				"boomerangStats": {},
				"econAdvantage": 0,
				"SecExp": {},
				"reminderEntry": "",
				"reminderWeek": "",
				"currentRule": null,
				"costs": 0,
				"seeBuilding": 0,
				"purchasedSagBGone": 0,
				"eliteFail": 0,
				"eliteFailTimer": 0,
				"nurseryGrowthStimsSetting": 0,
				"MadamIgnoresFlaws": 0,
				"MadamNoSex": 0,
				"farmyardBreeding": 0,
				"farmyardRestraints": 0,
				"farmyardShows": 0,
				"farmyardPregSetting": 0,
				"farmyardSlavesAssignThemselves": 0,
				"DJignoresFlaws": 0,
				"DJnoSex": 0,
				"lastWeeksCashIncome": {},
				"lastWeeksCashExpenses": {},
				"lastWeeksRepIncome": {},
				"lastWeeksRepExpenses": {},
				"showAllEntries": {
					"costsBudget": 0,
					"repBudget": 0
				},
				"lastWeeksCashErrors": [],
				"lastWeeksRepErrors": [],
				"econRate": 0,
				"arcologies": [],
				"HackingSkillMultiplier": 0,
				"upgradeMultiplierArcology": 0,
				"upgradeMultiplierMedicine": 0,
				"upgradeMultiplierTrade": 0,
				"JobIDMap": null,
				"averageTrust": 0,
				"averageDevotion": 0,
				"enduringTrust": 0,
				"enduringDevotion": 0,
				"defaultRules": [],
				"rulesToApplyOnce": {},
				"raDefaultMode": 0,
				"raConfirmDelete": 1,
				"addButtonsToSlaveLinks": true,
				"RECheckInIDs": [],
				"deathIDs": {
					"health": [],
					"overdose": [],
					"age": []
				},
				"burstIDs": [],
				"birthIDs": [],
				"induceIDs": [],
				"activeSlave": 0,
				"activeChild": 0,
				"reminders": [],
				"personalLog": [],
				"boomerangSlave": 0,
				"boomerangWeeks": 0,
				"boomerangBuyer": 0,
				"bioreactorPerfectedID": 0,
				"independenceDay": 0,
				"invasionVictory": 0,
				"daughtersVictory": 0,
				"dormitory": 20,
				"dormitoryPopulation": 0,
				"rooms": 5,
				"roomsPopulation": 0,
				"brothelDecoration": "standard",
				"brothelUpgradeDrugs": 0,
				"brothelAdsSpending": 0,
				"brothelAdsOld": 0,
				"brothelAdsModded": 0,
				"brothelAdsImplanted": 0,
				"brothelAdsStacked": 0,
				"brothelAdsPreg": 0,
				"brothelAdsXX": 0,
				"brothelName": "the Brothel",
				"brothel": 0,
				"brothelBoost": {
					"selected": 0,
					"eligible": 0
				},
				"dairyDecoration": "standard",
				"dairyPrepUpgrade": 0,
				"dairyStimulatorsUpgrade": 0,
				"dairyStimulatorsSetting": 0,
				"dairyFeedersUpgrade": 0,
				"dairyFeedersSetting": 0,
				"dairyPregUpgrade": 0,
				"dairyPregSetting": 0,
				"dairyRestraintsUpgrade": 0,
				"dairyRestraintsSetting": 0,
				"dairySlimMaintainUpgrade": 0,
				"dairySlimMaintain": 0,
				"dairyHyperPregRemodel": 0,
				"dairyWeightSetting": 0,
				"dairyHormonesSetting": 0,
				"dairyImplantsSetting": 1,
				"dairyUpgradeMenials": 0,
				"createBioreactors": 0,
				"bioreactorsAnnounced": 0,
				"bioreactorsHerm": 0,
				"bioreactorsXX": 0,
				"bioreactorsXY": 0,
				"bioreactorsBarren": 0,
				"dairyName": "the Dairy",
				"dairy": 0,
				"clubDecoration": "standard",
				"clubUpgradePDAs": 0,
				"clubAdsSpending": 0,
				"clubAdsOld": 0,
				"clubAdsModded": 0,
				"clubAdsImplanted": 0,
				"clubAdsStacked": 0,
				"clubAdsPreg": 0,
				"clubAdsXX": 0,
				"clubName": "the Club",
				"club": 0,
				"servantsQuartersDecoration": "standard",
				"servantsQuartersUpgradeMonitoring": 0,
				"servantsQuarters": 0,
				"servantsQuartersName": "the Servants' Quarters",
				"schoolroomDecoration": "standard",
				"schoolroomUpgradeSkills": 0,
				"schoolroomUpgradeLanguage": 0,
				"schoolroomUpgradeRemedial": 0,
				"schoolroomRemodelBimbo": 0,
				"schoolroom": 0,
				"schoolroomName": "the Schoolroom",
				"spaDecoration": "standard",
				"spa": 0,
				"spaSpots": 0,
				"spaUpgrade": 0,
				"spaFix": 0,
				"spaAggroSpermBan": 1,
				"spaName": "the Spa",
				"incubator": {
					"capacity": 0,
					"tanks": [],
					"maleSetting": {
						"imprint": "trust",
						"targetAge": 18
					},
					"femaleSetting": {
						"imprint": "trust",
						"targetAge": 18
					}
				},
				"clinicDecoration": "standard",
				"clinic": 0,
				"clinicUpgradeFilters": 0,
				"clinicUpgradeScanner": 0,
				"clinicUpgradePathogenSequencer": 0,
				"clinicUpgradePurge": 0,
				"clinicObservePregnancy": 1,
				"clinicInflateBelly": 0,
				"clinicRegularCheckups": 1,
				"clinicSpeedGestation": 0,
				"clinicName": "the Clinic",
				"arcadeDecoration": "standard",
				"arcadeUpgradeInjectors": 0,
				"arcadeUpgradeFuckdolls": 0,
				"arcadeUpgradeCollectors": 0,
				"arcadeUpgradeHealth": -1,
				"arcadeName": "the Arcade",
				"arcade": 0,
				"fuckdollsSold": 0,
				"cellblockDecoration": "standard",
				"cellblockUpgrade": 0,
				"cellblock": 0,
				"cellblockName": "the Cellblock",
				"cellblockWardenCumsInside": 1,
				"masterSuiteDecoration": "standard",
				"masterSuiteUpgradeLuxury": 0,
				"masterSuiteUpgradePregnancy": 0,
				"masterSuitePregnancyFertilityDrugs": 0,
				"masterSuitePregnancyFertilitySupplements": 0,
				"masterSuitePregnancySlaveLuxuries": 0,
				"universalHGImpregnateMasterSuiteToggle": 0,
				"masterSuiteHyperPregnancy": 0,
				"masterSuite": 0,
				"masterSuiteName": "the Master Suite",
				"nursery": 0,
				"nurseryNannies": 0,
				"nurseryCribs": 0,
				"nurseryChildren": 0,
				"nannyInfluence": 0,
				"nurseryDecoration": "standard",
				"nurseryWeight": 0,
				"nurseryMuscles": 0,
				"nurseryHormones": 0,
				"nurseryOrgans": 0,
				"nurseryImprintSetting": 0,
				"nurseryWeightSetting": 0,
				"nurseryMusclesSetting": 0,
				"nurseryHormonesSetting": 0,
				"nurseryName": "the Nursery",
				"nurserySex": false,
				"MatronIgnoresFlaws": false,
				"cribs": [],
				"cribsIndices": {},
				"sortNurseryList": "Unsorted",
				"targetAgeNursery": 18,
				"farmyard": 0,
				"farmyardFarmers": [],
				"farmMenials": 0,
				"farmMenialsSpace": 0,
				"farmyardDecoration": "standard",
				"farmyardUpgrades": {
					"pump": 0,
					"fertilizer": 0,
					"hydroponics": 0,
					"machinery": 0,
					"seeds": 0,
					"foodStorage": 150
				},
				"farmyardCrops": 0,
				"farmyardStables": 0,
				"farmyardKennels": 0,
				"farmyardCages": 0,
				"active": {
					"canine": null,
					"hooved": null,
					"feline": null
				},
				"animals": {
					"canine": [],
					"hooved": [],
					"feline": []
				},
				"customAnimals": new Map(),
				"farmyardName": "the Farmyard",
				"HGSuite": 0,
				"HGSuiteSurgery": 1,
				"HGSuiteDrugs": 1,
				"HGSuiteAbortion": 1,
				"HGSuiteHormones": 1,
				"HGSuiteEquality": 0,
				"HGSuiteName": "the Head Girl Suite",
				"pit": null,
				"threatened": [
					[],
					[],
					[],
					[],
					[]
				],
				"dojo": 0,
				"feeder": 0,
				"cockFeeder": 0,
				"suppository": 0,
				"weatherCladding": 0,
				"weatherAwareness": 0,
				"boobAccessibility": 0,
				"servantMilkers": 0,
				"studio": 0,
				"studioFeed": 0,
				"PCSlutContacts": 1,
				"pornStars": {},
				"pregInventor": 0,
				"pregInventorID": 0,
				"pregInventions": 0,
				"FSAnnounced": 0,
				"FSGotRepCredits": 0,
				"FSCreditCount": 5,
				"FSSingleSlaveRep": 10,
				"FSSpending": 0,
				"FSLockinLevel": 100,
				"newCorp": 1,
				"vanillaShareSplit": 1,
				"classSatisfied": {
					"lowerClass": 0,
					"middleClass": 0,
					"upperClass": 0,
					"topClass": 0
				},
				"whoreBudget": {
					"lowerClass": 7,
					"middleClass": 40,
					"upperClass": 200,
					"topClass": 1500
				},
				"sexDemandResult": {
					"lowerClass": 0,
					"middleClass": 0,
					"upperClass": 0,
					"topClass": 0
				},
				"arcadePrice": 2,
				"shelterSlave": 0,
				"shelterSlaveBought": 0,
				"shelterAbuse": 0,
				"pregAccessibility": 0,
				"dickAccessibility": 0,
				"ballsAccessibility": 0,
				"buttAccessibility": 0,
				"boughtItem": {
					"clothing": {
						"bunny": 0,
						"conservative": 0,
						"chains": 0,
						"western": 0,
						"oil": 0,
						"habit": 0,
						"toga": 0,
						"huipil": 0,
						"kimono": 0,
						"harem": 0,
						"qipao": 0,
						"imperialarmor": 0,
						"imperialsuit": 0,
						"egypt": 0,
						"belly": 0,
						"maternityDress": 0,
						"maternityLingerie": 0,
						"lazyClothes": 0,
						"bimbo": 0,
						"courtesan": 0,
						"petite": 0,
						"antebellum": 0,
						"military": 0,
						"cultural": 0,
						"middleEastern": 0,
						"pol": 0,
						"costume": 0,
						"pantsu": 0,
						"career": 0,
						"dresses": 0,
						"bodysuits": 0,
						"casual": 0,
						"underwear": 0,
						"sports": 0,
						"pony": 0,
						"swimwear": 0
					},
					"shoes": {
						"heels": 0
					},
					"toys": {
						"enema": 0,
						"medicalEnema": 0,
						"buckets": 0,
						"dildos": 0,
						"gags": 0,
						"vaginalAttachments": 0,
						"buttPlugs": 0,
						"buttPlugTails": 0,
						"smartVibes": 0,
						"smartVaginalAttachments": 0,
						"smartStrapon": 0
					}
				},
				"dairyPiping": 0,
				"milkPipeline": 0,
				"cumPipeline": 0,
				"wcPiping": 0,
				"slaveDeath": new Map(),
				"playerBred": 0,
				"propOutcome": 0,
				"EliteSires": [],
				"raped": -1,
				"rapedThisWeek": 0,
				"missingParentID": -10000,
				"pregSpeedControl": 0,
				"bodyswapAnnounced": 0,
				"surnamesForbidden": 0,
				"menstruation": 0,
				"FCNNstation": 0,
				"swanSong": 0,
				"failedElite": 0,
				"eugenicsFullControl": 0,
				"badC": 0,
				"poorKnight": 0,
				"imperialEventWeek": 0,
				"assholeKnight": 0,
				"newBaron": 0,
				"badB": 0,
				"schoolSuggestion": 0,
				"TSS": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"TUO": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"GRI": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"SCP": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"LDE": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"TGA": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"TCR": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"TFS": {
					"farmUpgrade": 0,
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0,
					"compromiseWeek": 0
				},
				"futaAddiction": 0,
				"HA": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"NUL": {
					"schoolUpgrade": 0,
					"schoolPresent": 0,
					"schoolProsperity": 0,
					"subsidize": 0,
					"schoolAnnexed": 0,
					"studentsBought": 0,
					"schoolSale": 0
				},
				"IDNumber": 1,
				"week": 1,
				"slaveTutor": {
					"HeadGirl": [],
					"Recruiter": [],
					"Bodyguard": [],
					"Madam": [],
					"DJ": [],
					"Nurse": [],
					"Teacher": [],
					"Attendant": [],
					"Matron": [],
					"Stewardess": [],
					"Milkmaid": [],
					"Farmer": [],
					"Wardeness": []
				},
				"weddingPlanned": 0,
				"personalAttention": {
					"task": "sex"
				},
				"HeadGirlID": 0,
				"HGTimeInGrade": 0,
				"RecruiterID": 0,
				"recruiterTarget": "desperate whores",
				"oldRecruiterTarget": "desperate whores",
				"recruiterProgress": 0,
				"recruiterIdleRule": "number",
				"recruiterIdleNumber": 20,
				"recruiterIOUs": 0,
				"recruiterSpecializations": {
					"beauty": 0,
					"height": 0,
					"intelligence": 0
				},
				"bodyguardTrains": 1,
				"BodyguardID": 0,
				"MadamID": 0,
				"djID": 0,
				"MilkmaidID": 0,
				"milkmaidImpregnates": 0,
				"FarmerID": 0,
				"StewardessID": 0,
				"stewardessImpregnates": 0,
				"SchoolteacherID": 0,
				"AttendantID": 0,
				"MatronID": 0,
				"NurseID": 0,
				"WardenessID": 0,
				"ConcubineID": 0,
				"justiceEvents": [
					"slave deal",
					"slave training",
					"majority deal",
					"indenture deal",
					"virginity deal",
					"breeding deal"
				],
				"prisonCircuit": [
					"low tier criminals",
					"gangs and smugglers",
					"white collar",
					"military prison",
					"juvenile detention"
				],
				"prisonCircuitIndex": 0,
				"ui": "start",
				"tooltipsEnabled": 0,
				"brandTarget": {
					"primary": "left buttock",
					"secondary": "left buttock",
					"local": "left buttock"
				},
				"brandDesign": {
					"primary": "your initials",
					"official": "your initials",
					"local": "your initials"
				},
				"scarTarget": {
					"primary": "left cheek",
					"secondary": "left cheek",
					"local": "left cheek"
				},
				"scarDesign": {
					"primary": "generic",
					"local": "generic"
				},
				"oralTotal": 0,
				"vaginalTotal": 0,
				"analTotal": 0,
				"mammaryTotal": 0,
				"penetrativeTotal": 0,
				"milkTotal": 0,
				"cumTotal": 0,
				"birthsTotal": 0,
				"abortionsTotal": 0,
				"miscarriagesTotal": 0,
				"bestialityTotal": 0,
				"pitKillsTotal": 0,
				"pitFightsTotal": 0,
				"collaboration": 0,
				"traitor": 0,
				"traitorType": 0,
				"traitorWeeks": 0,
				"traitorStats": 0,
				"hackerSupport": 0,
				"hostage": 0,
				"hostageWife": 0,
				"rival": {
					"state": 0,
					"duration": 0,
					"prosperity": 0,
					"power": 0,
					"FS": {
						"name": ""
					},
					"hostageState": 0
				},
				"nationHate": 0,
				"eventResults": {},
				"dispensary": 0,
				"dispensaryUpgrade": 0,
				"organFarmUpgrade": 0,
				"completedOrgans": [],
				"ImplantProductionUpgrade": 0,
				"permaPregImplant": 0,
				"injectionUpgrade": 0,
				"hormoneUpgradeMood": 0,
				"hormoneUpgradeShrinkage": 0,
				"hormoneUpgradePower": 0,
				"pubertyHormones": 0,
				"dietXXY": 0,
				"dietCleanse": 0,
				"cumProDiet": 0,
				"dietFertility": 0,
				"curativeUpgrade": 0,
				"growthStim": 0,
				"reproductionFormula": 0,
				"aphrodisiacUpgrade": 0,
				"aphrodisiacUpgradeRefine": 0,
				"healthyDrugsUpgrade": 0,
				"superFertilityDrugs": 0,
				"bellyImplants": 0,
				"cervixImplants": 0,
				"cervixImplantUpgrade": 0,
				"meshImplants": 0,
				"prostateImplants": 0,
				"youngerOvaries": 0,
				"immortalOvaries": 0,
				"sympatheticOvaries": 0,
				"fertilityImplant": 0,
				"asexualReproduction": 0,
				"animalOvaries": 0,
				"animalTesticles": 0,
				"animalMpreg": 0,
				"geneticMappingUpgrade": 0,
				"toyShop": false,
				"pregnancyMonitoringUpgrade": 0,
				"cloningSystem": 0,
				"geneticFlawLibrary": 0,
				"consumerDrugs": 0,
				"projectN": {
					"status": 0,
					"public": 0,
					"wellFunded": 0,
					"poorlyFunded": 0,
					"phase1": 0,
					"phase2": 0,
					"phase3": 0,
					"phase4": 0,
					"decisionMade": 0,
					"techReleased": 0
				},
				"bodyPuristRiot": 0,
				"puristsFurious": 0,
				"puristRiotDone": 0,
				"subjectDeltaName": "Bubbles",
				"growingNewCat": 0,
				"noDeadShit": 0,
				"surgeryUpgrade": 0,
				"barracks": 0,
				"mercenaries": 0,
				"mercenariesHelpCorp": 0,
				"personalArms": 0,
				"trinkets": new Map([]),
				"SPcost": 1000,
				"debtWarned": 0,
				"internationalTrade": 1,
				"internationalVariety": 0,
				"slaveCostFactor": 0.95,
				"menialDemandFactor": 0,
				"menialSupplyFactor": 0,
				"demandTimer": 0,
				"supplyTimer": 0,
				"elapsedDemandTimer": 0,
				"elapsedSupplyTimer": 0,
				"slaveCostRandom": 0,
				"deltaDemand": 0,
				"deltaDemandOld": 0,
				"deltaSupply": 0,
				"deltaSupplyOld": 0,
				"NPCSexSupply": {
					"lowerClass": 3000,
					"middleClass": 3000,
					"upperClass": 3000,
					"topClass": 3000
				},
				"NPCMarketShare": {
					"lowerClass": 1000,
					"middleClass": 1000,
					"upperClass": 1000,
					"topClass": 1000
				},
				"sexSubsidies": {
					"lowerClass": 0,
					"middleClass": 0,
					"upperClass": 0,
					"topClass": 0
				},
				"sexSupplyBarriers": {
					"lowerClass": 0,
					"middleClass": 0,
					"upperClass": 0,
					"topClass": 0
				},
				"facilityCost": 100,
				"enduringRep": 1000,
				"maximumRep": 30000,
				"rep": 0,
				"repLastWeek": 0,
				"arcologyUpgrade": {
					"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,
				"LSCBase": 800,
				"visitors": 0,
				"rentDefaults": {
					"lowerClass": 20,
					"middleClass": 50,
					"upperClass": 180,
					"topClass": 650
				},
				"rent": {
					"lowerClass": 20,
					"middleClass": 50,
					"upperClass": 180,
					"topClass": 650
				},
				"rentEffectL": 1,
				"middleClass": 890,
				"MCBase": 200,
				"rentEffectM": 1,
				"upperClass": 200,
				"UCBase": 40,
				"rentEffectU": 1,
				"topClass": 40,
				"TCBase": 20,
				"rentEffectT": 1,
				"GDP": 278.6,
				"NPCSlaves": 900,
				"ASlaves": 900,
				"AProsperityCap": 0,
				"revealFoodEffects": 0,
				"building": null,
				"menials": 0,
				"fuckdolls": 0,
				"menialBioreactors": 0,
				"prestigeAuctioned": 0,
				"slaveMarketLimit": 20,
				"slavesSeen": 0,
				"slaveOrphanageTotal": 0,
				"citizenOrphanageTotal": 0,
				"privateOrphanageTotal": 0,
				"breederOrphanageTotal": 0,
				"LurcherID": 0,
				"coursed": 0,
				"StudID": 0,
				"raided": 0,
				"FSSlaveProfLawTrigger": 0,
				"citizenRetirementTrigger": 0,
				"FSSupLawTrigger": 0,
				"FSSubLawTrigger": 0,
				"nicaea": {
					"announced": 0,
					"preparation": 0,
					"involvement": -2,
					"power": 0,
					"held": 0,
					"focus": "",
					"assignment": "",
					"achievement": "",
					"name": "",
					"influence": 0,
					"eventWeek": 0
				},
				"peacekeepers": {
					"state": 1
				},
				"mercRomeo": 0,
				"oralUseWeight": 5,
				"vaginalUseWeight": 5,
				"analUseWeight": 5,
				"mammaryUseWeight": 1,
				"penetrativeUseWeight": 1,
				"weatherToday": {},
				"weatherLastWeek": 0,
				"weatherType": 0,
				"weatherRemaining": 0,
				"customSlave": null,
				"customSlaveOrdered": 0,
				"customSlaveReorder": 0,
				"huskSlave": null,
				"huskSlaveOrdered": 0,
				"JFC": {
					"order": 0,
					"reorder": 0
				},
				"cheatMode": 0,
				"cheatModeM": 1,
				"slaveBotGeneration": 0,
				"experimental": {
					"nursery": 0,
					"food": 0,
					"animalOvaries": 0,
					"dinnerParty": 0,
					"reportMissingClothing": 0,
					"raGrowthExpr": 0,
					"sexOverhaul": 0,
					"interactions": 0,
					"clitoralPenetration": 0,
					"raSortOutput": 0
				},
				"NaNArray": [],
				"recruiterEugenics": 0,
				"prostheticsUpgrade": 0,
				"adjustProstheticsCompleted": 0,
				"adjustProsthetics": [],
				"researchLab": {
					"level": 0,
					"aiModule": 1,
					"tasks": [],
					"maxSpace": 0,
					"hired": 0,
					"menials": 0
				},
				"prosthetics": {},
				"merchantFSWares": [
					"AssetExpansionistResearch",
					"GenderRadicalistResearch",
					"HedonisticDecadenceResearch",
					"SlaveProfessionalismResearch",
					"SlimnessEnthusiastResearch",
					"TransformationFetishistResearch",
					"YouthPreferentialistResearch"
				],
				"merchantIllegalWares": [
					"AnimalOrgans",
					"asexualReproduction",
					"BlackmarketPregAdaptation",
					"childhoodFertilityInducedNCS",
					"PGHack",
					"RapidCellGrowthFormula",
					"optimizedSpermFormula",
					"optimizedBreedingFormula",
					"sympatheticOvaries",
					"UterineRestraintMesh"
				],
				"UterineRestraintMesh": 0,
				"PGHack": 0,
				"BlackmarketPregAdaptation": 0,
				"RapidCellGrowthFormula": 0,
				"immortalityFormula": 0,
				"bioEngineeredFlavoringResearch": 0,
				"optimizedSpermFormula": 0,
				"enhancedProductionFormula": 0,
				"optimizedBreedingFormula": 0,
				"doctor": {
					"state": 0,
					"cost": 500
				},
				"pSurgery": {
					"state": 0,
					"cooldown": 0,
					"nursePreg": 0,
					"disloyal": 0,
					"cost": 0
				},
				"pExoticSurgery": {
					"state": 0,
					"fakePreg": 0,
					"cooldown": 0,
					"visits": 0,
					"clones": []
				},
				"diversePronouns": 0,
				"antiWeatherFreeze": 0,
				"econWeatherDamage": 0,
				"disasterResponse": 0,
				"postSexCleanUp": 1,
				"sideBarOptions": {
					"Style": "expanded",
					"Cash": 1,
					"Upkeep": 1,
					"SexSlaveCount": 1,
					"roomPop": 1,
					"Rep": 1,
					"GSP": 1,
					"Authority": 1,
					"Security": 1,
					"Crime": 1,
					"confirmWeekEnd": 0,
					"notifyFS": 1,
					"notifyIncubator": 1,
					"notifyCorp": 1
				},
				"DefaultBirthDestination": "individually decided fates",
				"heroSlavesPurchased": [],
				"fcnn": [],
				"murderAttemptWeek": 80,
				"illegalDeals": {
					"military": 0,
					"trade": 0,
					"menialDrug": 0,
					"slave": 0
				},
				"tempEventToggle": 0,
				"favorites": [],
				"loans": [],
				"RAActions": {
					"slaves": {}
				}
			}
		);
	}
});


code:
App.Patch.register({
	releaseID: 1258,
	descriptionOfChanges: "This runs the legacy BC for older saves",
	post: (div) => {
		// call the legacy BC as patching didn't exist for this or earlier versions
		App.Patch.log("** Calling legacy BC **");
		App.UI.DOM.appendNewElement("div", div, App.Update.backwardsCompatibility());
	},
	slaveState: (div, actor, location) => {
		// call the valid parts of legacy BC for the slave
		App.Patch.log(`** Calling legacy BC **`);
		App.Update.Slave(actor, location === "gene pool");
		App.Update.SlaveDataSchemeCleanup(actor);
		App.Update.SlaveDatatypeCleanup(actor, location === "tank slave pool");
		/** @type {"normal" | "PC" | "detached" | "incubator"} */
		let slaveType = "normal";
		/** @type {App.Patch.Utils.HumanStateLocation[]} */
		const detachedLocations = ["detached boomerang", "detached hostage", "detached hostage wife", "detached shelter", "detached traitor"];
		if (location === "tank slave pool") {
			slaveType = "incubator";
		} else if (detachedLocations.includes(location)) {
			slaveType = "detached";
		}
		actor = /** @type {FC.SlaveState} */ (App.Update.human(actor, slaveType, div));
		return actor;
	},
	tankSlaveState: (div, actor) => {
		// call the valid parts of legacy BC for the tank slave
		App.Patch.log(`** Calling legacy BC **`);
		App.Update.Slave(actor);
		App.Update.SlaveDataSchemeCleanup(actor);
		App.Update.SlaveDatatypeCleanup(actor, true);
		actor = /** @type {FC.TankSlaveState} */ (App.Update.human(actor, "incubator", div));
		return actor;
	},
	playerState: (div, actor, location) => {
		// call the valid parts of legacy BC for the player
		App.Patch.log("** Calling legacy BC **");
		App.Update.Player(actor, location === "gene pool");
		actor = /** @type {FC.PlayerState} */ (App.Update.human(actor, "PC", div));
		return actor;
	},
	customSlaveOrder: (div, order, location) => {
		App.Patch.log(`** Calling legacy BC **`);
		App.Update.CustomSlaveOrder(order);
		return order;
	}
});