Source: ClothesManager.js

/**
 * @typedef {object} ClothesManager.clothesConfig
 * @property {string} ID - ID of the clothes
 * @property {string} [Face="Neutral"] - Face texture that will be used when the girl equips the clothes
 * @property {string} [Body="Default"] - Body texture that will be used when the girl equips the clothes
 * @property {boolean} Visible - Is this item visible at the beginning of the game
 * @property {boolean} Unlocked - Is this item unlocked at the beginning of the game
 * @property {string} Girl - The ID of the girl whose clothes these are for
 * @property {string} Name - Name of the clothes
 * @property {string} Description - Description of the clothes
 * @property {number} Level - The total level required to wear these clothes
 * @property {string} Shop - What shop the clothes should be available at. If they are not buyable just put "Quest"
 * @property {number} Cost - How much the clothes cost to buy
 * @property {object} Stats - The bonus given from wearing these clothes
 * @property {number} Stats.Recovery - The amount of stamina a girl recovers in a boss battle
 * @property {number} Stats.Stamina - The amount of extra stamina a girl will have with this item
 * @property {number} Stats.Hands - The girl's hands level increased by
 * @property {number} Stats.Feet - The girl's feet level increased by
 * @property {number} Stats.Throat - The girl's throat level increased by
 * @property {number} Stats.Tits - The girl's tits level increased by
 * @property {number} Stats.Pussy - The girl's pussy level increased by
 * @property {number} Stats.Anal - The girl's anal level increased by
 */

/**
 * @typedef {object} ClothesManager.dyeConfig
 * @property {string} clothesID - ID of clothes this dye is for
 * @property {string} dyeID - ID of dye
 * @property {function} condition - Function that is called to check if this dye is available to use, should return a boolean
 */

/**
 * @class ClothesManager
 */
class ClothesManager {
    constructor() {
        this._clothes = {};
        this._dyes = {};
    }

    _initClothes() {
        // Queen
        this.newDye('DefaultQueen', 'AlphaBlack', function () {
            return GAME.quest.isComplete('QueenAlphaBlack', 'Start');
        });
        this.newDye([{clothesID: "DefaultQueen", dyeID: "Blue"},
            {clothesID: "DefaultQueen", dyeID: "Green"},
            {clothesID: "DefaultQueen", dyeID: "Grey"},
            {clothesID: "DefaultQueen", dyeID: "Pink"},
            {clothesID: "DefaultQueen", dyeID: "Purple"},
            {clothesID: "DefaultQueen", dyeID: "Teal"},
            {clothesID: "DefaultQueen", dyeID: "Yellow"}]);
        this.newDye([{clothesID: "SchoolgirlQueen", dyeID: "Yellow"},
            {clothesID: "SchoolgirlQueen", dyeID: "Green"},
            {clothesID: "SchoolgirlQueen", dyeID: "Pink"},
            {clothesID: "SchoolgirlQueen", dyeID: "Purple"},
            {clothesID: "SchoolgirlQueen", dyeID: "Red"},
            {clothesID: "SchoolgirlQueen", dyeID: "Teal"},
            {clothesID: "SchoolgirlQueen", dyeID: "Grey"}]);
        this.newDye([{clothesID: "ForestQueen", dyeID: "Blue"},
            {clothesID: "ForestQueen", dyeID: "Pink"},
            {clothesID: "ForestQueen", dyeID: "Purple"},
            {clothesID: "ForestQueen", dyeID: "Red"},
            {clothesID: "ForestQueen", dyeID: "Teal"},
            {clothesID: "ForestQueen", dyeID: "Yellow"},
            {clothesID: "ForestQueen", dyeID: "Grey"}]);
        this.newDye("DefaultEsxea", "Blue");
        this.newDye("DefaultEsxea", "Green");
        this.newDye("DefaultEsxea", "Pink");
        this.newDye("DefaultEsxea", "Purple");
        this.newDye("DefaultEsxea", "Yellow");
        this.newDye("DefaultScarlett", "Green");
        this.newDye("DefaultScarlett", "Pink");
        this.newDye("DefaultScarlett", "Purple");
        this.newDye("DefaultScarlett", "Teal");
        this.newDye("DefaultScarlett", "Yellow");
        this.newDye("DefaultSuki", "Green");
        this.newDye("DefaultSuki", "Pink");
        this.newDye("DefaultSuki", "Purple");
        this.newDye("DefaultSuki", "Teal");
        this.newDye("DefaultSuki", "Yellow");
        this.newDye("ForestEsxea", "Blue");
        this.newDye("ForestEsxea", "Purple");
        this.newDye("ForestEsxea", "Teal");
        this.newDye("ForestEsxea", "Yellow");
        this.newDye("ForestScarlett", "Pink");
        this.newDye("ForestScarlett", "Purple");
        this.newDye("ForestScarlett", "Teal");
        this.newDye("ForestScarlett", "Yellow");
        this.newDye("ForestSuki", "Pink");
        this.newDye("ForestSuki", "Purple");
        this.newDye("ForestSuki", "Teal");
        this.newDye("ForestSuki", "Yellow");
        this.newDye("LeotardSuki", "Green");
        this.newDye("LeotardSuki", "Purple");
        this.newDye("LeotardSuki", "Teal");
        this.newDye("LeotardSuki", "Yellow");
        this.newDye("MudEsxea", "Blue");
        this.newDye("MudEsxea", "Green");
        this.newDye("MudEsxea", "Pink");
        this.newDye("MudEsxea", "Purple");
        this.newDye("MudEsxea", "Yellow");
        this.newDye("MudQueen", "Blue");
        this.newDye("MudQueen", "Green");
        this.newDye("MudQueen", "Grey");
        this.newDye("MudQueen", "Pink");
        this.newDye("MudQueen", "Purple");
        this.newDye("MudQueen", "Teal");
        this.newDye("MudScarlett", "Blue");
        this.newDye("MudScarlett", "Green");
        this.newDye("MudScarlett", "Pink");
        this.newDye("MudScarlett", "Purple");
        this.newDye("MudScarlett", "Yellow");
        this.newDye("MudSuki", "Blue");
        this.newDye("MudSuki", "Green");
        this.newDye("MudSuki", "Pink");
        this.newDye("MudSuki", "Purple");
        this.newDye("MudSuki", "Yellow");
        this.newDye("PrincessEsxea", "Green");
        this.newDye("PrincessEsxea", "Pink");
        this.newDye("PrincessEsxea", "Purple");
        this.newDye("PrincessEsxea", "Teal");
        this.newDye("PrincessEsxea", "Yellow");
        this.newDye("PrincessQueen", "Green");
        this.newDye("PrincessQueen", "Pink");
        this.newDye("PrincessQueen", "Purple");
        this.newDye("PrincessQueen", "Teal");
        this.newDye("PrincessQueen", "Yellow");
        this.newDye("PrincessScarlett", "Green");
        this.newDye("PrincessScarlett", "Pink");
        this.newDye("PrincessScarlett", "Purple");
        this.newDye("PrincessScarlett", "Teal");
        this.newDye("PrincessScarlett", "Yellow");
        this.newDye("PrincessSuki", "Green");
        this.newDye("PrincessSuki", "Pink");
        this.newDye("PrincessSuki", "Purple");
        this.newDye("PrincessSuki", "Teal");
        this.newDye("PrincessSuki", "Yellow");

        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "PrincessQueen",
            "Girl": "Queen",
            "Name": "Princess Outfit",
            "Level": 90,
            "Shop": false,
            "Description": "A dress a princess would wear, maybe not in front of her parents.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Tits": 3,
                "Pussy": 2
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "MudQueen",
            "Girl": "Queen",
            "Name": "Mud Outfit",
            "Level": 65,
            "Shop": false,
            "Description": "Not really clothes, just mud slathered onto her body.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Feet": 1,
                "Throat": 1,
                "Tits": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "ForestQueen",
            "Girl": "Queen",
            "Name": "Greenhaven Outfit",
            "Level": 26,
            "Shop": false,
            "Description": "Average clothing of Greenhaven. The women of Greenhaven don't seem to wear much clothing.",
            "Cost": 0,
            "Stats": {
                "Recovery": 0.2,
                "Throat": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": false,
            "ID": "SchoolgirlQueen",
            "Girl": "Queen",
            "Name": "Schoolgirl Outfit",
            "Level": 10,
            "Shop": true,
            "Description": "A female uniform for school.",
            "Cost": 1000,
            "Stats": {
                "Pussy": 3
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": true,
            ID: "DefaultQueen",
            Girl: "Queen",
            Level: 0,
            Stats: {}
        });

        // Suki
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "PrincessSuki",
            "Girl": "Suki",
            "Name": "Princess Outfit",
            "Level": 90,
            "Shop": false,
            "Description": "A dress a princess would wear, maybe not in front of her parents.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Tits": 3,
                "Pussy": 2
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "MudSuki",
            "Girl": "Suki",
            "Name": "Mud Outfit",
            "Level": 65,
            "Shop": false,
            "Description": "Not really clothes, just mud slathered onto her body.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Feet": 1,
                "Throat": 1,
                "Tits": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "ForestSuki",
            "Girl": "Suki",
            "Name": "Greenhaven Outfit",
            "Level": 30,
            "Shop": false,
            "Description": "Clothing of Greenhaven",
            "Cost": 0,
            "Stats": {
                "Recovery": 0.2,
                "Throat": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "LeotardSuki",
            "Girl": "Suki",
            "Name": "Leotard",
            "Level": 30,
            "Shop": true,
            "Description": "Made for ballerinas, tears easily.",
            "Cost": 3000,
            "Stats": {
                "Feet": 3,
                "Hands": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": true,
            "ID": "DefaultSuki",
            "Girl": "Suki",
            "Level": 0,
            "Stats": {
                "Pussy": 3
            }
        });

        // Esxea
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "PrincessEsxea",
            "Girl": "Esxea",
            "Name": "Princess Outfit",
            "Level": 90,
            "Shop": false,
            "Description": "A dress a princess would wear, maybe not in front of her parents.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Tits": 3,
                "Pussy": 2
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "MudEsxea",
            "Girl": "Esxea",
            "Name": "Mud Outfit",
            "Level": 65,
            "Shop": false,
            "Description": "Not really clothes, just mud slathered onto her body.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Feet": 1,
                "Throat": 1,
                "Tits": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "ForestEsxea",
            "Girl": "Esxea",
            "Name": "Greenhaven Outfit",
            "Level": 30,
            "Shop": false,
            "Description": "Clothing of Greenhaven",
            "Cost": 0,
            "Stats": {
                "Recovery": 0.2,
                "Throat": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": true,
            "ID": "DefaultEsxea",
            "Girl": "Esxea",
            "Level": 0,
            "Stats": {
                "Feet": 2
            }
        });

        // Scarlett
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "PrincessScarlett",
            "Girl": "Scarlett",
            "Name": "Princess Outfit",
            "Level": 90,
            "Shop": false,
            "Description": "A dress a princess would wear, maybe not in front of her parents.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Tits": 3,
                "Pussy": 2
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "MudScarlett",
            "Girl": "Scarlett",
            "Name": "Mud Outfit",
            "Level": 65,
            "Shop": false,
            "Description": "Not really clothes, just mud slathered onto her body.",
            "Cost": 0,
            "Stats": {
                "Hands": 1,
                "Feet": 1,
                "Throat": 1,
                "Tits": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": false,
            "Unlocked": false,
            "ID": "ForestScarlett",
            "Girl": "Scarlett",
            "Name": "Greenhaven Outfit",
            "Level": 30,
            "Shop": false,
            "Description": "Average clothing of Greenhaven. The women of Greenhaven don't seem to wear much clothing.",
            "Cost": 0,
            "Stats": {
                "Recovery": 0.2,
                "Throat": 1,
                "Pussy": 1
            }
        });
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": true,
            "ID": "DefaultScarlett",
            "Girl": "Scarlett",
            "Level": 0,
            "Stats": {
                "Tits": 3
            }
        });

        // Ardura
        this.newClothes({
            "Body": "Default",
            "Face": "Neutral",
            "Visible": true,
            "Unlocked": true,
            "ID": "DefaultArdura",
            "Girl": "Ardura",
            "Level": 0,
            "Stats": {
                "Anal": 1
            }
        });
    }

    /**
     * Returns an object of all the clothes
     * @method getAllClothes
     * @memberOf ClothesManager
     * @instance
     * @returns {Object}
     * */
    getAllClothes() {
        return this._clothes;
    }

    /**
     * @method buyClothes
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID - The ID of the clothes
     * @return {Promise<any>}
     */
    buyClothes(clothID) {
        return new Promise((resolve) => {
            if (gameData.clothes[clothID].Unlocked === false) {
                GAME.removeGold(GAME.clothes.getAllClothes()[clothID].Cost);
                GAME.clothes.unlockClothes(clothID);

                globalEvents.emit('refreshClothes');
            }
            resolve();
        })
    }

    /**
     * Unlocks clothes
     * @method unlockClothes
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID - The ID of the clothes
     */
    unlockClothes(clothID) {
        gameData.clothes[clothID].Unlocked = true;
        globalEvents.emit('refreshClothes');
    }

    /**
     * Sets clothes visibility
     * @method setVisible
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID - The ID of the clothes
     * @param {boolean} boolean - Visibility
     */
    setVisible(clothID, boolean) {
        gameData.clothes[clothID].Visible = boolean;
        globalEvents.emit('refreshClothes');
    }

    /**
     * Use this method to create new clothes
     * @method newClothes
     * @memberOf ClothesManager
     * @instance
     * @param {ClothesManager.clothesConfig} clothesConfig
     */
    newClothes(clothesConfig) {
        if (!clothesConfig.Body) {
            clothesConfig.Body = "Default";
        }
        if (!clothesConfig.Face) {
            clothesConfig.Face = "Neutral";
        }

        if (gameData.clothes.hasOwnProperty(clothesConfig.ID) === false) {
            gameData.clothes[clothesConfig.ID] = {
                "Visible": clothesConfig.Visible,
                "Unlocked": clothesConfig.Unlocked,
                "Dye": false
            }
        }

        if (this._clothes.hasOwnProperty(clothesConfig.Girl)) {
            this._clothes[clothesConfig.Girl].push(clothesConfig.ID);
        } else {
            this._clothes[clothesConfig.Girl] = [];
            this._clothes[clothesConfig.Girl].push(clothesConfig.ID);
        }

        this._clothes[clothesConfig.ID] = clothesConfig;
    }

    /**
     * Takes the three parameters or an array of {@link ClothesManager.dyeConfig}
     * @method newDye
     * @memberOf ClothesManager
     * @instance
     * @param {string|Array<ClothesManager.dyeConfig>} clothesID
     * @param {string} [dyeID]
     * @param {function} [condition] - function that should return true or false if you want this dye to only be available after a certain condition is met
     */
    newDye(clothesID, dyeID, condition) {
        if (typeof clothesID === "object") {
            for (let i of clothesID) {
                let cloth = i.clothesID;
                let dye = i.dyeID;
                i.condition = i.condition || function () {
                    return true;
                };

                if (this._dyes.hasOwnProperty(cloth)) {
                    this._dyes[cloth].push(i);
                } else {
                    this._dyes[cloth] = [];
                    this._dyes[cloth].push(i);
                }
            }
        } else {
            let obj = {
                clothesID: clothesID,
                dyeID: dyeID,
                condition: condition || function () {
                    return true
                }
            };

            if (this._dyes.hasOwnProperty(clothesID)) {
                this._dyes[clothesID].push(obj);
            } else {
                this._dyes[clothesID] = [];
                this._dyes[clothesID].push(obj);
            }
        }
    }

    /**
     * @method getClothes
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @returns {boolean|*}
     */
    getClothes(clothID) {
        if (this._clothes.hasOwnProperty(clothID)) {
            return this._clothes[clothID];
        } else {
            return false;
        }
    }

    /**
     * @method getDye
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @param {string} dyeID
     * @returns {ClothesManager.dyeConfig}
     */
    getDye(clothID, dyeID) {
        return this._dyes[clothID].find((dye) => dye.dyeID === dyeID) || false;
    }

    /**
     * @method getGirlDye
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @returns {boolean|string}
     */
    getGirlDye(clothID) {
        if (this._clothes.hasOwnProperty(clothID)) {
            return gameData.clothes[clothID].Dye;
        } else {
            return false;
        }
    }

    /**
     * Dyes the clothes a random color
     * @method dyeClothes
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @param {string} dyeID
     */
    dyeClothes(clothID, dyeID) {
        GAME.removeGold(100);
        GAME.clothes.setDye(clothID, dyeID);
    }

    /**
     * Sets the tint of the clothes to 0xFFFFFF
     * @method resetDye
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     */
    resetDye(clothID) {
        if (GAME.clothes.getGirlDye(clothID) !== false) {
            GAME.removeGold(100);
            GAME.clothes.setDye(clothID, false);
        }
    }

    /**
     * Default dye is 'false'
     * @method setDye
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @param {string|boolean} dyeID
     */
    setDye(clothID, dyeID) {
        gameData.clothes[clothID].Dye = dyeID;
    }

    /**
     * Returns all dyes for given clothes that have a condition of true
     * @method getClothesDyes
     * @memberOf ClothesManager
     * @instance
     * @param {string} clothID
     * @returns {Array<string>}
     */
    getClothesDyes(clothID) {
        if (this._dyes.hasOwnProperty(clothID)) {
            let dyeArray = [];
            for (let dye of this._dyes[clothID]) {
                if (dye.condition() === true) {
                    dyeArray.push(dye.dyeID);
                }
            }
            return dyeArray;
        } else {
            return [];
        }
    }
}