BvS Quickfield

GPS for fields

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name           BvS Quickfield
// @namespace      http://userscripts.org/users/dtkarlsson
// @description    GPS for fields
// @include        http*://*animecubed.com/billy/bvs/villagefields*
// @include        http*://*animecubedgaming.com/billy/bvs/villagefields*
// @licence        MIT; http://www.opensource.org/licenses/mit-license.php
// @copyright      2009, Daniel Karlsson
// @version        1.0.4
// @history        1.0.4 New domain - animecubedgaming.com - Channel28
// @history        1.0.3 Now https compatible (Updated by Channel28)
// @history        1.0.2 Fixed various issues (Updated by Sena)
// @history        1.0.1 Added grant permissions (Updated by Channel28)
// @history        1.0.0 Changed to a more console-y design
// @history        1.0.0 Simplified field reordering
// @history        1.0.0 Script now calculates field difficulty range
// @history        1.0.0 Minor tweaks here and there
// @history        0.3.0 Added key reordering by drag and drop
// @history        0.2.0 Change from GM_set/getValue to DOM Storage API
// @history        0.2.0 Redesigned the UI
// @grant          GM_log
// @grant          GM_addStyle
// ==/UserScript==
 
/*
        DOM Storage wrapper class
        Constructor:
                var store = new DOMStorage({"session"|"local"}, [<namespace>]);
        Set item:
                store.setItem(<key>, <value>);
        Get item:
                store.getItem(<key>[, <default value>]);
        Remove item:
                store.removeItem(<key>);
        Get all keys in namespace as array:
                var array = store.keys();
*/
function DOMStorage(type, namespace)
{
        var my = this;
       
        if (typeof(type) != "string")
                type = "session";
        switch (type) {
                case "local": my.storage = localStorage; break;
                case "session": my.storage = sessionStorage; break;
                default: my.storage = sessionStorage;
        }
       
        if (!namespace || typeof(namespace) != "string")
                namespace = "Greasemonkey";
 
        my.ns = namespace + ".";
        my.setItem = function(key, val) {
                try {
                        my.storage.setItem(encodeURIComponent(my.ns + key), val);
                }
                catch (e) {
                        GM_log(e);
                }
        },
        my.getItem = function(key, def) {
                try {
                        var val = my.storage.getItem(encodeURIComponent(my.ns + key));
                        if (val)
                                return val;
                        else
                                return def;
                }
                catch (e) {
                        return def;
                }
        }
        my.removeItem = function(key) {
                try {
                        // Kludge, avoid Firefox crash
                        my.storage.setItem(encodeURIComponent(my.ns + key), null);
                }
                catch (e) {
                        GM_log(e);
                }
        }
        my.keys = function() {
                // Return array of all keys in this namespace
                var arr = [];
                var i = 0;
                do {
                        try {
                                if (i>my.storage.length) {
                                        throw 'error';
                                }
                                var key = decodeURIComponent(my.storage.key(i));
                                if (key.indexOf(my.ns) == 0)
                                        arr.push(key.slice(my.ns.length));
                        }
                        catch (e) {
                                break;
                        }
                        i++;
                } while (true);
                return arr;
        }
}
var DS = new DOMStorage("local", "BvSQuickfield");
 
const KEYDIFF = {
        simple: 0, training: 0, aquafield: 0,
        dimlylit: 5, crumbling: 5, dealersroom: 5,
        blaring: 10, hairy: 10, parkinglot: 10,
        pulsating: 15, worst: 15, core: 15,
        hidden: 20, forbidden: 20, holyground: 20,
        darkside: 20,
        raging: 25, passionate: 25, melody: 25,
        cursed: 40, filthy: 40, noodleshop: 40,
        chosen: 60, hopeless: 60, nothingness: 60,
        brilliant: 65, delicious: 65, dancefloor: 65,
        beautiful: 70, passedover: 70, touchstone: 70,
        corrupted: 80, despaired: 80, paradise: 80,
        sickened: 100, imprisoned: 100, fallenangel: 100,
        merciless: 130, grieving: 130, furnace: 130
};
 
function Field()
{
        var my = this;
 
        my.keys = [];
        my.notes = "";
       
        my.unpack = function(str) {
                if (!str || typeof(str) != "string")
                        return false;
                // Restore from string "<key>|<key>|<key>|<notes>"
                var match = str.match(/(.*)\|(.*)\|(.*)\|(.*)/);
                if (match) {
                        var field = new Field();
                        my.keys = [];
                        my.keys[0] = match[1];
                        my.keys[1] = match[2];
                        my.keys[2] = match[3];
                        my.notes = match[4];
                        return true;
                }
                return false;
        }
        my.pack = function() {
                // Return string "<key>|<key>|<key>|<notes>"
                return my.keys.join("|") + "|" + my.notes;
        }
        my.difficulty = function() {
                return KEYDIFF[keyStyle(my.keys[0])] + KEYDIFF[keyStyle(my.keys[1])] +
                        KEYDIFF[keyStyle(my.keys[2])];
        }
}
 
function FieldList()
{
        var my = this;
       
        my.fields = [];
        my.load = function(store) {
                my.fields = [];
                var keys = store.keys();
                for (var i in keys) {
                        if (/field(\d+)/.test(keys[i])) {
                                var index = parseInt(RegExp.lastParen);
                                var field = new Field();
                                if (field.unpack(store.getItem(keys[i])))
                                        my.fields[index] = field;
                                else
                                        store.removeItem(keys[i]);
                        } else
                                store.removeItem(keys[i]);
                }
        }
        my.save = function(store) {
                var keys = store.keys();
                for (var i in keys)
                        store.removeItem(keys[i]);
                var i = 0;
                for (var j in my.fields) {
                        store.setItem("field" + i, my.fields[j].pack());
                        i++;
                }
        }
}
var FIELDLIST = new FieldList();
FIELDLIST.load(DS);
 
// Event handlers
 
// Update Add button and difficulty hint
function updateDifficulty()
{
        var f = new Field();
        f.keys = getField();
 
        var dnode = document.evaluate("//form/table/tbody/tr/td[@colspan='2'][contains(text(), 'Stamina')]", document, null,
                XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
        if (dnode) {
                var d = f.difficulty();
                var sta = dnode.textContent.replace(/Stamina.*/, "Stamina");
                dnode.textContent = sta + ", Difficulty: " + d + " - " + (d + 5) + ")";
        }
 
        var button = document.getElementById("addfield");
        if (button)
                button.textContent = "Add " + f.keys.join(" - ");
}
 
function buttonClick(event)
{
        var id = event.target.getAttribute("id");
        if (/remove(\d+)/.test(id)) {
                var index = parseInt(RegExp.lastParen);
                removeField(index);
        } else if (/setfield(\d+)/.test(id)) {
                var index = parseInt(RegExp.lastParen);
                setField(FIELDLIST.fields[index].keys);
                updateDifficulty();
        } else if (/addfield/.test(id)) {
                addField();
        }
}
 
var dragging = null;
var hover = null;
var prevHover = null;
function mousedownEvent(event)
{
        // Find td with class = "key"
        var cl = event.target.getAttribute("class");
        if (!/key/.test(cl))
                return;
 
        // Get parent tr
        dragging = event.target.parentNode;
        event.preventDefault();
        window.addEventListener('mouseup', mouseupEvent, true);
        window.addEventListener('mousemove', moveEvent, true);
}
 
function moveEvent(event)
{
        if (!dragging)
                return;
        event.preventDefault();
        var cl = event.target.getAttribute("class");
        if (!/key/.test(cl)) {
                window.removeEventListener('mouseup', mouseupEvent, true);
                window.removeEventListener('mousemove', moveEvent, true);
                dragging = null;
                hover = null;
                prevHover = null;
        }
        hover = event.target.parentNode;
 
        var r1 = parseInt(dragging.id.replace(/row/, ""));
        var r2 = parseInt(hover.id.replace(/row/, ""));
        if (r1 != r2) {
                var f = FIELDLIST.fields[r1];
                FIELDLIST.fields[r1] = FIELDLIST.fields[r2];
                FIELDLIST.fields[r2] = f;
                FIELDLIST.save(DS);
                updateTable();
                dragging = hover;
        }
}
 
function mouseupEvent(event)
{
        if (!dragging)
                return;
        window.removeEventListener('mouseup', mouseupEvent, true);
        window.removeEventListener('mousemove', moveEvent, true);
 
        dragging = null;
        hover = null;
        prevHover = null;
}
 
// UI
 
// Return currently selected item from dropdown
function getSelectedItem(xpath)
{
        var dropdown = document.evaluate(xpath, document, null,
                XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
        return dropdown.options[dropdown.selectedIndex].text;
}
 
// Current field keys
function getField()
{
        var keys = [];
        keys[0] = getSelectedItem("//select[@name='key_1']");
        keys[1] = getSelectedItem("//select[@name='key_2']");
        keys[2] = getSelectedItem("//select[@name='key_3']");
        return keys;
}
 
// Set field keys
function setField(keys)
{
        for (var i = 0; i < 3; i++) {
                var dropdown = document.evaluate("//select[@name='key_" + (i + 1) + "']", document,
                        null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
                for (var j in dropdown.options)
                        if (dropdown.options[j].text == keys[i]) {
                                dropdown.selectedIndex = j
                                break;
                        }
        }
        uselessCrap(keys, "cd ");
}
 
// Add a field to DB
function addField(keys)
{
        if (!keys)
                keys = getField();
 
        var notes = prompt("Notes for " + keys.join(" - "), "-");
        if (notes) {
                var field = new Field();
                field.keys = keys;
                field.notes = notes;
                FIELDLIST.fields.push(field);
                FIELDLIST.save(DS);
                updateTable();
                uselessCrap(keys, "mkdir -p ");
        }
}
 
// Change field notes
function changeNotes(index)
{
        var notes = prompt("Notes for " + FIELDLIST.fields[index].keys.join(" - "),
                FIELDLIST.fields[index].notes);
        if (notes) {
                FIELDLIST.fields[index].notes = notes;
                FIELDLIST.save(DS);
                updateTable();
        }
}
 
// Remove a field from DB
function removeField(index)
{
        if (FIELDLIST.fields[index] && confirm("Remove field " + FIELDLIST.fields[index].keys.join(" - ") + "?")) {
                var keys = FIELDLIST.fields[index].keys;
                FIELDLIST.fields.splice(index, 1);
                FIELDLIST.save(DS);
                updateTable();
                uselessCrap(keys, "rm -rf ");
        }
}
 
// Create the UI table
function createTable()
{
        var addtable = document.getElementById("quickfield");
        if (!addtable) {
                addtable = document.createElement("table");
                addtable.setAttribute("id", "quickfield");
                addtable.innerHTML = '<caption><span id="cli">//Quickfield</span>' +
                        '<span class="blink">_</span></caption>' +
                        '<col width="auto"/><col/><col/><col/>' +
                        '<col/><col width="auto"/><thead><tr><td/><td>Key 1</td><td>Key 2</td>' +
                        '<td>Key 3</td><td>Notes</td><td/></tr></thead><tfoot><tr><td colspan="6">' +
                        '<div id="addfield">Add Field</div></td></tr></tfoot><tbody/>';
        }
 
        var form = document.evaluate("//form[@name='field']", document, null,
                XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
        form.parentNode.appendChild(addtable);
       
        document.getElementById("addfield").addEventListener('click', buttonClick, false);
 
        updateTable();
}
 
// Helper: create TD with class=cls and style=sty
function tableData(html, cls, sty)
{
        var td = document.createElement("td");
        td.innerHTML = html;
        if (cls)
                td.setAttribute("class", cls);
        if (sty)
                td.setAttribute("style", sty);
        return td;
}
 
// Helper: remove non-alpha characters and convert to lower case
function keyStyle(key)
{
        if (key) {
                return key.replace(/\W/g, "").toLowerCase();
        }
        return "";
}
 
// Create a div with class="button" and attach eventlistener
function createButton(text, id, onclick)
{
        var div = document.createElement("div");
        div.appendChild(document.createTextNode(text));
        div.setAttribute("class", "button");
        div.setAttribute("id", id);
        div.addEventListener('click', onclick, false);
        return div;
}
 
// Create a field row
function tableRow(n, key1, key2, key3, notes)
{
        n = parseInt(n);
        var tr = document.createElement("tr");
        tr.setAttribute("id", "row" + n);
       
        var td = document.createElement("td");
        var b = createButton("X", "remove" + n, buttonClick);
        b.setAttribute("title", "Remove Field");
        td.appendChild(b);
        tr.appendChild(td);
        tr.appendChild(tableData(key1, "key " + keyStyle(key1)));
        tr.appendChild(tableData(key2, "key " + keyStyle(key2)));
        tr.appendChild(tableData(key3, "key " + keyStyle(key3)));
 
        td = document.createElement("td");
        td.setAttribute("class", "notes");
        td.appendChild(document.createTextNode(notes));
        td.addEventListener('mousedown', function(event) {changeNotes(n);}, false);
        tr.appendChild(td);
       
        td = document.createElement("td");
        b = createButton("Set", "setfield" + n, buttonClick);
        b.setAttribute("title", "Set Field");
        td.appendChild(b);
        tr.appendChild(td);
 
        return tr;
}
 
// Updates UI table, creates and removes rows if needed
function updateTable()
{
        var tbody = document.getElementById("quickfield").getElementsByTagName("tbody")[0];
        tbody.innerHTML = "";
       
        var i;
        for (i in FIELDLIST.fields) {
                var tr = document.getElementById("row" + i);
                if (tr) {
                        // Row exists, update content
                        var tds = tr.getElementsByTagName("td");
                        for (var k = 0; k < 3; k++) {
                                tds[k + 1].textContent = FIELDLIST.fields[i].keys[k];
                                tds[k + 1].setAttribute("class",  "key " + keyStyle(FIELDLIST.fields[i].keys[k]));
                        }
                        tds[4].textContent = FIELDLIST.fields[i].notes;
                        tds[4].setAttribute("title", "Difficulty: " + FIELDLIST.fields[i].difficulty() + " - " +
                                (FIELDLIST.fields[i] + 5));
                } else {
                        // Create new row
                        tr = tableRow(i, FIELDLIST.fields[i].keys[0], FIELDLIST.fields[i].keys[1],
                                FIELDLIST.fields[i].keys[2], FIELDLIST.fields[i].notes);
                        tr.getElementsByTagName("td")[4].setAttribute("title",
                                "Difficulty: " + FIELDLIST.fields[i].difficulty() + " - " +
                                (FIELDLIST.fields[i].difficulty() + 5));
                        tbody.appendChild(tr);
                }
        }
        // Remove remaining rows
        do {
                var tr = document.getElementById("row" + (++i));
                if (tr)
                        tr.parentNode.removeChild(tr);
        } while (tr);
}
 
var tehStuff = {};
function uselessCrap(keys, pre)
{
        if (tehStuff.timer)
                clearTimeout(tehStuff.timer);
        tehStuff.i = 0;
        tehStuff.str = pre;
        if (keys) {
                tehStuff.str += keys.join("/").replace(/\s/g, "_").toLowerCase().replace(/[^a-z_\/]/g, "");
        }
        tehStuff.el = document.getElementById("cli");
        tehStuff.timer = setTimeout(moarCrap, 50);
}
function moarCrap()
{
        if (tehStuff.i > tehStuff.str.length) {
                tehStuff.timer = null;
        } else {
                tehStuff.el.textContent = "# " + tehStuff.str.substr(0, tehStuff.i++);
                tehStuff.timer = setTimeout(moarCrap, 50);
        }
}
 
GM_addStyle("table#quickfield {width: 100%; background-color: black; color: rgb(33%, 100%, 0%); border-collapse: collapse; font-size: 12px;}");
GM_addStyle("#quickfield thead {font-weight: bold;}");
GM_addStyle("#quickfield caption {background-color: black; font-size: 18px; font-weight: bold; margin-top: 6px;}");
GM_addStyle("#quickfield td {border: 1px solid black; text-align: center;}");
GM_addStyle("#quickfield input {width: auto;}");
GM_addStyle("#quickfield td.key {font-variant: small-caps; cursor: move;}");
GM_addStyle("#quickfield td.notes {color: rgb(100%, 66%, 0%); cursor: pointer;}");
GM_addStyle("#addfield {border: 1px solid rgb(25%, 75%, 0%); background-color: black; color: rgb(25%, 75%, 0%); cursor: pointer;}");
GM_addStyle("#addfield:hover {border: 1px solid rgb(33%, 100%, 0%); background-color: rgb(16%, 50%, 0%); color: rgb(33%, 100%, 0%);}");
GM_addStyle("div.button {border: 1px solid rgb(25%, 75%, 0%); background-color: black; color: rgb(25%, 75%, 0%); cursor: pointer;}");
GM_addStyle("div.button:hover {border: 1px solid rgb(33%, 100%, 0%); background-color: rgb(16%, 50%, 0%); color: rgb(33%, 100%, 0%);}");
GM_addStyle("span.blink {text-decoration: blink;}"); // YA RLY
 
// tier 1 key style
GM_addStyle(".simple {color: #FFFFFF; background-color: #006600;}");
GM_addStyle(".training {color: #FFFFFF; background-color: #006666;}");
GM_addStyle(".aquafield {color: #FFFFFF; background-color: #006600;}");
 
// tier 2 key style
GM_addStyle(".dimlylit {color: #FFFFFF; background-color: #006666;}");
GM_addStyle(".crumbling {color: #FFFFFF; background-color: #006600;}");
GM_addStyle(".dealersroom {color: #FFFFFF; background-color: #006666;}");
 
// tier 3 key style
GM_addStyle(".blaring {color: #FFFFFF; background-color: #660000;}");
GM_addStyle(".hairy {color: #FFFFFF; background-color: #660000;}");
GM_addStyle(".parkinglot {color: #FFFFFF; background-color: #660000;}");
 
// tier 4 key style
GM_addStyle(".pulsating {color: #FFFFFF; background-color: #666600;}");
GM_addStyle(".worst {color: #FFFFFF; background-color: #663300;}");
GM_addStyle(".core {color: #FFFFFF; background-color: #666666;}");
 
// tier 5 key style
GM_addStyle(".hidden {color: #000000; background-color: #CCCC00;}");
GM_addStyle(".forbidden {color: #000000; background-color: #CCCC00;}");
GM_addStyle(".holyground {color: #000000; background-color: #CCCC00;}");
 
// tier 6 key style
GM_addStyle(".raging {color: #000000; background-color: #CC0000;}");
GM_addStyle(".passionate {color: #000000; background-color: #CC0000;}");
GM_addStyle(".melody {color: #000000; background-color: #CC0000;}");
 
// tier 7 key style
GM_addStyle(".cursed {color: #FFFFFF; background-color: #006666;}");
GM_addStyle(".filthy {color: #FFFFFF; background-color: #006666;}");
GM_addStyle(".noodleshop {color: #FFFFFF; background-color: #006666;}");
 
// tier 8 key style
GM_addStyle(".chosen {color: #FFFFFF; background-color: #000000;}");
GM_addStyle(".hopeless {color: #FFFFFF; background-color: #000000;}");
GM_addStyle(".nothingness {color: #FFFFFF; background-color: #000000;}");
 
// tier 9 key style
GM_addStyle(".brilliant {color: #FFFFCC; background-color: #666600;}");
GM_addStyle(".delicious {color: #FFFFCC; background-color: #666600;}");
GM_addStyle(".dancefloor {color: #FFFFCC; background-color: #666600;}");
 
// tier 10 key style
GM_addStyle(".beautiful {color: #FFCCCC; background-color: #660000;}");
GM_addStyle(".passedover {color: #FFCCCC; background-color: #660000;}");
GM_addStyle(".touchstone {color: #FFCCCC; background-color: #660000;}");
 
// tier 11 key style
GM_addStyle(".corrupted {color: #660000; background-color: #FF5555;}");
GM_addStyle(".despaired {color: #660000; background-color: #FF5555;}");
GM_addStyle(".paradise {color: #660000; background-color: #FF5555;}");
 
// tier 12 key style
GM_addStyle(".sickened {color: #222222; background-color: #DDDDDD;}");
GM_addStyle(".imprisoned {color: #222222; background-color: #DDDDDD;}");
GM_addStyle(".fallenangel {color: #222222; background-color: #DDDDDD;}");
 
createTable();
document.getElementById("quickfield").addEventListener('mousedown', mousedownEvent, true);
for (var i = 1; i < 4; i++) {
        var input = document.evaluate("//select[@name='key_" + i + "']", document, null,
                XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
        if (input)
                input.addEventListener('change', updateDifficulty, false);
}
updateDifficulty();