Source: BossManager.js

/**
 * @class BossManager
 */
class BossManager {
    constructor() {
        this._boss = {
            forestBeastQuest: {
                bodyParts: ['Throat', 'Pussy'],
                clients: {
                    Easy: []
                },
                rewards: {
                    Easy: {
                        EXP: 600,
                        Items: {
                            "Gloves": {
                                "Chance": 5,
                                "Amount": [1]
                            },
                            "Lollipop": {
                                "Chance": 5,
                                "Amount": [1]
                            },
                            "Lube": {
                                "Chance": 5,
                                "Amount": [1]
                            },
                            "Cum": {
                                "Chance": 100,
                                "Amount": [1, 6]
                            }
                        },
                        Clothes: {
                            "Array": ['ForestSuki', 'ForestEsxea', 'ForestScarlett'],
                            "Chance": 20
                        }
                    }
                }
            },
            swampBeastQuest: {
                bodyParts: ['Feet', 'Pussy'],
                clients: {
                    Easy: []
                },
                rewards: {
                    Easy: {
                        EXP: 1500,
                        Items: {
                            "Lollipop": {
                                "Chance": 8,
                                "Amount": [1]
                            },
                            "Lube": {
                                "Chance": 8,
                                "Amount": [1]
                            },
                            "Alcohol": {
                                "Chance": 4,
                                "Amount": [1]
                            },
                            "Cum": {
                                "Chance": 100,
                                "Amount": [5, 15]
                            }
                        },
                        Clothes: {
                            "Array": ['MudQueen', 'MudSuki', 'MudEsxea', 'MudScarlett'],
                            "Chance": 10
                        }
                    }
                }
            },
            kingsQuest: {
                bodyParts: ['Tits'],
                clients: {
                    Easy: []
                },
                rewards: {
                    Easy: {
                        EXP: 1200,
                        Items: {
                            "Cum": {
                                "Chance": 100,
                                "Amount": [5, 15]
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * @method _initBossClients
     * @memberOf BossManager
     * @instance
     * @private
     */
    _initBossClients() {
        // Greenhaven Boss
        this.addBossClients('forestBeastQuest', 'Easy', [new GAME.client.client('Werewolf', 15)]);

        // Morass Boss
        this.addBossClients('swampBeastQuest', 'Easy', [new GAME.client.client('WildGoblin', 10),
            new GAME.client.client('WildGoblin', 11),
            new GAME.client.client('WildGoblin', 12),
            new GAME.client.client('WildGoblin', 13),
            new GAME.client.client('WildGoblin', 14),
            new GAME.client.client('WildGoblin', 15),
            new GAME.client.client('WildGoblin', 16),
            new GAME.client.client('WildGoblin', 17),
            new GAME.client.client('WildGoblin', 18),
            new GAME.client.client('WildGoblin', 19),
            new GAME.client.client('WildGoblin', 20)]);

        // King Boss
        this.addBossClients('kingsQuest', 'Easy', [new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 15),
            new GAME.client.client('AviaGuard', 25),
            new GAME.client.client('AviaGuard', 35)]);
    }

    /**
     * Creates a new boss skeleton object you can populate using other functions
     * @method newBoss
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     */
    newBoss(bossID) {
        this._boss[bossID] = {
            bodyParts: [],
            clients: {},
            rewards: {}
        }
    }

    /**
     * Adds rewards for the given boss battle and difficulty
     * @method addBossRewards
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {string} bossDifficulty
     * @param {object} rewardsObj
     */
    addBossRewards(bossID, bossDifficulty, rewardsObj) {
        this._boss[bossID].rewards[bossDifficulty] = rewardsObj;
    }

    /**
     * Updates the client array for a boss
     * @addBossClients
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {'Easy'|'Normal'|'Hard'} bossDifficulty
     * @param {Array<ClientManager.client>} clientArray
     */
    addBossClients(bossID, bossDifficulty, clientArray) {
        this._boss[bossID].clients[bossDifficulty] = clientArray;
    }

    /**
     * Gets the clients for a boss battle
     * @method getBossClients
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {'Easy'|'Normal'|'Hard'} bossDifficulty
     * @returns {Array<ClientManager.client>}
     */
    getBossClients(bossID, bossDifficulty) {
        return [...this._boss[bossID].clients[bossDifficulty]];
    }

    /**
     * Returns an object that has all of the reward information
     * @method getBossRewards
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {'Easy'|'Normal'|'Hard'} bossDifficulty
     * @returns {Object}
     */
    getBossRewards(bossID, bossDifficulty) {
        let rewards = this._boss[bossID].rewards[bossDifficulty];
        rewards.bodyParts = GAME.boss.getBossBodyParts(bossID);

        return rewards;
    }

    /**
     * @method getBossBodyParts
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @returns {Array<GirlManager.bodyPart>}
     */
    getBossBodyParts(bossID) {
        return this._boss[bossID].bodyParts;
    }

    /**
     * Increases the times the player has beaten this boss
     * @method incrementBossCompleted
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {'Easy'|'Normal'|'Hard'} difficulty
     */
    incrementBossCompleted(bossID, difficulty) {
        if (gameData.bosses.hasOwnProperty(bossID) === false) {
            gameData.bosses[bossID] = {};
        }

        if (gameData.bosses.hasOwnProperty(difficulty) === false) {
            gameData.bosses[bossID][difficulty] = 0;
        }

        gameData.bosses[bossID][difficulty] += 1;
    }

    /**
     * Gives rewards for the boss battle
     * @method giveRewards
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {'Easy'|'Normal'|'Hard'} bossDifficulty
     */
    giveRewards(bossID, bossDifficulty) {
        let dropList = [];
        let rewards = GAME.boss.getBossRewards(bossID, bossDifficulty);
        let bodyParts = rewards.bodyParts;

        if (rewards.hasOwnProperty('Items')) {
            for (let i in rewards.Items) {
                if (chance.bool({likelihood: rewards.Items[i].Chance})) {
                    if (rewards.Items[i].Amount.length > 1) {
                        dropItem(i, chance.integer({min: rewards.Items[i].Amount[0], max: rewards.Items[i].Amount[1]}))
                    } else {
                        dropItem(i, rewards.Items[i].Amount[0]);
                    }
                }
            }
        }

        function dropItem(itemID, amount) {
            dropList.push({itemID: itemID, amount: amount, type: 'Item'});
            for (let i = 0; i < amount; i++) {
                GAME.item.pushItem(itemID, true);
            }

            GAME.notify('Boss dropped ' + GAME.item.getAllItems()[itemID].Name + '!');
        }

        if (rewards.hasOwnProperty('Clothes')) {
            let clothesArray = rewards.Clothes.Array;

            for (let i = clothesArray.length - 1; i >= 0; i--) {
                if (gameData.clothes[clothesArray[i]].Unlocked === true || gameData.character[GAME.clothes.getAllClothes()[clothesArray[i]].Girl].Unlocked === false) {
                    clothesArray.splice(i, 1);
                }
            }

            if (chance.bool({likelihood: rewards.Clothes.Chance}) && clothesArray.length !== 0) {
                let chosenCloth = chance.pickone(clothesArray);
                dropList.push({clothID: chosenCloth, type: 'Clothes'});
                GAME.clothes.unlockClothes(chosenCloth);
                GAME.notify('Boss dropped new clothes for ' + GAME.clothes.getAllClothes()[chosenCloth].Girl + '!');
            }
        }


        GAME.girl.splitExp(GAME.girl.getUnlocked(), rewards.EXP, bodyParts);

        dropList.EXP = rewards.EXP;

        GAME.boss.incrementBossCompleted(bossID, bossDifficulty);

        return dropList;
    }

    /**
     * @method startBossBattle
     * @memberOf BossManager
     * @instance
     * @param {string} bossID
     * @param {string} bossDifficulty
     * @returns {Promise<any>}
     */
    startBossBattle(bossID, bossDifficulty) {
        return new Promise((resolve) => {
            let bossClients = [];

            for (let client of GAME.boss.getBossClients(bossID, bossDifficulty)) {
                bossClients.push(Object.assign({}, client));
            }

            gameData.bossToday = true;

            GAME.battle.startBattle(bossClients, GAME.girl.getUnlocked(), GAME.boss.getBossBodyParts(bossID), bossDifficulty).then((answer) => {
                resolve(answer);
            });
        });
    }
}