IdleScape - Lootify

Addons for the IdleScape Fighting System

当前为 2021-01-24 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         IdleScape - Lootify
// @namespace    D4IS
// @version      1.2.3
// @description  Addons for the IdleScape Fighting System
// @author       D4M4G3X
// @match        http*://*idlescape.com/game
// @match        https://idlescape.com/game
// @match        https://www.idlescape.com/game
// @grant        none
// @require http://code.jquery.com/jquery-3.4.1.min.js
// @run-at document-start
// ==/UserScript==

(function() {
    'use strict';
    let ver = '1.2.3';
    let newver = getNewVer();
    let runs = [{}];
    let total = {};
    let totalLoot = {};
    let isSetup = false;
    let time = 0;
    let prices = getMarketPrices();
    let user = {};
    let headers = {};
        let timer = {
            'running': false,
            'starts': [],
            'stops': [],
            'interval': function() {
                let e = setInterval(()=> {
                    if(!isStatus('Fighting')) {
                        clearInterval(e);
                    }
                    if($('.time-stats').length) {
                        $('.time-stats').find('span').text('Elapsed: '+getTime());
                    }
                }, 10);
            },
            'update': setInterval(()=> {
                if($('.status-bar').length) {
                    if(isStatus('Fighting')) {
                        if (!timer.running) {
                            timer.running = true;
                            timer.starts.unshift(new Date());
                            timer.interval();
                        }
                    } else {
                        if(timer.running) {
                            timer.running = false;
                            timer.stops.unshift(new Date());
                        }
                    }
                }
            },500),
        }
    /* ############## CSS STYLES ############## */
    let styles = {};
    styles.boxshadow = {
        'webkit-box-shadow': '0 1px 3px rgba(0,0,0,.3),inset 0 1px 1px rgba(255,255,255,.2)',
        '-moz-box-shadow': '0 1px 3px rgba(0,0,0,.3),inset 0 1px 1px rgba(255,255,255,.2)',
        'box-shadow': '0 1px 3px rgba(0,0,0,.3),inset 0 1px 1px rgba(255,255,255,.2)',
    };
    styles.header = {
        'display': 'flex',
        'justify-content': 'space-between',
        'align-items': 'center',
        'border-radius': '8px',
        'padding': '4px 0 4px 10px',
        'background-color': '#2d2d2d',
    };
    styles.mobheader = Object.assign({}, styles.boxshadow, styles.header, {
        'margin': '4px auto',
    });
    styles.lootheader = Object.assign({}, styles.boxshadow, styles.header, {
        'margin': '0 auto',
        'border-bottom': '2px solid transparent'
    });
    styles.headerImage = Object.assign({}, styles.boxshadow, {
        'background-color': '#313b46',
        'border-radius': '100%',
        'padding': '4px',
        'height': '35px',
        'width': '35px',
    });
    styles.entry = {
        'border-radius': 'none',
        'padding': '4px 8px',
        'border-bottom': '1px dotted #2d2d2d',
    };
    styles.submenu = {
        'width': '80%',
        'margin': '0 auto',
        'padding': '5px 0',
    };
    styles.lootwrap = {
        'border-radius': '8px',
        'background-color': '#3c3c3c',
    };
    styles.setting = Object.assign({}, styles.boxshadow, {
        'width':'80%',
        'display':'flex',
        'margin':'4px auto',
        'padding': '4px 8px',
        'justify-content': 'space-between',
        'align-items': 'center',
        'background-color': '#3c3c3c',
        'border-radius': '8px',
    });
    styles.input = {
        'background-color': '#FFF',
        'margin': '0',
        'font-size': '14px',
    };
    styles.inputCheck = Object.assign({}, styles.input, {
        'margin': '0 25px',
        'opacity': '1',
        'position': 'relative',
        'pointer-events': 'auto',
        'transform': 'scale(1.5)',
    });
    styles.inputNumber = Object.assign({}, styles.input, {
        'height': '20px',
        'width': '50px',
        'border-radius': '10px',
        'padding': '0px 4px 0 10px',
    });
    /* ############## INTERVALS ############## */
    let mainInterval = setInterval(()=> {
        if ($('.status-bar').length) {
            if(!isSetup) {
                isSetup = true;
                updateUser();
                setupSettings();
                setupLogs();
                setupTimer();
                setupKPH();
                !isIron() ? setupGPH() : 1;
            }
            checkUpdates();
        }
        if (isStatus('Fighting')) {
            saveLogs();
            mergeLogs();
            renderLogs();
            renderKPH();
            !isIron() ? renderGPH() : 1;
        }
        if ($('.combat-zone').length) {
            $('.combat-zone').unbind().click(function() {
                let $zone = $(this);
                $.each(getLogMobs(), function(key, mob) {
                    if (!getZoneMobs($zone.text()).includes(mob)) {
                        submitStats(getLogs(), getTH());
                        clearLogs();
                    }
                });
            });
        }
        cleanChat();
    }, 1000);
    let pasteInterval = setInterval(()=> {
        if (isStatus('Fighting')) {
            if(window.localStorage.getItem(getUsername() + '-AutoPaster') == 'true') {
                submitStats(getLogs(), getTH());
                clearLogs('single');
            }
        }
    }, getPasteInterval() * 60 * 1000);
    let adInterval = setInterval(()=> {
        chat({
            'msg': 'Lootify - Please report bugs to D4M4G3X#6263 on Discord!',
            'color': '#00a0fd',
        });
    }, 15 * 60 * 1000);
    let updateInterval = setInterval(()=> {
        prices = getMarketPrices();
        newver = getNewVer();
        updateUser();
    }, 5 * 60 * 1000);
    /* ############## SETUP AND RENDER ############## */
    function setupSettings() {
        let $lootBtn;
        if ($('.btn-loot-log').length) {
            $('.btn-loot-log').remove();
        }
        if (getMenuItem('Loot Log')) {
            editMenuItem('Loot Log');
        }
        if(!getMenuItem('Lootify', 'category')) {
            let $ltfHeader = setMenuItem({
                'text': 'Lootify',
                'clone': 'Gathering',
                'before': getMenuItem('Gathering', 'category'),
            }, 'category');
            $ltfHeader.append($('<i/>').text(' (v'+ver+')').css('font-size','12px').insertAfter($ltfHeader));
        }
        if(!getMenuItem('Lootify')) {
            $lootBtn = setMenuItem({
                'icon': '/images/money_icon.png',
                'text': 'Lootify Settings',
                'class': 'btn-lootify',
                'after': getMenuItem('Lootify', 'category'),
                'click': function() {
                    $('.log-paster-settings').toggle();
                },
            });
        } else {
            $lootBtn = $('.btn-lootify');
        }
        if (!$('.log-paster-settings').length) {
            let $wrap = $('<div/>', {
                'class': 'log-paster-settings'
            }).hide();
            $lootBtn.after($wrap);

            addSetting({
                'text': 'Enable Auto Paster',
                'name': 'AutoPaster',
                'type': 'checkbox',
                'default': 'false',
                'change': function() {
                    window.localStorage.setItem(getUsername() + '-AutoPaster', $(this).prop('checked'));
                }
            }).appendTo($wrap);
            addSetting({
                'text': 'Paste Interval (minutes)',
                'name': 'AutoPasterInterval',
                'type': 'number',
                'min': 15,
                'max': 60,
                'default': 30,
                'change': function() {
                    if($(this).val() >= $(this).attr('min') && $(this).val() <= $(this).attr('max')) {
                        window.localStorage.setItem(getUsername() + '-AutoPasterInterval', $(this).val());
                    }
                }
            }).appendTo($wrap);
        }
    }
    function setupLogs() {
        if(!getMenuItem('Loot Log')) {
            setMenuItem({
                'icon': '/images/ui/inventory_icon.png',
                'text': 'Loot Log',
                'class': 'btn-loot-log',
                'before': getMenuItem('Gathering', 'category'),
                'click': function() {
                    $('.item-log-clone').toggle();
                },
            });
        }
        let $logwrap = $('.item-log-window');
        $logwrap.hide();
        let $clone = $logwrap.clone();
        $clone.addClass('item-log-clone').removeClass('hidden');
        $clone.css(styles.submenu);
        $clone.find('.item-log-timer').remove();
        $clone.find('.item-log-info').remove();
        $clone.find('.drawer-setting-large').addClass('clone').unbind().click(function() {
            submitStats(getLogs(), getTH());
            clearLogs();
        }).text('Paste and Reset Log');
        getMenuItem('Loot Log').after($clone);
    }
    function setupTimer() {
        if (!getMenuItem('Elapsed:')) {
            let $timeStats = setMenuItem({
                'class': 'time-stats',
                'text': 'Elapsed: 0S',
                'icon': '/images/clock.png',
                'after': $('.log-paster-settings'),
                'css': {
                    'font-size': '14px',
                }
            });
        }
    }
    function setupKPH() {
        if (!getMenuItem('Kills:')) {
            let $kphStats = setMenuItem({
                'class': 'kph-stats',
                'text': 'Kills: 0 p/h',
                'icon': '/images/combat/combat_level.png',
                'after': $('.time-stats'),
                'click': function() {
                    $('.kph-wrap').toggle();
                },
                'css': {
                    'font-size': '14px',
                },
            });
            $kphStats.after($('<div/>', {
                'class': 'kph-wrap'
            }).css(styles.submenu).hide());
        }
    }
    function renderKPH() {
        let mobkills = {};
        $.each(total, function(mob, mobinfo) {
            mobkills[mob] = mobinfo.count;
        });
        let totalkills = function() {
            let c = 0;
            $.each(mobkills, function(mob, kills) {
                c += kills;
            });
            return c;
        };
        $('.kph-stats').find('span').text('Kills: ' + addCommas(Math.floor((totalkills()/time)*3600)) + ' p/h');
        $('.kph-wrap').empty();
        $.each(sortObject(mobkills), function(mob, count) {
            let $mobwrap = $('<div/>').css(styles.mobheader).appendTo($('.kph-wrap'));
            $mobwrap.append($('<span/>').css('display','block').text(mob + ': ' + Math.floor((count/time)*3600) + ' p/h'));
        });
    }
    function setupGPH() {
        if (!getMenuItem('Gold:')) {
            let $gphStats = setMenuItem({
                'class': 'gph-stats',
                'text': 'Loot value: 0 p/h',
                'icon': '/images/ui/shop_icon.png',
                'after': $('.kph-wrap'),
                'click': function() {
                    $('.gph-wrap').toggle();
                },
                'css': {
                    'font-size': '14px',
                }
            });
            $gphStats.after($('<div/>', {
                'class': 'gph-wrap'
            }).css(styles.submenu).hide());
        }
    }
    function renderGPH() {
        let totalGold = 0;
        $.each(totalLoot, function(item, count) {
            if (item === 'Gold') {
                totalGold += count;
            } else {
                totalGold += prices[item] * count;
            }
        });
        $('.gph-stats').find('span').text('Gold: ' + addCommas(Math.floor((totalGold/time)*3600)) + ' p/h');
        $('.gph-wrap').empty();
        let $lootwrap = $('<div/>').css(styles.mobheader).appendTo($('.gph-wrap'));
        $lootwrap.append($('<span/>').css('display','block').text('Loot value: ' + addCommas(Math.floor(totalGold))));
    }
    function saveLogs() {
        let $logcats = $('.item-log-window:not(.item-log-clone)').find('.item-log-cateogry');
        if ($logcats.length) {
            $logcats.each(function() {
                if( $(this).find('.item-log-category-closed').length ) {
                    $(this).find('.item-log-category-closed').click();
                }
                let mobs = $(this).find('.item-log-category-open').text().split(" x ");
                !runs[0][mobs[0]] ? runs[0][mobs[0]] = {} : 1;
                runs[0][mobs[0]].count = parseInt(mobs[1]);
                $(this).find('.item-log-item').each(function() {
                    if( $(this).text() !== "None" ) {
                        let loot = $(this).text().split(" x ");
                        !runs[0][mobs[0]].loot ? runs[0][mobs[0]].loot = {} : 1;
                        !runs[0][mobs[0]].loot[loot[0]] ? runs[0][mobs[0]].loot[loot[0]] = {} : 1;
                        runs[0][mobs[0]].loot[loot[0]].count = parseInt(loot[1]);
                    }
                });
            });
        }
    }
    function mergeLogs() {
        if(runs) {
            total = {};
            totalLoot = {};
            $.each(runs, function(num, run) {
                $.each(run, function(mobname, mobinfo) {
                    !total[mobname] ? total[mobname] = {} : 1;
                    !total[mobname].count ? total[mobname].count = 0 : 1;
                    total[mobname].count += mobinfo.count;
                    $.each(mobinfo.loot, function(lootname, lootinfo) {
                        /* SET TOTAL LOOT PER MOB */
                        !total[mobname].loot ? total[mobname].loot = {} : 1;
                        !total[mobname].loot[lootname] ? total[mobname].loot[lootname] = {} : 1;
                        !total[mobname].loot[lootname].count ? total[mobname].loot[lootname].count = 0 : 1;
                        total[mobname].loot[lootname].count += lootinfo.count;
                        /* SET TOTAL LOOT OVERALL */
                        !totalLoot[lootname] ? totalLoot[lootname] = 0 : 1;
                        totalLoot[lootname] += lootinfo.count;
                    });
                });
            });
            delete total[''];
        }
    }
    function renderLogs() {
        if(!runs) { return; }
        let $cat, $mobwrap, $mobheader, $lootentry;
        $('.item-log-clone').find('.item-log-cateogry').remove();
        $.each(sortObject(total), function(mob, mobinfo) {
            $cat = $('<div/>', {
                'class':'item-log-cateogry noselect'
            }).css(styles.lootwrap);
            $mobwrap = $('<div/>').css(styles.lootheader).hover(function() {
                $(this).css('border-bottom', '2px solid #888');
            }, function() {
                $(this).css('border-bottom', '2px solid transparent');
            }).appendTo($cat);
            $cat.click(function() {
                headers[mob] = headers[mob] == false ? true : false;
                $mobwrap.find('.loot-entry').toggle();
            });
            $mobwrap.append($('<div/>').text(mob + ' x ' + mobinfo.count));
            $mobwrap.append($('<img/>').css(styles.headerImage).addClass('drawer-item-icon').attr('src', getMobIcon(mob)));
            if(mobinfo.loot) {
                $.each(sortObject(mobinfo.loot), function(loot, lootinfo) {
                    $lootentry = $('<div/>', {
                        'class': 'loot-entry'
                    }).css(styles.entry).text(loot + ' x ' + lootinfo.count).appendTo($cat);
                    headers[mob] = headers[mob] ? headers[mob] : true;
                    if (!headers[mob]) {
                        $lootentry.hide();
                    }
                });
            } else {
                $lootentry = $('<div/>', {
                    'class': 'loot-entry'
                }).css(styles.entry).html('<i>None</i>').appendTo($cat);
                headers[mob] = headers[mob] ? headers[mob] : false;
                if (!headers[mob]) {
                    $lootentry.hide();
                }
            }
            $('.drawer-setting-large.clone').before($cat);
        });
    }
    /* ############## ACTIONS ############## */
    function getLogs() {
        let logs = [];
        let $logcats = $('.item-log-window:not(.item-log-clone)').find('.item-log-cateogry');
        if ($logcats.length) {
            $logcats.each(function(k,v) {
                if( $(this).find('.item-log-category-closed').length ) {
                    $(this).find('.item-log-category-closed').click();
                }
                if( $(this).find('.item-log-category-open').length ) {
                    logs.push($(this).find('.item-log-category-open').text());
                    $(this).find('.item-log-item').each(function() {
                        if( $(this).text() !== "None" ) {
                            logs.push($(this).text());
                        }
                    });
                }
            });
        }
        return logs;
    }
    function clearLogs(m = 'all') {
        if (m == 'single') {
            runs.unshift({});
        } else if (m == 'all') {
            time = 0;
            runs = [{}];
            total = {};
            isSetup = false;
            $('.item-log-clone').remove();
        }
        $('.item-log-window').find('.drawer-setting-large.active:not(.clone)').click();
    }
    /* ############## GAME LIBRARY ############## */
    /* === FILTERS === */
    function isIron() {
        return $('.header-league-icon').attr('src') === '/images/leagues/ironman_league_icon_v5.png';
    }
    function isStatus(txt) {
        return $('.status-bar').length && ~$('.status-bar').text().indexOf(txt);
    }
    /* === GET DATA === */
    function getUsername() {
        return $('.navbar1-box').text().split(' ')[1];
    }
    function getTH() {
        return getEnchantment('32');
    }
    function getEnchantment(id) {
        let TH = 0;
        if(user.enchantments) {
            $.each(user.enchantments, function(k, v) {
                if(v.enchantmentID == id) {
                    TH = v.enchantmentStrength;
                }
            });
        }
        return TH;
    }
    function getLogMobs() {
        let mobs = [];
        $.each(total, function(mob, info) {
            mobs.push(mob);
        });
        return mobs;
    }
    function getZoneMobs(zone) {
        let mobs = [];
        switch (zone) {
            case 'Farm':
                mobs = ['Cow', 'Chicken', 'Small Rat'];
                break;
            case 'Caves':
                mobs = ['Imp', 'Greater Imp'];
                break;
            case 'City':
                mobs = ['Guard', 'Black Knight'];
                break;
            case 'Lava Maze':
                mobs = ['Deadly Red Spider', 'Lesser Demon'];
                break;
            case 'Valley of Giants':
                mobs = ['Fire Giant', 'Moss Giant', 'Ice Giant'];
                break;
        }
        return mobs;
    }
    function getPasteInterval() {
        let interval = parseInt($('.AutoPasterInterval').val());
        interval = interval ? interval : 30;
        interval = interval < 15 ? 15 : interval;
        interval = interval > 60 ? 60 : interval;
        return interval;
    }
    function getMarketPrices() {
        let p = {};
        $.getJSON( "https://api.idlescape.xyz/prices", function( data ) {
            if(data) {
                $.each(data.items, function(k, v) {
                    p[v.name] = v.price;
                });
            } else {
                p = false;
            }
        });
        return p;
    }
    function getMobIcon(name) {
        let link = 'https://idlescape.com/images/combat/monsters/';
        switch (name) {
            case 'Giant Rat':
                link += 'rat.png';
                break;
            case 'Chicken':
                link += 'chicken.png';
                break;
            case 'Cow':
                link += 'cow.png';
                break;
            case 'Goblin':
                link += 'goblin.png';
                break;
            case 'Imp':
            case 'Greater Imp':
                link += 'imp.png';
                break;
            case 'Guard':
                link += 'guard.svg';
                break;
            case 'Black Knight':
                link += 'black_knight.png';
                break;
            case 'Deadly Red Spider':
                link += 'deadly_red_spider.png';
                break;
            case 'Lesser Demon':
                link += 'lesser_demon_no_highlight.png';
                break;
            case 'Spriggan':
                link += 'spriggan.png';
                break;
            case 'Greater Demon':
                link += 'greater-demon.png';
                break;
            case 'Fire Giant':
                link += 'fire_giant.png';
                break;
            case 'Moss Giant':
                link += 'moss_giant.png';
                break;
            case 'Ice Giant':
                link += 'ice_giant.png';
                break;
            case 'Abberant Shrimp':
                link += 'shrimp_abberation.png';
                break;
        }
        return link;
    }
    /* === ACTIONS === */
    function chat(args) {
        let e = setInterval(()=> {
            let $chat = $('.chat-message-container > .chat-message-list > div');
            if( $chat.length ) {
                clearInterval(e);
                $chat.each(function() {
                    if (!$(this).find('.activity-log').length) {
                        let $msg = $('<div/>', {
                            'class': 'chat-message msg-lootify'
                        }).clone().appendTo($(this));
                        if (args['date'] !== false) {
                            let $date = $('<span/>', {
                                'class': 'message-time-stamp',
                            }).text('['+getDate(new Date)+']').appendTo($msg);
                        }
                        args['color'] = args['color'] ? args['color'] : '#00A0FD';
                        args['glow'] = args['glow'] ? '0 0 3px '+args['glow'] : 'none';
                        let $txt = $('<span/>', {
                            'class':'chat-message-system'
                        }).css({
                            'font-size': '14px',
                            'color': args['color'],
                            'text-shadow': args['glow'],
                        }).text(args['msg']).appendTo($msg);

                        args['ttl'] = args['ttl'] ? args['ttl'] : 5;
                        setTimeout(()=> {
                            $msg.remove();
                        }, args['ttl'] * 60 * 1000);
                    }
                });
            }
        }, 1000);
    }
    function cleanChat() {
        let $chat = $('.chat-message-container');
        if( $chat.length ) {
            $chat.each(function() {
                if($(this).find('.activity-log').length) {
                    $(this).find('.msg-lootify').remove();
                }
            });
        }
    }
    function checkUpdates() {
        if (ver < newver) {
            if (!$('.lootify-update').length) {
                $('<div/>', {
                    'class': 'lootify-update'
                }).css({
                    'color': 'red',
                    'width': '80%',
                    'margin': '0 auto',
                }).text('Update: v'+newver+' available!').insertBefore(getMenuItem('Lootify Settings'));
            }
        }
    }
    function setNewVer(v) {
        newver = v.toString();
    }
    function getNewVer() {
        $.get('https://digimol.net/lootify/api.php?a=ver').done(function(data) {
            setNewVer(data);
        });
    }
    function updateUser() {
        $.get('https://digimol.net/lootify/api.php?a=updateuser&id='+user.id+'&name='+user.name+'&v='+ver);
    }
    function submitStats(logs, th) {
        if (logs.length < 1) {
            return false;
        }
        let targetUrl = 'https://docs.google.com/forms/u/0/d/e/1FAIpQLSch3eG9Tqts0tIvnkk-C5JZeTwfbkWXhxkIpFnxyyaNO26h4Q/formResponse';
        let logEntryId = 'entry.558332813';
        let thEntryId = 'entry.22586929';
        let noteEntryId = 'entry.1726819066';
        let finalTH = (parseInt(th) > 0) ? 'TH '+th : 'None';
        let fullUrl = targetUrl + '?'+ noteEntryId + '=Lootify-' + ver + '&' + thEntryId + '=' + encodeURIComponent(finalTH) + '&' + logEntryId + '=' + encodeURIComponent(logs.join('\n'));
        $.get(fullUrl);
        $.get('https://digimol.net/lootify/api.php?a=paste&th='+th+'&user='+user.id+'&log='+encodeURIComponent(JSON.stringify(runs[0])));
        chat({
            'msg': 'Lootify - Loot log pasted!',
            'color': '#00a0fd',
        });
    }
    function setMenuItem(args, type = 'item') {
        let $item, $img, e;
        args['text'] = args['text'] ? args['text'] : 'Menu item';
        args['clone'] = args['clone'] ? args['clone'] : 'Shops';
        $item = getMenuItem(args['clone'], type).clone();
        if(args['class']) {
            $item.addClass(args['class']);
        }
        if(args['css']) {
            $item.css(args['css']);
        }
        $img = $item.find('img').clone();
        $item.unbind().empty();
        if(type === 'item') {
            $item.append($('<span/>').text(args['text']));
        } else if (type === 'category') {
            $item.append($('<b/>').text(args['text']));
        }
        if (args['icon']) {
            $img.attr('src', args['icon']).prependTo($item);
        }
        args['before'] ? args['before'].before($item) : 1;
        args['after'] ? args['after'].after($item) : 1;
        if (typeof args['click'] === 'function') {
            $item.click(args['click']);
        }
        return $item;
    }
    function getMenuItem(txt, type='item') {
        let $item;
        $.each($('.drawer-' + type), function() {
            if (~$(this).text().indexOf(txt)) {
                $item = $(this);
            }
        });
        return $item;
    }
    function editMenuItem(txt) {
        getMenuItem(txt).text('Hidden').hide();
    }
    function removeMenuItem(txt) {
        getMenuItem(txt).remove();
    }
    function addSetting(args) {
        args['text'] = args['text'] ? args['text'] : 'New setting';
        args['name'] = args['name'] ? args['name'] : args['text'].replace(' ', '-').toLowerCase();
        args['type'] = args['type'] ? args['type'] : 'text';
        args['default'] = args['default'] ? args['default'] : 0;
        let $setting = $('<div/>').css(styles.setting).append($('<span/>')).append($('<input/>'));;
        $setting.find('span').text(args['text']);
        $setting.find('input').addClass(args['name']).attr('type', args['type']);
        switch(args['type']) {
            case 'checkbox':
                $setting.find('input').css(styles.inputCheck);
                break;
            case 'number':
                $setting.find('input').css(styles.inputNumber);
                break;
        }
        if (args['min']) {
            $setting.find('input').attr('min', args['min']);
        }
        if (args['max']) {
            $setting.find('input').attr('max', args['max']);
        }
        let val = window.localStorage.getItem(getUsername() + '-' + args['name']);
        if (args['type'] === 'checkbox') {
            val = val ? val : args['default'];
            val = val == 'true' ? true : false;
            $setting.find('input').prop('checked', val);
        }
        if (val) {
            $setting.find('input').val(val)
        } else {
            $setting.find('input').val(args['default']);
        }
        if (args['change']) {
            $setting.find('input').change(args['change']);
        }
        return $setting;
    }
    /* ############## SOCKET SETUP ############## */
    const sockets = [];
    const nativeWebSocket = window.WebSocket;
    window.WebSocket = function(...args){
        const socket = new nativeWebSocket(...args);
        sockets.push(socket);
        return socket;
    };
    let setupSocket = setInterval(()=> {
        if(sockets.length != 0){
            clearInterval(setupSocket);
            sockets[0].addEventListener('message', (e) => messageHandler(e));
        }
    }, 1000);
    function messageHandler(e) {
        let msg = e.data;
        msg = (msg.match(/^[0-9]+(\[.+)$/) || [])[1];
        if(msg && ~msg.indexOf('"update player"')) {
            let data = JSON.parse(msg.split('Socket'))[1];
            if(~msg.indexOf('activeEnchantments')) {
                if(~msg.indexOf('"portion":"all"')) {
                    user.enchantments = data.value.activeEnchantments;
                    user.id = data.value.id;
                    user.name = data.value.username;
                } else {
                    user.enchantments = data.value[0];
                }
            }
        }
    }
    /* ############## GENERAL LIBRARY ############## */
    function addCommas(nStr) {
        nStr += '';
        let x = nStr.split('.');
        let x1 = x[0];
        let x2 = x.length > 1 ? '.' + x[1] : '';
        let rgx = /(\d+)(\d{3})/;
        while (rgx.test(x1)) {
            x1 = x1.replace(rgx, '$1' + ',' + '$2');
        }
        return x1 + x2;
    }
    function getDate(date) {
        let h = date.getHours();
        let m = date.getMinutes();
        let s = date.getSeconds()
        m = m < 10 ? '0'+m : m;
        s = s < 10 ? '0'+s : s;
        let strTime = h + ':' + m + ':' + s;
        if(~$('.chat-message .message-time-stamp').text().indexOf(' AM]') || ~$('.chat-message .message-time-stamp').text().indexOf(' PM]')) {
            let ampm = h >= 12 ? 'PM' : 'AM';
            h = h % 12;
            h = h ? h : 12;
            strTime = h + ':' + m + ':' + s + ' '  + ampm
        }
        return strTime;
    }
    function getTime() {
        let count = 0;
        $.each(timer.starts, function(k, start) {
            let stop = !timer.stops[k] ? new Date() : timer.stops[k];
            count += +stop - +start;
        });
        let s = Math.floor((count /  1000)) % 60;
        let m = Math.floor((count / 60000)) % 60;
        let h = Math.floor((count / 3600000)) % 24;
        let d = Math.floor((count / 86400000)) % 7;
        let w = Math.floor((count / 604800000)) % 52;
        let y = Math.floor((count / 31557600000));
        let timeStr = '';
        timeStr += (y>0) ? y+'Y ' : '';
        timeStr += (w>0) ? w+'W ' : '';
        timeStr += (d>0) ? d+'D ' : '';
        timeStr += (h>0) ? h+'H ' : '';
        timeStr += (m>0) ? m+'M ' : '';
        timeStr += (s>0) ? s+'S ' : '';
        time = s;
        return timeStr;
    }
    function sortObject(o) {
        var sorted = {},
            key, a = [];
        for (key in o) {
            if (o.hasOwnProperty(key)) {
                a.push(key);
            }
        }
        a.sort();
        for (key = 0; key < a.length; key++) {
            sorted[a[key]] = o[a[key]];
        }
        return sorted;
    }
})();