Source: ClientManager.js

/**
 * @typedef {object} ClientManager.client
 * @property {string} ID - Client ID
 * @property {string} Name - Client's name
 * @property {Array<BattleManager.comboObj>} Combo - Current battle combo for this client
 * @property {number} Cum - How close a client is to cumming (0-100)
 * @property {number} Level - client level
 * @property {array} Status - Client's status effects
 */

/**
 * @typedef {object} ClientManager.clientObj
 * @property {string} Name - Full name of client
 * @property {string} ID - ID of client
 * @property {string} Region - Region of client
 * @property {number} EXP - Experience given each time client is fucked
 * @property {number} Gold - Gold given if client cums in a battle
 * @property {number} BaseLevel - Level used for determining min and max gold/exp
 * @property {number} Difficulty - How easy it is to make this client cum, higher is harder, 6 is default
 * @property {boolean} BrothelBoss - Is this client a stronger "boss" that should appear by chance?
 */

/**
 * @class ClientManager
 */
class ClientManager {
    constructor() {
        this._goldMultipler = 3;
        this._clients = {
            "EasthollowResident": {
                "Name": "Easthollow Resident",
                "ID": "EasthollowResident",
                "Region": "Easthollow",
                "EXP": 10,
                "Gold": 12,
                "BaseLevel": 1,
                "Difficulty": 6,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return true;
                }
            },
            "GreenhavenResident": {
                "Name": "Greenhaven Resident",
                "ID": "GreenhavenResident",
                "Region": "Greenhaven",
                "EXP": 15,
                "Gold": 15,
                "BaseLevel": 1,
                "Difficulty": 6,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('forestBeastQuest', 'FuckGreenhaven');
                }
            },
            "Goblin": {
                "Name": "Goblin",
                "ID": "Goblin",
                "Region": "MoaningMorass",
                "EXP": 30,
                "Gold": 20,
                "BaseLevel": 1,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('swampBeastQuest', 'Completed');
                }
            },
            "AviaResident": {
                "Name": "Avia Resident",
                "ID": "AviaResident",
                "Region": "Avia",
                "EXP": 40,
                "Gold": 30,
                "BaseLevel": 1,
                "Difficulty": 10,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('kingsQuest', 'Completed');
                }
            },
            "Leon": {
                "Name": "Leon",
                "ID": "Leon",
                "Region": "Easthollow",
                "EXP": 25,
                "Gold": 20,
                "BaseLevel": 1,
                "Difficulty": 10,
                "Reputation": 100,
                "BrothelBoss": true,
                "Unlocked": function () {
                    return true;
                }
            },
            "Geoff": {
                "Name": "Geoff",
                "ID": "Geoff",
                "Region": "Easthollow",
                "EXP": 40,
                "Gold": 25,
                "BaseLevel": 1,
                "Difficulty": 12,
                "Reputation": 300,
                "BrothelBoss": true,
                "Unlocked": function () {
                    return GAME.quest.isComplete('geoffUnlock', 'RecruitGeoff');
                }
            },
            "Boris": {
                "Name": "Boris",
                "ID": "Boris",
                "Region": "Greenhaven",
                "EXP": 20,
                "BaseLevel": 15,
                "Difficulty": 120,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                }
            },
            "WildGoblin": {
                "Name": "Wild Goblin",
                "ID": "WildGoblin",
                "Region": "MoaningMorass",
                "EXP": 30,
                "BaseLevel": 10,
                "Difficulty": 20,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                }
            },
            "Peasant": {
                "Name": "Peasant",
                "ID": "Peasant",
                "Region": "Avia",
                "EXP": 15,
                "BaseLevel": 5,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                }
            },
            "AviaGuard": {
                "Name": "Guard of Avia",
                "ID": "AviaGuard",
                "Region": "Avia",
                "EXP": 30,
                "BaseLevel": 15,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                }
            },
            "AviaGuard2": {
                "Name": "Guard of Avia",
                "ID": "AviaGuard2",
                "Region": "Avia",
                "EXP": 30,
                "BaseLevel": 5,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                }
            }
        };
    }

    /**
     * Returns the gold multiplier which is used to increase the amount of gold a client gives based on their level
     * @method getGoldMultipler
     * @memberOf ClientManager
     * @instance
     * @returns {number}
     */
    getGoldMultiplier() {
        return this._goldMultipler;
    }

    /**
     * Sets the gold multiplier
     * @method setGoldMultipler
     * @memberOf ClientManager
     * @instance
     * @param {number} amount
     */
    setGoldMultipler(amount) {
        this._goldMultipler = amount;
    }

    /**
     * Returns the object list of all clients
     * @method getClientObj
     * @memberOf ClientManager
     * @instance
     * @param clientID
     * @returns {Object}
     */
    getClientObj(clientID) {
        return this._clients[clientID];
    }

    /**
     * @method guyDrops
     * @memberOf ClientManager
     * @instance
     * @param {string} clientID
     */
    guyDrops(clientID) {
        switch (clientID) {
            case 'Leon':
                if (chance.bool({likelihood: 1}) === true) {
                    dropItem(chance.pickone(['Lube', 'Lollipop', 'Gloves']));
                }
                break;
            case 'Principal':
                if (chance.bool({likelihood: 2}) === true) {
                    dropItem(chance.pickone(['Lube', 'Lollipop', 'Gloves']));
                }
                break;
            case 'Geoff':
                if (chance.bool({likelihood: 5}) === true) {
                    dropItem(chance.pickone(['Lube', 'Lollipop', 'Gloves']));
                }
                break;
            case 'Darrak':
                if (chance.bool({likelihood: 5}) === true) {
                    dropItem(chance.pickone(['Lube', 'Lollipop', 'Gloves', 'Alcohol']));
                }
                break;
            default:
                break;
        }

        if (chance.bool({likelihood: 20}) === true) {
            dropItem('Cum');
        }

        function dropItem(itemID) {
            GAME.item.pushItem(itemID, true);
            GAME.notify(GAME.client.getClientObj(clientID).Name + " dropped " + GAME.item.getAllItems()[itemID].Name + "!");
        }
    }

    /**
     * Returns an array of unlocked clients that aren't bosses
     * @method getUnlockedClients
     * @memberOf ClientManager
     * @instance
     * @return {Array<string>}
     */
    getUnlockedClients() {
        let clientArray = [];
        for (let i in this._clients) {
            if (this._clients[i].Unlocked() === true && this._clients[i].BrothelBoss === false) {
                clientArray.push(this._clients[i].ID);
            }
        }

        return clientArray;
    }

    /**
     * Returns an array of brothel bosses that could come today. Only gives bosses that are unlocked and whose reputation is lower than the brothel's
     * @method getUnlockedBrothelBosses
     * @memberOf ClientManager
     * @instance
     * @returns {Array<string>}
     */
    getUnlockedBrothelBosses() {
        let bosses = [];
        for (let i in this._clients) {
            if (this._clients[i].Unlocked() === true && this._clients[i].BrothelBoss === true && GAME.getReputation() >= this._clients[i].Reputation) {
                bosses.push(this._clients[i].ID);
            }
        }
        return bosses;
    }

    /**
     * Returns the amount of exp a client will give
     * @method getClientExp
     * @memberOf ClientManager
     * @instance
     * @param {string} clientID
     * @return {number}
     */
    getClientExp(clientID) {
        let expBoost = 1;
        let clientObj = GAME.client.getClientObj(clientID);
        switch (clientObj.Region) {
            case 'Easthollow':
                expBoost = GAME.buildingStats('Gloryhole').EXP / 100;
                break;
            case 'Greenhaven':
                expBoost = GAME.buildingStats('TreeHouse').EXP / 100;
                break;
            case 'MoaningMorass':
                expBoost = GAME.buildingStats('Mudpot').EXP / 100;
                break;
            case 'Avia':
                expBoost = GAME.buildingStats('Bukkake').EXP / 100;
                break;
            default:
                expBoost = 1;
        }
        return Math.floor(clientObj.EXP * expBoost);
    }

    /**
     * Returns the amount of gold a client will give
     * @method getClientGold
     * @memberOf ClientManager
     * @instance
     * @param {string} clientID
     * @param {number} [clientLevel] - If you want to scale the gold based on the clients level
     * @return {number}
     */
    getClientGold(clientID, clientLevel) {
        clientLevel = clientLevel || 1;
        let clientObj = GAME.client.getClientObj(clientID);
        if (clientObj.hasOwnProperty('Gold')) {
            if (clientObj.hasOwnProperty('BaseLevel')) {
                let maxGold = clientObj.Gold * GAME.client.getGoldMultiplier();
                let minGold = clientObj.Gold;
                let maxLevel = clientObj.BaseLevel + MAX_LEVEL;

                return Math.floor(minGold + ((maxGold - minGold) * (clientLevel / maxLevel)));
            } else {
                return clientObj.Gold;
            }
        } else {
            return 0;
        }
    }

    /**
     * Generates an array of clients that could have been summoned with the current stats, used for updating the clients after going to sleep
     * @method getClientPack
     * @memberOf ClientManager
     * @instance
     */
    getClientPack() {
        let clientLength = 2;
        if (GAME.getReputation() > 100) {
            clientLength = 3;
        }
        if (GAME.getReputation() > 300) {
            clientLength = 4;
        }
        if (GAME.getReputation() > 600) {
            clientLength = 5;
        }
        if (GAME.getReputation() > 900) {
            clientLength = 6;
        }
        let clientLevel = Math.ceil((GAME.getReputation() / 1000) * MAX_LEVEL);
        let availableClients = GAME.client.getUnlockedClients();

        let clients = [];

        do {
            clients.push(chance.pickone(availableClients));
        } while (clients.length < clientLength);

        if (chance.bool({likelihood: 30})) {
            let bosses = GAME.client.getUnlockedBrothelBosses();
            if (bosses.length > 0) {
                clients.pop();
                clients.push(chance.pickone(bosses));
            }
        }

        clients = Phaser.Utils.Array.Shuffle(clients);

        for (let i in clients) {
            clients[i] = new GAME.client.client(clients[i], clientLevel);
        }


        return clients;
    }
}

/**
 * Constructor for creating clients.
 * @hideconstructor
 * @memberOf ClientManager
 * @param {string} clientID
 * @param {number} clientLevel
 * @returns {ClientManager.client}
 * @example
 * let client = new GAME.client.client('EasthollowResident', 5);
 * let client = new GAME.client.client('Leon', 10, 'Queen', 'Pussy');
 */
ClientManager.prototype.client = function (clientID, clientLevel) {
    return {
        ID: clientID,
        Name: GAME.client.getClientObj(clientID).Name,
        Combo: [],
        Cum: 0,
        Level: clientLevel,
        Status: []
    }
};