NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name faster slots
// @version 2.5
// @author Ahab [1735214]
// @match https://www.torn.com/page.php?sid=slots
// @run-at document-idle
// @grant none
// @updateURL https://openuserjs.org/meta/Ahab/faster_slots.meta.js
// @downloadURL https://openuserjs.org/install/Ahab/faster_slots.user.js
// @license MIT
// ==/UserScript==
$('<style>')
.text(`
:is(.notblured, .blured):not(
#barrel0 > :nth-child(2) :is(.notblured, .blured),
#barrel1 > :nth-child(2) :is(.notblured, .blured),
#barrel2 > :nth-child(2) :is(.notblured, .blured)
) {
display: none !important;
}
`)
.appendTo('head');
let lastStake = null
let playerTokens = 0
let playerMoney = 0
let nextSpinAllowedAt = 0
let spinDelay = 500
let delayStep = 100
let count = 0
let sounds = {}
const tracksList = ['clickstart','reelspinend0','cashout','won1','won2','won3','won4','won5']
$(document).ajaxSuccess(function(event, xhr, settings) {
if (!settings.url.includes('sid=slotsData')) return
const response = JSON.parse(xhr.responseText)
playerTokens = response.tokens
playerMoney = response.money
})
function bet(stake){
const barrel0 = $('#barrel0 > :nth-child(2)').find('.notblured')[0]
const barrel1 = $('#barrel1 > :nth-child(2)').find('.notblured')[0]
const barrel2 = $('#barrel2 > :nth-child(2)').find('.notblured')[0]
$.get('https://www.torn.com/page.php?rfcv='+getRFC()+'&sid=slotsData&step=play&stake='+stake, function (response) {
if(!response.error){
playerTokens = response.tokens
playerMoney = response.money
updateBetButtons();
$('span[id=moneyAmount]')[0].innerText = toNumberFormat(response.money)
$('span[id=tokens]')[0].innerText = response.tokens
$('span[id=moneyWon]')[0].innerText = toNumberFormat(response.moneyWon)
barrel0.classList.replace(barrel0.classList[2], response.images[0].match(/\/([^/]+)\.[^.]+$/)?.[1])
barrel1.classList.replace(barrel1.classList[2], response.images[1].match(/\/([^/]+)\.[^.]+$/)?.[1])
barrel2.classList.replace(barrel2.classList[2], response.images[2].match(/\/([^/]+)\.[^.]+$/)?.[1])
if(count == 5){
spinDelay = Math.max(500, spinDelay - 10)
count = 0
}
count += 1
if(response.comboTitle != null){
updateGameresult('win', response.comboTitle, {winAmount:response.moneyWon, totalMoney:response.moneyTotal, playerTokens:response.tokens})
}else{
updateGameresult('lose', "JACKPOT: $"+toNumberFormat(response.currentJackpot), {totalMoney:response.moneyTotal, playerTokens:response.tokens})
}
}else{
if(response.error.toLowerCase().includes('slots spin is already in')){
spinDelay += delayStep
}
updateGameresult('error', response.error)
}
}).fail(function (xhr, status, error) {
console.error('GET failed:', status, error)
});
}
function updateGameresult(type, message, data = {}){
const {winAmount = null, totalMoney = null, playerTokens = null} = data
if(type == 'error'){
soundit('clickstart')
$('#gameResult').css('font-size', '16px')
$('#gameResult').html("<span id='grv'></span><span id='grh'>"+message+"</span>")
$('#gameResultSr').text("Error. "+message);
}else if(type == 'win'){
var rate = data.winAmount / lastStake;
var sound = 'won';
if (rate < 4)
{
sound += 1;
}
else if(rate < 8)
{
sound += 2;
}
else if(rate < 200)
{
sound += 3;
}
else if(rate < 2000)
{
sound += 4;
}
else
{
sound += 5;
}
soundit(sound);
soundit('cashout')
$('#gameResult').css('font-size', '34px')
$('#gameResult').html("<span id='grv'></span><span id='grh'>"+message+"</span>")
$('#gameResultSr').text(message + ". Won $" + toNumberFormat(data.winAmount) + ". Money $" + toNumberFormat(data.totalMoney) + ". Tokens left: " + data.playerTokens + ".")
}else if(type == 'lose'){
soundit('reelspinend0')
$('#gameResult').css('font-size', '34px')
$('#gameResult').html("<span id='grv'></span><span id='grh'>"+message+"</span>")
$('#gameResultSr').text("No win. Money $" + toNumberFormat(data.totalMoney) + ". Tokens left: " + data.playerTokens + ".")
}
var inter = setInterval(function(){
$('#gameResult #grv').append( $('#gameResult #grh').html().slice(0, 1))
$('#gameResult #grh').html( $('#gameResult #grh').html().slice(1))
if ( $('#gameResult #grh').html().length == 0) clearInterval(inter)
}, 50)
}
function updateBetButtons() {
$('.betbtn').each(function () {
const stake = Number(this.dataset.bet);
const disabled = playerTokens <= 0 || stake > playerMoney
$(this)
.toggleClass('disabled', disabled)
.attr('aria-disabled', disabled ? 'true' : 'false')
});
}
function betCheck(stake){
const now = performance.now();
if (now < nextSpinAllowedAt) {
return
}
if(playerTokens == 0){
updateGameresult('error', "YOU HAVE ALREADY USED YOUR TOKENS FOR TODAY!")
return
}
else if(playerMoney < stake){
updateGameresult('error', "YOU DON'T HAVE ENOUGH MONEY TO MAKE THIS STAKE!")
return
}
else if(stake == 0){
updateGameresult('error', "PLEASE SELECT A STAKE!")
return
}
nextSpinAllowedAt = now + spinDelay
bet(stake)
}
function loadSounds() {
if (typeof window.buzz === 'undefined') {
setTimeout(loadSounds, 100)
return;
}
for (const track of tracksList) {
sounds[track] = new buzz.sound(
'/casino/slots/audio/' + track,
{
formats: ['ogg', 'mp3'],
preload: true,
autoplay: false
}
);
}
}
function soundit(soundID, volume = 25){
if ($('li[class*=btn-sound]').attr('aria-pressed') === 'false') return
const sound = sounds[soundID]
if (!sound) return
sound.stop()
sound.setVolume(volume)
sound.play()
};
loadSounds()
window.addEventListener('pointerdown', event => {
if (event.button === 2) return
const button = event.target.closest?.('.betbtn')
if (!button) return
event.preventDefault()
event.stopImmediatePropagation()
$(button).addClass('pressed')
lastStake = Number(button.dataset.bet)
betCheck(lastStake)
}, true);
window.addEventListener('pointerup', event => {
if (event.button === 2) return
const button = event.target.closest?.('.betbtn')
if (!button) return
$(button).removeClass('pressed')
}, true);
window.addEventListener('keydown', event => {
if ((event.key !== ' ' && event.key !== 'Enter') || event.target.closest('input, textarea, select, button:not(.betbtn), a, [contenteditable], .slots-main-wrap .btn-sound, .btn-pay-table')) return
event.preventDefault()
event.stopImmediatePropagation()
$('li[data-bet='+lastStake+']').addClass('pressed')
if (event.repeat) return
betCheck(lastStake)
}, true);
window.addEventListener('keyup', event => {
if ((event.key !== ' ' && event.key !== 'Enter') || event.target.closest('input, textarea, select, button:not(.betbtn), a, [contenteditable], .slots-main-wrap .btn-sound, .btn-pay-table')) return
$('li[data-bet='+lastStake+']').removeClass('pressed')
}, true);