v3.2.3 + Version Jump to v3.3.3 + Fix CSS Injection
// ==UserScript==
// @name High-Low Oracle (WIP) v3.3.3
// @namespace http://tampermonkey.net/
// @version 3.3.3
// @description v3.2.3 + Version Jump to v3.3.3 + Fix CSS Injection
// @author Gemini
// @match *://www.torn.com/page.php?sid=highlow*
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const getFreshDeck = () => ({ 2:4, 3:4, 4:4, 5:4, 6:4, 7:4, 8:4, 9:4, 10:4, 11:4, 12:4, 13:4, 14:4 });
const SUIT_SYMBOLS = { 'S': '♠', 'H': '♥', 'D': '♦', 'C': '♣' };
const SUIT_COLORS = { 'S': '#fff', 'C': '#fff', 'H': '#ff4444', 'D': '#ff4444' };
const VALUES = [2,3,4,5,6,7,8,9,10,11,12,13,14];
const SUITS = ['S', 'H', 'D', 'C'];
let state = JSON.parse(localStorage.getItem('hi_lo_stable_state')) || {
deck: getFreshDeck(),
history: [], suitHistory: [], streakHistory: [],
currentStreak: 0,
phase: "DEALER", pos: { x: 20, y: 70 },
gridOpen: false, suitGridOpen: false, helpOpen: false,
selectedVal: 14, selectedSuit: 'S',
displayDealer: '--', displayDealerSuit: '',
displayPlayer: '--', displayPlayerSuit: '',
isShuffled: false
};
const save = () => localStorage.setItem('hi_lo_stable_state', JSON.stringify(state));
const injectStyles = () => {
// Clean up any old versions of the script styles to prevent conflicts
const oldStyles = document.querySelectorAll('style[id^="oracle-"]');
oldStyles.forEach(s => s.remove());
const s = document.createElement('style');
s.id = 'oracle-v333-fixed-css';
s.innerHTML = `
#oracle-root {
position: fixed !important; z-index: 999999999 !important;
background: rgba(10,10,10,0.98) !important; color: #fff !important;
width: 310px !important; border: 2px solid #00ffcc; border-radius: 12px;
padding: 12px !important; font-family: sans-serif !important;
left: ${state.pos.x}px; top: ${state.pos.y}px;
box-shadow: 0 0 20px rgba(0,0,0,0.8);
touch-action: none;
display: block !important;
visibility: visible !important;
}
.header-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; font-weight: bold; border-bottom: 1px solid #333; padding-bottom: 5px; cursor: grab; padding: 5px; }
#help-trigger { background: #007bff; color: white; width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; cursor: pointer; }
#dna-btn { color: #f2b01f; border: 1px solid #f2b01f; padding: 2px 8px; border-radius: 4px; font-size: 10px; cursor: pointer; font-weight: bold; }
.track-val { font-size: 20px; font-weight: bold; min-height: 24px; text-align: center; }
.main-display { text-align: center; padding: 10px 0; }
.btn-grid { display: flex; gap: 8px; margin-top: 8px; height: 50px; }
.bottom-row { display: flex; gap: 8px; margin-top: 10px; height: 40px; }
.c-btn { background: #1a1a1a; color: #fff; border: 1px solid #444; flex: 1; border-radius: 8px; font-size: 20px; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.a-btn { background: #00ffcc !important; color: #000 !important; flex: 1.5; border-radius: 8px; font-size: 18px; font-weight: bold; cursor: pointer; border: none; }
#reset-btn { flex: 2; background: #311; color: #f44; border: 1px solid #522; border-radius: 8px; font-weight: bold; cursor: pointer; }
#undo-btn { flex: 1; background: #222; color: #888; border: 1px solid #444; border-radius: 8px; font-weight: bold; cursor: pointer; }
.grid-item { background: #222; padding: 12px; text-align: center; border-radius: 6px; font-weight: bold; border: 1px solid #444; cursor: pointer; }
.grid-item.active { background: #00ffcc; color: #000; }
#help-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.98); z-index: 1000000000; display: flex; flex-direction: column; padding: 25px; box-sizing: border-box; overflow-y: auto; }
.help-header { color: #00ffcc; font-size: 24px; font-weight: bold; margin-bottom: 15px; border-bottom: 2px solid #00ffcc; padding-bottom: 8px; }
.help-step { margin-bottom: 12px; font-size: 15px; line-height: 1.4; color: #eee; }
.const-box { border: 1px solid #f2b01f; padding: 12px; border-radius: 8px; margin: 10px 0; background: rgba(242, 176, 31, 0.05); }
.help-close { background: #00ffcc; color: #000; text-align: center; padding: 15px; border-radius: 10px; cursor: pointer; font-weight: bold; font-size: 18px; margin-top: 15px; }
`;
document.head.appendChild(s);
};
const initUI = () => {
if (document.getElementById('oracle-root')) return;
injectStyles();
const container = document.createElement('div');
container.id = 'oracle-root';
document.body.appendChild(container);
let active = false;
let currentX, currentY, initialX, initialY, xOffset = state.pos.x, yOffset = state.pos.y;
const dragStart = (e) => {
if (e.target.closest('.header-bar')) {
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
active = true;
}
};
const dragEnd = () => {
active = false;
state.pos.x = xOffset;
state.pos.y = yOffset;
save();
};
const drag = (e) => {
if (active) {
e.preventDefault();
let newX = e.clientX - initialX;
let newY = e.clientY - initialY;
const rect = container.getBoundingClientRect();
const maxX = window.innerWidth - rect.width;
const maxY = window.innerHeight - rect.height;
xOffset = Math.max(0, Math.min(newX, maxX));
yOffset = Math.max(0, Math.min(newY, maxY));
container.style.left = `${xOffset}px`;
container.style.top = `${yOffset}px`;
}
};
document.addEventListener("pointerdown", dragStart, false);
document.addEventListener("pointerup", dragEnd, false);
document.addEventListener("pointermove", drag, false);
const render = () => {
const d = (v) => v===14?'A':v===11?'J':v===12?'Q':v===13?'K':v;
const lastLogged = state.history[state.history.length - 1];
let hi = 0, lo = 0, same = 0, total = 0;
if (lastLogged) {
for (let v in state.deck) {
let valInt = parseInt(v);
if (valInt > lastLogged) hi += state.deck[v];
else if (valInt < lastLogged) lo += state.deck[v];
else same += state.deck[v];
}
total = hi + lo + same;
}
let move = 'WAIT', color = '#aaa', icon = '⏳';
if (state.isShuffled || (state.phase === "DEALER" && state.history.length > 0)) {
move = 'CONTINUE'; color = '#007bff'; icon = '🔵';
} else if (total > 0) {
move = hi >= lo ? 'HIGHER' : 'LOWER';
color = hi >= lo ? '#00ffcc' : '#ff4444';
let conf = (Math.max(hi, lo) / total) * 100;
if (conf >= 90) icon = '😍'; else if (conf >= 75) icon = '😎'; else if (conf >= 60) icon = '🙂'; else icon = '😐';
}
let overlay = document.getElementById('help-overlay');
if (state.helpOpen) {
if (!overlay) { overlay = document.createElement('div'); overlay.id = 'help-overlay'; document.body.appendChild(overlay); }
overlay.innerHTML = `
<div class="help-header">Oracle Guide</div>
<div class="help-step"><strong>1. Dealer Logging:</strong> Select card value/suit under "DEALER" and press ADD.</div>
<div class="help-step"><strong>2. Predictions:</strong> Follow the HIGHER/LOWER command and emoji.</div>
<div class="help-step"><strong>3. Player Logging:</strong> After clicking Higher/Lower in Torn, select YOUR card and press ADD.</div>
<div class="help-step"><strong>4. States:</strong> ⏳ WAIT = First card needed. 🔵 CONTINUE = Click 'Continue' in Torn.</div>
<div class="const-box">
<div class="const-title">Operational Constraints</div>
<div class="help-step">• <strong>Bet Amount:</strong> Always bet exactly $10.</div>
<div class="help-step">• <strong>Prayer:</strong> Do not use the "Prayer" feature.</div>
<div class="help-step">• <strong>Objective:</strong> Reach a 25-streak without cashing in.</div>
</div>
<div class="const-box" style="border-color: #00ffcc;">
<div class="const-title" style="color: #00ffcc;">End of Session</div>
<div class="help-step">Once you have used your daily tokens, click the <strong>DNA</strong> button to copy data.</div>
<div class="help-step">Profile: <a href="https://www.torn.com/profiles.php?XID=3262527" style="color:#00ffcc">3262527</a></div>
</div>
<div class="help-close" id="close-help">RETURN TO GAME</div>
`;
overlay.querySelector('#close-help').onclick = () => { state.helpOpen = false; overlay.remove(); render(); };
}
let content = `
<div class="header-bar">
<div id="help-trigger">?</div>
<div style="font-size:10px; color:#00ffcc;">ORACLE (WIP) v3.3.3</div>
<div id="dna-btn">DNA</div>
</div>`;
if (state.gridOpen) {
content += `<div style="display:grid; grid-template-columns: repeat(4, 1fr); gap: 5px; margin-top:10px;">
${VALUES.map(v => `<div class="grid-item val-sel ${state.selectedVal === v ? 'active' : ''}" data-val="${v}">${d(v)}</div>`).join('')}
</div>`;
} else if (state.suitGridOpen) {
content += `<div style="display:grid; grid-template-columns: repeat(2, 1fr); gap: 5px; margin-top:10px;">
${SUITS.map(s => `<div class="grid-item suit-sel" data-suit="${s}" style="color:${SUIT_COLORS[s]}">${SUIT_SYMBOLS[s]}</div>`).join('')}
</div>`;
} else {
content += `
<div style="display: flex; justify-content: space-around; margin-top: 10px;">
<div>DLER:<div class="track-val" style="color:${SUIT_COLORS[state.displayDealerSuit]}">${state.displayDealer}${SUIT_SYMBOLS[state.displayDealerSuit]||''}</div></div>
<div>YOU:<div class="track-val" style="color:${SUIT_COLORS[state.displayPlayerSuit]}">${state.displayPlayer}${SUIT_SYMBOLS[state.displayPlayerSuit]||''}</div></div>
</div>
<div class="main-display">
<div style="font-size:28px; font-weight:bold; color:${color}">${move}</div>
<div style="font-size:30px;">${icon}</div>
</div>
<div class="btn-grid">
<div class="c-btn" id="open-val">${d(state.selectedVal)}</div>
<div class="c-btn" id="open-suit" style="color:${SUIT_COLORS[state.selectedSuit]}">${SUIT_SYMBOLS[state.selectedSuit]}</div>
<button class="a-btn" id="add-btn">ADD</button>
</div>
<div class="bottom-row">
<button id="reset-btn">SHUFFLE</button>
<button id="undo-btn">UNDO</button>
</div>`;
}
container.innerHTML = content;
const tap = (id, fn) => { const el = container.querySelector(id); if(el) el.onclick = fn; };
tap('#help-trigger', () => { state.helpOpen = true; render(); });
tap('#dna-btn', () => {
const data = btoa(JSON.stringify({ history: state.history, suits: state.suitHistory, deck: state.deck }));
navigator.clipboard.writeText(data).then(() => alert("DNA Copied."));
});
tap('#open-val', () => { state.gridOpen = true; render(); });
tap('#open-suit', () => { state.suitGridOpen = true; render(); });
container.querySelectorAll('.val-sel').forEach(el => el.onclick = () => { state.selectedVal = parseInt(el.dataset.val); state.gridOpen = false; state.suitGridOpen = true; render(); });
container.querySelectorAll('.suit-sel').forEach(el => el.onclick = () => { state.selectedSuit = el.dataset.suit; state.suitGridOpen = false; render(); });
tap('#add-btn', () => {
const val = state.selectedVal; const suit = state.selectedSuit;
if (state.deck[val] > 0) {
state.isShuffled = false;
if (state.phase === "DEALER") { state.displayDealer = d(val); state.displayDealerSuit = suit; state.phase = "PLAYER"; }
else { state.displayPlayer = d(val); state.displayPlayerSuit = suit; state.phase = "DEALER"; }
state.deck[val]--; state.history.push(val); state.suitHistory.push(suit);
save(); render();
}
});
tap('#reset-btn', () => { state.deck = getFreshDeck(); state.history = []; state.displayDealer = '--'; state.displayPlayer = '--'; state.isShuffled = true; state.phase = "DEALER"; save(); render(); });
tap('#undo-btn', () => { if(state.history.length > 0) { state.deck[state.history.pop()]++; state.suitHistory.pop(); state.phase = (state.phase === "DEALER") ? "PLAYER" : "DEALER"; save(); render(); } });
};
render();
};
// Use a delay to ensure the page body is fully ready
if (document.readyState === 'complete') {
initUI();
} else {
window.addEventListener('load', initUI);
}
})();