您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Combines, organizes and sorts your inventory and calculates the number of shots you have in your weapons.
// ==UserScript== // @name UD Item Combiner, Organizer and Sorter // @description Combines, organizes and sorts your inventory and calculates the number of shots you have in your weapons. // @namespace http://aichon.com // @include http://urbandead.com/map.cgi* // @include http://www.urbandead.com/map.cgi* // @exclude http://urbandead.com/map.cgi?logout // @exclude http://www.urbandead.com/map.cgi?logout // @version 0.0.1.20210919202127 // ==/UserScript== /* Urban Dead Item Combiner, Organizer and Sorter * v1.2.2 * * Copyright (C) 2014 Bradley Sattem -- [email protected] * Copyright (C) 2008 Ville Jokela -- [email protected] * Copyright (C) 2005 Ryan Forsythe -- [email protected] * * Released under the terms of the GNU GPL V2, which can be found at http://www.gnu.org/copyleft/gpl.html * * Changes: * 1.2.2: * * added a "Special" section for items like the DSS Sat Phone that can't be altered in any way * 1.2.1: * * made several items that waste AP when used cease showing up in the inventory * 1.2: * * added NecroTech syringe to Science (a syringe is named like this if you lack NT skills) * * unknown items should work properly now * 1.1: * * items matched with regular expressions (most of the decorations) didn't work. now they do * 1.0: * * complete rewrite to make compatible with Opera and Google Chrome * * merged "Medical" category to "Science" * * all carried radios are now shown entirely separately, so that each of their frequencies can be adjusted individually * * syringes are no longer dumped to Unknown when the character doesn't know how to revive * * christmas trees and lights added, though not tested * * unrecognized items are preserved as they are, and not combined * * "drop item" list is also sorted and duplicates removed * 0.5: (skips over that other dude's obfuscated 0.4) * * new category: decorations * * shows total shots for pistol clips, similar to pistols * * alphabetically sorts items inside categories * * inventory header now looks same as without the script (also in 0.4) * * shows encumbrance percentage (also in 0.4) * * added flavour-melee weapons (also in 0.4) * 0.3: * * Added "kitchen knife" to weapons * * Added "radio" to other items * * Added "radio transmitter" to other items * * Added "binoculars" to other items * * Changed namespace * * Fixed pattern matching bug, non ammo items with brackets(i.e. radio) should be displayed correctly now * 0.2: * * Added "portable generator" to other items. * * Added newline fix (thx Kieren and Joshua). * * Removed some newlines, fixed the namespace. */ var weaponList = [ 'baseball bat', 'cricket bat', 'crowbar', 'fencing foil', 'fire axe', 'flare gun', 'golf club', 'hockey stick', 'length of pipe', 'kitchen knife', 'knife', 'pistol', 'pool cue', 'shotgun', 'ski pole', 'tennis racket', ]; var ammoList = [ 'pistol clip', 'shotgun shell', ]; var bevList = [ 'bottle of beer', 'bottle of wine', ]; var sciList = [ 'DNA extractor', 'first-aid kit', 'NecroTech syringe', // without skills 'revivification syringe', // with skills ]; var otherList = [ 'binoculars', 'book', 'crucifix', 'flak jacket', 'fuel can', 'GPS unit', 'mobile phone', 'newspaper', 'pair of wirecutters', 'poetry book', 'portable generator', 'radio', 'radio transmitter', 'spray can', 'toolbox', 'stale candy', ]; var specialList = [ 'satellite phone' ]; var specialContainer = []; var decoList = [ 'antique mirror', 'blown-glass sculpture', 'terracotta statue', 'clay figurine', 'skull', ]; var wastedClicks = [ 'fire axe', 'flak jacket', 'spray can', 'toolbox', ]; var rexList = [ { rex: 'glass .*', cat: 'Decorations' }, { rex: '.* painting', cat: 'Decorations' }, { rex: '.* urn', cat: 'Decorations' }, { rex: '.* vase', cat: 'Decorations' }, { rex: '.* sculpture', cat: 'Decorations' }, { rex: '.* skeleton', cat: 'Decorations' }, { rex: 'stuffed .*', cat: 'Decorations' }, { rex: '.* tapestry', cat: 'Decorations' }, { rex: '.* lights', cat: 'Decorations' }, { rex: '.* tree', cat: 'Decorations' }, ]; var categoryHash = { 'Weapons': weaponList, 'Ammo': ammoList, 'Science': sciList, 'Beverages': bevList, 'Others': otherList, 'Decorations': decoList, }; // the order in which the categories are printed var categoryList = [ 'Weapons', 'Ammo', 'Science', 'Beverages', 'Others', 'Decorations', 'Unknown', ]; // Unknown items are also uncombined var uncombineList = { 'radio': true, }; var calcShotsList = { 'pistol': { fromExtra: true }, 'shotgun': { fromExtra: true }, 'pistol clip': { multiplier: 6 }, }; function reorganizeInventory() { var preInventory = findPreInventory(); if (!preInventory) // no inventory return; var itemHash = processItems(preInventory.nextSibling); var categoryTable = categorizeItems(itemHash); var table = genTable(categoryTable); preInventory.parentNode.insertBefore(table, preInventory.nextSibling); } function findPreInventory() { var pgraphs = document.evaluate('//td[@class="gp"]/p', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < pgraphs.snapshotLength; i++) { p = pgraphs.snapshotItem(i); if (p.firstChild) if (p.firstChild.textContent == 'Inventory (click to use):') return p.nextSibling; } return null; } function processItems(form) { var iHash = {}; // "itemname" -> { num: "n:o of occurences", command: "?command", extras: [ "<select>"/"<hidden radio stuff>"/"(ammo)" ] } associative array while (isItem(form)) { var input = form.firstChild; var itemName = input.value; if(!isSpecialItem(itemName)) { if(!isWastedClick(itemName)) { var info = iHash[itemName]; if (!info) { info = {}; info.num = 0; var matches = form.action.match(/\?(.*)$/); if (matches) // not sure if this is needed. all items appear to have a use-code info.command = matches[1]; info.extras = []; } info.num++; info.extras.push(getExtra(form)); iHash[itemName] = info; } } else specialContainer.push(form); var oldForm = form; form = form.nextSibling.nextSibling; // skips over the ' ' between items form.parentNode.removeChild(oldForm); } pruneNulls(iHash); return iHash; } function isSpecialItem(itemName) { for(var i = 0; i < specialList.length; i++) if(itemName == specialList[i]) return true; return false; } function isWastedClick(itemName) { for(var i = 0; i < wastedClicks.length; i++) if(itemName == wastedClicks[i]) return true; return false; } function isItem(form) { if (form.nodeName == 'FORM') return true; return false; } function getExtra(form) { var frag = document.createDocumentFragment(); for (var i = 1; i < form.childNodes.length; i++) frag.appendChild(form.childNodes[i].cloneNode(true)); if (frag.childNodes.length) return frag; else return null; } function pruneNulls(iHash) { for (var item in iHash) { if (iHash[item].extras) { oldExtras = iHash[item].extras; newExtras = []; while (oldExtras.length) { var val = oldExtras.shift(); if (val) newExtras.push(val); } if (newExtras.length) iHash[item].extras = newExtras; else iHash[item].extras = null; } } } function categorizeItems(itemHash) { var cHashHash = createCategoryHashHash(); for (var item in itemHash) cHashHash[resolveCategory(item)][item] = itemHash[item]; return cHashHash; } function createCategoryHashHash() { cHashHash = {}; for (var i in categoryList) cHashHash[categoryList[i]] = {}; return cHashHash; } function resolveCategory(item) { var i2cHash = createItemCategoryHash(); var cat = i2cHash[item]; if (cat) return cat; else for (var i = 0; i < rexList.length; i++) { rexItem = rexList[i]; var matches = item.match(rexItem.rex); if (matches) return rexItem.cat; } // found neither in hash nor regexes, thus Unknown return 'Unknown'; } function createItemCategoryHash() { var i2cHash = {}; for (var catName in categoryHash) { itemList = categoryHash[catName]; for (var i in itemList) i2cHash[itemList[i]] = catName; } return i2cHash; } function genTable(categoryTable) { var table = document.createElement('table'); for (var i in categoryList) { var row = genRow(categoryTable[categoryList[i]], categoryList[i]); if (row) table.appendChild(row); } row = genSpecialRow("Special"); if (row) table.appendChild(row); return table; } function genRow(cat, name) { var keys = getHashKeys(cat); if (!keys.length) return null; var row = document.createElement('tr'); var title = document.createElement('td'); title.style.borderBottom = '3px solid #676'; var titletext = document.createTextNode(name); title.appendChild(titletext); row.appendChild(title); var content = document.createElement('td'); content.style.borderBottom = '3px solid #676'; keys.sort(); for (var i in keys) { var item = keys[i]; var add; if (uncombineList[item] || name == 'Unknown') add = uncombineItems(item, cat[item]); else add = genItem(item, cat[item]); content.appendChild(add); content.appendChild(document.createTextNode(' ')); for(var j in specialContainer) { content.appendChild(specialContainer[j]); content.appendChild(document.createTextNode(' ')); } } row.appendChild(content); return row; } function genSpecialRow(name) { if (!specialContainer.length) return null; var row = document.createElement('tr'); var title = document.createElement('td'); title.style.borderBottom = '3px solid #676'; var titletext = document.createTextNode(name); title.appendChild(titletext); row.appendChild(title); var content = document.createElement('td'); content.style.borderBottom = '3px solid #676'; for(var j in specialContainer) { content.appendChild(specialContainer[j]); content.appendChild(document.createTextNode(' ')); } row.appendChild(content); return row; } function genItem(name, info) { var form = document.createElement('form'); form.action = 'map.cgi?' + info.command; form.method = 'POST'; form.className = 'a'; if (info.num > 1) form.appendChild(document.createTextNode(info.num + ' \xD7 ')); // multiplication sign var button = document.createElement('input'); button.setAttribute('class', 'm'); button.setAttribute('type', 'submit'); button.setAttribute('value', name); form.appendChild(button); if (calcShotsList[name]) form.appendChild(calcShots(info, calcShotsList[name])); else if (info.extras) form.appendChild(info.extras[0]); return form; } function calcShots(info, def) { var frag = document.createDocumentFragment(); var shots = 0; if (def.fromExtra) { var gunRex = /\((.)\)/; var str = ' ('; info.extras.sort(sortExtras); for (var i = 0; i < info.extras.length; i++) { var matches = info.extras[i].childNodes[0].textContent.match(gunRex); var n = 1 * matches[1]; shots += n; str += n; if (i + 1 != info.extras.length) str += ', '; } str += ')'; frag.appendChild(document.createTextNode(str)); } else shots = def.multiplier * info.num; frag.appendChild(document.createTextNode(' \u2192 ' + shots)); // right arrow return frag; } function sortExtras(a, b) { if (a.textContent < b.textContent) return -1; else if (a.textContent == b.textContent) return 0; else return 1; } function uncombineItems(name, info) { var frag = document.createDocumentFragment(); if (info.extras) { info.num = 1; for (var i = 0; i < info.extras.length; i++) { info.extras[0] = info.extras[i]; var item = genItem(name, info); frag.appendChild(item); if (i != (info.extras.length - 1)) frag.appendChild(document.createTextNode(' ')); } } else { // pruneNulls() may remove .extras from unknown items for (var i = 0; i < info.num; i++) { var item = genItem(name, info); frag.appendChild(item); if (i != (info.num - 1)) frag.appendChild(document.createTextNode(' ')); } } return frag; } function getHashKeys(hash) { var keys = []; for (var key in hash) keys.push(key); return keys; } function processDropList() { var dropList = document.evaluate('//select[@name="drop"]', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0); var dl = []; if(dropList != null) { for (var i = 0; i < dropList.childNodes.length; i++) dl.push(dropList.childNodes[i].cloneNode(true)); while (dropList.hasChildNodes()) dropList.removeChild(dropList.firstChild); var pruned = pruneDuplicates(dl.sort(sortOptions)); for (var i in pruned) dropList.appendChild(pruned[i]); } } function sortOptions(a, b) { var r; var astr = a.firstChild.textContent; var bstr = b.firstChild.textContent; if (astr < bstr) r = -1; else if (astr == bstr) r = 0; else r = 1; return r; } function pruneDuplicates(dl) { var pruned = [ dl[0] ]; for (var i = 1; i < dl.length; i++) { if (dl[i].value != pruned[pruned.length-1].value) pruned.push(dl[i]); } return pruned; } reorganizeInventory(); processDropList();