Torn Pickpocketing Colors

Color codes crimes based on difficulty

// ==UserScript==
// @name         Torn Pickpocketing Colors
// @version      0.5
// @namespace    https://github.com/Korbrm
// @description  Color codes crimes based on difficulty
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @author       TheDawgLives [3733696] tweaked from Korbrm [2931507]
// @license      MIT License
// @match        https://www.torn.com/page.php?sid=crimes*
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  const categoryColorMap = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#74b816",
    Unsafe: "#f59f00",
    Risky: "#f76707",
    Dangerous: "#f03e3e",
    "Very Dangerous": "#7048e8",
  };

  const tier1 = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#f76707",
    Unsafe: "#f03e3e",
    Risky: "#f03e3e",
    Dangerous: "#f03e3e",
    "Very Dangerous": "#7048e8",
  };
  const tier2 = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#37b24d",
    Unsafe: "#f76707",
    Risky: "#f03e3e",
    Dangerous: "#f03e3e",
    "Very Dangerous": "#7048e8",
  };
  const tier3 = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#37b24d",
    Unsafe: "#37b24d",
    Risky: "#f76707",
    Dangerous: "#f03e3e",
    "Very Dangerous": "#7048e8",
  };
  const tier4 = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#37b24d",
    Unsafe: "#37b24d",
    Risky: "#37b24d",
    Dangerous: "#f76707",
    "Very Dangerous": "#7048e8",
  };
  const tier5 = {
    Safe: "#37b24d",
    "Moderately Unsafe": "#37b24d",
    Unsafe: "#37b24d",
    Risky: "#37b24d",
    Dangerous: "#37b24d",
    "Very Dangerous": "#7048e8",
  };

  const markGroups = {
    Safe: [
      "Drunk man",
      "Drunk woman",
      "Homeless person",
      "Junkie",
      "Elderly man",
      "Elderly woman",
    ],
    "Moderately Unsafe": [
      "Classy lady",
      "Laborer",
      "Postal worker",
      "Young man",
      "Young woman",
      "Student",
    ],
    Unsafe: ["Rich kid", "Sex worker", "Thug"],
    Risky: ["Jogger", "Businessman", "Businesswoman", "Gang member", "Mobster"],
    Dangerous: ["Cyclist"],
    "Very Dangerous": ["Police officer"],
  };

  const distractedBonus = ["-34px", "-68px", "-102px", "-170px"];

  function updateDivColors(targetNode) {
    const url = window.location.href;
    if (!url.includes("#/pickpocketing")) {
      return;
    }

    var spanElement = document.querySelector(
      ".value___FdkAT.copyTrigger___fsdzI"
    );

    let tier = 1;
    let pickpocketSkill = 1;
    if (spanElement) {
      const ps = Number(spanElement.textContent);
      if (!isNaN(ps)) {
        pickpocketSkill = ps;
      }
    }
    if (pickpocketSkill < 10) {
      tier = 1;
    } else if (pickpocketSkill < 35) {
      tier = 2;
    } else if (pickpocketSkill < 65) {
      tier = 3;
    } else if (pickpocketSkill < 80) {
      tier = 4;
    } else {
      tier = 5;
    }

    const divElements = targetNode.querySelectorAll(
      ".crime-option:not(.processed)"
    );
    divElements.forEach((divElement) => {
      const titleElement = divElement.querySelector(".titleAndProps___DdeVu");
      if (!titleElement) {
        return;
      }
      const divContent = titleElement
        .querySelector("div")
        .textContent.trim()
        .replace(/ \(.*\)/, "");
      const activityDiv = divElement.querySelector('div[class^="activity"]');

      if (activityDiv) {
        const iconNode = activityDiv.querySelector('div[class^="icon"]');
        const iconOffset = iconNode?.style["background-position-y"];
        const distracted = distractedBonus.indexOf(iconOffset) >= 0;

        console.debug(
          "distracted = " + distracted + " iconOffset: ",
          iconOffset
        );

        const localTier = tier + (distracted ? 1 : 0);

        let tierColorMap = categoryColorMap;

        if (localTier === 1) {
          tierColorMap = tier1;
        } else if (localTier === 2) {
          tierColorMap = tier2;
        } else if (localTier === 3) {
          tierColorMap = tier3;
        } else if (localTier === 4) {
          tierColorMap = tier4;
        } else {
          tierColorMap = tier5;
        }

        for (const category in markGroups) {
          if (
            markGroups[category].some((group) => divContent.includes(group))
          ) {
            titleElement.querySelector("div").style.color =
              tierColorMap[category];
            if (window.innerWidth > 386) {
              titleElement.querySelector("div").textContent =
                `${divContent} (${category})` +
                (distracted ? " (distracted)" : "");
            }

            const button = divElement.querySelector("button.commit-button");
            if (button) {
              button.style.color = tierColorMap[category];
            }

            divElement.classList.add("processed");
            divElement.style.borderLeft = `3px solid ${tierColorMap[category]}`;

            break;
          }
        }
      }
    });
  }

  function initMonitor() {
    const targetNode = document.querySelector(
      '.pickpocketing-root div[class^="virtualList"]'
    );

    if (!targetNode) {
      setTimeout(initMonitor, 1000);
      return;
    }

    updateDivColors(targetNode);

    // Options for the observer (which mutations to observe)
    const config = { attributes: false, childList: true, subtree: false };

    // Create an observer instance linked to the callback function
    const observer = new MutationObserver(() => updateDivColors(targetNode));

    // Start observing the target node for configured mutations
    observer.observe(targetNode, config);
  }

  initMonitor();
})();