您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add bunker bucks calculation to item previews
// ==UserScript== // @name TORN Bunker Bucks Calculator On Item Market Listings // @namespace http://tampermonkey.net/ // @version 1.1 // @description Add bunker bucks calculation to item previews // @author swervelord // @match https://www.torn.com/page.php?sid=ItemMarket* // @grant none // ==/UserScript== (function() { 'use strict'; // Bunker Buck values const bunkerBuckTable = { 'Yellow': { 'Pistol / SMG': 4, 'Melee': 6, 'Shotgun/rifle': 10, 'Armour': 12, 'Heavies': 14 }, 'Orange': { 1: { 'Pistol / SMG': 12, 'Melee': 18, 'Shotgun/rifle': 30, 'Armour': 26, 'Heavies': 42 }, 2: { 'Pistol / SMG': 18, 'Melee': 27, 'Shotgun/rifle': 45, 'Armour': 26, 'Heavies': 63 } }, 'Red': { 1: { 'Pistol / SMG': 36, 'Melee': 54, 'Shotgun/rifle': 90, 'Armour': 108, 'Heavies': 126 }, 2: { 'Pistol / SMG': 54, 'Melee': 81, 'Shotgun/rifle': 135, 'Armour': 108, 'Heavies': 189 } } }; // Hardcoded weapon lists for accurate classification const weaponLists = { 'Armour': [ 'EOD Boots', 'EOD Gloves', 'EOD Helmet', 'EOD Pants', 'EOD Apron', 'Sentinel Helmet', 'Sentinel Apron', 'Sentinel Pants', 'Sentinel Gloves', 'Sentinel Boots', 'Marauder Boots', 'Marauder Gloves', 'Marauder Pants', 'Marauder Body', 'Delta Boots', 'Delta Gloves', 'Delta Gas Mask', 'Delta Pants', 'Delta Body', 'Vanguard Respirator', 'Vanguard Body', 'Vanguard Pants', 'Vanguard Gloves', 'Vanguard Boots', 'Assault Boots', 'Assault Gloves', 'Assault Helmet', 'Assault Pants', 'Assault Body', 'Riot Boots', 'Riot Gloves', 'Riot Pants', 'Riot Body', 'Dune Boots', 'Dune Gloves', 'Dune Helmet', 'Dune Pants', 'Dune Vest' ], 'Heavies': [ 'China Lake', 'Egg Propelled Launcher', 'Flamethrower', 'Milkor MGL', '73 Neutrilux', 'RPG Launcher', 'SMAW Launcher', 'Type 98 Anti Tank', 'Negev NG-5', 'M249 SAW', 'Minigun', 'PKM', 'Rheinmetall MG 3', 'Stoner 96' ], 'Shotgun/rifle': [ 'Benelli M1 Tactical', 'Benelli M4 Super', 'Blunderbuss', 'Homemade Pocket Shotgun', 'Ithaca 37', 'Jackhammer', 'Mag 7', 'Nock Gun', 'Sawed-Off Shotgun', 'AK-47', 'ArmaLite M-15A4', 'Enfield SA-80', 'Heckler & Koch SL8', 'M16 A2 Rifle', 'M4A1 Colt Carbine', 'SIG 550', 'SIG 552', 'Steyr AUG', 'Tavor TAR-21', 'Vektor CR-21', 'XM8 Rifle', 'SKS Carbine' ], 'Melee': [ 'Axe', 'Baseball Bat', 'Bo Staff', 'Bread Knife', 'Butterfly Knife', 'Chain Whip', 'Chainsaw', 'Claymore Sword', 'Cleaver', 'Cricket Bat', 'Crowbar', 'Dagger', 'Diamond Bladed Knife', 'Fine Chisel', 'Flail', 'Frying Pan', 'Golf Club', 'Guandao', 'Hammer', 'Ice Pick', 'Kama', 'Katana', 'Kitchen Knife', 'Knuckle Dusters', 'Kodachi', 'Lead Pipe', 'Leather Bullwhip', 'Macana', 'Metal Nunchakus', 'Naval Cutlass', 'Ninja Claws', 'Pen Knife', 'Poison Umbrella', 'Riding Crop', 'Sai', 'Samurai Sword', 'Scalpel', 'Scimitar', 'Sledgehammer', 'Spear', 'Swiss Army Knife', 'Wooden Nunchaku', 'Yasukuni Sword' ], 'Pistol / SMG': [ 'Beretta 92FS', 'Beretta M9', 'Beretta Pico', 'Desert Eagle', 'Fiveseven', 'Glock 17', 'Luger', 'Magnum', 'Qsz-92', 'Raven MP25', 'Ruger 57', 'S&W M29', 'S&W Revolver', 'Springfield 1911', 'Taurus', 'USP 9mm', 'Uzi', 'AK74U', 'BT MP9', 'MP5 Navy', 'MP5k', 'P90', 'Skorpion', 'TMP', 'Thompson', 'MP 40' ] }; // Function to get item name from the popup function getItemName(itemInfo) { const descriptionElement = itemInfo.querySelector('.description___xJ1N5'); if (descriptionElement) { const boldElement = descriptionElement.querySelector('.bold'); if (boldElement) return boldElement.textContent.trim(); } return ''; } // Function to extract weapon type from item name function getWeaponType(itemName) { if (!itemName) return null; const name = itemName.trim(); // Check hardcoded weapon lists first for (const [category, weapons] of Object.entries(weaponLists)) { if (weapons.includes(name) || weapons.some(weapon => name.includes(weapon) || weapon.includes(name))) { return category; } } // Fallback text-based detection const text = itemName.toLowerCase(); if (text.includes('pistol') || text.includes('smg') || text.includes('uzi') || text.includes('glock') || text.includes('beretta')) return 'Pistol / SMG'; if (text.includes('shotgun') || text.includes('rifle') || text.includes('ak-') || text.includes('m4')) return 'Shotgun/rifle'; if (text.includes('armor') || text.includes('armour') || text.includes('vest')) return 'Armour'; if (text.includes('heavy') || text.includes('minigun') || text.includes('flamethrower')) return 'Heavies'; if (text.includes('melee') || text.includes('knife') || text.includes('sword') || text.includes('bat')) return 'Melee'; return null; } // Function to extract rarity from quality section function getRarity(itemInfo) { let qualityElement = itemInfo.querySelector('.rarity___bDCDD'); if (!qualityElement) qualityElement = itemInfo.querySelector('[class*="rarity"]'); if (qualityElement) { if (qualityElement.className.includes('yellow')) return 'Yellow'; if (qualityElement.className.includes('red')) return 'Red'; if (qualityElement.className.includes('orange')) return 'Orange'; } return null; } // Function to count bonuses function countBonuses(itemInfo) { let bonusCount = 0; itemInfo.querySelectorAll('.title___DbORn').forEach(element => { if (element.textContent.trim() === 'Bonus:') bonusCount++; }); return bonusCount; } // Function to calculate bunker bucks function calculateBunkerBucks(rarity, weaponType, bonusCount) { if (rarity === 'Yellow') { return bunkerBuckTable['Yellow'][weaponType] || null; } else if (rarity === 'Orange' || rarity === 'Red') { if (bonusCount === 0) return null; const bonusKey = bonusCount >= 2 ? 2 : 1; if (bunkerBuckTable[rarity][bonusKey] && bunkerBuckTable[rarity][bonusKey][weaponType]) { return bunkerBuckTable[rarity][bonusKey][weaponType]; } } return null; } // Function to format number with commas function formatNumber(num) { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } // Main function to add bunker bucks to item popup function addBunkerBucks(itemInfo) { if (itemInfo.dataset.bunkerBucksAdded) return; itemInfo.dataset.bunkerBucksAdded = 'true'; const itemName = getItemName(itemInfo); const weaponType = getWeaponType(itemName); const rarity = getRarity(itemInfo); const bonusCount = countBonuses(itemInfo); if (!weaponType || !rarity) return; const bunkerBucks = calculateBunkerBucks(rarity, weaponType, bonusCount); if (bunkerBucks === null) return; const propertiesList = itemInfo.querySelector('.properties___pva_l'); if (!propertiesList) return; // Expand popup height slightly to ensure visibility const previewWrapper = itemInfo.querySelector('.previewAndPropertiesWrapper___hqsZP'); if (previewWrapper) { const currentHeight = parseInt(previewWrapper.style.height) || 203; previewWrapper.style.height = (currentHeight + 40) + 'px'; } // Look for an empty row to populate const allWrappers = propertiesList.querySelectorAll('.propertyWrapper___xSOH1'); let emptyRow = null; for (let wrapper of allWrappers) { const propertyDiv = wrapper.querySelector('.property___hqXXN'); if (propertyDiv && propertyDiv.children.length === 0) { emptyRow = wrapper; break; } } if (emptyRow) { // Populate existing empty row const propertyDiv = emptyRow.querySelector('.property___hqXXN'); propertyDiv.innerHTML = ` <span class="title___DbORn">Bunker Bucks:</span> <div class="valueWrapper___vVHLn t-overflow" data-is-tooltip-opened="false"> <span class="t-overflow">${formatNumber(bunkerBucks)} BB</span> </div> `; } else { // Fallback: create new row const bunkerRow = document.createElement('li'); bunkerRow.className = 'propertyWrapper___xSOH1 property___vsfqU'; bunkerRow.innerHTML = ` <div class="property___hqXXN"> <span class="title___DbORn">Bunker Bucks:</span> <div class="valueWrapper___vVHLn t-overflow" data-is-tooltip-opened="false"> <span class="t-overflow">${formatNumber(bunkerBucks)} BB</span> </div> </div> `; propertiesList.appendChild(bunkerRow); } } // Observer to watch for item popups const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1 && node.classList) { if (node.classList.contains('itemInfoWrapper___nA_eu') || node.classList.contains('itemInfo___mNZ5j')) { const popup = node.classList.contains('itemInfo___mNZ5j') ? node : node.querySelector('.itemInfo___mNZ5j'); if (popup) { setTimeout(() => addBunkerBucks(popup), 100); setTimeout(() => addBunkerBucks(popup), 500); } } } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })();