avatar
Untitled

Guest 71 22nd Apr, 2024

MARKUP 59.27 KB
                                           
                         // ==UserScript==
// @name         Panel Dodatków NI
// @namespace	 http://the-crudness.xaa.pl/NIAddons/panel.user.js
// @version      3.0.1.15
// @description  Dodaje do wbudowanego panelu dodatków inne dodatki.
// @author       Priweejt
// @include		 http*://*.margonem.com/
// @include		 http*://*.margonem.pl/
// @grant        none
// ==/UserScript==
// ==Changelog==
// 3.0 - w pewnym stopniu ogarnąłem spaghetti jakim to było, cały czas nie jest za dobrze ale już da się nad tym pracować normalnie xD
// 2.6 - w sumie to samo co 2.5
// 2.5 - znów pełno zmian w API, kolejny nowy dodatek
// 2.4 - pierdyliard zmian w API, nowy dodatek, usunięte na obecną chwile dodatki darrefulla bo mu hosting padł czy coś
// 2.3 - nowy dodatek, naprawione loader.require
// 2.2 - włączenie dodatku pokazywanie kolizji dla angielskiego margonem, bo działają już tam widgety. Trochę wewnętrznych zmian w tym skrypcie
// 2.1 - dodatek lepsza walka, trochę zmian w tym kodzie żeby łatwiej się robiło dodatki (event emmitery anyone?)
// 2.0.1 - pierwsza nietestowa wersja
// ==/Changelog==
$(document).ready(() => {
new (function() {
    // check if the script was loaded on the new interface
    if (typeof Engine == "undefined" || typeof parseClanBB == "undefined" || typeof linkify == "undefined") return;

    const addons = this;
    window.priwAddons = this;
    window.API.priw = this;
    const Storage = API.Storage;
    const Templates = API.Templates;
    const protocol = window.location.protocol;

    /*
        CURSOR CSS STYLES
    */
    this.cursors = {
        default: "url("+protocol+"//aldous.margonem.pl/img/gui/cursor/1.png), auto",
        npctalk: "url("+protocol+"//aldous.margonem.pl/img/gui/cursor/2.png), auto",
        fight: "url("+protocol+"//aldous.margonem.pl/img/gui/cursor/3.png), auto",
        grab: "url("+protocol+"//aldous.margonem.pl/img/gui/cursor/4.png), auto",
        pointer: "url("+protocol+"//aldous.margonem.pl/img/gui/cursor/5.png), auto"
    };


    /*
        ADDON LIST
        holds addon data
    */
    this.list = {
        /*priw_ntpd: { Eee, nie mam chyba kodu tego xD Jak ktoś BARDZO chce to mogę zrobić nowy
            namePL: "Notatnik",
            nameEN: "Notepad",
            descPL: "Dodaje prosty notatnik, dostępny pod torbami.",
            descEN: "Adds a simple notepad in the area under the bags.",
            urlPL: "http://priweejt.ct8.pl/NIAddons/get/notepadNI.js?",
            urlEN: "http://priweejt.ct8.pl/NIAddons/get/notepadNI.js?"
        },*/
        priw_extl: {
            namePL: "Instalator zewnętrznych skryptów",
            nameEN: "External script loader",
            descPL: "Pozwala instalować zewnętrzne dodatki przez wpisanie adresu do skryptu.",
            descEN: "Allows installing external scripts from a given url.",
            urlPL: protocol+"//priw8.com/margo/addon/extl/extl.js",
            //urlPL: "http://127.0.0.1:8080/NIextLoader.js?",
            urlEN: protocol+"//priw8.com/margo/addon/extl/extl.js"
        },
        priw_mmp: {
            namePL: "miniMap+",
            nameEN: "miniMap+",
            descPL: "Dodaje do gry wielofunkcyjną minimapę. Domyślnie otwiera sie klawiszem [R]",
            descEN: "Adds a multifunctional minimap. Default hotkey to open it is set to [R]. Note that it hasn't been translated to English.",
            //urlPL: "http://127.0.0.1:8080/mmp.js",
            urlPL: protocol+"//priw8.com/margo/addon/mmp/mmp.js",
            urlEN: protocol+"//priw8.com/margo/addon/mmp/mmp.js"
        },
        priw_tth: {
            namePL: "Titan Helper+",
            nameEN: "Titan Helper+",
            descPL: "Pomimo nazwy dodatek przydatny nie tylko na tytanach. Pokazuje wiele dodatkowych informacji w walce, takich jak ile tur działają już spowolnienia i inne umki, jaki cios specjalny ładuje tytan, i wiele innych rzeczy.",
            descEN: "Despite the name, useful not only for titan fights. It shows a lot of extra information during battles, such as how many turns ago slowdowns and other spells were casted, what special attack is currently being charged by a titan, and numerous other nice things.",
            //urlPL: "http://127.0.0.1:8080/thp.js",
            urlPL: protocol+"//priw8.com/margo/addon/thp/thp.js",
            urlEN: protocol+"//priw8.com/margo/addon/thp/thp.js"
        },
        priw_changeCharacter: {
            namePL: "Change character",
            nameEN: "Change character",
            descPL: "Pozwala na błyskawiczne zmienianie postaci na aktualnym świecie: <a href='https://imgur.com/hnJ6wQ3' target='_blank'>wyglada tak</a>. Kolejność postaci można zmienić klikając na którąś ppm.",
            descEN: "Allows quickly switching between characters on the current world: <a href='https://imgur.com/hnJ6wQ3' target='_blank'>looks like this</a>. The order in which the characters are displayed can be changed by right-clicking one of them.",
            urlPL: protocol+"//priw8.com/margo/addon/cc/cc.js",
            urlEN: protocol+"//priw8.com/margo/addon/cc/cc.js"
        },
        priw_PartyStats: {
            namePL: "Statystyki grupy",
            nameEN: "Party stats",
            descPL: "Wyświetla w oknie grupy informacje o profesjach i poziomach jej członków. Powiadamia też o za dużej różnicy poziomów w grp (zaznaczając min/max lvl na czerwono - może nie działać jak należy na światach prywatnych, bo tam chyba inny wzorek).",
            descEN: "Displays info about party members (profession, level) in the party window. It also notifies you if the level difference of the party members is too high (by making the min/max level display red).",
            urlPL: protocol+"//priw8.com/margo/addon/PartyStats/PartyStats.js",
            urlEN: protocol+"//priw8.com/margo/addon/PartyStats/PartyStats.js"
        },
        priw_instantTurnNotif: {
            namePL: "Natychmiastowe powiadomienie o turze",
            nameEN: "Instant turn notification",
            descPL: "Zamiast po 5s, dźwięk powiadomienia o turze jest odtwarzany od razu.",
            descEN: "Makes the turn notification sound play instantly, rather than playing it after 5 seconds.",
            urlPL: protocol+"//priw8.com/margo/addon/instantTurnNotif/instantTurnNotif.js",
            urlEN: protocol+"//priw8.com/margo/addon/instantTurnNotif/instantTurnNotif.js"
        },
        priw_npcIconRemover: {
            namePL: "Usuwacz ikon NPC",
            nameEN: "NPC icon remover",
            descPL: "Usuwa ikonki leczenia, depozytu, sklepu, poczty i hotelu nad NPCami.",
            descEN: "Removes heal, deposit, shop, mail and inn icons from NPCs.",
            urlPL: protocol+"//priw8.com/margo/addon/npcIconRemover/npcIconRemover.js",
            urlEN: protocol+"//priw8.com/margo/addon/npcIconRemover/npcIconRemover.js"
        },
    }
    this.addonIds = Object.keys(addons.list);


    /* 
        COMMON FUNCTIONS
    */
    function error(module, txt) {
        console.error(`priwAddonPanel::${module}: ${txt}`);
    }

    function warn(module, txt) {
        console.warn(`priwAddonPanel::${module}: ${txt}`);
    }

    function log(module, txt) {
        console.warn(`priwAddonPanel::${module}: ${txt}`);
    }


    function detourBefore(obj, key, clb, exArgs=[]) {
        const _prev = obj[key];
        obj[key] = function() {
            const fullArgs = [];
            for (let i=0; i<arguments.length; ++i) {
                fullArgs.push(arguments[i]);
            }
            for (let i=0; i<exArgs.length; ++i) {
                fullArgs.push(exArgs[i]);
            }
            if (!clb.apply(this, fullArgs))
                return _prev.apply(this, arguments);
        }
    }

    function detourAfter(obj, key, clb, exArgs=[]) {
        const _prev = obj[key];
        obj[key] = function() {
            const fullArgs = [];
            for (let i=0; i<arguments.length; ++i) {
                fullArgs.push(arguments[i]);
            }
            for (let i=0; i<exArgs.length; ++i) {
                fullArgs.push(exArgs[i]);
            }
            const ret = _prev.apply(this, arguments);
            clb.apply(this, fullArgs);
            return ret;
        }
    }

    /*
        DICTIONARY MODULE
        provides simple dictionary functionality for multiple languages
    */
    this.dictionary = new (function() {
        var list = {};
        this.get = function(id, data) {
            var str = list[id];
            if (!str) return "missing["+id+"]";
            str = str[_l()];
            if (!str) return "nolang["+id+"]";
            for (var i in data) {
                str = str.replace(i, data[i]);
            };
            return str;
        };
        this.add = function(id, txt) {
            list[id] = txt; //txt = {en: "txten", pl: "txtpl"}
        };
        this.addMany = function(data) {
            for (var i=0; i<data.length; i++) {
                this.add(data[i].id, data[i].txt);
            };
        };
    })();
    const _txt = this.dictionary.get;



    /*
        EMITTER CLASS
        probably not properly implemented because I wrote this in 2 minutes
    */
    this.Emmiter = function() {
        var on = [];
        var once = [];
        this.on = function(type, fun) {
            on.push(type, fun);
            return fun;
        };
        this.once = function(type, fun) {
            once.push(type, fun);
            return fun;
        };
        this.off = function(fun) {
            for (var i=1; i<on.length; i+=2) {
                if (on[i] == fun) {
                    return on.splice(i-1, 2);
                };
            };
        };
        this.emit = function(type, data) {
            for (var i=0; i<once.length; i+=2) {
                if (once[i] == type) {
                    once[i+1](data);
                    once.splice(i, 2);
                    i -= 2;
                };
            };
            for (var i=0; i<on.length; i+=2) {
                if (on[i] == type) {
                    on[i+1](data);
                }
            };
        };
    };


    /*
        BUTTON MODULE
        create buttons. wowie!
    */
    this.Button = class Button {
        constructor(options) {
            /* 
                example options {
                    type?: "className", (defaults to "small")
                    label: "black label",
                    clb: button => alert("siema")
                }
            */
            this.$ = API.Templates.get("button")[0];
            this.$.classList.add(options.type ? options.type : "small");
            this.$.addEventListener("click", options.clb);
            this.setLabel(options.label);
        }

        get$() {
            return this.$;
        }

        setLabel(label) {
            this.$.querySelector(".label").innerText = label;
        }
    }



    /*
        WINDOW MODULE
        wrapper of the normal API.Window for convenience
    */
    this.Window = class Window {
        /* =OPTIONS=
          WYMAGANE:
            /Jedno z dwóch:
                -txt: zawartość HTML okna
                -element: element do podpięcia do zawartości okna
            /
            -header: nagłówek okna
          OPCJONALNE
            -likemAlert: bool, czy okno ma posiadać klasę mAlert (default: false)
            -noClose: bool, czy ma zostać usunięty przycisk zamykania (default: false)
            -callbacks: array, taki sam jak ma mAlert w drugim argumencie (default: [])
            -onclose: f, funkcja jaka wykona się przy zamknięciu okna (default: none)
            -css: style css które będą nadane oknu
        */
        constructor(options) {
            this.wnd = window.Engine.windowManager.add({
                content: " ", // Needs to have a non-falseish value because NI is actual hot garbage
                nameWindow: options.header || " ", // Same thing here!
                parentObj: null,
                title: options.header,
                onclose: options.onclose
            });
            this.wnd.addNameToWindow(options.header);
            this.$ = this.wnd.$[0];
            this.$content = document.createElement("div");
            this.$userContent = document.createElement("div");
            this.$content.appendChild(this.$userContent);

            // this.wnd.title(options.header);

            if (typeof options.txt != "undefined")
                this.$userContent.innerHTML = options.txt;
            else if (typeof options.element != "undefined")
                this.$userContent.appendChild(options.element);

            if (options.likemAlert)
                this.$.classList.add("mAlert");

            if (options.noClose) {
                const $close = this.getCloseBtt();
                if ($close)
                    $close.parentElement.removeChild($close);
            }

            if (options.callbacks) {
                for (let i=0; i<options.callbacks.length; ++i) {
                    const data = options.callbacks[i];
                    const btt = new addons.Button({
                        label: data.txt,
                        clb: data.clb
                    });
                    this.$content.appendChild(btt.get$());
                }
            }

            if (options.css) {
                Object.assign(this.$.style, options.css);
            }

            this.wnd.content(this.$content);
            this.wnd.addToMAlertLayer();
            this.wnd.setWndOnPeak();
            this.wnd.center();
            //addons.modules.Interface.$mLayer[0].appendChild(this.$);
        }

        getCloseBtt() {
            const $close = this.$.querySelector(".close-button-corner-decor");
            if ($close) {
                return $close;
            } else {
                error("Window::constructor", "unable to find close element");
                return null;
            }
        }

        setContent(content) {
            if (typeof content == "string")
                this.$userContent.innerHTML = content;
            else
                this.$userContent.appendChild(content);
        }

        setHeader(header) {
            this.wnd.title(header);
        }

        setLabel(label) {
            this.wnd.label(label);
        }

        appendContent(el) {
            this.$userContent.appendChild(el);
        }

        clearContent() {
            this.$userContent.innerHTML = "";
        }

        close() {
            this.wnd.close();
        }
        getInnerWnd() {
            return this.wnd;
        }
    }


    /*
        EMITTER MODULE
        ...just an instance of the class above.
    */
    this.emmiter = new this.Emmiter();


    /*
        STORAGE MODULE
        stores which addons are installed (that's all)
    */
    this.storage = new (function() {
        this.storageKey = "priwAddons";
        this.storageCache = null;
        this.get = function() {
            if (!this.storageCache) {
                try {
                    this.storageCache = localStorage.getItem(this.storageKey) ? JSON.parse(localStorage.getItem(this.storageKey)) : [];
                } catch(e) {
                    error("storage::get", "bad JSON");
                    return this.storageCache = [];
                }
            };
            return this.storageCache;
        };
        this.set = function(storage) {
            this.storageCache = storage;
            localStorage.setItem(this.storageKey, JSON.stringify(storage));
        };
        this.getAddonState = function(id) {
            var storage = this.get();
            return (storage.indexOf(id) > -1);
        };
        this.toggleAddon = function(id) {
            var storage = this.get();
            if (storage.indexOf(id) > -1) {
                storage.splice(storage.indexOf(id), 1);
            } else {
                storage.push(id);
            };
            this.set(storage);
        };
    })();

    
    /*
        MODULES MODULE (wowie!)
        gets modules from the game, or something
    */
    this.modules = new (function() {
        this.init = function() {
            this.Interface = window.Engine.interface; // no dobra, skoro tak zrobili to fajnie

            this.Console = window.Engine.console; // konsola teraz tez jest dostepna
        };
    })();
    this.modules.init();


    /*
        CONSOLE MODULE
        handles custom commands, allows easier logging etc 
    */
    this.console = new (function() {
        var self = this;
        var Console = null;
        var $content = null;
        var commandLine = null;
        var customCmds = {
            "!help": {
                handler: () => {
                    for (var i in customCmds) {
                        if (customCmds[i].help)
                            window.log("<b>"+i+"</b> - "+customCmds[i].help);
                    }
                }
            }
        };

        this.loadConsoleIfNeeded = function() {
            if (Console == null) {
                if (!window.Engine.console)
                    return false;

                Console = window.Engine.console;
                commandLine = Console.commandLine;
                $content = Console.wnd.$[0].querySelector(".console-content");
                var _sendMessage = commandLine.sendMessage;
                commandLine.sendMessage = function(cmd) {
                    if (!self.cmdExists(cmd)) {
                        _sendMessage.apply(this, arguments);
                    } else {
                        window.log("<i style=color:white>> "+cmd+"</i>");
                        document.querySelector("#console_input").value = "";
                        self.parseCmd(cmd);
                    }
                }
            }
            return true;
        }

        this.newCustomCmd = function(cmd) {
            /* przykładowe cmd:
                cmd = {
                    name: "nazwa komendy",
                    handler: n => console.log(n),
                    [help: "opis co komanda robi"]
                }

            */
            customCmds[cmd.name] = cmd;
        };
        this.cmdExists = function(cmd) {
            cmd = cmd.split(" ")[0];
            return customCmds[cmd] ? true : false;
        }
        this.parseCmd = function(cmd) {
            var args = cmd.split(" ");
            cmd = args.splice(0, 1)[0];
            cmd = customCmds[cmd];
            cmd.handler.apply(window, args);
        }
        this.log = function(txt, level) {
            switch (level) {
                case 1:
                    txt = "<span style='color: yellow'>Warning: "+txt+"</span>";
                break;
                case 2:
                    txt = "<span style='color: #9a6400'>Error: "+txt+"</span>";
                break;
                case 3:
                    txt = "<span style='color: red; font-weight: bold;'>Fatal error: "+txt+"</span>";
                break;
            }
            if (this.loadConsoleIfNeeded()) {
                var $log = document.createElement("div");
                $log.classList.add("console-message");
                $log.innerHTML = txt;
                $content.appendChild($log);
                if (level) {
                    Console.showConNotif();
                };
                if (level == 3) Console.open();
            } else {
                console.warn("Panel dodatków NI: błąd ładowania konsoli, nie można wyświetlić logu w grze");
                console.log(txt);
            }
        }
    })();

    /*
        REQUEST PARSER MODULE
        parsing and modifying sent/received things
    */
    this.requestParser = new (function() {
        // websocket version
        detourBefore(Engine.communication, "send2", (query) => {
            return this.onRequest(query);
        });
        // ajax version
        detourBefore(Engine.communication, "send", (query) => {
            return this.onRequest(query);
        });

        this.onRequest = function(query) {
            if (query.substring(0, 4) == "init" && addons.loader.tryLoadAddons(query)) {
                return true; // addons need to be loaded before init is continued - return true to prevent execution of the original func
            }
            return false;
        }

        detourBefore(Engine.communication, "parseJSON", data => {
            this.emitEvents(data, true);
        });
        detourAfter(Engine.communication, "parseJSON", data => {
            this.emitEvents(data, false);
        });

        detourAfter(Engine.interface, "initBanners", () => {
            addons.emmiter.emit("game-load");
        });
        detourAfter(Engine.interface, "afterUnlock", () => {
            addons.emmiter.emit("interface-load");
        });

        this.emitEvents = function(data, before) {
            for (let i in data) {
                addons.emmiter.emit((before ? "before-" : "")+i, data[i]);
            };
            addons.emmiter.emit((before ? "before-" : "")+"game-response", data);
        };
    })();




    /* 
        LOADER MODULE
        crucial module that loads addons and fires some important events on the emitter
    */
    this.loader = new (function(){
        var self = this;
        var lastAddonId;
        this.addonsLoaded = 0;
        this.waitForInterfaceChanger = false; //eliminuje potencjalną możliwość zagryzienia się z dodatkiem SI2NI

        this.tryLoadAddons = function(query) {
            if (self.addonsLoaded < addons.addonIds.length) {
                const isFirstInit = query.indexOf("configGet=1") > -1;
                if (isFirstInit) {
                    // If first init is being blocked, this needs to be done for proper ServerStorage loading on re-init
                    Engine.setFirstLoadInit1(true);
                }
                window.Engine.setBlockSendNextInit(true);
                this.loadAddon();
                return true;
            } else {
                return false;
            }
        }

        this.loadAddon = function() {
            var id = addons.addonIds[this.addonsLoaded];
            lastAddonId = id;
            if (addons.storage.getAddonState(id)) {
                var addon = addons.list[id];
                if (addon.beforeInstall && addon.beforeInstall()) { //failsafe jakby ktoś coś odwalił
                    addons.storage.toggleAddon(id);
                    return this.onAddonLoad(true);
                };
                if (!$.cachedScript) jQuery.cachedScript=function(e,c){return c=$.extend(c||{},{dataType:"script",cache:!0,url:e}),jQuery.ajax(c)};
                var url = this.getUrl(addon);
                window.__currentAddon = {
                    id: addons.addonIds[this.addonsLoaded],
                    data: addon.data
                };
                if (url.indexOf("?") > -1) url += "&v="+((new Date()).toLocaleDateString());
                else url += "?v="+((new Date()).toLocaleDateString());
                $.cachedScript(url).done(this.onAddonLoad).fail((xhr) => this.failedAddonLoad(id, xhr));
                //$.getScript(url).done(this.onAddonLoad).fail((xhr) => this.failedAddonLoad(id, xhr));
            } else {
                this.onAddonLoad(true);
            };
        };

        this.onAddonLoad = function(notLoaded) {
            if (notLoaded !== true) {
                var addon = addons.list[lastAddonId];
                addons.console.log("addon '"+ (_l() == "pl" ? addon.namePL : addon.nameEN) + "' loaded succesfully");
            };
            self.addonsLoaded++;
            if (self.addonsLoaded < addons.addonIds.length) {
                self.loadAddon();
            } else {
                self.loadExtraAddons();
            };
        };

        var extraLoadFinished = false;
        var extraAddonsLoaded = -1;
        this.loadExtraAddons = function(failed) {
            if (extraAddonsLoaded >= 0 && !failed) addons.console.log("script from "+extraAddons[extraAddonsLoaded]+" loaded succesfully");
            extraAddonsLoaded++;
            if (extraAddonsLoaded < extraAddons.length) {
                var url = extraAddons[extraAddonsLoaded];
                $.cachedScript(url).done(self.loadExtraAddons).fail((xhr) => self.failedExtraAddonLoad(url, xhr));
            } else {
                if (!self.waitForInterfaceChanger) {
                    extraLoadFinished = true;
                    Engine.setBlockSendNextInit(false);
                    Engine.reCallInitQueue();
                };
            };
        };

        this.require = function(url) {
            if (!extraLoadFinished) extraAddons.push(url);
            else throw "Ładowanie już się zakończyło.";
        };

        var extraAddons = [];
        this.failedAddonLoad = function(id, xhr) {
            var addon = addons.list[id];
            //if (_l() == "pl") console.warn("Nie udało się załadować dodatku "+addon.namePL+" ["+this.getUrl(addon)+"] ("+xhr.status + " - "+xhr.statusText+")");
            //else console.warn("Failed to load addon "+addon.nameEN+" ["+this.getUrl(addon)+"] ("+xhr.status + " - "+xhr.statusText+")");
            addons.console.log("failed to load addon '"+(_l() == "pl" ? addon.namePL : addon.nameEN)+"' ("+xhr.status + " - "+xhr.statusText+")", 1);
            this.onAddonLoad(true);
        };
        this.failedExtraAddonLoad = function(url, xhr) {
            //if (_l() == "pl") console.warn("Nie udało się załadować skryptu z require "+url);
            //else console.warn("Failed to load required script "+url);
            addons.console.log("failed to load script from "+url+" ("+xhr.status + " - "+xhr.statusText+")", 1);
            this.loadExtraAddons(true);
        };
        this.getUrl = function(addon) {
            return _l() == "pl" ? addon.urlPL : addon.urlEN;
        };
    })();


    /* 
        ADDON WINDOW MODULE
        the actual body of the custom addon panel
    */
    this.customPanel = new (function() {
        const self = this;
        this.addedCustomAddons = false;
        this.content = null;
        this.template = null;
        addons.dictionary.addMany([
            {
                id: "priwAddonPanel::label",
                txt: {
                    "pl": "> Dodatki Priweejta <",
                    "en": "> Priw8's addons <"
                }
            },
            {
                id: "priwAddonPanel::title",
                txt: {
                    "pl": "Dodatki Priweejta",
                    "en": "Priw8's addons"
                }
            },
            {
                id: "priwAddonPanel::enableAddon",
                txt: {
                    "pl": "Włącz",
                    "en": "Enable"
                }
            },
            {
                id: "priwAddonPanel::disableAddon",
                txt: {
                    "pl": "Wyłącz",
                    "en": "Disable"
                }
            }
        ])
        this.openCustomAddons = function() {
            const wnd = new addons.Window({
                header: addons.dictionary.get("priwAddonPanel::title"),
                element: self.content
            });
            wnd.setLabel(addons.dictionary.get("priwAddonPanel::title"));
        }
    
        this.addCustomAddonButton = function() {
            const $wnd = window.Engine.addonsPanel.wnd.$[0];
            const $list = $wnd.querySelector(".addon-list");
            const $header = document.createElement("div");
            $header.classList.add("custom-addon-header");
            $header.innerHTML = addons.dictionary.get("priwAddonPanel::label");
            $header.addEventListener("click", this.openCustomAddons);
            $list.appendChild($header);
        };
    
        this.initCss = function() {
            const css = `
                .addon-author {
                    font-size: 75%;
                    text-align: right;
                    color: #333333;
                }
                .custom-addon-header {
                    text-align: center;
                    border-bottom: 1px solid #4b4949;
                    font-size: 125%;
                    color: #777777;
                    height: 70px;
                    line-height: 70px;
                    cursor: pointer;
                }
                .custom-addon-header:hover {
                    color: #AAAAAA;
                }
                .priw-addon {
                    display: flex;
                    flex-direction: row;
                    justify-content: space-between;
                    align-items: center;
                    margin-top: 5px;
                    margin-bottom: 5px;
                    width: 420px;
                    padding: 5px;
                    background: rgba(255, 255, 255, 0.2);
                    border: 1px solid #80808080;
                }
                .priw-addon-name {
                    font-weight: bold;
                }
                .priw-addon-desc {
                    font-size: 90%;
                }
            `;
            $("<style>"+css+"</style>").appendTo("head");
        };

        this.generateSingleAddon = function(data, id) {
            const $addon = this.template.cloneNode(true);
            $addon.querySelector(".priw-addon-name").innerHTML = _l() == "pl" ? data.namePL : data.nameEN;
            $addon.querySelector(".priw-addon-desc").innerHTML = _l() == "pl" ? data.descPL : data.descEN;

            const btt = new addons.Button({
                label: addons.storage.getAddonState(id) ? addons.dictionary.get("priwAddonPanel::disableAddon") : addons.dictionary.get("priwAddonPanel::enableAddon"),
                clb: () => {
                    addons.storage.toggleAddon(id);
                    if (addons.storage.getAddonState(id)) {
                        btt.setLabel(addons.dictionary.get("priwAddonPanel::disableAddon"));
                        btt.$.classList.add("green");
                    } else {
                        btt.setLabel(addons.dictionary.get("priwAddonPanel::enableAddon"));
                        btt.$.classList.remove("green");
                    }
                }
            });
            if (addons.storage.getAddonState(id))
                btt.$.classList.add("green");
            
            $addon.querySelector(".priw-addon-toggle").appendChild(btt.get$());
            return $addon;
        }

        this.generateContent = function() {
            this.content = document.createElement("div");
            for (let id in addons.list) {
                const addon = addons.list[id];
                if ((_l() == "pl" && !addon.disablePL) || (_l() == "en" && !addon.disableEN)) {
                    this.content.appendChild(
                        this.generateSingleAddon(addon, id)
                    );
                }
            }
        };

        this.initTemplate = function() {
            this.template = document.createElement("div");
            this.template.classList.add("priw-addon");
            this.template.innerHTML = `
<div class="priw-addon-info">
    <div class="priw-addon-name"></div>
    <div class="priw-addon-desc"></div>
</div>
<div class="priw-addon-toggle">`
        }

        this.initTemplate();
        this.generateContent();
        this.initCss();
        addons.emmiter.on("game-load", () => {
            detourAfter(Engine.addonsPanel, "manageVisible", () => {
                if (!this.addedCustomAddons) {
                    this.addCustomAddonButton();
                    this.addedCustomAddons = true;
                };
                addons.emmiter.emit("addons-toggle");
            });
        });
    })();


    /* 
        POPUP MENU
        kept for compatibility reasons...
    */
    this.popupMenu = function(menu, e) {
        window.Engine.interface.showPopupMenu(menu, e);
    };

    
    /*
        SETTINGS MODULE
        provides custom settings
    */
    this.settings = new (function() {
        var self = this;
        var extraSettings = [];
        var $extraSettings, $scrollPane;
        addons.dictionary.add("addon_settings", {
            pl: "Ustawienia dodatków",
            en: "Addon settings"
        })
        if (!Storage.get("addonsettings")) {
            Storage.set("addonsettings", {});
        };
        this.init = function() {
            var _old = Engine.settings.toggle;
            Engine.settings.toggle = function() {
                var ret = _old.apply(this, arguments);
                self.manageExtraSettings();
                addons.emmiter.emit("settings-toggle");
                return ret;
            };
        };
        this.updateSettingTable = function() {
            $extraSettings = document.createElement("div");
            $extraSettings.classList.add("seccond-c");

            var $header = document.createElement("h2");
            $header.classList.add("settings-addons");
            $header.innerHTML = "<span>"+_txt("addon_settings")+"</span>";
            $extraSettings.appendChild($header);

            var $list = document.createElement("ul");
            $list.classList.add("hero-options");
            var html = "", setting, enabled;
            for (var i=0; i<extraSettings.length; i++) {
                setting = extraSettings[i];
                enabled = Storage.get("addonsettings/"+setting.id) ? " active" : "";
                html += "<li data-setting_id='"+setting.id+"'><span class='checkbox"+enabled+"'></span><span class='label'>"+setting.txt+"</span></li>";
            };
            $list.innerHTML = html;
            $list.addEventListener("click", this.toggleSetting);
            $extraSettings.appendChild($list);
        };
        this.toggleSetting = function(e) {
            const path = e.composedPath(); // e.path tylko na chrome jest, upsik
            for (var i=0; i<path.length; i++) {
                if (path[i].dataset["setting_id"]) {
                    var li = path[i];
                    var children = li.children;
                    var enabled = !Storage.get("addonsettings/"+li.dataset["setting_id"]);
                    Storage.set("addonsettings/"+li.dataset["setting_id"], enabled);
                    for (var i=0; i<children.length; i++) {
                        if (children[i].classList.contains("checkbox")) {
                            if (enabled) children[i].classList.add("active");
                            else children[i].classList.remove("active");
                            break;
                        };
                    };
                    addons.emmiter.emit("toggle-addon-"+li.dataset["setting_id"], enabled);
                    break;
                };
            };
        };
        this.manageExtraSettings = function() {
            if (!extraSettings.length) return;
            var $settings = document.getElementsByClassName("settings-window")[0];
            if ($settings) {
                //tfw uparłeś się na nieużywanie jquery
                var children = $settings.children;
                for (var i=0; i<children.length; i++) {
                    if (children[i].classList.contains("hero-options-config")) {
                        children = children[i].children[0].children; //xd
                        break;
                    };
                };
                for (var i=0; i<children.length; i++) {
                    if (children[i].classList.contains("scroll-pane")) {
                        $scrollPane = children[i];
                        break;
                    };
                };
                if (!$scrollPane) return console.warn("coś się zepsuło");
                $scrollPane.appendChild($extraSettings);
            };
        };
        this.add = function(data) {
            extraSettings.push(data);
            self.updateSettingTable();
            if (Storage.get("addonsettings/"+data.id) == null) Storage.set("addonsettings/"+data.id, data.default);
        };
        this.get = function(id) {
            return Storage.get("addonsettings/"+id);
        };
        //this.add({
        //	txt: "test",
        //	id: "test-setting",
        //	default: true
        //});
        addons.emmiter.once("interface-load", this.init);
    })();



    /*
        ADDON DISPLAY MODULE
        provide shared area where user can switch between multiple addon displays
    */
    this.addonDisplay = new (function(addons) {
        //TODO
        //zmienić pokazywanie ikonek i nazwy klas bo założenia się trochę zmieniły w trakcie robienia a nazwy zostały
        var self = this,
            list = [],
            movedToWindow = [],
            hidden = true,
            $wrapper,
            $singleWrapper,
            $scrollWrapper,
            $scrollContent,
            $title,
            $bagHide,
            $bag,
            $CLLTable,
            currentDisplay = false,
            loadQueue = [];
        this.add = function(options) {
            if ($wrapper == null) {
                loadQueue.push(options);
                return;
            }
            if (hidden) {
                $wrapper.style["display"] = "block";
                hidden = false;
            }
            var $element = document.createElement("div");
            $element.classList.add("addonDisplay-single-display")
            if (options.noTitle) {
                $element.classList.add("long");
            }
            if (options.noForcedWndHeight) {
                $element.classList.add("noForcedWndHeight");
            }
            if (options.html) {
                $element.innerHTML += options.html;
            } else if (options.element) {
                $element.appendChild(options.element);
            }
            var $shortcut = document.createElement("div");
            if (!options.icon) {
                $shortcut.innerHTML = options.name.charAt(0);
            } else {
                $shortcut.innerHTML = "<img width='25px' height='25px' src='"+options.icon+"'>";
            }
            $shortcut.addEventListener("click", () => {
                this.loadDisplay(options.id);
            });
            $shortcut.addEventListener("contextmenu", e => {
                e.preventDefault();
                this.moveDisplayToWindow(options.id);
            });
            $($shortcut).tip(options.name);
            $scrollContent.appendChild($shortcut);
            list.push({
                $: $element,
                $short: $shortcut,
                id: options.id,
                name: options.name,
                wndStyle: options.wndStyle,
                noTitle: options.noTitle,
                noForcedWndHeight: options.noForcedWndHeight
            })
        }
        this.moveDisplayToWindow = function(id) {
            var display = this.getDisplayById(id);
            display.$short.style["display"] = "none";
            if (currentDisplay == display) {
                //display.$.remove();
                //$title.innerHTML = "";
                //currentDisplay = false;
                for (var i=0; i<list.length; i++) {
                    var disp = list[i];
                    if (disp.id != display.id && movedToWindow.indexOf(disp.id) == -1) {
                        this.loadDisplay(disp.id);
                        break;
                    }
                    if (i+1 == list.length) {
                        currentDisplay = false;
                    }
                }
            }
            if (movedToWindow.indexOf(id) == -1) {
                movedToWindow.push(id);
                Storage.set("addonDisplay/movedToWindow", movedToWindow);
            }
            if (movedToWindow.length == list.length) {
                hidden = true;
                $wrapper.style["display"] = "none";
            }
            this.createDisplayWindow(display);
        }
        this.createDisplayWindows = function() {
            for (var i=0; i<movedToWindow.length; i++) {
                var display = this.getDisplayById(movedToWindow[i]);
                if (display) {
                    this.moveDisplayToWindow(display.id);
                } else {
                    movedToWindow.splice(i,1);
                    i -= 1;
                }
            }
            Storage.set("addonDisplay/movedToWindow", movedToWindow);
        }
        this.createDisplayWindow = function(display) {
            var hwnd = new addons.Window({
                onclose: () => {
                    var html = display.$.parentElement.innerHTML;
                    display.$.remove();
                    hwnd.setContent(html);
                    this.removeDisplayWindow(display);
                    hwnd.getInnerWnd().fadeAndRemove();
                }
            });
            hwnd.$.style.width = "241px;";
            if (!display.noForcedWndHeight) hwnd.$.style.height = display.noTitle ? "290px" : "260px";
            if (display.wndStyle) {
                Object.assign(hwnd.$.style, display.wndStyle);
            }
            hwnd.setHeader(display.noTitle ? "" : display.name);
            hwnd.setContent(display.$);
            const innerWnd = hwnd.getInnerWnd();
            innerWnd.setTransparentWindow();
            innerWnd.changeDraggableContainment('.game-window-positioner'); // zmienili z dragable na draggable, ktoś umie angielski
            //innerWnd.setSavePosWnd("display_"+display.id, {
            //    x: '251',
            //    y: '100'
            //});
            //$('.alerts-layer').append(hwnd.$);
            innerWnd.updatePos();
        }
        this.removeDisplayWindow = function(display) {
            if (movedToWindow.length == list.length) {
                hidden = false;
                $wrapper.style["display"] = "block";
                this.loadDisplay(display.id);
            }
            display.$short.style["display"] = "block";
            movedToWindow.splice(movedToWindow.indexOf(display.id),1);
            Storage.set("addonDisplay/movedToWindow", movedToWindow);
        }
        this.loadDefaultDisplay = function() {
            var lastId = Storage.get("addonDisplay/active");
            if (lastId == null) lastId = list[0].id;
            self.loadDisplay(lastId);
            self.createDisplayWindows();
        }
        this.getDisplayById = function(id) {
            for (var i=0; i<list.length; i++) {
                if (list[i].id == id) return list[i];
            }
            return false;
        }
        this.loadDisplay = function(id) {
            var display = this.getDisplayById(id);
            if (!display) display = list[0];
            if (currentDisplay) {
                $singleWrapper.removeChild(currentDisplay.$);
                currentDisplay.$short.classList.remove("active");
            }
            display.$short.classList.add("active");
            $singleWrapper.appendChild(display.$);
            if (display.noTitle) {
                $title.style["display"] = "none";
                $singleWrapper.classList.add("long");
            } else {
                $title.style["display"] = "block";
                $title.innerHTML = display.name;
                $singleWrapper.classList.remove("long");
            };
            currentDisplay = display;
            Storage.set("addonDisplay/active", id);
            addons.emmiter.emit("display-load-"+id);
        }
        this.tutorial = function() {
            if (Storage.get("addonDisplay/tutorial") || list.length == 0) return;
            new addons.Window({
                header: "Tutorial",
                txt: _l() == "pl" ?
`Wygląda na to, że zainstalowałeś dodatek wykorzystujący mechanikę pokazywania rzeczy pod torbami. Kilka informacji:
<br>- na dole są ikonki dodatków korzystających z tej mechaniki. Klikając je można się między nimi przełączać.
<br>- kliknięcie ikonki prawym przyciskiem myszy spowoduje przeniesienie dodatku spod toreb do oddzielnego okienka,
które można dowolnie przesuwać.
<br>- jeżeli masz mały monitor, to w ustawieniach jest opcja włączenia przycisku do ukrywania toreb, który znajduje się obok zestawów eq.`
                :
`It appears that an addon which uses the so-called addon display system has been installed. You can find it under the bags in your inventory. Usage:
<br>- if you have multiple addons that use this system, you can switch between their displays by using the icons located under the display.
<br>- right-clicking an icon will cause the display to be moved to a separate window, which can then be freely moved.
<br>- in case the display doesn't fit on your screen, you can enable a bag-hiding button in the game settings. Upon enabling, it will appear next to the battleset buttons.
`,
                css: {
                    "max-width": "350px"
                }
            })
            Storage.set("addonDisplay/tutorial", true);
        }
        this.catchCLLTable = function() {
            var timers = document.getElementsByClassName("cll-timers");
            if (timers.length) {
                addons.settings.add({
                    txt: _l() == "pl" ? "Umieszczaj minutniki klanowe pod torbami" : "Show guild timers under the bags",
                    id: "API_clan_timer_display",
                    default: false
                });
                addons.emmiter.on("toggle-addon-API_clan_timer_display", () => message(_l() == "pl" ? "Zmiany będą widoczne po odświeżeniu gry" : "Changes will come into effect once the page has been reloaded"));
                if (!addons.settings.get("API_clan_timer_display")) return;
                while(timers.length) {
                    var $timer = timers[0];
                    $($timer).trigger("mouseenter");
                    $($timer).draggable("disable");
                    Object.assign($timer.style, {
                        "position": "static",
                        "margin-top": "3px",
                        "margin-left": "1px"
                    });
                    var css = $timer.getAttribute("style");
                    $timer.setAttribute("style", css.replace("static;", "static !important;"));
                    var name = $timer.getAttribute("id").split("cll-timers-")[1].replace(/_/g, " ");
                    this.add({
                        name: _l() == "pl" ? "Minutniki klanowe "+name : "Clan timers "+name,
                        element: $timer,
                        id: "cll-timer-"+name,
                        icon: ""+protocol+"//grooove.pl/favicon.ico",
                        noTitle: true
                    })
                }
            }
        }
        this.onGameLoad = function() {
            self.catchCLLTable();
            if (list.length > 0) {
                self.loadDefaultDisplay();
            }
        }
        this.initSettings = function() {
            addons.settings.add({
                txt: _l() == "pl" ? "Przycisk ukrycia toreb" : "Bag hide button",
                id: "API_hide_bag",
                default: false
            });
            var buttonState = addons.settings.get("API_hide_bag");
            this.toggleBagHideBtt(buttonState, true);
            addons.emmiter.on("toggle-addon-API_hide_bag", this.toggleBagHideBtt);

            var show = Storage.get("addonDisplay/showBag");
            if (show == null || !buttonState) show = true;
            this.toggleBag(show);
        }
        this.toggleBagHideBtt = function(show, init) {
            $bagHide.style["display"] = show ? "block" : "none";
            if (!init) self.toggleBag(true);
        }
        this.toggleBag = function(show) {
            show = typeof(show) != "object" ? show : $bag.style["display"] == "none";
            $bag.style["display"] = show ? "block" : "none";
            $bagBG.style["display"] = show ? "block" : "none";
            $bagWrapper.style["height"] = show ? "" : "0px";

            if (show) $wrapper.style["margin-top"] = 0;
            else $wrapper.style["margin-top"] = "-205px";
            Storage.set("addonDisplay/showBag", show);
        }
        this.init = function() {
            if (Storage.get("addonDisplay") == null) {
                Storage.set("addonDisplay", {});
            }
            var moved = Storage.get("addonDisplay/movedToWindow")
            if (moved) movedToWindow = moved;
            $wrapper = document.querySelector(".b_wrapper");
            $wrapper.innerHTML = "";

            $scrollWrapper = document.createElement("div");
            $scrollWrapper.classList.add("addonDisplay-scroll-wrapper");
            $scrollContent = document.createElement("div");
            $scrollContent.classList.add("addonDisplay-scroll-content");
            $scrollWrapper.appendChild($scrollContent);
            $wrapper.appendChild($scrollWrapper);

            $title = document.createElement("div");
            $title.classList.add("addonDisplay-header");
            // $wrapper.appendChild($title);

            $singleWrapper = document.createElement("div");
            $singleWrapper.classList.add("addonDisplay-single-wrapper");
            $wrapper.appendChild($singleWrapper);

            $bagHide = document.createElement("div");
            $bagHide.classList.add("addonDisplay-hide-bag");
            $bagHide.addEventListener("click", this.toggleBag);
            $bagHide.dataset["tip"] = "ukryj/pokaż torbę";

            $bag = document.querySelector(".inventory-grid");
            $bagBG = document.querySelector(".inventory-grid-bg");
            $bagWrapper = document.querySelector(".inventory_wrapper");

            $bagWrapper.appendChild($bagHide);

            var style = `
                .b_wrapper {
                    width: 241px;
                    display: none;
                    background: rgba(0,0,0,0.3);
                    color: white;
                    margin-left: 10px;
                }
                .addonDisplay-single-wrapper {
                    overflow: hidden;
                    width: 100%;
                    padding: 5px;
                    height: 260px;
                }
                .addonDisplay-single-wrapper.long {
                    height: 290px;
                }
                .addonDisplay-single-display {
                    color: white;
                    width: 100%;
                    overflow-y: scroll;
                    overflow-x: hidden;
                    height: 260px;
                    padding-right: 17px;
                    margin-top: 4px;
                }
                .addonDisplay-single-display.long {
                    height: 290px;
                }
                .addonDisplay-single-display.noForcedWndHeight {
                    height: initial;
                }
                .addonDisplay-single-wrapper > .addonDisplay-single-display.long {
                    height: 302px;
                    margin-top: -7px;
                }
                .addonDisplay-header {
                    border-bottom: 1px gray dashed;
                    font-size: 125%;
                    padding: 5px;
                    height: 20px;
                    line-height: 20px;
                }
                .addonDisplay-scroll-wrapper {
                    width: 100%;
                    height: 27px;
                    border-bottom: 1px gray dashed;
                }
                .addonDisplay-scroll-content > div {
                    float: left;
                    width: 24.5px;
                    height: 25px;
                    line-height: 25px;
                    font-size: 110%;
                    text-align: center;
                    border: 1px solid black;
                    border-collapse: collapse;
                    background: rgba(0,0,0,0.08);
                    cursor: url(${protocol}//aldous.margonem.pl/img/gui/cursor/5.png), auto;;
                    transition: background .1s ease-in-out;
                }
                .addonDisplay-scroll-content > div:hover {
                    background: rgba(55,55,55,0.47);
                }
                .addonDisplay-scroll-content > div.active {
                    background: rgba(70,70,70,0.47);
                }
                .addonDisplay-hide-bag {
                    background: url(https://i.imgur.com/PpUPE6G.png);
                    width: 32px;
                    height: 32px;
                    position: absolute;
                    top: -35px;
                    left: 73px;
                    display: none;
                    cursor: ${addons.cursors.pointer};
                }
            `;
            var $style = document.createElement("style");
            $style.innerHTML = style;
            document.head.appendChild($style);
            
            for (let i=0; i<loadQueue.length; ++i) {
                this.add(loadQueue[i]);
            }
            loadQueue.splice(0, loadQueue.length);

            this.initSettings();
            this.tutorial();
            this.onGameLoad();
        }

        addons.emmiter.once("interface-load", () => this.init());
    })(this);

    /*detourBefore(Engine.windowManager, "add", () => {
        console.trace();
    });*/
})();
});
                      
                                       
To share this paste please copy this url and send to your friends
RAW Paste Data
Recent Pastes
Ta strona używa plików cookie w celu usprawnienia i ułatwienia dostępu do serwisu oraz prowadzenia danych statystycznych. Dalsze korzystanie z tej witryny oznacza akceptację tego stanu rzeczy.
Wykorzystywanie plików Cookie
Jak wyłączyć cookies?
ROZUMIEM