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 slaveOrZero(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 = slaveOrZero(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() {
		const ngUpdateGenePool = function(genePool = []) {
			const transferredSlaveIds = (V.slaves || [])
				.filter(s => s.ID >= NGPOffset)
				.map(s => s.ID - NGPOffset);
			return genePool
				.filter(s => (transferredSlaveIds.includes(s.ID)))
				.map(function(s) {
					const result = jQuery.extend(true, {}, s);
					result.ID += NGPOffset;
					return result;
				});
		};

		const ngUpdateMissingTable = function(missingTable) {
			const newTable = {};

			(V.slaves || [])
				.forEach(s => ([s.pregSource + NGPOffset, s.mother + NGPOffset, s.father + NGPOffset]
					.filter(i => (i in missingTable))
					.forEach(i => {
						newTable[i - NGPOffset] = missingTable[i];
						newTable[i - NGPOffset].ID -= NGPOffset;
					})));

			return newTable;
		};

		V.slaves.deleteWith((s) => s.assignment !== Job.IMPORTED);

		for (let slave of V.slaves) {
			slave.ID += NGPOffset;
			slave.assignment = Job.REST;
			slave.weekAcquired = 0;
			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";
		}
		V.slaveIndices = slaves2indices();
		for (let slave of V.slaves) {
			slave.pregSource = slaveOrZero(slave.pregSource);
			slave.cloneID = slaveOrZero(slave.cloneID);
			slave.relationshipTarget = slaveOrZero(slave.relationshipTarget);
		}
		V.genePool = ngUpdateGenePool(V.genePool);
		if (typeof V.missingTable === undefined || V.showMissingSlaves === false) {
			V.missingTable = {};
		} else {
			V.missingTable = ngUpdateMissingTable(V.missingTable);
		}
		let validRelationship = (s) => (s.relationshipTarget !== 0 && getSlave(s.relationshipTarget).relationshipTarget === s.ID);
		for (let slave of V.slaves) {
			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.lifetimeCashExpenses = 0;
			slave.lifetimeCashIncome = 0;
			slave.lastWeeksCashIncome = 0;
			slave.lifetimeRepExpenses = 0;
			slave.lifetimeRepIncome = 0;
			slave.lastWeeksRepExpenses = 0;
			slave.lastWeeksRepIncome = 0;
		}
	}

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

	return doNGPSetup;
})();

src/data/newGamePlus.js