| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /proc/3951574/root/tmp/rrpkg/ |
Upload File : |
/* Reel Royale – GambleEngine: Verdopplungsspiel (Rot/Schwarz-Gewinnleiter).
Serverautoritär (api/gamble.php). Im Auto-Spin 3s-Fenster, sonst Auto-Nehmen. */
import { $, money, postJSON, wait } from '../util.js';
const AUTO_SECONDS = 3;
export class GambleEngine {
constructor({ boot, audio, particles }) {
this.boot = boot;
this.audio = audio;
this.particles = particles;
this.busy = false;
}
/** Bietet das Verdopplungsspiel an. Promise<balance|null>. */
offer(amount, isAuto) {
return new Promise((resolve) => {
const ov = $('gambleOverlay');
const teaser = $('gambleTeaser');
const elAmt = $('gambleAmount');
const elDeck = $('gambleDeck');
const elStatus = $('gambleStatus');
const elTimer = $('gambleTimer');
const btnRed = $('gambleRed');
const btnBlack = $('gambleBlack');
const btnCollect = $('gambleCollect');
let current = amount;
let lastBalance = null;
let timer = null;
let finished = false;
const setAmount = (v) => { elAmt.textContent = money(v); };
const setLadder = (step) => {
const l = $('gambleLadder');
l.innerHTML = '';
for (let i = 1; i <= 5; i++) {
const d = document.createElement('span');
d.className = 'rr-ladder-rung' + (i <= step ? ' on' : '');
d.textContent = '×' + Math.pow(2, i);
l.appendChild(d);
}
};
const clearTimer = () => { if (timer) { clearInterval(timer); timer = null; } elTimer.textContent = ''; };
const startAutoTimer = () => {
if (!isAuto) return;
clearTimer();
let left = AUTO_SECONDS;
elTimer.textContent = `(${left})`;
timer = setInterval(() => {
left--;
elTimer.textContent = left > 0 ? `(${left})` : '';
if (left <= 0) { clearTimer(); doCollect(); }
}, 1000);
};
const enable = (on) => { btnRed.disabled = !on; btnBlack.disabled = !on; btnCollect.disabled = !on; };
// Klick auf das Teaser-Panel klappt es auf und stoppt das Auto-Nehmen (Bedenkzeit).
const expand = () => {
if (ov.classList.contains('is-open')) return;
ov.classList.add('is-open');
clearTimer();
enable(true);
};
const close = (balance) => {
if (finished) return;
finished = true;
clearTimer();
ov.classList.remove('is-open');
ov.hidden = true;
teaser.onclick = btnRed.onclick = btnBlack.onclick = btnCollect.onclick = null;
resolve(balance);
};
const doCollect = async () => {
clearTimer(); enable(false);
try {
const data = await postJSON('api/gamble.php', { action: 'collect', csrf: this.boot.csrf });
this.audio.play('coin');
close(data.balance);
} catch { close(lastBalance); }
};
const doGamble = async (guess) => {
clearTimer(); enable(false);
elStatus.textContent = 'Karte wird gezogen…';
elDeck.className = 'rr-gamble-deck flipping';
this.audio.play('click');
let data;
try {
data = await postJSON('api/gamble.php', { action: 'gamble', guess, csrf: this.boot.csrf });
} catch (e) { elStatus.textContent = e.message; enable(true); startAutoTimer(); return; }
await wait(450);
lastBalance = data.balance;
const red = data.card === 'red';
elDeck.className = 'rr-gamble-deck ' + (red ? 'is-red' : 'is-black');
elDeck.textContent = red ? '♥' : '♠';
setLadder(data.steps);
if (data.win) {
current = data.amount;
setAmount(current);
this.audio.play(data.amount >= amount * 8 ? 'bigwin' : 'win');
this.particles.burst(window.innerWidth / 2, window.innerHeight * 0.4, 'gold', 14);
if (data.can_continue) {
elStatus.textContent = `Gewonnen! Weiter oder nehmen?`;
enable(true);
startAutoTimer();
} else {
elStatus.textContent = data.capped ? 'Maximum erreicht – Gewinn gesichert!' : 'Gewonnen!';
this.particles.coinShower(40);
await wait(1100);
close(data.balance);
}
} else {
current = 0;
setAmount(0);
this.audio.play('chipOff');
elStatus.textContent = 'Verloren!';
await wait(1100);
close(data.balance);
}
};
// Initialisierung – eingeklappt rechts einblenden; Reels & Gewinnlinien bleiben sichtbar.
finished = false;
setAmount(current);
setLadder(0);
elDeck.className = 'rr-gamble-deck';
elDeck.textContent = '?';
elStatus.textContent = 'Rot oder Schwarz wählen';
enable(true);
ov.classList.remove('is-open');
ov.hidden = false;
teaser.onclick = expand;
btnRed.onclick = () => doGamble('red');
btnBlack.onclick = () => doGamble('black');
btnCollect.onclick = () => doCollect();
startAutoTimer();
});
}
}