code:
// IDB v7.1.1 https://github.com/jakearchibald/idb

// @ts-nocheck
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.AI_IDB = {}));
})(this, (function (exports) { 'use strict';

    const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);

    let idbProxyableTypes;
    let cursorAdvanceMethods;
    // This is a function to prevent it throwing up in node environments.
    function getIdbProxyableTypes() {
        return (idbProxyableTypes ||
            (idbProxyableTypes = [
                IDBDatabase,
                IDBObjectStore,
                IDBIndex,
                IDBCursor,
                IDBTransaction,
            ]));
    }
    // This is a function to prevent it throwing up in node environments.
    function getCursorAdvanceMethods() {
        return (cursorAdvanceMethods ||
            (cursorAdvanceMethods = [
                IDBCursor.prototype.advance,
                IDBCursor.prototype.continue,
                IDBCursor.prototype.continuePrimaryKey,
            ]));
    }
    const cursorRequestMap = new WeakMap();
    const transactionDoneMap = new WeakMap();
    const transactionStoreNamesMap = new WeakMap();
    const transformCache = new WeakMap();
    const reverseTransformCache = new WeakMap();
    function promisifyRequest(request) {
        const promise = new Promise((resolve, reject) => {
            const unlisten = () => {
                request.removeEventListener('success', success);
                request.removeEventListener('error', error);
            };
            const success = () => {
                resolve(wrap(request.result));
                unlisten();
            };
            const error = () => {
                reject(request.error);
                unlisten();
            };
            request.addEventListener('success', success);
            request.addEventListener('error', error);
        });
        promise
            .then((value) => {
            // Since cursoring reuses the IDBRequest (*sigh*), we cache it for later retrieval
            // (see wrapFunction).
            if (value instanceof IDBCursor) {
                cursorRequestMap.set(value, request);
            }
            // Catching to avoid "Uncaught Promise exceptions"
        })
            .catch(() => { });
        // This mapping exists in reverseTransformCache but doesn't doesn't exist in transformCache. This
        // is because we create many promises from a single IDBRequest.
        reverseTransformCache.set(promise, request);
        return promise;
    }
    function cacheDonePromiseForTransaction(tx) {
        // Early bail if we've already created a done promise for this transaction.
        if (transactionDoneMap.has(tx))
            return;
        const done = new Promise((resolve, reject) => {
            const unlisten = () => {
                tx.removeEventListener('complete', complete);
                tx.removeEventListener('error', error);
                tx.removeEventListener('abort', error);
            };
            const complete = () => {
                resolve();
                unlisten();
            };
            const error = () => {
                reject(tx.error || new DOMException('AbortError', 'AbortError'));
                unlisten();
            };
            tx.addEventListener('complete', complete);
            tx.addEventListener('error', error);
            tx.addEventListener('abort', error);
        });
        // Cache it for later retrieval.
        transactionDoneMap.set(tx, done);
    }
    let idbProxyTraps = {
        get(target, prop, receiver) {
            if (target instanceof IDBTransaction) {
                // Special handling for transaction.done.
                if (prop === 'done')
                    return transactionDoneMap.get(target);
                // Polyfill for objectStoreNames because of Edge.
                if (prop === 'objectStoreNames') {
                    return target.objectStoreNames || transactionStoreNamesMap.get(target);
                }
                // Make tx.store return the only store in the transaction, or undefined if there are many.
                if (prop === 'store') {
                    return receiver.objectStoreNames[1]
                        ? undefined
                        : receiver.objectStore(receiver.objectStoreNames[0]);
                }
            }
            // Else transform whatever we get back.
            return wrap(target[prop]);
        },
        set(target, prop, value) {
            target[prop] = value;
            return true;
        },
        has(target, prop) {
            if (target instanceof IDBTransaction &&
                (prop === 'done' || prop === 'store')) {
                return true;
            }
            return prop in target;
        },
    };
    function replaceTraps(callback) {
        idbProxyTraps = callback(idbProxyTraps);
    }
    function wrapFunction(func) {
        // Due to expected object equality (which is enforced by the caching in `wrap`), we
        // only create one new func per func.
        // Edge doesn't support objectStoreNames (booo), so we polyfill it here.
        if (func === IDBDatabase.prototype.transaction &&
            !('objectStoreNames' in IDBTransaction.prototype)) {
            return function (storeNames, ...args) {
                const tx = func.call(unwrap(this), storeNames, ...args);
                transactionStoreNamesMap.set(tx, storeNames.sort ? storeNames.sort() : [storeNames]);
                return wrap(tx);
            };
        }
        // Cursor methods are special, as the behavior is a little more different to standard IDB. In
        // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
        // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
        // with real promises, so each advance methods returns a new promise for the cursor object, or
        // undefined if the end of the cursor has been reached.
        if (getCursorAdvanceMethods().includes(func)) {
            return function (...args) {
                // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
                // the original object.
                func.apply(unwrap(this), args);
                return wrap(cursorRequestMap.get(this));
            };
        }
        return function (...args) {
            // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
            // the original object.
            return wrap(func.apply(unwrap(this), args));
        };
    }
    function transformCachableValue(value) {
        if (typeof value === 'function')
            return wrapFunction(value);
        // This doesn't return, it just creates a 'done' promise for the transaction,
        // which is later returned for transaction.done (see idbObjectHandler).
        if (value instanceof IDBTransaction)
            cacheDonePromiseForTransaction(value);
        if (instanceOfAny(value, getIdbProxyableTypes()))
            return new Proxy(value, idbProxyTraps);
        // Return the same value back if we're not going to transform it.
        return value;
    }
    function wrap(value) {
        // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
        // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
        if (value instanceof IDBRequest)
            return promisifyRequest(value);
        // If we've already transformed this value before, reuse the transformed value.
        // This is faster, but it also provides object equality.
        if (transformCache.has(value))
            return transformCache.get(value);
        const newValue = transformCachableValue(value);
        // Not all types are transformed.
        // These may be primitive types, so they can't be WeakMap keys.
        if (newValue !== value) {
            transformCache.set(value, newValue);
            reverseTransformCache.set(newValue, value);
        }
        return newValue;
    }
    const unwrap = (value) => reverseTransformCache.get(value);

    /**
     * Open a database.
     *
     * @param name Name of the database.
     * @param version Schema version.
     * @param callbacks Additional callbacks.
     */
    // @ts-ignore
    function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
        const request = indexedDB.open(name, version);
        const openPromise = wrap(request);
        if (upgrade) {
            request.addEventListener('upgradeneeded', (event) => {
                upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
            });
        }
        if (blocked) {
            request.addEventListener('blocked', (event) => blocked(
            // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
            event.oldVersion, event.newVersion, event));
        }
        openPromise
            .then((db) => {
            if (terminated)
                db.addEventListener('close', () => terminated());
            if (blocking) {
                db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
            }
        })
            .catch(() => { });
        return openPromise;
    }
    /**
     * Delete a database.
     *
     * @param name Name of the database.
     */
    // @ts-ignore
    function deleteDB(name, { blocked } = {}) {
        const request = indexedDB.deleteDatabase(name);
        if (blocked) {
            request.addEventListener('blocked', (event) => blocked(
            // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
            event.oldVersion, event));
        }
        return wrap(request).then(() => undefined);
    }

    const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
    const writeMethods = ['put', 'add', 'delete', 'clear'];
    const cachedMethods = new Map();
    function getMethod(target, prop) {
        if (!(target instanceof IDBDatabase &&
            !(prop in target) &&
            typeof prop === 'string')) {
            return;
        }
        if (cachedMethods.get(prop))
            return cachedMethods.get(prop);
        const targetFuncName = prop.replace(/FromIndex$/, '');
        const useIndex = prop !== targetFuncName;
        const isWrite = writeMethods.includes(targetFuncName);
        if (
        // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.
        !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||
            !(isWrite || readMethods.includes(targetFuncName))) {
            return;
        }
        const method = async function (storeName, ...args) {
            // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(
            const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');
            let target = tx.store;
            if (useIndex)
                target = target.index(args.shift());
            // Must reject if op rejects.
            // If it's a write operation, must reject if tx.done rejects.
            // Must reject with op rejection first.
            // Must resolve with op value.
            // Must handle both promises (no unhandled rejections)
            return (await Promise.all([
                target[targetFuncName](...args),
                isWrite && tx.done,
            ]))[0];
        };
        cachedMethods.set(prop, method);
        return method;
    }
    replaceTraps((oldTraps) => ({
        ...oldTraps,
        get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
        has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),
    }));

    const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
    const methodMap = {};
    const advanceResults = new WeakMap();
    const ittrProxiedCursorToOriginalProxy = new WeakMap();
    const cursorIteratorTraps = {
        get(target, prop) {
            if (!advanceMethodProps.includes(prop))
                return target[prop];
            let cachedFunc = methodMap[prop];
            if (!cachedFunc) {
                cachedFunc = methodMap[prop] = function (...args) {
                    advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
                };
            }
            return cachedFunc;
        },
    };
    async function* iterate(...args) {
        // tslint:disable-next-line:no-this-assignment
        let cursor = this;
        if (!(cursor instanceof IDBCursor)) {
            cursor = await cursor.openCursor(...args);
        }
        if (!cursor)
            return;
        cursor = cursor;
        const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
        ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
        // Map this double-proxy back to the original, so other cursor methods work.
        reverseTransformCache.set(proxiedCursor, unwrap(cursor));
        while (cursor) {
            yield proxiedCursor;
            // If one of the advancing methods was not called, call continue().
            cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
            advanceResults.delete(proxiedCursor);
        }
    }
    function isIteratorProp(target, prop) {
        return ((prop === Symbol.asyncIterator &&
            instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
            (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));
    }
    replaceTraps((oldTraps) => ({
        ...oldTraps,
        get(target, prop, receiver) {
            if (isIteratorProp(target, prop))
                return iterate;
            return oldTraps.get(target, prop, receiver);
        },
        has(target, prop) {
            return isIteratorProp(target, prop) || oldTraps.has(target, prop);
        },
    }));

    exports.deleteDB = deleteDB;
    exports.openDB = openDB;
    exports.unwrap = unwrap;
    exports.wrap = wrap;

}));


code:
/* eslint-disable no-var */
// @ts-ignore
"use strict";

var App = {}; // eslint-disable-line no-redeclare

// When adding namespace declarations, please consider needs of those using VSCode:
// when you declare App.A{ A1:{}, A2:{} }, VSCode considers A, A1, and A2 to be
// sealed namespaces and no new members are added to them with nested declaration later on.
// This breaks code completion completely. Please instead declare them as:
// App.A = {}; App.A.A1 = {}; App.A.A2 = {}. Thank you.

// Also, such declaration basically required only for namespaces that span more than a single file.

App.Arcology = {};
App.Arcology.Cell = {};
App.Art = {};
App.Art.GenAI = {};
App.Art.GenAI.UI = {};
App.Art.GenAI.Ill = {}; // For Illustrious prompts
App.Budget = {};
App.Corporate = {};
App.Corporate.Division = {};
App.Corporate.Shared = {};
App.Data = {};
App.Data.Arcology = {};
App.Data.Art = {};
App.Data.FCTV = {};
App.Data.HeroSlaves = {};
App.Data.Medicine = {};
App.Data.Policies = {};
App.Data.Policies.Selection = {};
App.Data.SecExp = {};
App.Data.Slave = {};
App.Data.Weather = {};
App.Debug = {};
App.Desc = {};
App.Desc.Player = {};
App.Encyclopedia = {};
App.EndWeek = {};
App.EndWeek.Player = {};
App.EndWeek.Shared = {};
App.Entity = {};
App.Events = {};
App.Facilities = {};
App.Facilities.Arcade = {};
App.Facilities.Brothel = {};
App.Facilities.Cellblock = {};
App.Facilities.Clinic = {};
App.Facilities.Club = {};
App.Facilities.Dairy = {};
App.Facilities.Farmyard = {};
App.Facilities.HGSuite = {};
App.Facilities.Incubator = {};
App.Facilities.MasterSuite = {};
App.Facilities.Nursery = {};
App.Facilities.Pit = {};
App.Facilities.Pit.Fights = {};
App.Facilities.Schoolroom = {};
App.Facilities.ServantsQuarters = {};
App.Facilities.Spa = {};
App.Facilities.TransportHub = {};
App.Interact = {};
App.Interact.Sale = {};
App.Intro = {};
App.MainView = {};
App.Markets = {};
App.Medicine = {};
App.Medicine.Modification = {};
App.Medicine.Modification.Brands = {};
App.Medicine.Modification.Select = {};
App.Medicine.OrganFarm = {};
App.Medicine.Salon = {};
App.Medicine.Surgery = {};
App.Medicine.Surgery.Procedures = {};
App.Medicine.Surgery.Reactions = {};
App.Mods = {};
App.Mods.DinnerParty = {};
App.Mods.Drugs = {};
App.Mods.events = {
	nonRandom: [],
	random: {
		individual: [],
		nonindividual: [],
		recruitment: [],
	},
	recruit: [],
};
App.Mods.SecExp = {};
App.Mods.SF = {};
App.Neighbor = {};
App.PersonalAttention = {};
/**
 * The patching system that replaces the legacy BC.
 * Its primary file and instructions are located at `/src/data/patches/patch.js`.
 * See {@link App.Patch.Patches} and {@link App.Patch.applyAll}
 */
App.Patch = {};
/**
 * Stores patches.
 * DO NOT ADD DIRECTLY TO THIS!
 * Create a patch following the instructions at the top of `/src/data/patches/patch.js` instead.
 * Look in `/src/data/patches/releases/` for examples from existing patches.
 * @type {{[key: number]: App.Patch.Utils.PatchRecord}}
 */
App.Patch.Patches = {};
/**
 * Utilities used internally by the patching system.
 * Stored in `/src/data/patches/patchUtils.js`.
 */
App.Patch.Utils = {};
App.Porn = {};
App.RA = {};
App.RA.Activation = {};
App.Ratings = {};
App.SlaveAssignment = {};
App.StartingGirls = {};
App.Status = {};
App.Status.storyReady = false;
App.UI = {};
App.UI.Cheat = {};
App.UI.DOM = {};
App.UI.DOM.Widgets = {};
App.UI.DressingRoom = {};
App.UI.SlaveInteract = {};
App.UI.SlaveInteract.SlaveBot = {};
App.UI.SlaveInteract.SlaveBot.Generate = {};
App.UI.ChildInteract = {};
App.UI.View = {};
/**
 * The legacy BC.
 * While it is depreciated, it should not be removed or modifed as it is used as a patch in the new patching system.
 * Its files are stored in `/src/data/backwardsCompatibility/`.
 * @deprecated Replaced by `App.Patch.applyAll()`.
 * See {@link App.Patch} and {@link App.Patch.applyAll}
 */
App.Update = {};
App.Utils = {};
App.Utils.Math = {};
/**
 * The validation system. This replaces the validation that was done in the legacy BC.
 * Its primary file and instructions are located at `/src/data/verification/zVerify.js`.
 * See {@link App.Verify.everything}
 */
App.Verify = {};
/**
 * Storage for validation instructions.
 * These are functions that should be added to one or more instruction set(s) in `App.Verify.instructions`.
 * See {@link App.Verify.instructions}
 */
App.Verify.I = {};
/**
 * Utilities used internally by the validation system.
 * Stored in `/src/data/verification/verifyUtils.js`.
 */
App.Verify.Utils = {};

repo_name: Nithhogg/fc

license: mit


code:
App.Data.Arcology.Terrain = ["marine", "marine", "oceanic", "ravine", "rural", "rural", "rural", "urban", "urban"];
App.Data.Arcology.Continents = ["Africa", "Asia", "Asia", "Australia", "Western Europe", "Southern Europe", "Central Europe", "Eastern Europe", "Scandinavia", "Japan", "North America", "North America", "South America", "the Middle East"];


code:
App.Data.Assistant = {};
/**
 * Assistant appearances mapped to the FS that love seeing her look like she do.
 * @type {Map<FC.FutureSociety, Array<assistantAppearance>>}
 */
App.Data.Assistant.appearanceForFS = new Map([
	["FSSupremacist", ["amazon", "monstergirl", "succubus"]],
	["FSSubjugationist", ["amazon", "businesswoman", "imp"]],
	["FSGenderRadicalist", ["incubus", "monstergirl", "shemale", "succubus", "witch"]],
	["FSGenderFundamentalist", ["angel", "cherub", "fairy", "goddess", "hypergoddess", "loli", "preggololi", "pregnant fairy", "schoolgirl", "succubus", "witch"]],
	["FSDegradationist", ["businesswoman", "imp", "incubus", "monstergirl", "preggololi", "succubus"]],
	["FSPaternalist", ["angel", "cherub", "fairy", "goddess", "hypergoddess", "loli", "preggololi", "pregnant fairy", "schoolgirl"]],
	["FSBodyPurist", ["amazon", "angel", "fairy", "goddess", "incubus", "loli", "pregnant fairy", "succubus", "witch"]],
	["FSTransformationFetishist", ["businesswoman", "ERROR_1606_APPEARANCE_FILE_CORRUPT", "incubus", "shemale", "succubus", "witch"]],
	["FSYouthPreferentialist", ["angel", "cherub", "imp", "loli", "preggololi", "schoolgirl", "shemale", "succubus", "witch"]],
	["FSMaturityPreferentialist", ["angel", "businesswoman", "goddess", "incubus", "succubus", "witch"]],
	["FSSlimnessEnthusiast", ["cherub", "imp", "loli", "schoolgirl", "shemale", "succubus", "witch"]],
	["FSAssetExpansionist", ["businesswoman", "hypergoddess", "incubus", "shemale", "succubus", "witch"]],
	["FSPastoralist", ["cowgirl", "goddess", "hypergoddess", "incubus", "shemale", "succubus", "witch"]],
	["FSPhysicalIdealist", ["amazon", "incubus", "shemale", "succubus", "witch"]],
	["FSHedonisticDecadence", ["goddess", "hypergoddess", "imp", "incubus", "preggololi", "succubus", "witch"]],
	["FSChattelReligionist", ["angel", "cherub", "goddess", "imp", "incubus", "monstergirl", "succubus", "witch"]],
	["FSNull", []],
	["FSRomanRevivalist", ["amazon", "businesswoman", "incubus", "succubus"]],
	["FSNeoImperialist", ["amazon", "businesswoman", "incubus", "shemale", "angel"]],
	["FSEgyptianRevivalist", ["goddess", "incubus", "monstergirl", "succubus"]],
	["FSEdoRevivalist", ["amazon", "incubus", "kitsunegirl", "loli", "monstergirl", "succubus"]],
	["FSArabianRevivalist", ["businesswoman", "incubus", "schoolgirl", "succubus"]],
	["FSChineseRevivalist", ["incubus", "monstergirl", "schoolgirl", "succubus"]],
	["FSAztecRevivalist", ["amazon", "businesswoman", "incubus", "succubus"]],
	["FSAntebellumRevivalist", ["angel", "businesswoman", "goddess", "monstergirl", "succubus", "witch"]],
	["FSRepopulationFocus", ["goddess", "hypergoddess", "preggololi", "pregnant fairy", "succubus", "witch"]],
	["FSRestart", ["angel", "businesswoman", "goddess", "incubus", "loli", "schoolgirl", "succubus", "witch"]],
	["FSIntellectualDependency", ["shemale", "succubus", "witch"]],
	["FSSlaveProfessionalism", ["angel", "businesswoman", "incubus", "goddess", "schoolgirl", "succubus"]],
	["FSPetiteAdmiration", ["cherub", "fairy", "imp", "incubus", "loli", "preggololi", "pregnant fairy", "schoolgirl", "succubus", "witch"]],
	["FSStatuesqueGlorification", ["amazon", "goddess", "incubus", "succubus", "witch"]]
]);

/**
 * @type {Map<assistantAppearance, {readonly requirements: boolean}>}
 */
App.Data.Assistant.appearances = new Map([
	["normal", {get requirements() { return true; }}],
	["monstergirl", {get requirements() { return (V.seeDicks > 0); }}],
	["shemale", {get requirements() { return V.seeDicks > 0; }}],
	["amazon", {get requirements() { return true; }}],
	["businesswoman", {get requirements() { return true; }}],
	["goddess", {get requirements() { return (V.seePreg !== 0); }}],
	["hypergoddess", {get requirements() { return (V.seePreg !== 0 && V.seeHyperPreg !== 0); }}],
	["schoolgirl", {get requirements() { return true; }}],
	["loli", {get requirements() { return (V.minimumSlaveAge < 13); }}],
	["preggololi", {get requirements() { return (V.seePreg !== 0 && V.minimumSlaveAge < 13); }}],
	["fairy", {get requirements() { return true; }}],
	["pregnant fairy", {get requirements() { return (V.seePreg !== 0); }}],

	// Extra
	["slimegirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],
	["cowgirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],
	["harpygirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],
	["kitsunegirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],
	["lamiagirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],
	["spidergirl", {get requirements() { return (V.assistant.Extra1 === 1); }}],

	// Extra 2
	["angel", {get requirements() { return (V.assistant.Extra2 === 1); }}],
	["cherub", {get requirements() { return (V.assistant.Extra2 === 1); }}],
	["incubus", {get requirements() { return (V.assistant.Extra2 === 1 && V.seeDicks > 0); }}],
	["succubus", {get requirements() { return (V.assistant.Extra2 === 1); }}],
	["imp", {get requirements() { return (V.assistant.Extra2 === 1); }}],
	["witch", {get requirements() { return (V.assistant.Extra2 === 1); }}],
	["ERROR_1606_APPEARANCE_FILE_CORRUPT", {get requirements() { return (V.assistant.Extra2 === 1); }}],
]);


code:
/**
 * @typedef {object} itemFS
 * @property {FC.FutureSociety} [unlocks] Automatically unlocked with this FS.
 * @property {Set<FC.FutureSociety>} [loves] FS loves to see this outfit.
 * @property {Set<FC.FutureSociety>} [tolerates] FS tolerates this outfit.
 * @property {Set<FC.FutureSociety>} [hates] FS hates to see this outfit.
 */

/**
 * @typedef {object} clothingDescription
 * @property {function(FC.SlaveState):string} [summary] General description of the outfit, tailored to the slave, but not hyper focused on a body part like boobs or butt.
 * @property {function(FC.SlaveState):string} [upperFace]
 * @property {function(FC.SlaveState):string} [hStyle]
 * @property {function(FC.SlaveState):string} [earPiercing]
 * @property {function(FC.SlaveState):string} [corsetPiercing]
 * @property {function(FC.SlaveState):string} [bellyImplant]
 * @property {function(FC.SlaveState):string} [belly]
 * @property {function(FC.SlaveState):string} [inflation]
 * @property {function(FC.SlaveState):string} [crotch]
 * @property {function(FC.SlaveState):string} [butt]
 * @property {function(FC.SlaveState):string} [buttplug]
 * @property {function(FC.SlaveState):string} [clothingCorset]
 * @property {function(FC.SlaveState):string} [boobs]
 */

/**
 * @typedef {object} clothes
 * @property {string} name
 * @property {0|1|2|3|4} exposure 0: Modest, 1: Acceptable, 2: Slutty, 3: Humiliating (exposes genitals), 4: Might as well be nude
 * @property {itemFS} [fs]
 * @property {boolean} [requirements]
 * @property {boolean} [harsh]
 * @property {boolean} [topless]
 * @property {boolean} [fuckdoll]
 * @property {string} [note]
 * @property {clothingDescription} [desc]
 */

/** @type {Map.<FC.Clothes, clothes>} The string here will be what is applied to the relevant slave property. Slave.clothes = "a bunny outfit", not "Bunny outfit".*/
App.Data.clothes = (new Map())
	.set("a Fuckdoll suit",
		{
			name: "Fuckdoll suit",
			exposure: 3,
			fuckdoll: true
		}
	)
	.set("attractive lingerie for a pregnant woman",
		{
			name: "Maternity lingerie",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSIntellectualDependency", "FSRepopulationFocus"]),
			},
			get requirements() { return V.boughtItem.clothing.maternityLingerie === 1; },
			exposure: 2
		}
	)
	.set("a bunny outfit",
		{
			name: "Bunny outfit",
			fs: {
				unlocks: "FSGenderFundamentalist",
				loves: new Set(["FSGenderFundamentalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.bunny === 1; },
			exposure: 1
		}
	)
	.set("body oil",
		{
			name: "Body oil",
			fs: {
				unlocks: "FSPhysicalIdealist",
				loves: new Set(["FSPhysicalIdealist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.oil === 1; },
			exposure: 4
		}
	)
	.set("a chattel habit",
		{
			name: "Chattel habit",
			fs: {
				unlocks: "FSChattelReligionist",
				loves: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.habit === 1; },
			exposure: 3
		}
	)
	.set("conservative clothing",
		{
			name: "Conservative clothing",
			fs: {
				unlocks: "FSPaternalist",
				loves: new Set(["FSPaternalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.conservative === 1; },
			exposure: 0
		}
	)
	.set("harem gauze",
		{
			name: "Harem gauze",
			fs: {
				unlocks: "FSArabianRevivalist",
				loves: new Set(["FSArabianRevivalist"]),
			},
			get requirements() { return V.boughtItem.clothing.harem === 1; },
			exposure: 1
		}
	)
	.set("a huipil",
		{
			name: "Huipil",
			fs: {
				unlocks: "FSAztecRevivalist",
				loves: new Set(["FSAztecRevivalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.huipil === 1; },
			exposure: 0
		}
	)
	.set("a kimono",
		{
			name: "Kimono",
			fs: {
				unlocks: "FSEdoRevivalist",
				loves: new Set(["FSEdoRevivalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return (V.boughtItem.clothing.kimono === 1 || V.continent === "Japan"); },
			exposure: 0
		}
	)
	.set("a maternity dress",
		{
			name: "Maternity dress",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSRepopulationFocus"]),
			},
			get requirements() { return V.boughtItem.clothing.maternityDress === 1; },
			exposure: 0,
		}
	)
	.set("a slutty qipao",
		{
			name: "Qipao (slutty)",
			fs: {
				unlocks: "FSChineseRevivalist",
				loves: new Set(["FSChineseRevivalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.qipao === 1; },
			exposure: 2
		}
	)
	.set("a long qipao",
		{
			name: "Qipao (long)",
			fs: {
				unlocks: "FSChineseRevivalist",
				loves: new Set(["FSChineseRevivalist"]),
			},
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("Imperial Plate",
		{
			name: "Imperial Plate",
			fs: {
				unlocks: "FSNeoImperialist",
				loves: new Set(["FSNeoImperialist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.imperialarmor === 1; },
			exposure: 0
		}
	)
	.set("a tight Imperial bodysuit",
		{
			name: "Imperial Bodysuit",
			fs: {
				unlocks: "FSNeoImperialist",
				loves: new Set(["FSNeoImperialist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.imperialsuit === 1; },
			exposure: 2
		}
	)
	.set("stretch pants and a crop-top",
		{
			name: "Stretch pants and a crop-top",
			fs: {unlocks: "FSHedonisticDecadence"},
			get requirements() { return V.boughtItem.clothing.lazyClothes === 1; },
			exposure: 0
		}
	)
	.set("a toga",
		{
			name: "Toga",
			fs: {
				unlocks: "FSRomanRevivalist",
				loves: new Set(["FSRomanRevivalist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.toga === 1; },
			exposure: 1
		}
	)
	.set("Western clothing",
		{
			name: "Western clothing",
			fs: {
				unlocks: "FSPastoralist",
				loves: new Set(["FSPastoralist"]),
			},
			get requirements() { return V.boughtItem.clothing.western === 1; },
			exposure: 3
		}
	)
	.set("a courtesan dress",
		{
			name: "Courtesan dress",
			fs: {
				unlocks: "FSSlaveProfessionalism",
				loves: new Set(["FSSlaveProfessionalism"]),
			},
			get requirements() { return V.boughtItem.clothing.courtesan === 1; },
			exposure: 1
		}
	)
	.set("a bimbo outfit",
		{
			name: "Bimbo outfit",
			fs: {
				unlocks: "FSIntellectualDependency",
				loves: new Set(["FSIntellectualDependency"]),
			},
			get requirements() { return V.boughtItem.clothing.bimbo === 1; },
			exposure: 2
		}
	)
	.set("petite admi outfit",
		{
			name: "Petite admi outfit",
			fs: {
				unlocks: "FSPetiteAdmiration",
				loves: new Set(["FSPetiteAdmiration"]),
			},
			get requirements() { return V.boughtItem.clothing.petite === 1; },
			exposure: 0
		}
	)
	.set("battlearmor",
		{
			name: "Battlearmor",
			get requirements() { return V.boughtItem.clothing.military === 1; },
			exposure: 0
		}
	)
	.set("a military uniform",
		{
			name: "Military uniform",
			fs: {
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.military === 1; },
			exposure: 0
		}
	)
	.set("a red army uniform",
		{
			name: "Red Army uniform",
			get requirements() { return V.boughtItem.clothing.military === 1; },
			exposure: 0
		}
	)
	.set("battledress",
		{
			name: "Battledress",
			get requirements() { return V.boughtItem.clothing.military === 1; },
			exposure: 0
		}
	)
	.set("a biyelgee costume",
		{
			name: "Biyelgee costume",
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("a dirndl",
		{
			name: "Dirndl",
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("lederhosen",
		{
			name: "Lederhosen",
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("a mounty outfit",
		{
			name: "Mounty outfit",
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("a hanbok",
		{
			name: "Hanbok",
			get requirements() { return V.boughtItem.clothing.cultural === 1; },
			exposure: 0
		}
	)
	.set("a burqa",
		{
			name: "Burqa",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.middleEastern === 1 || V.continent === "the Middle East"; },
			exposure: 0
		}
	)
	.set("a niqab and abaya",
		{
			name: "Niqab and abaya",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.middleEastern === 1 || V.continent === "the Middle East"; },
			exposure: 0
		}
	)
	.set("a hijab and blouse",
		{
			name: "Hijab and blouse",
			fs: {
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return (V.boughtItem.clothing.conservative === 1 || V.continent === "the Middle East"); },
			exposure: 0
		}
	)
	.set("a burkini",
		{
			name: "Burkini",
			get requirements() { return V.boughtItem.clothing.swimwear === 1 && (V.boughtItem.clothing.swimwear === 1 || V.continent === "the Middle East"); },
			exposure: 1
		}
	)
	.set("a Santa dress",
		{
			name: "Santa dress",
			get requirements() { return V.boughtItem.clothing.costume === 1; },
			exposure: 2
		}
	)
	.set("a klan robe",
		{
			name: "Klan robe",
			get requirements() { return V.boughtItem.clothing.pol === 1; },
			exposure: 0
		}
	)
	.set("a slutty klan robe",
		{
			name: "Slutty klan robe",
			get requirements() { return V.boughtItem.clothing.pol === 1; },
			exposure: 2
		}
	)
	.set("a schutzstaffel uniform",
		{
			name: "Schutzstaffel uniform",
			get requirements() { return V.boughtItem.clothing.pol === 1; },
			exposure: 0
		}
	)
	.set("a slutty schutzstaffel uniform",
		{
			name: "Slutty schutzstaffel uniform",
			get requirements() { return V.boughtItem.clothing.pol === 1; },
			exposure: 2
		}
	)
	.set("nice business attire",
		{
			name: "Nice business attire",
			get requirements() { return V.boughtItem.clothing.career === 1; },
			exposure: 0,
			fs: {
				loves: new Set(["FSMaturityPreferentialist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
		}
	)
	.set("a nice nurse outfit",
		{
			name: "Nurse (nice)",
			fs: {
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.career === 1; },
			exposure: 0
		}
	)
	.set("a police uniform",
		{
			name: "Police uniform",
			get requirements() { return V.boughtItem.clothing.career === 1; },
			exposure: 0
		}
	)
	.set("a nice maid outfit",
		{
			name: "Maid (nice)",
			get requirements() { return V.boughtItem.clothing.career === 1 || V.PC.career === "servant" || V.PC.career === "handmaiden" || V.PC.career === "child servant"; },
			exposure: 0,
			fs: {
				loves: new Set(["FSMaturityPreferentialist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
		}
	)
	.set("a ball gown",
		{
			name: "Ballgown",
			get requirements() { return V.boughtItem.clothing.dresses === 1; },
			exposure: 0,
			fs: {
				loves: new Set(["FSAntebellumRevivalist"])
			}
		}
	)
	.set("a gothic lolita dress",
		{
			name: "Gothic lolita dress",
			get requirements() { return V.boughtItem.clothing.dresses === 1; },
			exposure: 0,
			fs: {
				tolerates: new Set(["FSAntebellumRevivalist"])
			}
		}
	)
	.set("a cybersuit",
		{
			name: "Cybersuit",
			get requirements() { return V.boughtItem.clothing.bodysuits === 1; },
			exposure: 0
		}
	)
	.set("a latex catsuit",
		{
			name: "Latex catsuit",
			get requirements() { return V.boughtItem.clothing.bodysuits === 1; },
			exposure: 1
		}
	)
	.set("a button-up shirt and panties",
		{
			name: "Button-up shirt and panties",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2
		}
	)
	.set("a button-up shirt",
		{
			name: "Button-up shirt",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("cutoffs",
		{
			name: "Cutoffs",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2
		}
	)
	.set("jeans",
		{
			name: "Jeans",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2,
			topless: true
		}
	)
	.set("leather pants and a tube top",
		{
			name: "Leather pants and a tube top",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 1
		}
	)
	.set("leather pants",
		{
			name: "Leather pants",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2,
			topless: true
		}
	)
	.set("an oversized t-shirt",
		{
			name: "Oversized t-shirt",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("a sweater and cutoffs",
		{
			name: "Sweater and cutoffs",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 0
		}
	)
	.set("a sweater and panties",
		{
			name: "Sweater and panties",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2
		}
	)
	.set("a sweater",
		{
			name: "Sweater",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("a t-shirt and jeans",
		{
			name: "T-shirt and jeans",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 0
		}
	)
	.set("a t-shirt and panties",
		{
			name: "T-shirt and panties",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2
		}
	)
	.set("a t-shirt",
		{
			name: "T-shirt",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("a tank-top and panties",
		{
			name: "Tank-top and panties",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 2
		}
	)
	.set("a tank-top",
		{
			name: "Tank-top",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("a tube top",
		{
			name: "Tube top",
			get requirements() { return V.boughtItem.clothing.casual === 1; },
			exposure: 3
		}
	)
	.set("boyshorts",
		{
			name: "Boyshorts",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 2,
			topless: true
		}
	)
	.set("a bra",
		{
			name: "Bra",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 3
		}
	)
	.set("kitty lingerie",
		{
			name: "Kitty lingerie",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 2
		}
	)
	.set("panties and pasties",
		{
			name: "Panties and pasties",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 2
		}
	)
	.set("a skimpy loincloth",
		{
			name: "Skimpy loincloth",
			fs: {
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 3
		}
	)
	.set("a thong",
		{
			name: "Thong",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 3,
			topless: true
		}
	)
	.set("pasties",
		{
			name: "Pasties",
			get requirements() { return V.boughtItem.clothing.underwear === 1; },
			exposure: 3
		}
	)
	.set("leather pants and pasties",
		{
			name: "Leather pants and pasties",
			get requirements() { return V.boughtItem.clothing.underwear === 1 && V.boughtItem.clothing.casual === 1; },
			exposure: 2,
		}
	)
	.set("a t-shirt and thong",
		{
			name: "T-shirt and thong",
			get requirements() { return V.boughtItem.clothing.underwear === 1 && V.boughtItem.clothing.casual === 1; },
			exposure: 3,
		}
	)
	.set("a tube top and thong",
		{
			name: "Tube top and thong",
			get requirements() { return V.boughtItem.clothing.underwear === 1 && V.boughtItem.clothing.casual === 1; },
			exposure: 3,
		}
	)
	.set("an oversized t-shirt and boyshorts",
		{
			name: "Oversized t-shirt and boyshorts",
			get requirements() { return V.boughtItem.clothing.underwear === 1 && V.boughtItem.clothing.casual === 1; },
			exposure: 0,
		}
	)
	.set("sport shorts and a sports bra",
		{
			name: "Sport shorts and a sports bra",
			get requirements() { return V.boughtItem.clothing.sports === 1; },
			exposure: 1,
		}
	)
	.set("sport shorts",
		{
			name: "Sport shorts",
			get requirements() { return V.boughtItem.clothing.sports === 1; },
			exposure: 2,
			topless: true
		}
	)
	.set("a sports bra",
		{
			name: "Sports bra",
			get requirements() { return V.boughtItem.clothing.sports === 1; },
			exposure: 3
		}
	)
	.set("sport shorts and a t-shirt",
		{
			name: "Sport shorts and a t-shirt",
			get requirements() { return V.boughtItem.clothing.sports === 1 && V.boughtItem.clothing.casual === 1; },
			exposure: 0
		}
	)
	.set("a nice pony outfit",
		{
			name: "Pony outfit (nice)",
			get requirements() { return V.boughtItem.clothing.pony === 1; },
			exposure: 1
		}
	)
	.set("a slutty pony outfit",
		{
			name: "Pony outfit (slutty)",
			get requirements() { return V.boughtItem.clothing.pony === 1; },
			exposure: 2
		}
	)
	.set("a monokini",
		{
			name: "Monokini",
			get requirements() { return V.boughtItem.clothing.swimwear === 1; },
			exposure: 3,
			note: "Boob fetishists enjoy."
		}
	)
	.set("a one-piece swimsuit",
		{
			name: "One-piece swimsuit",
			get requirements() { return V.boughtItem.clothing.swimwear === 1; },
			exposure: 1
		}
	)
	.set("a striped bra",
		{
			name: "Striped bra",
			get requirements() { return V.boughtItem.clothing.pantsu === 1 || V.continent === "Japan"; },
			exposure: 3
		}
	)
	.set("striped panties",
		{
			name: "Striped panties",
			get requirements() { return V.boughtItem.clothing.pantsu === 1 || V.continent === "Japan"; },
			exposure: 2,
			topless: true
		}
	)
	.set("striped underwear",
		{
			name: "Striped underwear",
			get requirements() { return V.boughtItem.clothing.pantsu === 1 || V.continent === "Japan"; },
			exposure: 2,
		}
	)
	.set("a confederate army uniform",
		{
			name: "Confederate Army uniform",
			get requirements() { return V.boughtItem.clothing.antebellum === 1; },
			exposure: 0,
			fs: {
				loves: new Set(["FSAntebellumRevivalist"])
			}
		}
	)
	.set("an evening dress",
		{
			name: "Evening dress",
			get requirements() { return V.boughtItem.clothing.antebellum === 1; },
			exposure: 1,
			fs: {
				loves: new Set(["FSAntebellumRevivalist"])
			}
		}
	)

	// Begin NewMisc Outfits --- All outfits are WIP, missing descriptions and are intended to use with AI-Art Generation
	.set("a superhero outfit",
		{
			name: "Superhero outfit",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a cardigan",
		{
			name: "Cardigan",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a streetwear outfit",
		{
			name: "Streetwear outfit",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a country outfit",
		{
			name: "Country girl outfit",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a leather outfit",
		{
			name: "Leather outfit",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a turtleneck and miniskirt",
		{
			name: "Turtleneck outfit",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a sundress",
		{
			name: "Sundress",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("an eastern european outfit",
		{
			name: "Eastern european outfit",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a samba outfit",
		{
			name: "Samba outfit",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a tribal outfit",
		{
			name: "Tribal outfit",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a tropical outfit",
		{
			name: "Tropical outfit",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a valkyrie outfit",
		{
			name: "Valkyrie outfit",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a red priestess outfit",
		{
			name: "Red priestess outfit",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a baroque dress",
		{
			name: "Baroque Dress",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a cocktail dress",
		{
			name: "Cocktail dress",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("an ice queen outfit",
		{
			name: "Ice queen outfit",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a magical girl costume",
		{
			name: "Magical girl costume",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a wedding dress",
		{
			name: "Wedding dress",
			exposure: 1,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("an armored dress",
		{
			name: "Armored dress",
			exposure: 0,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a babydoll",
		{
			name: "Babydoll",
			exposure: 3,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a coat and corset",
		{
			name: "Coat and corset",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	.set("a frilly bikini",
		{
			name: "Frilly bikini",
			exposure: 2,
			get requirements() { return (V.boughtItem.clothing.newmisc === 1); },
		}
	)
	// End NewMisc

	// "Normal" things:
	.set("an apron",
		{
			name: "Apron",
			exposure: 2,
			note: "Increases just devotion for submissives, humiliation fetishists and visibly pregnant pregnancy fetishists regardless of devotion level."
		}
	)
	.set("slutty jewelry",
		{
			name: "Bangles",
			exposure: 3,
			fs: {loves: new Set(["FSEgyptianRevivalist", "FSArabianRevivalist"])}
		}
	)
	.set("clubslut netting",
		{
			name: "Clubslut netting",
			exposure: 3,
			fs: {loves: new Set(["FSBodyPurist", "FSIntellectualDependency"])},
		}
	)
	.set("cutoffs and a t-shirt",
		{
			name: "Cutoffs and a t-shirt",
			exposure: 0
		}
	)
	.set("a comfortable bodysuit",
		{
			name: "Bodysuit",
			exposure: 1,
			fs: {loves: new Set(["FSBodyPurist"])},
		}
	)
	.set("a cheerleader outfit",
		{
			name: "Cheerleader",
			exposure: 2,
			fs: {loves: new Set(["FSGenderFundamentalist", "FSYouthPreferentialist"])},
		}
	)
	.set("a fallen nuns habit",
		{
			name: "Fallen nun",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			exposure: 3
		}
	)
	.set("a hijab and abaya",
		{
			name: "Hijab and abaya",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			exposure: 0
		}
	)
	.set("a leotard",
		{
			name: "Leotard",
			exposure: 1,
			fs: {loves: new Set(["FSBodyPurist"])},
		}
	)
	.set("a slutty maid outfit",
		{
			name: "Maid (slutty)",
			exposure: 2,
			fs: {loves: new Set(["FSSlaveProfessionalism", "FSIntellectualDependency"])},
		}
	)
	.set("a mini dress",
		{
			name: "Mini dress",
			exposure: 2
		}
	)
	.set("attractive lingerie",
		{
			name: "Nice lingerie",
			exposure: 2
		}
	)
	.set("a slutty nurse outfit",
		{
			name: "Nurse (slutty)",
			exposure: 2
		}
	)
	.set("overalls",
		{
			name: "Overalls",
			exposure: 1
		}
	)
	.set("panties",
		{
			name: "Panties",
			exposure: 2,
			topless: true
		}
	)
	.set("a scalemail bikini",
		{
			name: "Scalemail bikini",
			exposure: 2
		}
	)
	.set("a schoolgirl outfit",
		{
			name: "Schoolgirl",
			exposure: 1,
			fs: {loves: new Set(["FSGenderFundamentalist", "FSYouthPreferentialist"])},
		}
	)
	.set("a slutty outfit",
		{
			name: "Slutty outfit",
			exposure: 2,
			fs: {loves: new Set(["FSIntellectualDependency"])},
		}
	)
	.set("spats and a tank top",
		{
			name: "Spats and a tank top",
			exposure: 0
		}
	)
	.set("a string bikini",
		{
			name: "String bikini",
			exposure: 3,
			fs: {loves: new Set(["FSBodyPurist", "FSIntellectualDependency"])},
		}
	)
	.set("a nipple bikini",
		{
			name: "Nipple bikini",
			exposure: 3,
			fs: {loves: new Set(["FSBodyPurist", "FSIntellectualDependency", "FSAssetExpansionist"])},
		}
	)
	.set("a succubus outfit",
		{
			name: "Succubus costume",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			exposure: 3
		}
	)
	.set("slutty business attire",
		{
			name: "Suit (slutty)",
			exposure: 2,
			fs: {
				loves: new Set(["FSMaturityPreferentialist", "FSSlaveProfessionalism"])
			},
		}
	)
	.set("a halter top dress",
		{
			name: "Haltertop dress",
			exposure: 0,
			fs: {loves: new Set(["FSBodyPurist", "FSSlaveProfessionalism"])},
		}
	)
	.set("chains",
		{
			name: "Chains",
			fs: {
				unlocks: "FSDegradationist",
				loves: new Set(["FSDegradationist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			get requirements() { return V.boughtItem.clothing.chains === 1; },
			exposure: 4,
			harsh: true,
			note: "Increases devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism."
		}
	)
	.set("no clothing",
		{
			name: "Naked",
			exposure: 4,
			harsh: true,
			fs: {
				loves: new Set(["FSPhysicalIdealist", "FSIntellectualDependency"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
		}
	)
	.set("a penitent nuns habit",
		{
			name: "Penitent nun",
			fs: {
				loves: new Set(["FSChattelReligionist"]),
			},
			exposure: 0,
			harsh: true,
			note: "Increases devotion and fear but damages health, may cause masochism."
		}
	)
	.set("restrictive latex",
		{
			name: "Restrictive latex",
			fs: {loves: new Set(["FSBodyPurist"])},
			exposure: 3,
			harsh: true,
			note: "Increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives."
		}
	)
	.set("shibari ropes",
		{
			name: "Shibari ropes",
			fs: {
				loves: new Set(["FSDegradationist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			exposure: 4,
			harsh: true,
			note: "Increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives."
		}
	)
	.set("uncomfortable straps",
		{
			name: "Uncomfortable straps",
			exposure: 3,
			harsh: true,
			fs: {
				loves: new Set(["FSDegradationist"]),
				tolerates: new Set(["FSChattelReligionist"]),
			},
			note: "Increases devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism."
		}
	);

/**
 * @typedef {object} slaveWear
 * @property {string} name
 * @property {itemFS} [fs]
 * @property {boolean} [requirements]
 * @property {boolean} [harsh]
 * @property {string} [note]
 */

/**
 * @typedef {Map<string, slaveWear>} slaveWearCategory
 */

/** @type {{[key: string]: slaveWearCategory}} string should be the slave property being modified.*/
App.Data.slaveWear = {
	collar: new Map([
		["stylish leather", {name: "Stylish leather"}],
		["satin choker", {name: "Satin choker"}],
		["silk ribbon", {name: "Silken ribbon"}],
		["heavy gold", {name: "Heavy gold"}],
		["pretty jewelry", {name: "Pretty jewelry"}],
		["nice retirement counter",
			{
				name: "Nice retirement counter",
				get requirements() {
					return V.seeAge === 1;
				}
			}
		],
		["preg biometrics",
			{
				name: "Pregnancy biometrics",
				get requirements() {
					return V.seePreg === 1;
				},
				note: "Increases devotion for those who have pregnancy fetish while fertile or a humiliation fetish. For others obedient ones gain devotion, ambivalent ones gain fear and devotion and resistant ones lose devotion and gain fear."
			}
		],
		["bell collar",
			{
				name: "Bell",
				note: "On non-obedient slaves reduces fear a lot and devotion somewhat."
			},
		],
		["leather with cowbell",
			{
				name: "Cowbell",
				note: "On obedient slaves with boob fetish increases devotion, on disobedient slaves reduces fear a lot and devotion somewhat."
			}
		],
		["bowtie",
			{
				name: "Bowtie collar",
				fs: {
					unlocks: "FSGenderFundamentalist",
					loves: new Set(["FSGenderFundamentalist"]),
				},
				get requirements() {
					return V.boughtItem.clothing.bunny === 1;
				}
			}
		],
		["neck tie",
			{
				name: "Neck tie",
				fs: {
					unlocks: "FSPaternalist",
					loves: new Set(["FSPaternalist"]),
				},
				get requirements() {
					return V.boughtItem.clothing.conservative === 1;
				}
			}
		],
		["ancient Egyptian",
			{
				name: "Ancient Egyptian",
				fs: {
					unlocks: "FSEgyptianRevivalist",
					loves: new Set(["FSEgyptianRevivalist"]),
				},
				get requirements() {
					return V.boughtItem.clothing.egypt === 1;
				}
			}
		],
		["tight steel",
			{
				name: "Tight steel",
				fs: {
					loves: new Set(["FSChattelReligionist"])
				},
				harsh: true
			}
		],
		["cruel retirement counter",
			{
				name: "Cruel retirement counter",
				fs: {
					loves: new Set(["FSChattelReligionist"])
				},
				get requirements() {
					return V.seeAge === 1;
				},
				harsh: true
			}
		],
		["uncomfortable leather",
			{
				name: "Uncomfortable leather",
				fs: {
					loves: new Set(["FSChattelReligionist"])
				},
				harsh: true
			}
		],
		["shock punishment",
			{
				name: "Shock punishment",
				harsh: true,
				note: "For non-obedient slaves increases fear a great deal and reduces devotion, for resistant non-odd slaves it affects both much more a single time and gives the odd flaw."
			}
		],
		["neck corset",
			{
				name: "Neck corset",
				harsh: true
			}
		],
	]),

	faceAccessory: new Map([
		["porcelain mask",
			{
				name: "Porcelain mask",
				note: "Obscures the face, increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one."
			}
		],
		["cat ears",
			{
				name: "Cat ears",
				note: "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one."
			}
		],
	]),

	vaginalAttachment: new Map([
		["none", {name: "None"}],
		["vibrator",
			{
				name: "Vibrating attachment",
				get requirements() {
					return V.boughtItem.toys.vaginalAttachments === 1;
				},
				vibrates: 1
			}
		],
		["smart vibrator",
			{
				name: "Smart vibrating attachment",
				get requirements() {
					return V.boughtItem.toys.smartVaginalAttachments === 1;
				},
				vibrates: 2
			}
		]
	]),

	dickAccessory: new Map([
		["none", {name: "None"}],
		["bullet vibrator",
			{
				name: "Bullet vibrator",
				get requirements() {
					return V.boughtItem.toys.dildos === 1;
				},
				vibrates: 1,
			}
		],
		["smart bullet vibrator",
			{
				name: "Smart bullet vibrator",
				get requirements() {
					return V.boughtItem.toys.smartVibes === 1;
				},
				vibrates: 2,
			}
		]
	]),

	buttplugAttachment: new Map([
		["none", {name: "None"}],
		["tail",
			{
				name: "Tail",
				get requirements() {
					return V.boughtItem.toys.buttPlugTails === 1;
				}
			}
		],
		["fox tail",
			{
				name: "Fox tail",
				get requirements() {
					return V.boughtItem.toys.buttPlugTails === 1;
				}
			}
		],
		["cat tail",
			{
				name: "Cat tail",
				get requirements() {
					return V.boughtItem.toys.buttPlugTails === 1;
				}
			}
		],
		["cow tail",
			{
				name: "Cow tail",
				get requirements() {
					return V.boughtItem.toys.buttPlugTails === 1;
				}
			}
		]
	]),

	armAccessory: new Map([
		// ["none", {name: "None"}],
		["hand gloves", {name: "Hand gloves"}],
		["elbow gloves", {name: "Elbow gloves"}]

	]),

	legAccessory: new Map([
		// ["none", {name: "None"}],
		["short stockings", {name: "Short stockings"}],
		["long stockings", {name: "Long stockings"}]

	]),
};

/**
 * @typedef {object} mouthAccessory
 * @property {string} name
 * @property {boolean} [requirements]
 * @property {string} [note]
 */

/** @type {Map<FC.MouthAccessory, mouthAccessory>} */
App.Data.mouthAccessory = new Map([
	["ball gag",
		{
			name: "Ball gag",
			note: "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one."
		}
	],
	["bit gag",
		{
			name: "Bit gag",
			note: "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one."
		}
	],
	["ring gag",
		{
			name: "Ring gag",
			note: "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one."
		}
	],
	["massive dildo gag",
		{
			name: "Massive dildo gag",
			get requirements() {
				return V.boughtItem.toys.gags === 1;
			},
			note: "Increases oral skill up to a point and causes fear for disobedient slaves."
		}
	],
	["dildo gag",
		{
			name: "Dildo gag",
			note: "Increases oral skill up to a point and causes fear for disobedient slaves."
		}
	],
]);

/**
 * @typedef {object} slaveShoes
 * @property {string} name
 * @property {itemFS} [fs]
 * @property {boolean} [requirements]
 * @property {boolean} [harsh]
 * @property {number} heelHeight height in cm. Over 4cm they may totter. 21cm and over (8 inch heels) will be painful/extreme
 * @property {number} platformHeight height in cm. Adds to heel height.
 */

/**
 * @type {Map<FC.WithNone<FC.Shoes>, slaveShoes>} slaveShoesCategory
 */
App.Data.shoes = new Map([ // TODO: add lift property
	["none",
		{
			name: "Barefoot",
			heelHeight: 0,
			platformHeight: 0
		}
	],
	["flats",
		{
			name: "Flats",
			heelHeight: 0,
			platformHeight: 0
		}
	],
	["pumps",
		{
			name: "Pumps",
			heelHeight: 5, // 2 inch heels
			platformHeight: 0
		}
	],
	["heels",
		{
			name: "Heels",
			heelHeight: 13, // 5 inch heels
			platformHeight: 0
		}
	],
	["boots",
		{
			name: "Thigh boots",
			heelHeight: 13, // 5 inch heels
			platformHeight: 0
		}
	],
	["extreme heels",
		{
			name: "Painfully extreme heels",
			heelHeight: 21, // 8 inch heels
			platformHeight: 0
		}
	],
	["platform shoes",
		{
			name: "Platforms",
			fs: {
				unlocks: "FSStatuesqueGlorification",
				loves: new Set(["FSStatuesqueGlorification"])
			},
			get requirements() {
				return (V.boughtItem.shoes.heels === 1);
			},
			heelHeight: 0,
			platformHeight: 8 // 3 inch platform, no heels
		}
	],
	["platform heels",
		{
			name: "Platform heels",
			fs: {
				unlocks: "FSStatuesqueGlorification",
				loves: new Set(["FSStatuesqueGlorification"])
			},
			get requirements() {
				return (V.boughtItem.shoes.heels === 1);
			},
			heelHeight: 13, // 8 inches, but not painful like extremes (3 inch platforms)
			platformHeight: 8
		}
	],
	["extreme platform heels",
		{
			name: "Painfully extreme platform heels",
			fs: {
				unlocks: "FSStatuesqueGlorification",
				loves: new Set(["FSStatuesqueGlorification"])
			},
			get requirements() {
				return (V.boughtItem.shoes.heels === 1);
			},
			heelHeight: 21, // 12 inches! 8 inch heel, 4 inch platform
			platformHeight: 10
		}
	],
]);

/**
 * @typedef {object} slaveButtplugs
 * @property {string} name
 * @property {itemFS} [fs]
 * @property {boolean} [requirements]
 * @property {0|1|2|3} width
 * @property {0|1|2} length
 */

/**
 * @type {Map<string, slaveButtplugs>}
 */
App.Data.buttplug = new Map([
	["none",
		{
			name: "None",
			width: 0,
			length: 0
		}
	],
	["plug",
		{
			name: "Standard plug",
			width: 1,
			length: 1
		}
	],
	["long plug",
		{
			name: "Long plug",
			get requirements() {
				return V.boughtItem.toys.buttPlugs === 1;
			},
			width: 1,
			length: 2
		}
	],
	["large plug",
		{
			name: "Large plug",
			width: 2,
			length: 1
		}
	],
	["long, large plug",
		{
			name: "Long, large plug",
			get requirements() {
				return V.boughtItem.toys.buttPlugs === 1;
			},
			width: 2,
			length: 2
		}
	],
	["huge plug",
		{
			name: "Huge plug",
			width: 3,
			length: 1
		}
	],
	["long, huge plug",
		{
			name: "Long, huge plug",
			get requirements() {
				return V.boughtItem.toys.buttPlugs === 1;
			},
			width: 3,
			length: 2
		}
	]
]);
/**
 * @typedef {object} vaginalAccessories
 * @property {string} name
 * @property {itemFS} [fs]
 * @property {boolean} [requirements]
 * @property {0|1|2|3} width
 * @property {0|1|2} length
 * @property {0|1|2} [vibrates=0] 0: none, 1: standard, 2: "smart" vibe
 */

/**
 * @type {Map<string, vaginalAccessories>}
 */
App.Data.vaginalAccessory = new Map([
	["none",
		{
			name: "None",
			width: 0,
			length: 0
		}
	],
	["bullet vibrator",
		{
			name: "Bullet vibrator",
			width: 0,
			length: 1,
			vibrates: 1
		}
	],
	["smart bullet vibrator",
		{
			name: "Smart bullet vibrator",
			get requirements() {
				return V.boughtItem.toys.smartVibes === 1;
			},
			width: 0,
			length: 1,
			vibrates: 2
		}
	],
	["dildo",
		{
			name: "Dildo",
			width: 1,
			length: 1
		}
	],
	["long dildo",
		{
			name: "Long dildo",
			get requirements() {
				return V.boughtItem.toys.dildos === 1;
			},
			width: 1,
			length: 2
		}
	],
	["large dildo",
		{
			name: "Large dildo",
			width: 2,
			length: 1
		}
	],
	["long, large dildo",
		{
			name: "Long, large dildo",
			get requirements() {
				return V.boughtItem.toys.dildos === 1;
			},
			width: 2,
			length: 2
		}
	],
	["huge dildo",
		{
			name: "Huge dildo",
			get requirements() {
				return V.boughtItem.toys.dildos === 1;
			},
			width: 3,
			length: 1
		}
	],
	["long, huge dildo",
		{
			name: "Long, huge dildo",
			get requirements() {
				return V.boughtItem.toys.dildos === 1;
			},
			width: 3,
			length: 2
		}
	]
]);

/**
 * @typedef {slaveWear} bellyAccessory
 * @property {1|2|3|4} [empathyBelly]
 */
/** @type {Map<FC.BellyAccessory, bellyAccessory>} */
App.Data.bellyAccessory = new Map([
	["none", {name: "None"}],
	["a corset",
		{
			name: "Tight corset",
			note: "Slowly narrows the waist through femininity into the start of a waspish hourglass."
		}
	],
	["an extreme corset",
		{
			name: "Extreme corset",
			note: "Narrows the waist through waspish into absurd levels, painfully if waist is feminine or wider (increasing obedience and fear in resistant slaves), but risks miscarriage if a pregnant belly becomes too big."
		}
	],
	["a support band",
		{
			name: "Supportive band",
			note: "Eases the pains of pregnancy and reduces chance of miscarriage."
		}
	],
	["a small empathy belly",
		{
			name: "1st Trimester belly",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSRepopulationFocus"])
			},
			get requirements() {
				return V.boughtItem.clothing.belly === 1;
			},
			empathyBelly: 1
		}
	],
	["a medium empathy belly",
		{
			name: "2nd Trimester belly",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSRepopulationFocus"])
			},
			get requirements() {
				return V.boughtItem.clothing.belly === 1;
			},
			empathyBelly: 2
		}
	],
	["a large empathy belly",
		{
			name: "3rd Trimester belly",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSRepopulationFocus"])
			},
			get requirements() {
				return V.boughtItem.clothing.belly === 1;
			},
			empathyBelly: 3
		}
	],
	["a huge empathy belly",
		{
			name: "3rd Trimester twins belly",
			fs: {
				unlocks: "FSRepopulationFocus",
				loves: new Set(["FSRepopulationFocus"])
			},
			get requirements() {
				return V.boughtItem.clothing.belly === 1;
			},
			empathyBelly: 4
		}
	]
]);
/**
 * @typedef {object} slaveWearChastity
 * @property {string} name
 * @property {object} updateSlave
 * @property {string} [note]
 * @property {itemFS} [fs]
 */

/** @type {Map<string, slaveWearChastity>} */
App.Data.chastity = new Map([
	// '.value' must be a string, so using update slave so I can update multiple values.
	["none",
		{
			name: "None",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 0,
				chastityPenis: 0,
				chastityVagina: 0
			},
		}
	],
	["anal chastity",
		{
			name: "Anal chastity",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 1,
				chastityPenis: 0,
				chastityVagina: 0
			},
			note: "Prevents losing anal virginity."
		}
	],
	["chastity belt",
		{
			name: "Chastity belt",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 0,
				chastityPenis: 0,
				chastityVagina: 1
			},
			note: "Prevents losing virginity, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected."
		}
	],
	["combined chastity belt",
		{
			name: "Combined chastity belt",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 1,
				chastityPenis: 0,
				chastityVagina: 1
			},
			note: "Prevents losing virginities, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected."
		}
	],
	["chastity cage",
		{
			name: "Chastity cage",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 0,
				chastityPenis: 1,
				chastityVagina: 0
			},
			note: "Prevents using penis, has various effects, devotion, trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls."
		}
	],
	["combined chastity cage",
		{
			name: "Combined chastity cage",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 1,
				chastityPenis: 1,
				chastityVagina: 0
			},
			note: "Protects both penis and anus from sex, has various effects, devotion and trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls."
		}
	],
	["genital chastity",
		{
			name: "Genital chastity",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 0,
				chastityPenis: 1,
				chastityVagina: 1
			},
			note: "Protects both penis and vagina from sex, has various effects."
		}
	],
	["full chastity",
		{
			name: "Full chastity",
			updateSlave: {
				choosesOwnChastity: 0,
				chastityAnus: 1,
				chastityPenis: 1,
				chastityVagina: 1
			},
			note: "Protects penis, vagina and anus, has various effects."
		}
	],
	["choose own chastity",
		{
			name: "Choose own chastity",
			fs: {unlocks: "FSRestart"},
			updateSlave: {
				choosesOwnChastity: 1
			},
		}
	],
	["revoke choosing own chastity",
		{
			name: "Revoke choosing own chastity",
			fs: {unlocks: "FSRestart"},
			updateSlave: {
				choosesOwnChastity: 0
			},
		}
	]
]);


code:
App.Data.clothes.set("a slave gown",
	{
		name: "Slave gown",
		exposure: 0,
		fs: {loves: new Set(["FSBodyPurist"])},
		desc: {
			summary: function(slave) {
				const r = [];
				const {He, he, his} = getPronouns(slave);
				const bothFeet = hasBothLegs(slave);
				const feet = bothFeet ? "feet" : "foot";

				r.push(`a gorgeous affair`);
				if (isAmputee(slave)) {
					r.push(`tailored to favor ${his} lack of arms and legs.`);
				} else if (!hasAnyLegs(slave)) {
					r.push(`with cuts that offer tantalizing glimpses of delicate flesh.`);
				} else {
					r.push(`with cuts that offer tantalizing glimpses of delicate flesh.`);
					r.push(`${He} completes the look with`);
					switch (slave.shoes) {
						case "flats":
							if (bothFeet) {
								r.push(`a pair of fashionable slingback sandals.`);
							} else {
								r.push(`a fashionable slingback sandal.`);
							}
							break;
						case "boots":
							if (bothFeet) {
								r.push(`elegant worked leather boots.`);
							} else {
								r.push(`an elegant worked leather boot.`);
							}
							break;
						case "heels":
							if (bothFeet) {
								r.push(`kitten heels.`);
							} else {
								r.push(`a kitten heel.`);
							}
							break;
						case "pumps":
							if (bothFeet) {
								r.push(`sleek pumps.`);
							} else {
								r.push(`a sleek heel.`);
							}
							break;
						case "extreme heels":
							if (bothFeet) {
								r.push(`daring spike heels so high ${his} butt is at dick height.`);
							} else {
								r.push(`a daring spike heel so high ${he} can't even stand.`);
							}
							break;
						case "platform shoes":
							if (bothFeet) {
								r.push(`stylish platform shoes.`);
							} else {
								r.push(`a stylish platform shoe.`);
							}
							break;
						case "platform heels":
							if (bothFeet) {
								r.push(`elegant platform heels.`);
							} else {
								r.push(`an elegant platform heel.`);
							}
							break;
						case "extreme platform heels":
							if (bothFeet) {
								r.push(`elegant platform heels so high ${his} butt is at dick height.`);
							} else {
								r.push(`an elegant platform heel so high ${he} can't stand even with assistance.`);
							}
							break;
						default:
							r.push(`nothing on ${his} bare ${feet}.`);
					}
				}
				return r.join(" ");
			},
			upperFace: function(slave) {
				return `nice frameless glasses,`;
			},
			hStyle: function(slave) {
				const r = [];
				const {
					he, his
				} = getPronouns(slave);

				if (slave.fuckdoll === 0) {
					switch (slave.hStyle) {
						case "neat":
							if (slave.hLength > 100) {
								r.push(`cascades gorgeously down ${his} bare back.`);
							} else if (slave.hLength > 30) {
								r.push(`flows fashionably down ${his} bare back.`);
							} else if (slave.hLength > 10) {
								r.push(`follows the latest fashion.`);
							} else {
								r.push(`is gelled into a fashionable wave.`);
							}
							break;
						case "up":
							if (slave.hLength > 100) {
								r.push(`is piled up on ${his} head in a perfect 60's beehive.`);
							} else if (slave.hLength > 30) {
								r.push(`is piled up on ${his} head in a perfect 60's beehive.`);
							} else if (slave.hLength > 10) {
								r.push(`is piled up on ${his} head in a perfect 60's 'do.`);
							} else {
								r.push(`is combed back.`);
							}
							break;
						case "tails":
							if (slave.hLength > 100) {
								r.push(`is combed into beautiful long tails, one of which comes around to run down ${his} chest.`);
							} else if (slave.hLength > 30) {
								r.push(`is combed into beautiful tails, one of which comes around to fall between ${his} breasts.`);
							} else if (slave.hLength > 10) {
								r.push(`is combed into short tails set low at the nape of ${his} neck.`);
							} else {
								r.push(`is too short to be kept in proper tails, so it's simply combed back.`);
							}
							break;
						case "ponytail":
							if (slave.hLength > 100) {
								r.push(`is combed into a beautiful long ponytail, which swooshes as ${he} moves.`);
							} else if (slave.hLength > 30) {
								r.push(`is combed into a beautiful ponytail, which swooshes as ${he} moves.`);
							} else if (slave.hLength > 10) {
								r.push(`is combed into a short ponytail set low at the nape of ${his} neck.`);
							} else {
								r.push(`is too short to be kept in a proper ponytail, so it's simply combed back.`);
							}
							break;
						case "braided":
							if (slave.hLength > 100) {
								r.push(`is combed into beautiful long braids, one of which comes around to run down ${his} chest.`);
							} else if (slave.hLength > 30) {
								r.push(`is in beautiful braids, one of which comes around to fall between ${his} breasts.`);
							} else if (slave.hLength > 10) {
								r.push(`is combed into short braids set low at the nape of ${his} neck.`);
							} else {
								r.push(`is too short to be kept in proper braids, so it's simply combed back.`);
							}
							break;
						case "dreadlocks":
							if (slave.hLength > 100) {
								r.push(`is in dreadlocks, spreading out in many directions and almost reaching the ground.`);
							} else if (slave.hLength > 30) {
								r.push(`is in dreadlocks, spreading out in many directions.`);
							} else if (slave.hLength > 10) {
								r.push(`is in short dreadlocks, spreading around ${his} head.`);
							} else {
								r.push(`is too short to be kept in proper dreadlocks, so it's simply combed back.`);
							}
							break;
						case "curled":
							if (slave.hLength > 100) {
								r.push(`is curled into long flowing locks, almost reaching the ground.`);
							} else if (slave.hLength > 30) {
								r.push(`is curled into long locks, reaching past ${his} shoulders.`);
							} else if (slave.hLength > 10) {
								r.push(`is curled into short locks.`);
							} else {
								r.push(`is in short curls.`);
							}
							break;
						case "permed":
							if (slave.hLength > 100) {
								r.push(`is permed into long flowing curls, almost reaching the ground.`);
							} else if (slave.hLength > 30) {
								r.push(`is permed, reaching past ${his} shoulders.`);
							} else if (slave.hLength > 10) {
								r.push(`is permed into short waves.`);
							} else {
								r.push(`is permed into short curls.`);
							}
							break;
						case "luxurious":
							if (slave.hLength > 100) {
								r.push(`is in luxurious layered locks flowing gorgeously down ${his} bare back.`);
							} else if (slave.hLength > 30) {
								r.push(`is in luxurious layered locks flowing gorgeously down ${his} bare back.`);
							} else if (slave.hLength > 10) {
								r.push(`is in luxuriously styled short locks.`);
							} else {
								r.push(`is in luxuriously styled short locks.`);
							}
							break;
						case "strip":
							if (slave.hLength > 100) {
								r.push(`is shaved into a strip atop ${his} head that cascades magnificently down ${his} back.`);
							} else if (slave.hLength > 30) {
								r.push(`is shaved into a long braided strip.`);
							} else if (slave.hLength > 10) {
								r.push(`is shaved into a strip.`);
							} else {
								r.push(`is shaved into a mohawk.`);
							}
							break;
						case "undercut":
							if (slave.hLength > 100) {
								r.push(`is shaved on one side into a long undercut that falls well past ${his} breasts.`);
							} else if (slave.hLength > 30) {
								r.push(`is shaved to one side, the other half falling down to ${his} neck.`);
							} else if (slave.hLength > 10) {
								r.push(`is shaved to one side, the other half falling just over one eye.`);
							} else {
								r.push(`is shaved to one side in a pixie-like undercut.`);
							}
							break;
						case "bangs":
							if (slave.hLength > 100) {
								r.push(`is cut straight across ${his} face, hiding ${his} eyes.`);
							} else if (slave.hLength > 30) {
								r.push(`is cut straight across ${his} face, partially hiding ${his} eyes.`);
							} else if (slave.hLength > 10) {
								r.push(`is cut straight above ${his} eyebrows.`);
							} else {
								r.push(`is cut straight across ${his} forehead.`);
							}
							break;
						case "hime":
							if (slave.hLength > 100) {
								r.push(`cascades down ${his} bare back in a hime cut with shoulder-length side-locks.`);
							} else if (slave.hLength > 30) {
								r.push(`flows down ${his} bare back in a hime cut with cheek-length side-locks.`);
							} else if (slave.hLength > 10) {
								r.push(`is styled into a hime cut with cheek-length side-locks.`);
							} else {
								r.push(`is styled into a hime cut with cheek-length side-locks.`);
							}
							break;
						case "drills":
							if (slave.hLength > 100) {
								r.push(`is wound into enormous, exquisite coils that come to rest across ${his} chest.`);
							} else if (slave.hLength > 30) {
								r.push(`is wound into large coils which rest atop ${his} breasts.`);
							} else if (slave.hLength > 10) {
								r.push(`is in a pair of short coils.`);
							} else {
								r.push(`is too short to be kept in proper tails, so it's simply combed back.`);
							}
							break;
						case "crown braid":
							if (slave.hLength >= 100) {
								r.push(`is partly braided into a grand-looking crown braid that circles ${his} head, while the rest of it flows down to ${his} calves.`);
							} else if (slave.hLength >= 30) {
								r.push(`is partly braided into a elegant-looking crown braid that circles ${his} head, while the rest of it flows down to ${his} shoulders.`);
							} else if (slave.hLength >= 10) {
								r.push(`is braided into a small crown braid that circles ${his} head.`);
							} else {
								r.push(`is too short to be kept in a crown braid so it's simply combed back.`);
							}
							break;
						case "dutch braid":
							if (slave.hLength >= 100) {
								r.push(`is braided into a single dutch braid that reaches down to ${his} calves.`);
							} else if (slave.hLength >= 30) {
								r.push(`is braided into a single dutch braid that reaches down to below ${his} shoulders.`);
							} else if (slave.hLength >= 10) {
								r.push(`is braided into a single dutch braid that reaches down to just below ${his} neck.`);
							} else {
								r.push(`is too short to be kept in a dutch braid so it's simply combed back.`);
							}
							break;
						case "double dutch braid":
							if (slave.hLength >= 100) {
								r.push(`is braided into two dutch braids that reach down to ${his} calves.`);
							} else if (slave.hLength >= 30) {
								r.push(`is braided into two dutch braids that reach down to below ${his} shoulders.`);
							} else if (slave.hLength >= 10) {
								r.push(`is braided into two dutch braids that reach down to just below ${his} neck.`);
							} else {
								r.push(`is too short to be kept in dutch braids so it's simply combed back.`);
							}
							break;
						case "bald":
							r.push(`is completely bald.`);
					}
				}
				return r.join(" ");
			},
			earPiercing: function(slave) {
				const {He} = getPronouns(slave);
				return `${He}'s wearing lovely diamond earrings; the stones are cut in an alluring, feminine style.`;
			},
			corsetPiercing: function(slave) {
				const {his} = getPronouns(slave);
				return `they're revealed by the swooping back of ${his} gown and laced up with matching silk ribbon.`;
			},
			clothingCorset: function(slave) {
				const r =[];
				const {His, his} = getPronouns(slave);
				if (slave.bellyAccessory === "a corset") {
					r.push(`${His} gown has an elegant integral corset.`);
				} else if (slave.bellyAccessory === "an extreme corset") {
					r.push(`${His} gown has extreme corsetage built into it.`);
				} else if (slave.bellyAccessory === "a support band") {
					r.push(`${His} support band is concealed by ${his} gown.`);
				}
				return r.join(" ");
			},
			boobs: function(slave) {
				const r = [];
				const {his} = getPronouns(slave);
				const noun = App.Desc.boobBits.noun(slave.boobs, false, false);
				const adjNoun = App.Desc.boobBits.noun(slave.boobs, false, true);
				r.push(`${slave.slaveName}'s slave gown`);
				if (slave.boobs > 12000) {
					r.push(`is no longer able to cover ${his} ${adjNoun}. Instead, it has been redesigned to draw the eye to them.`);
				} else if (slave.boobs > 4000) {
					r.push(`is carefully engineered and is somehow able to cover the enormous mass of ${his} breasts.`);
				} else if (slave.boobs > 800) {
					r.push(`is carefully tailored, tastefully covering yet enhancing ${his} ${adjNoun}.`);
				} else if (slave.boobs < 300) {
					r.push(`is carefully tailored to closely hug ${his} flat chest.`);
				} else {
					r.push(`subtly accentuates ${his} ${noun}.`);
				}
				return r.join(" ");
			},
			belly: function(slave) {
				const r = [];
				const {his, him} = getPronouns(slave);
				const isBellyFluidLargest = (slave.bellyFluid >= slave.bellyPreg && slave.bellyFluid >= slave.bellyImplant);

				if (slave.belly >= 1000000) {
					if (isBellyFluidLargest) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material. When not worn, it looks more like a circus tent than something meant to be worn by a human being. On the slave, it gives ${him} a sensual, motherly look as it caresses ${his} unfathomable, hyper-swollen, ${slave.inflationType}-filled belly.`);
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material, and gives ${him} a sensual, motherly look as it caresses ${his} unfathomable, hyper-swollen, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material, and gives ${him} a sensual, motherly look as it caresses and supports ${his} unfathomable, hyper-swollen pregnant belly. Despite its size, it still has enough give to allow ${his} unborn children to bulge and squirm as desired.`);
					}
				} else if (slave.belly >= 750000) {
					if (isBellyFluidLargest) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material. When not worn, it looks more like a couch cover than something meant to be worn by a human being. On ${him}, it gives ${him} a sensual, motherly look as it carefully caresses ${his} monolithic, ${slave.inflationType}-filled belly.`);
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material, and gives ${him} a sensual, motherly look as it carefully caresses ${his} monolithic, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored using a huge quantity of material, and gives ${him} a sensual, motherly look as it carefully caresses and supports ${his} monolithic pregnant belly. It has enough give to allow ${his} unborn children to bulge and squirm as desired.`);
					}
				} else if (slave.belly >= 600000) {
					if (isBellyFluidLargest) {
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} titanic, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses and supports ${his} titanic bulging pregnant belly.`);
					}
				} else if (slave.belly >= 450000) {
					if (isBellyFluidLargest) {
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} gigantic, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses and supports ${his} gigantic pregnant belly.`);
					}
				} else if (slave.belly >= 300000) {
					if (isBellyFluidLargest) {
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} massive, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses and supports ${his} massive pregnant belly.`);
					}
				} else if (slave.belly >= 120000) {
					if (isBellyFluidLargest) {
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} giant, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses and supports ${his} giant pregnant belly.`);
					}
				} else if (slave.weight > 190) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging every curve and fold of ${his} massively fat belly. Every motion in ${his} impressive gut is elegantly embraced by ${his} gown.`);
				} else if (slave.belly >= 15000 || (slave.bellyAccessory === "a huge empathy belly")) {
					if (slave.bellyAccessory === "a huge empathy belly") {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} huge pregnant belly.`);
					} else if (isBellyFluidLargest) {
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} huge, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} huge pregnant belly.`);
					}
				} else if (slave.belly >= 10000 || (slave.bellyAccessory === "a large empathy belly")) {
					if (slave.bellyAccessory === "a large empathy belly") {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} big pregnant belly.`);
					} else if (isBellyFluidLargest) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, almost motherly look, as it carefully caresses ${his} hugely swollen belly.`);
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} big, implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} big pregnant belly.`);
					}
				} else if (slave.weight > 160) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging every curve and fold of ${his} hugely fat belly.`);
				} else if (slave.weight > 130) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging every curve and fold of ${his} big fat belly.`);
				} else if (slave.belly >= 5000 || (slave.bellyAccessory === "a medium empathy belly")) {
					if (slave.bellyAccessory === "a medium empathy belly") {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} pregnant belly.`);
					} else if (isBellyFluidLargest) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} jiggling ${slave.inflationType}-filled belly.`);
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} implant-filled belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} pregnant belly.`);
					}
				} else if (slave.weight > 95) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging every curve of ${his} fat belly.`);
				} else if (slave.belly >= 1500 || slave.bellyAccessory === "a small empathy belly") {
					if (slave.bellyAccessory === "a small empathy belly") {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual, motherly look as it carefully caresses ${his} small belly.`);
					} else if (isBellyFluidLargest) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual look as it carefully caresses ${his} ${slave.inflationType}-swollen belly.`);
					} else if (slave.bellyImplant > 0) {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual look as it carefully caresses ${his} implant-rounded belly.`);
					} else {
						r.push(`${slave.slaveName}'s slave gown is carefully tailored, giving ${him} a sensual look as it carefully caresses ${his} growing belly.`);
					}
				} else if (slave.weight > 30) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging every curve of ${his} chubby belly.`);
				} else if (slave.bellyPreg >= 100 || slave.bellyImplant >= 100) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging even the slight bulge to ${his} lower belly.`);
				} else if (slave.muscles > 30) {
					r.push(`${slave.slaveName}'s slave gown is carefully tailored, accentuating and hugging ${his} ripped abs.`);
				}
				return r.join(" ");
			},
			crotch: function(slave) {
				const r = [];
				const {his} = getPronouns(slave);
				r.push(`${slave.slaveName}'s`);
				if (slave.dick > 6) {
					r.push(`lovely gown cannot hide the fact that something massive is lurking`);
					if (hasBothLegs(slave)) {
						r.push(`between ${his} legs.`);
					} else {
						r.push(`underneath it.`);
					}
				} else if (slave.dick > 3) {
					r.push(`cock tents the front of ${his} lovely gown.`);
				} else if (slave.dick > 0 && slave.vagina > -1) {
					r.push(`hermaphroditic genitalia are hidden by ${his} lovely gown.`);
				} else if (slave.dick > 0) {
					r.push(`cock is hidden by ${his} lovely gown.`);
				} else if (slave.vagina === -1) {
					r.push(`featureless groin is concealed by ${his} lovely gown.`);
				} else {
					r.push(`pussy is concealed by ${his} lovely gown.`);
				}
				return r.join(" ");
			},
			butt: function(slave) {
				const r = [];
				const {His, his} = getPronouns(slave);
				r.push(`${His} slave gown`);
				if (slave.butt > 10) {
					r.push(`is tailored as tastefully as possible for ${his} inhuman`);
				} else if (slave.butt > 6) {
					r.push(`is tailored as tastefully as possible for ${his} massive`);
				} else if (slave.butt > 3) {
					r.push(`is tailored to flatter ${his} big`);
				} else {
					r.push(`tastefully clings to ${his}`);
				}
				r.push(`buttocks.`);
				return r.join(" ");
			},
			buttplug: function(slave) {
				const r = [];
				const {His, his} = getPronouns(slave);
				if (slave.chastityAnus) {
					r.push(`${His} pretty gown hides ${his} anal chastity accessory underneath.`);
				} else {
					r.push(`Though ${his} gown is very pretty, ${his} asshole is bare beneath it.`);
				}
				return r.join(" ");
			},
		}
	}
);