Torn Drug Cooldown v2

Colored coded drug cooldown indicator in newsfeed. Credits: FLC for original version

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Torn Drug Cooldown v2
// @namespace    https://greasyfork.org/users/blacksmithop
// @version      1.4
// @description  Colored coded drug cooldown indicator in newsfeed. Credits: FLC for original version
// @match        https://www.torn.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  const BANNER_ID      = 'drugCooldownInHeader';
  const CHECK_INTERVAL = 1000;
  const FLASH_INTERVAL = 30000;   // Total cycle
  const FLASH_DURATION = 5000;    // Visible time
  const RIGHT_PADDING  = '12px';

  let banner = null;
  let flashTimeout = null;
  let isOnCooldown = false;

  // -------------------------------------------------
  function waitForElm(selector) {
    return new Promise(resolve => {
      if (document.querySelector(selector)) return resolve(document.querySelector(selector));
      const observer = new MutationObserver(() => {
        if (document.querySelector(selector)) {
          observer.disconnect();
          resolve(document.querySelector(selector));
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
    });
  }

  // -------------------------------------------------
  function ensureBanner() {
    if (banner) return banner;
    banner = document.getElementById(BANNER_ID);
    if (!banner) {
      banner = document.createElement('span');
      banner.id = BANNER_ID;
      Object.assign(banner.style, {
        display: 'inline-block',
        fontSize: '12px',
        fontWeight: 'bold',
        marginLeft: '8px',
        verticalAlign: 'middle',
        whiteSpace: 'nowrap',
        pointerEvents: 'none',
        zIndex: '9999',
        opacity: '0',
        transition: 'opacity 0.3s ease',
        paddingRight: '0'
      });
    }
    return banner;
  }

  // -------------------------------------------------
  function parseCooldownTime(text) {
    const match = text.match(/(\d+)\s+(\d+)/);
    if (!match) return null;
    const minutes = parseInt(match[1], 10);
    const seconds = parseInt(match[2], 10);
    return minutes * 60 + seconds;
  }

  function getDrugName(text) {
    const lower = text.toLowerCase();
    if (lower.includes('xanax')) return 'Xanax';
    if (lower.includes('lsd')) return 'LSD';
    if (lower.includes('opium')) return 'Opium';
    if (lower.includes('shrooms')) return 'Shrooms';
    if (lower.includes('weed')) return 'Weed';
    if (lower.includes('pc')) return 'PCP';
    if (lower.includes('meth')) return 'Meth';
    if (lower.includes('cocaine')) return 'Cocaine';
    if (lower.includes('ecstasy')) return 'Ecstasy';
    return 'Drug';
  }

  function getDisplayInfo() {
    const ariaEl = document.querySelector("[aria-label^='Drug Cooldown:']");
    const rawText = ariaEl ? ariaEl.getAttribute('aria-label').trim() : null;

    if (!rawText || rawText.includes('ready')) {
      return { text: 'Not Using', color: '#ff69b4', isOnCD: false }; // Hot Pink
    }

    const timeSec = parseCooldownTime(rawText);
    if (timeSec === null) {
      return { text: rawText, color: '#fff', isOnCD: true };
    }

    const drug = getDrugName(rawText);
    const mins = Math.floor(timeSec / 60);
    const secs = timeSec % 60;
    const timer = `${mins}:${secs.toString().padStart(2, '0')}`;

    // Color: 0–8 minutes → green → yellow → red
    const ratio = Math.min(timeSec / (8 * 60), 1); // 0 to 1
    let r, g;

    if (ratio <= 0.5) {
      // Green → Yellow
      r = Math.round(255 * (ratio * 2));
      g = 255;
    } else {
      // Yellow → Red
      r = 255;
      g = Math.round(255 * (2 - ratio * 2));
    }

    const color = `rgb(${r}, ${g}, 0)`;

    return { text: `${drug} ${timer}`, color, isOnCD: true };
  }

  // -------------------------------------------------
  function showBanner(text, color) {
    if (!banner) return;
    banner.textContent = text;
    banner.style.color = color;
    banner.style.opacity = '1';
    banner.style.paddingRight = RIGHT_PADDING;
  }

  function hideBanner() {
    if (!banner) return;
    banner.style.opacity = '0';
    banner.style.paddingRight = '0';
  }

  // -------------------------------------------------
  function updateDisplay() {
    const info = getDisplayInfo();
    const currentlyOnCD = info.isOnCD;

    if (currentlyOnCD !== isOnCooldown) {
      isOnCooldown = currentlyOnCD;
      clearTimeout(flashTimeout);
      hideBanner();

      if (!isOnCooldown) {
        showBanner(info.text, info.color); // Sticky: Not Using
      } else {
        triggerFlash(info);
      }
    } else if (!isOnCooldown) {
      // Update text/color if still off CD
      showBanner(info.text, info.color);
    }
  }

  function triggerFlash(info) {
    if (!isOnCooldown) return;
    showBanner(info.text, info.color);
    flashTimeout = setTimeout(() => {
      hideBanner();
      setTimeout(() => triggerFlash(getDisplayInfo()), FLASH_INTERVAL - FLASH_DURATION);
    }, FLASH_DURATION);
  }

  // -------------------------------------------------
  waitForElm('.news-ticker-slider-wrapper').then(wrapper => {
    banner = ensureBanner();

    if (!wrapper.querySelector(`#${BANNER_ID}`)) {
      const icon = wrapper.querySelector('svg');
      if (icon && icon.parentNode) {
        icon.parentNode.insertBefore(banner, icon.nextSibling);
      } else {
        wrapper.appendChild(banner);
      }
    }

    updateDisplay();
    setInterval(updateDisplay, CHECK_INTERVAL);
  });

})();