您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Travel helper for TornPDA: exports flower/plushie points, works during flights by using the "items" API selection. Merges all sources automatically.
当前为
// ==UserScript== // @name 🌺 🐫 Points Exporter (Above PDA) — Works While Flying // @namespace http://tampermonkey.net/ // @version 3.5.0 // @description Travel helper for TornPDA: exports flower/plushie points, works during flights by using the "items" API selection. Merges all sources automatically. // @author Nova // @match https://www.torn.com/page.php?sid=travel* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function() { 'use strict'; if (!/page\.php\?sid=travel/.test(location.href)) return; // --- ITEMS LISTS --- const FLOWERS = { "Dahlia": "MX 🇲🇽", "Orchid": "HW 🏝️", "African Violet": "SA 🇿🇦", "Cherry Blossom": "JP 🇯🇵", "Peony": "CN 🇨🇳", "Ceibo Flower": "AR 🇦🇷", "Edelweiss": "CH 🇨🇭", "Crocus": "CA 🇨🇦", "Heather": "UK 🇬🇧", "Tribulus Omanense": "AE 🇦🇪", "Banana Orchid": "KY 🇰🇾" }; const PLUSHIES = { "Sheep Plushie": "B.B 🏪", "Teddy Bear Plushie": "B.B 🏪", "Kitten Plushie": "B.B 🏪", "Jaguar Plushie": "MX 🇲🇽", "Wolverine Plushie": "CA 🇨🇦", "Nessie Plushie": "UK 🇬🇧", "Red Fox Plushie": "UK 🇬🇧", "Monkey Plushie": "AR 🇦🇷", "Chamois Plushie": "CH 🇨🇭", "Panda Plushie": "CN 🇨🇳", "Lion Plushie": "SA 🇿🇦", "Camel Plushie": "AE 🇦🇪", "Stingray Plushie": "KY 🇰🇾" }; const ALL_ITEMS = { ...FLOWERS, ...PLUSHIES }; // --- STYLES --- GM_addStyle(` #pointsExporter { position: fixed; top: 42px; left: 15px; z-index: 99999; background: #0b0b0b; color: #eee; font-size: 9px; font-family: monospace; border: 1px solid #444; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.6); padding: 5px; width: 260px; max-height: 65vh; overflow-y: auto; } #pointsExporter h3 { margin: 0; cursor: pointer; font-size: 10px; background: #121212; padding: 4px; border-bottom: 1px solid #333; } #pointsExporterContent { display: none; padding-top: 4px; } .ctrls button { margin: 2px 2px; font-size: 9px; padding: 2px 5px; background: #171717; color: #eee; border: 1px solid #333; border-radius: 3px; } .ctrls button:hover { background: #232323; } .summary { margin-top: 4px; font-weight: 700; font-size: 10px; color: #bcdfff; } .low { color: #ff6060; margin-bottom: 6px; font-weight: bold; } .item-row { display:flex; justify-content:space-between; margin: 2px 0; } .item-name { flex: 1; } .item-loc { color:#bbb; font-size:8.5px; text-align:right; width:60px; } `); const panel = document.createElement('div'); panel.id = 'pointsExporter'; panel.innerHTML = ` <h3>▶ 🌺 🐫 Points Exporter</h3> <div id="pointsExporterContent"> <div class="ctrls"> <button id="exp_refresh">Refresh</button> <button id="exp_setkey">Set API Key</button> <button id="exp_resetkey">Reset Key</button> </div> <div id="exp_status">Waiting for API key...</div> <div class="summary" id="exp_summary"></div> <div id="exp_list"></div> </div> `; document.body.appendChild(panel); const header = panel.querySelector('h3'); const content = panel.querySelector('#pointsExporterContent'); header.addEventListener('click', () => { const open = content.style.display === 'block'; content.style.display = open ? 'none' : 'block'; header.textContent = (open ? '▶' : '▼') + ' 🌺 🐫 Points Exporter'; }); const apiKeyStored = GM_getValue('tornAPIKey', null); let apiKey = apiKeyStored || null; const status = panel.querySelector('#exp_status'); const summary = panel.querySelector('#exp_summary'); const list = panel.querySelector('#exp_list'); panel.querySelector('#exp_setkey').onclick = () => { const newKey = prompt('Enter your Torn API key (needs "items" permission):', apiKey || ''); if (newKey) { apiKey = newKey.trim(); GM_setValue('tornAPIKey', apiKey); status.textContent = 'API key saved.'; loadData(); } }; panel.querySelector('#exp_resetkey').onclick = () => { GM_setValue('tornAPIKey', null); apiKey = null; status.textContent = 'API key cleared.'; }; panel.querySelector('#exp_refresh').onclick = () => loadData(); // --- Fetch items via "items" (works during flights) --- async function loadData() { if (!apiKey) { status.textContent = 'No key. Please set API key.'; return; } status.textContent = 'Fetching your items (works during flight)...'; try { const res = await fetch(`https://api.torn.com/user/?selections=items&key=${apiKey}`); const data = await res.json(); if (data.error) { status.textContent = `API error: ${data.error.error} (${data.error.code})`; return; } const itemList = data.items || {}; const totals = {}; // Sum counts for each name we care about for (const id in itemList) { const entry = itemList[id]; const name = entry.name; if (ALL_ITEMS[name]) { totals[name] = (totals[name] || 0) + entry.quantity; } } renderUI(totals); status.textContent = 'Updated successfully ✅'; } catch (err) { status.textContent = `Error fetching: ${err.message}`; } } // --- UI Rendering --- function renderUI(totals) { const flowerCounts = Object.entries(FLOWERS).map(([name, loc]) => ({ name, loc, qty: totals[name] || 0 })); const plushCounts = Object.entries(PLUSHIES).map(([name, loc]) => ({ name, loc, qty: totals[name] || 0 })); const flowerMin = Math.min(...flowerCounts.map(i => i.qty)); const plushMin = Math.min(...plushCounts.map(i => i.qty)); const sets = flowerMin + plushMin; const points = sets * 10; summary.textContent = `Sets: ${sets} | Points: ${points}`; const lowFlower = flowerCounts.reduce((a, b) => (a.qty < b.qty ? a : b)); const lowPlush = plushCounts.reduce((a, b) => (a.qty < b.qty ? a : b)); let html = ''; html += `<div class="low">🌸 Low flower: ${lowFlower.name} (${lowFlower.qty}) — ${lowFlower.loc}</div>`; html += `<div class="low">🧸 Low plushie: ${lowPlush.name} (${lowPlush.qty}) — ${lowPlush.loc}</div>`; html += `<div><b>🌸 Flowers:</b></div>`; flowerCounts.forEach(i => html += `<div class="item-row"><span class="item-name">${i.name}</span><span>${i.qty}</span><span class="item-loc">${i.loc}</span></div>`); html += `<div style="margin-top:6px;"><b>🧸 Plushies:</b></div>`; plushCounts.forEach(i => html += `<div class="item-row"><span class="item-name">${i.name}</span><span>${i.qty}</span><span class="item-loc">${i.loc}</span></div>`); list.innerHTML = html; } // --- Init --- if (apiKey) loadData(); })();