Fast Roulette

Speed up roulette by skipping the animation :)

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Fast Roulette
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Speed up roulette by skipping the animation :)
// @author       Lollipop [2717731]
// @match        https://www.torn.com/page.php?sid=roulette*
// @icon         https://www.torn.com/favicon.ico
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  console.log('Fast Roulette: Initialized');

  // Store the last detected stake data
  let lastStakeData = {
    rfcv: null,
    decodedStake: null
  };

  // Function to add the custom repeat element
  function addCustomElement() {
    // Check if infoSpot exists
    const infoSpot = document.getElementById('infoSpot');
    if (!infoSpot || document.getElementById('customRepeatButton')) {
      return; // Element not found or button already exists
    }

    console.log('Fast Roulette: Adding custom repeat button');

    // Create the custom element with the same styling as infoSpot
    const customElement = document.createElement('div');
    customElement.id = 'customRepeatButton';
    customElement.className = 'info-msg-cont border-round m-top10';

    customElement.innerHTML = `
      <div class="info-msg border-round">
        <i class="info-icon"></i>
        <div class="delimiter">
          <div class="msg right-round" id="customRepeatText" style="color: #FF69B4;">Repeat Last Bet</div>
        </div>
      </div>
    `;

    // Add some cursor pointer style to make it look clickable
    customElement.style.cursor = 'pointer';

    // Insert the custom element after infoSpot
    infoSpot.parentNode.insertBefore(customElement, infoSpot.nextSibling);

    // Add click event listener
    customElement.addEventListener('click', function() {
      console.log('Fast Roulette: Custom repeat button clicked');

      if (lastStakeData.rfcv && lastStakeData.decodedStake) {
        console.log('Fast Roulette: Repeating bet with stake:', lastStakeData.decodedStake);

        // Use jQuery's AJAX to match Torn's format
        $.ajax({
          url: 'page.php',
          type: 'GET',
          data: {
            rfcv: lastStakeData.rfcv,
            sid: 'rouletteData',
            step: 'processStakes',
            mode: 'html',
            stake0: lastStakeData.decodedStake
          },
          success: onSuccessResponse,
          error: function(error) {
            console.error('Fast Roulette: Error placing bet:', error);
            displayInfo('Failed to place bet. Please try again.', 'red');
          }
        });
      } else {
        console.log('Fast Roulette: No previous bet data available');
        displayInfo('No previous bet data available. Place a bet first.', 'red');
      }
    });
  }

  // Function to handle bet response without animation
  function onSuccessResponse(response) {
    try {
      // Parse the response if it's a string
      if (typeof response === 'string') {
        try {
          response = JSON.parse(response);
        } catch (e) {
          console.error('Fast Roulette: Failed to parse response:', e);
          displayInfo('Failed to parse response. Please try again.', 'red');
          return;
        }
      }

      // Update UI with result
      const title = response.won ? `You won \$${response.won}!` : 'You lost...';
      const message = ' The ball landed on ' + response.number;

      // Display result info
      displayInfo(title + message, response.won ? 'green' : 'red');

      // Update money and tokens (no animation)
      $('#st_money_val').html('$' + toNumberFormat(response.totalAmount));
      $('#st_tokens_val').html(response.tokens);

      // Update other UI elements if needed
      if (response.bet) {
        $('#st_bet_val').html(response.bet);
      }

      if (response.won) {
        $('#st_won_val').html('$' + toNumberFormat(response.won));
      } else {
        $('#st_won_val').html('$0');
      }
    } catch (e) {
      console.error('Fast Roulette: Error handling bet response:', e);
      displayInfo('Error handling bet response. Please try again.', 'red');
    }
  }

  // Helper function to display info message
  function displayInfo(message, color) {
    const infoSpotText = document.getElementById('infoSpotText');
    if (infoSpotText) {
      infoSpotText.textContent = message;
      infoSpotText.style.color = color || '';

      // Reset color after a delay
      setTimeout(() => {
        infoSpotText.style.color = '';
      }, 5000);
    }
  }

  // Helper function to format numbers like Torn does
  function toNumberFormat(number) {
    return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

  // Function to safely decode a URL component
  function safeDecodeURIComponent(str) {
    try {
      return decodeURIComponent(str);
    } catch (e) {
      console.error('Fast Roulette: Error decoding:', str);
      return str;
    }
  }

  // Create a proxy for the original XMLHttpRequest
  const originalXHR = window.XMLHttpRequest;

  function newXHR() {
    const xhr = new originalXHR();
    const originalOpen = xhr.open;
    const originalSend = xhr.send;

    xhr.open = function() {
      this._url = arguments[1];
      return originalOpen.apply(this, arguments);
    };

    xhr.send = function() {
      const url = this._url;

      if (url && typeof url === 'string') {
        // Check if this is a processStakes request
        if (
          url.includes('sid=rouletteData') &&
          url.includes('step=processStakes') &&
          url.includes('stake0=')
        ) {
          // Extract the rfcv value
          const rfcvMatch = url.match(/rfcv=([^&]+)/);
          const rfcv = rfcvMatch ? rfcvMatch[1] : null;

          // Extract the stake0 value
          const stakeMatch = url.match(/stake0=([^&]+)/);
          const encodedStake = stakeMatch ? stakeMatch[1] : null;

          if (rfcv && encodedStake) {
            // Decode the stake value
            const decodedStake = safeDecodeURIComponent(encodedStake);

            console.log('Fast Roulette: Detected stake processing request');
            console.log('Fast Roulette: Decoded Stake:', decodedStake);

            // Store the stake data
            lastStakeData = {
              rfcv: rfcv,
              decodedStake: decodedStake
            };

            // Add or update the custom element after a short delay
            setTimeout(addCustomElement, 500);
          }
        }
      }

      return originalSend.apply(this, arguments);
    };

    return xhr;
  }

  // Replace the global XMLHttpRequest with our proxied version
  window.XMLHttpRequest = newXHR;

  // Also handle fetch requests
  const originalFetch = window.fetch;
  window.fetch = function(input, init) {
    if (input && typeof input === 'string') {
      // Check if this is a processStakes request
      if (
        input.includes('sid=rouletteData') &&
        input.includes('step=processStakes') &&
        input.includes('stake0=')
      ) {
        // Extract the rfcv value
        const rfcvMatch = input.match(/rfcv=([^&]+)/);
        const rfcv = rfcvMatch ? rfcvMatch[1] : null;

        // Extract the stake0 value
        const stakeMatch = input.match(/stake0=([^&]+)/);
        const encodedStake = stakeMatch ? stakeMatch[1] : null;

        if (rfcv && encodedStake) {
          // Decode the stake value
          const decodedStake = safeDecodeURIComponent(encodedStake);

          console.log('Fast Roulette: Detected stake processing fetch request');
          console.log('Fast Roulette: Decoded Stake:', decodedStake);

          // Store the stake data
          lastStakeData = {
            rfcv: rfcv,
            decodedStake: decodedStake
          };

          // Add or update the custom element after a short delay
          setTimeout(addCustomElement, 500);
        }
      }
    }

    return originalFetch.apply(this, arguments);
  };
})();