jackpot-jamboree / components /slot-machine.js
muranja's picture
add the casino games from known casino games formats
159bf5f verified
```javascript
class SlotMachine extends HTMLElement {
constructor() {
super();
this.balance = 1000;
this.bet = 10;
this.isSpinning = false;
this.symbols = ['πŸ’', 'πŸ‹', '🍊', 'πŸ‰', '⭐', 'πŸ’Ž', '7️⃣'];
this.symbolValues = {
'πŸ’': 2,
'πŸ‹': 3,
'🍊': 4,
'πŸ‰': 5,
'⭐': 10,
'πŸ’Ž': 20,
'7️⃣': 50
};
}
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.render();
this.setupEventListeners();
this.updateDisplay();
}
render() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
max-width: 500px;
margin: 0 auto;
}
.slot-container {
background: linear-gradient(135deg, #1e293b, #334155);
border: 2px solid #ef4444;
border-radius: 1rem;
padding: 2rem;
box-shadow: 0 10px 30px rgba(239, 68, 68, 0.2);
}
.balance-display {
text-align: center;
margin-bottom: 1rem;
font-size: 1.25rem;
font-weight: bold;
}
.reels {
display: flex;
gap: 0.5rem;
justify-content: center;
margin: 2rem 0;
background: #000;
padding: 1.5rem;
border-radius: 0.5rem;
border: 3px solid #374151;
}
.reel {
width: 80px;
height: 80px;
background: linear-gradient(to bottom, #fbbf24, #f59e0b);
border: 2px solid #92400e;
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.5rem;
font-weight: bold;
transition: transform 0.1s;
}
.reel.spinning {
animation: spin 0.3s linear infinite;
}
@keyframes spin {
0% { transform: translateY(-20px); opacity: 0.5; }
100% { transform: translateY(20px); opacity: 1; }
}
.controls {
display: flex;
flex-direction: column;
gap: 1rem;
}
.bet-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.bet-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: #ef4444;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
}
.bet-btn:hover {
background: #dc2626;
transform: scale(1.1);
}
.bet-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.spin-btn {
background: linear-gradient(45deg, #ef4444, #dc2626);
color: white;
border: none;
padding: 1rem 3rem;
border-radius: 0.5rem;
font-size: 1.25rem;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
text-transform: uppercase;
letter-spacing: 1px;
}
.spin-btn:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(239, 68, 68, 0.3);
}
.spin-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.message {
text-align: center;
margin-top: 1rem;
font-size: 1.125rem;
font-weight: 600;
min-height: 1.5rem;
}
.win {
color: #22c55e;
animation: pulse 0.5s;
}
.lose {
color: #ef4444;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
.payout-table {
margin-top: 1.5rem;
background: rgba(55, 65, 81, 0.5);
border-radius: 0.5rem;
padding: 1rem;
}
.payout-table h4 {
margin: 0 0 0.5rem 0;
text-align: center;
color: #ef4444;
}
.payout-row {
display: flex;
justify-content: space-between;
font-size: 0.875rem;
padding: 0.25rem 0;
}
</style>
<div class="slot-container">
<div class="balance-display">πŸ’° Balance: $<span id="balance">1000</span></div>
<div class="reels">
<div class="reel" id="reel1">πŸ’</div>
<div class="reel" id="reel2">πŸ‹</div>
<div class="reel" id="reel3">🍊</div>
</div>
<div class="controls">
<div class="bet-controls">
<button class="bet-btn" id="decreaseBet">-</button>
<span>Bet: $<span id="betAmount">10</span></span>
<button class="bet-btn" id="increaseBet">+</button>
</div>
<button class="spin-btn" id="spinBtn">SPIN</button>
</div>
<div class="message" id="message"></div>
<div class="payout-table">
<h4>Payouts (x bet)</h4>
<div class="payout-row"><span>πŸ’ 3x</span><span>2x</span></div>
<div class="payout-row"><span>πŸ‹ 3x</span><span>3x</span></div>
<div class="payout-row"><span>🍊 3x</span><span>4x</span></div>
<div class="payout-row"><span>πŸ‰ 3x</span><span>5x</span></div>
<div class="payout-row"><span>⭐ 3x</span><span>10x</span></div>
<div class="payout-row"><span>πŸ’Ž 3x</span><span>20x</span></div>
<div class="payout-row"><span>7️⃣ 3x</span><span>50x JACKPOT!</span></div>
</div>
</div>
`;
}
setupEventListeners() {
this.shadowRoot.getElementById('spinBtn').addEventListener('click', () => this.spin());
this.shadowRoot.getElementById('increaseBet').addEventListener('click', () => this.changeBet(5));
this.shadowRoot.getElementById('decreaseBet').addEventListener('click', () => this.changeBet(-5));
}
changeBet(amount) {
if (this.isSpinning) return;
this.bet = Math.max(5, Math.min(100, this.bet + amount));
this.updateDisplay();
}
async spin() {
if (this.isSpinning || this.balance < this.bet) {
if (this.balance < this.bet) {
this.showMessage('❌ Insufficient balance!', 'lose');
}
return;
}
this.isSpinning = true;
this.balance -= this.bet;
this.updateDisplay();
const reel1 = this.shadowRoot.getElementById('reel1');
const reel2 = this.shadowRoot.getElementById('reel2');
const reel3 = this.shadowRoot.getElementById('reel3');
const spinBtn = this.shadowRoot.getElementById('spinBtn');
spinBtn.textContent = 'SPINNING...';
spinBtn.disabled = true;
reel1.classList.add('spinning');
reel2.classList.add('spinning');
reel3.classList.add('spinning');
// Simulate spinning
const spinDuration = 2000;
const spinInterval = 100;
const startTime = Date.now();
const spinReels = setInterval(() => {
reel1.textContent = this.symbols[Math.floor(Math.random() * this.symbols.length)];
reel2.textContent = this.symbols[Math.floor(Math.random() * this.symbols.length)];
reel3.textContent = this.symbols[Math.floor(Math.random() * this.symbols.length)];
if (Date.now() - startTime > spinDuration) {
clearInterval(spinReels);
this.stopSpin();
}
}, spinInterval);
}
stopSpin() {
const reel1 = this.shadowRoot.getElementById('reel1');
const reel2 = this.shadowRoot.getElementById('reel2');
const reel3 = this.shadowRoot.getElementById('reel3');
const spinBtn = this.shadowRoot.getElementById('spinBtn');
reel1.classList.remove('spinning');
reel2.classList.remove('spinning');
reel3.classList.remove('spinning');
// Final results
const result1 = this.symbols[Math.floor(Math.random() * this.symbols.length)];
const result2 = this.symbols[Math.floor(Math.random() * this.symbols.length)];
const result3 = this.symbols[Math.floor(Math.random() * this.symbols.length)];
reel1.textContent = result1;
reel2.textContent = result2;
reel3.textContent = result3;
this.calculateWinnings(result1, result2, result3);
spinBtn.textContent = 'SPIN';
spinBtn.disabled = false;
this.isSpinning = false;
}
calculateWinnings(r1, r2, r3) {
if (r1 === r2 && r2 === r3) {
const multiplier = this.symbolValues[r1];
const winnings = this.bet * multiplier;
this.balance += winnings;
this.showMessage(`πŸŽ‰ JACKPOT! You won $${winnings}!`, 'win');
// Generate redemption code for big wins
if (winnings >= 100) {
setTimeout(() => {
alert(`πŸ† CONGRATULATIONS! You've earned a redemption code: WIN-${Math.random().toString(36).substr(2, 9).toUpperCase()}`);
}, 1000);
}
} else if (r1 === r2 || r2 === r3 || r1 === r3) {
const smallWin = this.bet * 0.5;
this.balance += smallWin;
this.showMessage(`πŸ’° Small win! $${smallWin}`, 'win');
} else {
this.showMessage('πŸ˜” Try again!', 'lose');
}
this.updateDisplay();
}
showMessage(text, type) {
const messageEl = this.shadowRoot.getElementById('message');
messageEl.textContent = text;
messageEl.className = `message ${type}`;
}
updateDisplay() {
this.shadowRoot.getElementById('balance').textContent = this.balance;
this.shadowRoot.getElementById('betAmount').textContent = this.bet;