RW MV calculator & buy/sell calculator (customizable)

click green button, get read out. buttons nxt to left numbers put that number * 'buyperc', on right they copy the number they are on

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         RW MV calculator & buy/sell calculator (customizable)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  click green button, get read out. buttons nxt to left numbers put that number * 'buyperc', on right they copy the number they are on
// @author       Tuit
// @match        https://www.torn.com/war.php?step=rankreport&rankID*
// @grant        none
// @run-at       document-end
// @license MIT
// ==/UserScript==
(function() {
  'use strict';
  const API_KEY = 'PUTYOURAPIHERE'; // put ur API in the ''
  const buyperc=.95 //prcentage of MV u wanna buy/sell at
  // item ids
  const cacheMap = {
    "Armor Cache": 1118,
    "Melee Cache": 1119,
    "Small Arms Cache": 1120,
    "Medium Arms Cache": 1121,
    "Heavy Arms Cache": 1122
  };
  // cache counter
  function extractCacheCounts(text) {
    const counts = {};
    Object.keys(cacheMap).forEach(cache => {
      const match = text.match(new RegExp(`(\\d+)x\\s+${cache}`));
      if (match) counts[cache] = parseInt(match[1], 10);
    });
    return counts;
  }
  // Fetch mvs
  async function fetchCacheMarketValues() {
    const resp = await fetch(`https://api.torn.com/torn/?selections=items&key=${API_KEY}`);
    if (!resp.ok) {
      alert(`API error: ${resp.status}`);
      return null;
    }
    const data = await resp.json();
    if (!data.items) {
      alert("API returned no items data.");
      return null;
    }
    // Extract cache mv
    const mvConstants = {};
    for (const cacheName in cacheMap) {
      const itemId = cacheMap[cacheName];
      mvConstants[itemId] = data.items[itemId]?.market_value || 0;
    }
    return mvConstants;
  }
  // calc tots
  function calculateTotals(counts, marketValues) {
    let total = 0;
    Object.entries(counts).forEach(([cache, count]) => {
      const mv = marketValues[cacheMap[cache]] || 0;
      total += mv * count;
    });
    return total;
  }
  // overlay and ui shit
  function createOverlay(id, label, value, topPos, rightPos) {//if you want to modify overlay stuff do it here, the `${}px` stuff has to be modified in the ovelay section
    const overlay = document.createElement('div');
    Object.assign(overlay, { id, className: 'cache-overlay' });
    Object.assign(overlay.style, {
      position: 'fixed',
      top: `${topPos}px`,
      right: `${rightPos}px`,
      backgroundColor: 'rgba(0, 0, 0, 0.7)',
      color: 'white',
      padding: '8px 12px',
      borderRadius: '4px',
      zIndex: '9999',
      fontSize: '14px',
      fontFamily: 'Arial, sans-serif',
      pointerEvents: 'none'
    });
    overlay.textContent = `${label}: $${value.toLocaleString()}`;
    document.body.appendChild(overlay);
  }
  function removeExistingOverlays() {//this resets overlays, mostly helps for debugging in console, you can probably cut this if u want
    document.querySelectorAll('.cache-overlay').forEach(el => el.remove());
  }
  function addCopyButton(value, topPos, width,right) {//if you want to modify button stuff do it here, the `${}px` stuff has to be modified in the ovelay section
    const button = document.createElement('button');
    Object.assign(button.style, {
      position: 'fixed',
      top: `${topPos}px`,
      right: `${right}px`,
      width:`${width}px`,
      height: '30px',
      backgroundColor: '#4CAF50',
      border: 'none',
      borderRadius: '4px',
      cursor: 'pointer',
      zIndex: '10000'
    });
    button.addEventListener('click', () => {
      const buyVal = Math.round(value * buyperc);//keep in mind that this is not actually taking the value of the thing its next to but instead first variable * buyperc
      const formatted = `$${buyVal.toLocaleString()}`;
      navigator.clipboard.writeText(formatted)
        .catch(err => console.error('Copy failed:', err));//idk what this shit is
    });
    document.body.appendChild(button);
  }
  function addTriggerButton() {//this posittions the trigger button
    const button = document.createElement('button');
    button.id = 'cacheTotalButton';
    button.textContent = 'Calculate Cache Totals';
    Object.assign(button.style, {
      position: 'fixed',
      top: '5px',
      right: '10px',
      padding: '10px 15px',
      backgroundColor: '#4CAF50',
      color: 'white',
      border: 'none',
      borderRadius: '4px',
      cursor: 'pointer',
      zIndex: '10000'
    });
    button.addEventListener('click', async () => {
      removeExistingOverlays();
      //this is a bunch id variables needed for displays, some of these are customizable
      const mvConstants = await fetchCacheMarketValues();
      if (!mvConstants) return; // Stop if API fetch failed
      const topText = document.querySelectorAll('.memberBonusRow___XJqsX')[0]?.innerText || '';
      const bottomText = document.querySelectorAll('.memberBonusRow___XJqsX')[1]?.innerText || '';
      const topCounts = extractCacheCounts(topText);
      const bottomCounts = extractCacheCounts(bottomText);
      const topTotal = calculateTotals(topCounts, mvConstants);
      const bottomTotal = calculateTotals(bottomCounts, mvConstants);
      const mv1118 = mvConstants[1118] || 0;
      const mv1119 = mvConstants[1119] || 0;
      const mv1120 = mvConstants[1120] || 0;
      const mv1121 = mvConstants[1121] || 0;
      const mv1122 = mvConstants[1122] || 0;
      if (topTotal === null || bottomTotal === null) return;
      const topBuy = Math.round(topTotal * buyperc);
      const bottomBuy = Math.round(bottomTotal * buyperc);
      //constants for qol. u dont HAVE to use these
      const opftr=80//overlay, pixels from top, right (this pushes the whole stack down)
      const opftl=5//overlay, pixels from top, left (this pushes the whole stack down)
      const sep=31//seperation distance btw overlays & buttons (all) make ur own l/r o/b things if you are that pedantic (or pay me 5m in torn to do it for you kek)
      const pfrtots=0//pixel from right for total overlays
      const pfrbuys=23//pixel from right buy overlays
      //overlay creation createOverlay(first part doesnt matter, text b4 value, value printed, pixels from top, pixels from right [nothing puts it all the way to the left])
      createOverlay('top-cache-overlay', 'Top Total', topTotal, opftr,pfrtots);
      createOverlay('bottom-cache-overlay', 'Bottom Total', bottomTotal, opftr+(sep*1),pfrtots);
      createOverlay('topbuy', 'Top Buy', topBuy, opftr+(sep*2),pfrbuys);
      createOverlay('bottombuy', 'Bottom Buy', bottomBuy, opftr+(sep*3),pfrbuys);
      createOverlay('',"Armor",mv1118,opftl);
      createOverlay('',"Melee",mv1119,opftl+(sep*1));
      createOverlay('',"Small",mv1120,opftl+(sep*2));
      createOverlay('',"Medium",mv1121,opftl+(sep*3));
      createOverlay('',"Heavy",mv1122,opftl+(sep*4));
      //constants for qol. u dont HAVE to use these
      const bpftr=80 //button, pixels from top, right (this pushes the whole stack down)
      const bpftl=5 //button, pixels from top, left (this pushes the whole stack down)
      const bwr=30 //button, width, right
      const bwl=10 //button, width, left
      // (value to * by buyperc, pixels from top, width, pixels from right)
      addCopyButton(topTotal,bpftr+(sep*2),bwr,0);
      addCopyButton(bottomTotal,bpftr+(sep*3),bwr,0);
      addCopyButton(mv1118,bpftl+(sep*0),bwl);// *0 is not needed here but whatevs
      addCopyButton(mv1119,bpftl+(sep*1),bwl);
      addCopyButton(mv1120,bpftl+(sep*2),bwl);
      addCopyButton(mv1121,bpftl+(sep*3),bwl);
      addCopyButton(mv1122,bpftl+(sep*4),bwl);
    });
    document.body.appendChild(button);
  }
  addTriggerButton();
})();