KoLE2-alpha

Misc enhancements for kingdom of loathing

当前为 2014-09-15 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        KoLE2-alpha
// @namespace   fnoot/kol/kole2-alpha
// @description Misc enhancements for kingdom of loathing
// @include     http://www.kingdomofloathing.com/*
// @version     0.1
// @grant       none
// ==/UserScript==
(function() {

    var saveSettings = function() {
        localStorage.kole2Settings = JSON.stringify(top.kole.userSettings);
    };

    // used by getSetting() when called before top.kole is initialised
    var userSettingsPreload = typeof localStorage.kole2Settings == "undefined" ? {} : JSON.parse(localStorage.kole2Settings);

    var controlTypes = {
        input: function(name, spec, parent) {
            var input = crel("input", {}, parent);
            input.id = "kole_config_" + name;
            var setValue = function() {
                if (spec.onchange) spec.onchange(input.value);
                top.kole.userSettings[name] = input.value;
                saveSettings();
            };
            input.value = getSetting(name);
            input.onkeyup = setValue;
            input.onpaste = setValue;
        },
        yesno: function(name, spec, parent) {
            var select = crel("select", {}, parent);
            select.id = "kole_config_" + name;
            with(crel("option", {}, select)) {
                innerHTML = "Yes";
                value = 1;
            }
            with(crel("option", {}, select)) {
                innerHTML = "No";
                value = 0;
            }
            select.selectedIndex = getSetting(name) ? 0 : 1;
            select.onchange = function() {
                top.kole.userSettings[name] = this.selectedIndex == 0;
                saveSettings();
            };
        },
        check: function(name, spec, parent) {
            var cbox = crel("input", {}, parent);
            cbox.checked = getSetting(name);
            cbox.id = "kole_config_" + name;
            cbox.type = "checkbox";
            cbox.onclick = function() {
                top.kole.userSettings[name] = this.checked;
                saveSettings();
                if (spec.onchange) spec.onchange();
            }
        },
        spin: function(name, spec, parent) {
            var min = spec.range[0],
                max = spec.range[1];
            var value = getSetting(name);
            var displayCallback = spec.displayCallback || function(v) {
                return v;
            };
            var downButton = crel("button", {}, parent);
            downButton.innerHTML = "<";
            var valueSpan = crel("span", {
                display: "inline-block",
                "margin": "0 6px",
                "width": "50px",
                "text-align": "center"
            }, parent);
            var fixPrecision = function() {
                value = Math.round(value * 100) / 100;
            }
            valueSpan.innerHTML = displayCallback(value);
            var upButton = crel("button", {}, parent);
            upButton.innerHTML = ">";
            downButton.onclick = function() {
                value -= spec.step;
                fixPrecision();
                if (value < min) value = min;
                valueSpan.innerHTML = displayCallback(value);
                top.kole.userSettings[name] = value;
                if (spec.onchange) spec.onchange(value);
                saveSettings();
            };
            upButton.onclick = function() {
                value += spec.step;
                fixPrecision();
                if (value > max) value = max;
                valueSpan.innerHTML = displayCallback(value);
                top.kole.userSettings[name] = value;
                if (spec.onchange) spec.onchange(value);
                saveSettings();
            };
        },
        button: function(name, spec, parent) {
            with(crel("a", {}, parent)) {
                onclick = function() {
                    spec.onclick();
                    return false;
                };
                href = "#" + name;
                innerHTML = spec.buttonCaption;
            }
        },
        raw: function(name, spec, parent) {
            parent.innerHTML = spec.html;
        }
    };

    var getSetting = function(name) {
        var source = typeof top.kole == "undefined" || top.kole == null || typeof top.kole.userSettings == "undefined" ? userSettingsPreload : top.kole.userSettings;
        return typeof source[name] == "undefined" ? configOptions[name].default : source[name];
    };

    var itemLookup = function(fuzzyName) {
        if (!top.kole) return null;
        var matches = [];
        var item = null;
        for (var name in top.kole.itemIds) {
            if (name.trim().toUpperCase().indexOf(fuzzyName.toUpperCase()) > -1) {
                if (name.toLowerCase() == fuzzyName.toLowerCase()) {
                    return {
                        name: name,
                        id: top.kole.itemIds[name]
                    };
                }
                matches.push({
                    name: name,
                    id: top.kole.itemIds[name]
                });
            }
        }
        if (matches.length > 1) {
            return {
                error: "Multiple matches for \"" + fuzzyName + "\". Please be more specific."
            };
        } else if (matches.length == 1) {
            return matches[0];
        }
        return null;
    };

    var configOptions = {
        hoverHints: {
            default: true,
            control: "check",
            caption: "Hover hints",
            description: "Shows information about an item/effect/icon when the mouse pointer hovers over it"
        },
        hintDelay: {
            default: 230,
            caption: "Hint delay (milliseconds)",
            description: "Specifies how long you need to hover over an item/effect/icon before its description is shown",
            control: "spin",
            range: [0, 2000],
            step: 25
        },
        darkness: {
            default: 0.35,
            caption: "Darkness",
            description: "Darkens the whole game; great for headaches and photosensitives!",
            control: "spin",
            range: [0, 0.8],
            step: 0.1,
            onchange: function(value) {
                top.kole.setDarkness(value);
            },
            displayCallback: function(value) {
                return ((value / 0.8) * 100).toFixed(1).replace(/(\d+)\.0+$/, '$1') + "%";
            }
        },
        stayLoggedIn: {
            default: true,
            caption: "Stay logged in",
            description: "Defeats the timeout that logs you out after an idle period by sending a dummy request every two minutes",
            control: "check",
            onchange: function(value) {
                if (value) xhr("main.php", function() {}, false);
            }
        },
        nullifySword: {
            default: true,
            caption: "Fix prepositions",
            description: "Undoes the effect of the Sword",
            control: "check"
        },
        autoFight: {
            default: false,
            caption: "Automatic fighting",
            description: "Always clicks the last item in the combat bar or \"Adventure again\" when available; requires combat bar enabled in KoL options",
            control: "check"
        },
        autoFightDelay: {
            default: 4000,
            caption: "Automatic fighting delay",
            description: "Defines how long to wait before taking an automatic action in a fight",
            control: "spin",
            range: [1000, 10000],
            step: 500,
            displayCallback: function(v) {
                return (v / 1000) + "sec";
            }
        },
        chatHelp: {
            caption: "Chat commands",
            buttonCaption: "Show",
            "description": "Shows a list of chat commands added by KoLE",
            "control": "button",
            onclick: function() {
                var pop = crel("div", {
                    padding: "12px"
                });
                crel("h1", {
                    margin: "0 0 12px 0",
                    "font-weight": "100"
                }, pop).innerHTML = "KoLE Chat Commands";
                crel("p", {
                    "font-size": "small"
                }, pop).innerHTML = "These commands require <i>Modern</i> chat version selected in <a href='account.php?tab=chat'>KoL options</a>";
                pop.appendChild(tabulate([
                    ["<code>/wiki &lt;searchterm&gt;</code>", "Search Coldfront KoL wiki"],
                    ["<code>/qs [amount] &lt;itemname&gt;</code>", "Quicksell item"]
                ], "rgba(0,0,0,0.06"));
                poop(pop);
            }
        },
        donate: {
            caption: "Appreciation",
            control: "raw",
            description: "I am poorly and well below the poverty line. Has this been useful?",
            html: '<form target="_blank" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" style="margin:none;padding:none;display:inline">' +
                '<input type="hidden" name="cmd" value="_s-xclick">' +
                '<input type="hidden" name="hosted_button_id" value="G33Q3HVDX4G3Y">' +
                '<input type="submit" value="Show via PayPal" src="https://www.paypalobjects.com/en_GB/i/btn/btn_donate_SM.gif" border="0" name="submit">' +
                '<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">' +
                '</form>'
        }

    };




    var prepositions = ["about", "above", "across", "after", "against", "along", "among", "around", "at", "before",
        "behind", "below", "beneath", "beside", "between", "beyond", "by", "down", "during", "except",
        "for", "from", "in", "inside", "into", "like", "near", "of", "off", "on", "onto", "out", "outside",
        "over", "past", "through", "throughout", "to", "under", "up", "upon", "with", "within", "without"
    ];



    var nullifySword = function(s) {
        for (var i = 0; i < prepositions.length; i++) {
            var prep = prepositions[i];
            var search = new RegExp(" " + prep, "g");
            s = s.replace(search, "\x09" + prep);
            var search = new RegExp(prep + " ", "g");
            s = s.replace(search, prep + "\x09");
        }
        return s;
    };

    var tabulate = function(data, altColour) {
        var table = crel("table", {
            width: "100%",
            "font-size": "small"
        });
        table.setAttribute("cellspacing", 0);
        table.setAttribute("cellpadding", 4);
        var tb = crel("tbody", {}, table);
        if (data.length == 0) return table;
        var alt = false;
        for (var i = 0; i < data.length; i++) {
            var row = data[i];
            var tr = crel("tr", {}, tb);
            if (alt) tr.style.background = altColour;
            alt = !alt;
            for (var x = 0; x < row.length; x++) {
                var td = crel("td", {}, tr);
                td.innerHTML = row[x];
            }
        }
        return table;
    };

    var applyStyles = function(el, styles) {
        for (var k in styles) {
            el.style.setProperty(k, styles[k]);
            //lazily prepend browser-specific prefixes
            el.style.setProperty("-moz-" + k, styles[k]);
            el.style.setProperty("-webkit-" + k, styles[k]);
        }
    };

    // document.createElement > applyStyles > parent.append shortcut
    var crel = function(tag, styles, parent) {
        var el = document.createElement(tag);
        if (typeof styles != "undefined") applyStyles(el, styles);
        if (typeof parent != "undefined") parent.appendChild(el);
        return el;
    };

    var elX = function(el) {
        return el.offsetParent ? elX(el.offsetParent) + el.offsetLeft : el.offsetLeft;
    };
    var elY = function(el) {
        return el.offsetParent ? elY(el.offsetParent) + el.offsetTop : el.offsetTop;
    };


    var darkCover = crel("div", {
        "position": "fixed",
        "top": "0",
        "left": "0",
        "right": "0",
        "bottom": "0",
        "background": "#000",
        "opacity": 0,
        "pointer-events": "none",
        "z-index": 999999,
    }, document.body);
    var hintBox = crel("div", {
        "position": "absolute",
        "width": "260px",
        "padding": "12px 0px",
        "border": "1px #bbb solid",
        "border-radius": "5px",
        "box-shadow": "2px 2px 3px rgba(0,0,0,0.4)",
        "pointer-events": "none",
        "background": "#fff",
        "opacity": 0,
        "transform": "scale(0.1,0.1)",
        "transition": "100ms opacity ease-out, 100ms transform ease-out, 100ms -moz-transform ease-out, 100ms -webkit-transform ease-out",
        "z-index": 999998,
        "font-size": "small"
    }, document.body);
    setTimeout(function() {
        darkCover.style.transition = "600ms opacity";
    });

    var initialHintWidth = hintBox.clientWidth;
    var showHint = function(forEl, html) {
        forX = elX(forEl);
        forY = elY(forEl);
        hintBox.innerHTML = html;
        hintBox.style.width = initialHintWidth + "px";
        hintBox.style.left = forX + forEl.clientWidth + 12 + "px";
        if ((elX(hintBox) + hintBox.clientWidth) > document.body.clientWidth) {
            hintBox.style.width = document.body.clientWidth - elX(hintBox) + "px";
        }
        //     hintBox.style.left = (forX+forEl.clientWidth+12+hintBox.clientWidth) > document.body.clientWidth
        //      ? forX - (hintBox.clientWidth +12)+"px"
        //      : forX +forEl.clientWidth +12+"px";
        hintBox.style.top = (forY + (hintBox.clientHeight * 1.5)) > document.body.scrollHeight ? document.body.scrollHeight - (hintBox.clientHeight * 1.5) + "px" : forY + "px";
        crel("div", {
            background: "rgba(100, 150, 255,0.04)",
            "position": "absolute",
            "box-shadow": "0 0 22px rgba(100, 150, 255,0.09)",
            "top": "42px",
            "left": "0",
            "right": "0",
            "bottom": "0"
        }, hintBox);
        applyStyles(hintBox, {
            opacity: 1,
            transform: "scale(1,1)"
        });
        hintElement = forEl;
    };

    var hintTimer = null;
    var hintElement = null;

    var xhr = function(url, callback, cached) {
        if (cached && typeof top.kole.xhrCache[url] != "undefined") {
            setTimeout(function() {
                callback(top.kole.xhrCache[url]);
            }, 0);
            return {
                cancel: function() {}
            };
        };
        var canceled = false;
        var req = new XMLHttpRequest();
        var stateChange = function() {
            if (this.readyState == 4) {
                top.kole.xhrCache[url] = this.responseText;
                if (!canceled)
                    callback(this.responseText);
                req.removeEventListener("readystatechange", stateChange);
            }
        };
        req.addEventListener("readystatechange", stateChange, false);
        req.open("GET", url, true);
        req.send();
        return {
            cancel: function() {
                canceled = true;
            }
        }
    };

    var extractDescription = function(url, callback, cached) {
        return xhr(url, function(response) {
            var tempEl = crel("div");
            tempEl.innerHTML = response;
            var scripts = tempEl.querySelectorAll("script");
            for (var i = scripts.length - 1; i >= 0; i--) scripts[i].parentNode.removeChild(scripts[i]);
            callback(tempEl.querySelectorAll("#description")[0].innerHTML);
        }, cached);
    };

    var cancelLastHintCallback = function() {};

    var cancelHint = function() {
        cancelLastHintCallback();
        if (hintTimer !== null) clearTimeout(hintTimer);
        applyStyles(hintBox, {
            opacity: 0,
            transform: "scale(0.9,0.9)"
        });
    };

    // htmlCallback(done(html)) should return {cancel:function(){...}}
    var setHintTimer = function(el, htmlCallback, ___args) {
        cancelHint();
        // show when both timer AND callback async complete
        var asyncRemaining = 2;
        var hintHtml = "";
        var asyncDone = function() {
            asyncRemaining--;
            if (asyncRemaining == 0) {
                showHint(el, hintHtml);
            }
        };
        hintTimer = setTimeout(asyncDone, getSetting("hintDelay"));
        var cancelLastHintCallback = htmlCallback(function(html) {
            hintHtml = html;
            asyncDone();
        }).cancel;
    };


    if (window == top) {
        var whenReady = function(cb) {
            for (var i = 0; i < frames.length; i++)
                if (typeof frames[i].kole == "undefined") {
                    setTimeout(function() {
                        whenReady(cb);
                    }, 200);
                    return;
                }
            cb();
        }
        if (typeof this.kole != "undefined") {
            alert("A browser plugin or KoL update is conflicting with KoLE");
            return;
        }
        window.kole = null;
        whenReady(function() {
            window.kole = {
                setDarkness: function(darkness) {
                    for (var i = 0; i < frames.length; i++) {
                        frames[i].window.kole.setDarkness(darkness);
                    }
                },
                itemIds: typeof localStorage.itemIds == "undefined" ? {} : JSON.parse(localStorage.itemIds),
                xhrCache: {},
                userSettings: userSettingsPreload
            };
        });
    } else {
        window.kole = {
            setDarkness: function(darkness) {
                darkCover.style.opacity = darkness + 0.00001; // fixes gre render bug
            },
            top: top.kole
        };
        kole.setDarkness(getSetting("darkness"));
    }

    var timedClick = function(el, delay, cancelCaption, oncancel) {
        var cancelButton = crel("button", {
            background: "#fff",
            border: "2px #000 solid",
            transition: delay + "ms box-shadow linear",
            "box-shadow": "inset 0 0 0 rgba(255,0,0,0.9)",
            position: "fixed",
            bottom: 0,
            right: 0,
            padding: "4px",
            width: "200px"
        }, document.body);
        applyStyles(el, {
            transition: delay + "ms box-shadow linear, " + delay + "ms border-color linear",
            "box-shadow": "inset 0 0 0 rgba(0,255,0,0.5)",
            "border-color": "rgba(0,255,0,0)"
        });
        cancelButton.innerHTML = cancelCaption;
        var timer = setTimeout(function() {
            el.click();
        }, delay + 100);
        setTimeout(function() {
            cancelButton.style.boxShadow = "inset 208px 0 0 rgba(255,0,0,1)";
            el.style.boxShadow = "inset " + el.scrollWidth + "px 0 0 rgba(0,255,0,0.3)";
            el.style.borderColor = "rgba(0,255,0,1)";
        }, 100);
        window.CLICKEL = el;
        cancelButton.onclick = function() {
            if (oncancel) oncancel();
            clearTimeout(timer);
            document.body.removeChild(cancelButton);
        };
    };


    if (window.name == "mainpane") {
        var openPanel = function() {
            koleButton.disabled = true;
            var panel = crel("div", {
                "position": "fixed",
                "top": "0",
                "left": "0",
                "right": "0",
                "max-height": "100%",
                "box-shadow": "0 0 8px rgba(0,0,0,0.6)",
                "border-bottom": "1px #888 solid",
                "transform": "scale(0.1,0.1)",
                "transform-origin": "100% 0",
                "padding": "12px",
                "overflow": "auto",
                "opacity": 0,
                "z-index": 9001,
                background: "#eef",
                "transition": "220ms all ease-in"
            }, document.body);
            crel("h1", {
                "font-weight": "100"
            }, panel).innerHTML = "KoLE Settings";
            var settingsTable = crel("table", {
                "font-size": "small",
                "width": "100%",
            }, panel);
            settingsTable.setAttribute("cellpadding", 4);
            settingsTable.setAttribute("cellspacing", 0);
            var tbody = crel("tbody", {}, settingsTable);
            var alt = false;
            for (var name in configOptions) {
                alt = !alt;
                var spec = configOptions[name];
                var tr = crel("tr", {
                    background: alt ? "rgba(255,255,255,0.5)" : "transparent"
                }, tbody);
                var labelCell = crel("td", {
                    height: "2em",
                    "width": "200px",
                    "vertical-align": "middle"
                }, tr);
                var label = crel("label", {}, labelCell);
                label.innerHTML = spec.caption;
                label.setAttribute("for", "kole_config_" + name);
                var editCell = crel("td", {
                    "vertical-align": "middle"
                }, tr);
                controlTypes[spec.control](name, spec, editCell);
                if (spec.description) {
                    var descTr = crel("tr", {
                        "font-size": "0.8em",
                        "color": "#666",
                        background: alt ? "rgba(255,255,255,0.5)" : "transparent"
                    }, tbody);
                    var descTd = crel("td", {}, descTr);
                    descTd.innerHTML = spec.description;
                    descTd.setAttribute("colspan", 2);
                }
            }
            with(crel("p", {
                "font-size": "small"
            }, panel)) {
                innerHTML = "Kingdom of Loathing Enhancement <b>alpha</b> by <a href='showplayer.php?who=2362564'>fnoot</a><br>This is an <b>alpha testing</b> version; please report any problems by kmail.";
            }
            var closeButton = crel("button", {
                position: "absolute",
                top: 0,
                right: 0
            }, panel);
            closeButton.innerHTML = "X";
            closeButton.onclick = function() {
                koleButton.disabled = false;
                applyStyles(panel, {
                    opacity: 0,
                    "pointer-events": "none",
                    transform: "scale(0.2,0.2)"
                });
                setTimeout(function() {
                    document.body.removeChild(panel);
                    panel = null;
                }, 2000);
            };
            setTimeout(function() {
                applyStyles(panel, {
                    opacity: 1,
                    transform: "scale(1,1)"
                });
            }, 100)
        };
        var koleButton = crel("button", {
            "position": "fixed",
            "top": "0",
            "right": "0",
            "z-index": 9000
        }, document.body);
        with(koleButton) {
            innerHTML = "KoLE";
            onclick = openPanel;
        }

        if (getSetting("autoFight")) {
            (function() { // auto fighting
                var links = document.querySelectorAll("a");
                var adventureAgainRegex = /Adventure Again \(/;
                for (var i = 0; i < links.length; i++) {
                    if (adventureAgainRegex.test(links[i].innerHTML)) {
                        timedClick(links[i], getSetting("autoFightDelay"), "Cancel automatic fighting", function() {
                            top.kole.userSettings.autoFight = false;
                            saveSettings();
                        });
                        return;
                    }
                }
                var button12 = document.getElementById("button12");
                if (button12 != null) {
                    timedClick(button12, getSetting("autoFightDelay"), "Cancel automatic fighting", function() {
                        top.kole.userSettings.autoFight = false;
                        saveSettings();
                    });
                }
            })();
        }

        setInterval(function() {
            if (getSetting("stayLoggedIn")) {
                xhr("main.php", function() {}, false);
            }
        }, 1000 * 60 * 2);
        var scanItems = function() {
            if (top.kole == null) return;
            var itemIds = top.kole.itemIds;
            var learnedItems = false;
            var itemCells = document.querySelectorAll(".stuffbox table.item .ircm");
            for (var i = 0; i < itemCells.length; i++) {
                var cell = itemCells[i];
                var itemName = cell.innerHTML;
                if (typeof itemIds[itemName] == "undefined") {
                    learnedItems = true;
                    itemIds[itemName] = cell.parentNode.id.replace(/i/, '');
                    //         console.log("Learned item '"+itemName +"' id: "+itemIds[itemName]);
                }
            }
            if (learnedItems) localStorage.itemIds = JSON.stringify(itemIds);
        };
        setInterval(scanItems, 3500);

    } // /mainpane

    if (window.name == "chatpane") {
        var chatLog = function(s) {
            handleMessage({
                type: 'event',
                msg: "<span style='color:#08c'><span style='opacity:0.5'>[</span>kole<span style='opacity:0.5'>]</span></span> " + s
            });
        };
        var chatCommands = {
            wiki: function(args) {
                window.open("http://kol.coldfront.net/thekolwiki/index.php/Special:Search?search=" + encodeURIComponent(args.trim()) + "&go=Go");
            },
            qs: function(args) {
                args = args.trim();
                var amountMatches = args.match(/(\d+|\*)\s+([\w\s]+)/);
                if (amountMatches && amountMatches.length > 1) {
                    var amount = amountMatches[1];
                    args = amountMatches[2];
                } else {
                    var amount = 1;
                }
                var item = itemLookup(args);
                if (item === null) {
                    chatLog("KoLE doesn't know that item! Teach it by opening your inventory.");
                } else if (item.error) {
                    chatLog("" + item.error);
                } else {
                    chatLog("Quickselling " + amount + " x " + item.name);
                    dojax("sellstuff.php?action=sell&ajax=1&type=quant&whichitem%5B%5D=" + item.id + "&howmany=" + amount + "&pwd=" + pwdhash);
                }
            }
        }

        var previousOnload = window.onload;
        window.onload = function() {
            if (previousOnload) previousOnload.apply(this, arguments);
            var oldForm = document.getElementById('InputForm');
            if (oldForm == null) return;
            oldForm = oldForm.parentNode;
            newForm = oldForm.cloneNode(true);
            newForm.style.background = "red";
            oldForm.parentNode.replaceChild(newForm, oldForm);
            var old$inp = $inp;
            $inp = $$("#graf");
            newForm.onsubmit = function(ev) {
                ev.preventDefault();
                var inp = $inp.val();
                var matches = inp.match(/^\/(\w+)(\s+(.*))?/);
                if (matches && matches.length > 0) {
                    var cmd = matches[1];
                    if (typeof chatCommands[cmd] != "undefined") {
                        $inp.val("");
                        chatCommands[cmd].call(this, matches.length > 1 ? matches[2] : undefined);
                        return;
                    }
                }
                old$inp.val(getSetting("nullifySword") ? nullifySword($inp.val()) : $inp.val());
                $inp.val("");
                submitchat(ev);
            };
        };
    };

    var poop = function(htmlOrElement) {
        var cover = crel("div", {
            position: "fixed",
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            background: "rgba(0,0,0,0.2)",
            opacity: 0,
            transition: "200ms all",
            "z-index": 9002
        });
        var win = crel("div", {
            width: "420px",
            margin: "9% auto 0 auto",
            background: "#fff",
            position: "relative",
            transform: "scale(3,3)",
            opacity: 0,
            transition: "300ms all",
            "box-shadow": "1px 1px 6px rgba(0,0,0,0.4)"
        }, cover);
        var winner = crel("div", {
            padding: "12px"
        }, win);
        if (typeof htmlOrElement == "string") {
            winner.innerHTML = htmlOrElement;
        } else {
            winner.appendChild(htmlOrElement)
        }
        with(crel("button", {
            position: "absolute",
            top: 0,
            right: 0
        }, win)) {
            onclick = function() {
                cover.style.opacity = 0;
                applyStyles(win, {
                    "transform": "scale(3,3)",
                    opacity: 0
                });
                setTimeout(function() {
                    document.body.removeChild(cover);
                }, 600);
            };
            innerHTML = "X";
        }
        document.body.appendChild(cover);
        setTimeout(function() {
            cover.style.opacity = 1;
            applyStyles(win, {
                "transform": "scale(1,1)",
                opacity: 1
            });
        }, 100);
    };

    var applyHoverHints = function() {
        var els = document.querySelectorAll("a,img");
        var onclickRegex = /\b(descitem|eff|javascript:poop)\("?([\w\.\?\=]+)"?\b(\s*,\s*(\w+)\b\))?/;
        for (var i = 0; i < els.length; i++) {
            var funcUrls = {
                descitem: "desc_item.php?whichitem=",
                eff: "desc_effect.php?whicheffect=",
                "javascript:poop": ""
            };
            var onclick = els[i].getAttribute("onclick") + "";
            var matches = onclick.match(onclickRegex);
            if (onclick && matches && (matches.length > 0)) {
                if (typeof els[i]['@kole2_hoverhint_init'] == "undefined") {
                    els[i]['@kole2_hoverhint_init'] = true;
                    els[i].style.cursor = "help";
                    els[i].title = "";
                    with({
                            func: matches[1],
                            itemId: matches[2],
                            otherPlayer: matches[4]
                        }) {
                            els[i].addEventListener("mouseenter", function() {
                                cancelHint();
                                if (!getSetting("hoverHints")) return;
                                hintElement = this;
                                var query = typeof otherPlayer == "undefined" ? itemId : itemId + "&otherplayer=" + otherPlayer;
                                setHintTimer(this, function(callback) {
                                    return extractDescription(funcUrls[func] + query, callback, true);
                                });
                            }, false);
                            els[i].addEventListener("mouseout", function() {
                                if (this == hintElement) cancelHint();
                            }, false);
                        } // with
                } // if not init
            } // if onclick match
        } // for i in els
    }; // applyHoverHints()

    applyHoverHints();
    setInterval(applyHoverHints, 2500);

})();