Source: ClientManager.js

/**
 * @typedef {object} ClientManager.client
 * @property {string} ID - Client ID
 * @property {string} Name - Client's name
 * @property {number} Cum - How close a client is to cumming (0-100)
 * @property {number} Level - client level
 * @property {string} Girl - The girl the client wants or "Any"
 * @property {string} BodyPart - The body part the client wants or "Any"
 * @property {array} Status - Client's status effects
 */

/**
 * @typedef {object} ClientManager.clientObj
 * @property {number} Tint
 * @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} Difficulty - How easy it is to make this client cum, higher is harder, 6 is default
 * @property {function} getAttack - Function called to see what attack should come next from this client, utilize the parameters to make battles interesting. return 'default' for a regular 1 damage, any body part attack
 */

/**
 * @class ClientManager
 */
class ClientManager {
    constructor() {
        this._clients = {
            "ERTutorial": {
                "Tint": 0xFFFFCC,
                "Name": "Easthollow Resident",
                "ID": "ERTutorial",
                "Region": "Easthollow",
                "EXP": 10,
                "Gold": 12,
                "Difficulty": 2,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "tutorial"
                }
            },
            "EasthollowResident": {
                "Tint": 0xFFFFCC,
                "Name": "Easthollow Resident",
                "ID": "EasthollowResident",
                "Region": "Easthollow",
                "EXP": 10,
                "Gold": 12,
                "Difficulty": 2,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return true;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "default"
                }
            },
            "GreenhavenResident": {
                "Tint": 0x86583b,
                "Name": "Greenhaven Resident",
                "ID": "GreenhavenResident",
                "Region": "Greenhaven",
                "EXP": 15,
                "Gold": 15,
                "Difficulty": 6,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('forestBeastQuest', 'FuckGreenhaven');
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (chance.bool({likelihood: 20})) {
                        return ["randomGirl", "default"];
                    }

                    return "default"
                }
            },
            "Goblin": {
                "Tint": 0x337829,
                "Name": "Goblin",
                "ID": "Goblin",
                "Region": "MoaningMorass",
                "EXP": 30,
                "Gold": 20,
                "Difficulty": 6,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('swampBeastQuest', 'Completed');
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (chance.bool({likelihood: 20}) && GAME.battle.getGirlsTrap(BATTLE, girlID, 'goblinMushroom') === false) {
                        return 'goblinMushroom';
                    }

                    return "default"
                }
            },
            "AviaResident": {
                "Tint": 0xa2ffec,
                "Name": "Avia Resident",
                "ID": "AviaResident",
                "Region": "Avia",
                "EXP": 40,
                "Gold": 30,
                "Difficulty": 10,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return GAME.quest.isComplete('kingsQuest', 'Completed');
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "ARdefault";
                }
            },
            "Leon": {
                "Tint": 0xffa150,
                "Name": "Leon",
                "ID": "Leon",
                "Region": "Easthollow",
                "EXP": 25,
                "Gold": 20,
                "Difficulty": 6,
                "Reputation": 100,
                "BrothelBoss": true,
                "Unlocked": function () {
                    return true;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "default"
                }
            },
            "Geoff": {
                "Tint": 0x35F26D,
                "Name": "Geoff",
                "ID": "Geoff",
                "Region": "Easthollow",
                "EXP": 40,
                "Gold": 25,
                "Difficulty": 8,
                "Reputation": 300,
                "BrothelBoss": true,
                "Unlocked": function () {
                    return GAME.quest.isComplete('geoffUnlock', 'RecruitGeoff');
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (chance.bool({likelihood: 20}) && GAME.battle.getClientStatus(BATTLE, CLIENT, 'edge') === false) {
                        return 'edge';
                    }

                    return "default"
                }
            },
            "Principal": {
                "Tint": 0xCC77A0,
                "Name": "Principal",
                "ID": "Principal",
                "Region": "Easthollow",
                "EXP": 64,
                "Gold": 30,
                "Difficulty": 10,
                "Reputation": 600,
                "BrothelBoss": true,
                "Unlocked": function () {
                    // return GAME.quest.isComplete('worldQuests', 'principalUnlock');
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "default"
                }
            },
            "Werewolf": {
                "Tint": 0x7c8b88,
                "Name": "Werewolf",
                "ID": "Werewolf",
                "EXP": 20,
                "Difficulty": 120,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (CLIENT.Cum > 15) {
                        if (chance.bool({likelihood: 45}) === true && GAME.battle.getGirlsTrap(BATTLE, girlID, 'werewolfVines') === false) {
                            return 'werewolfVines';
                        }
                    }

                    return 'werewolfAttack';
                }
            },
            "WildGoblin": {
                "Tint": 0x337829,
                "Name": "Wild Goblin",
                "ID": "WildGoblin",
                "EXP": 30,
                "Difficulty": 12,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (CLIENT.Cum > 5) {
                        if (chance.bool({likelihood: 60}) === true && GAME.battle.getGirlsTrap(BATTLE, girlID, 'goblinMushroom') === false) {
                            return 'goblinMushroom';
                        }
                    }

                    return 'wildGoblinFaster';
                }
            },
            "Peasant": {
                "Tint": 0x7c8b88,
                "Name": "Peasant",
                "ID": "Peasant",
                "EXP": 15,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "peasantTitFuck";
                }
            },
            "AviaGuard": {
                "Tint": 0x7c8b88,
                "Name": "Guard of Avia",
                "ID": "AviaGuard",
                "EXP": 30,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    if (chance.bool({likelihood: 30}) === true && GAME.battle.getGirlStatus(BATTLE, girlID, 'lactating') !== false) {
                        return 'aviaGuardSuck';
                    }

                    return "aviaGuardFuck";
                }
            },
            "AviaGuard2": {
                "Tint": 0x7c8b88,
                "Name": "Guard of Avia",
                "ID": "AviaGuard2",
                "EXP": 30,
                "Difficulty": 8,
                "BrothelBoss": false,
                "Unlocked": function () {
                    return false;
                },
                "getAttack": function (BATTLE, CLIENT, girlID, bodyPart) {
                    return "aviaGuard2Fuck";
                }
            }
        };
    }

    /**
     * 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);
    }

    /**
     * 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);

            // Chance for client wanting a specific girl
            if (chance.bool({likelihood: 10})) {
                clients[i].Girl = chance.pickone(GAME.getUnlocked());
            }

            // Chance for client wanting a specific body part
            if (chance.bool({likelihood: 10})) {
                clients[i].BodyPart = chance.pickone(GAME.girl.getUnlockedBodyParts());
            }
        }


        return clients;
    }
}

/**
 * Constructor for creating clients.
 * @hideconstructor
 * @memberOf ClientManager
 * @param {string} clientID
 * @param {number} clientLevel
 * @param {string} [wantsGirl]
 * @param {GirlManager.bodyPart} [wantsBodyPart]
 * @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, wantsGirl, wantsBodyPart) {
    wantsGirl = wantsGirl || "Any";
    wantsBodyPart = wantsBodyPart || "Any";
    return {
        ID: clientID,
        Name: GAME.client.getClientObj(clientID).Name,
        Cum: 0,
        Level: clientLevel,
        Girl: wantsGirl,
        BodyPart: wantsBodyPart,
        Status: []
    }
};