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

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 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();
})();