// SET MESSAGE (WIN/LOSE) function setMessage(text, status) { messageEl.textContent = text; messageEl.className = status; // 'win', 'lose', atau '' (tie) } // Fungsi untuk update balance ke server async function updateBalanceToServer(newBalance) { try { const response = await fetch('update_balance.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ balance: newBalance }), }); const data = await response.json(); if (!data.success) { console.error('Failed to update balance:', data.error); } } catch (error) { console.error('Error updating balance:', error); } } // Simple Blackjack implementation const SUITS = ['♠', '♥', '♦', '♣']; const RANKS = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; // DOM const dealerHandEl = document.getElementById('dealer-hand'); const playerHandEl = document.getElementById('player-hand'); const dealerValueEl = document.getElementById('dealer-value'); const playerValueEl = document.getElementById('player-value'); const balanceEl = document.getElementById('balance'); const betInput = document.getElementById('bet-input'); const betBtn = document.getElementById('bet-btn'); const currentBetEl = document.getElementById('current-bet'); const hitBtn = document.getElementById('hit'); const standBtn = document.getElementById('stand'); const doubleBtn = document.getElementById('double'); const newRoundBtn = document.getElementById('new-round'); const messageEl = document.getElementById('message'); let deck = []; let dealer = []; let player = []; let dealerHidden = true; // Initialize balance from the HTML (PHP output) let balance = parseInt(document.getElementById('balance').innerText.replace(/[^\d]/g, '')) || 0; let currentBet = 0; let inRound = false; function makeDeck() { deck = []; for (const s of SUITS) { for (const r of RANKS) { deck.push({ suit: s, rank: r }); } } } function shuffle() { for (let i = deck.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [deck[i], deck[j]] = [deck[j], deck[i]]; } } function cardValue(card) { const r = card.rank; if (r === 'A') return [1, 11]; if (['J', 'Q', 'K'].includes(r)) return [10]; return [parseInt(r, 10)]; } function handValues(hand) { let totals = [0]; for (const c of hand) { const vals = cardValue(c); const newTotals = []; for (const t of totals) { for (const v of vals) { newTotals.push(t + v); } } totals = Array.from(new Set(newTotals)); } const valid = totals.filter(t => t <= 21); if (valid.length) return Math.max(...valid); return Math.min(...totals); } function renderHand(el, hand, hideFirst = false) { el.innerHTML = ''; hand.forEach((c, i) => { const div = document.createElement('div'); div.className = 'card' + (c.suit === '♥' || c.suit === '♦' ? ' red' : ''); if (hideFirst && i === 0) { div.className = 'card back'; div.textContent = 'HIDEN'; } else { const top = document.createElement('div'); top.textContent = c.rank + ' ' + c.suit; const bot = document.createElement('div'); bot.style.alignSelf = 'flex-end'; bot.textContent = c.rank + ' ' + c.suit; div.appendChild(top); div.appendChild(bot); } el.appendChild(div); }); } function updateUI() { renderHand(dealerHandEl, dealer, dealerHidden); renderHand(playerHandEl, player, false); dealerValueEl.textContent = dealerHidden ? '??' : 'Nilai: ' + handValues(dealer); playerValueEl.textContent = 'Nilai: ' + handValues(player); balanceEl.textContent = balance.toLocaleString('id-ID'); // Format with dots currentBetEl.textContent = currentBet.toLocaleString('id-ID'); } function startRound() { if (inRound) return; const bet = Number(betInput.value) || 0; if (bet <= 0 || bet > balance) { alert(' BANK TIDAK CUKUP! '); return; } currentBet = bet; balance -= bet; updateBalanceToServer(balance); // Update to server inRound = true; dealerHidden = true; setMessage('', ''); // RESET MESSAGE makeDeck(); shuffle(); dealer = [deck.pop(), deck.pop()]; player = [deck.pop(), deck.pop()]; updateUI(); // NATURAL BLACKJACK if (handValues(player) === 21) { dealerHidden = false; updateUI(); const dealerVal = handValues(dealer); if (dealerVal === 21) { balance += currentBet; updateBalanceToServer(balance); // Update to server setMessage('Tie (seri).', ''); } else { const payout = Math.floor(currentBet * 2.5); balance += payout; updateBalanceToServer(balance); // Update to server setMessage('Blackjack! You Win!', 'win'); } inRound = false; currentBet = 0; updateUI(); } } function playerHit() { if (!inRound) return; player.push(deck.pop()); updateUI(); if (handValues(player) > 21) { dealerHidden = false; setMessage('Bust! You Lose!', 'lose'); inRound = false; currentBet = 0; updateUI(); } } function playerStand() { if (!inRound) return; dealerHidden = false; while (handValues(dealer) < 17) { dealer.push(deck.pop()); } const pv = handValues(player); const dv = handValues(dealer); if (dv > 21 || pv > dv) { balance += currentBet * 2; updateBalanceToServer(balance); // Update to server setMessage('You Win!', 'win'); } else if (pv === dv) { balance += currentBet; updateBalanceToServer(balance); // Update to server setMessage('Tie (seri).', ''); } else { setMessage('You Lose!', 'lose'); } inRound = false; currentBet = 0; updateUI(); } function playerDouble() { if (!inRound) return; if (balance < currentBet) { alert('Bank tidak cukup untuk double.'); return; } balance -= currentBet; updateBalanceToServer(balance); // Update to server currentBet *= 2; player.push(deck.pop()); updateUI(); if (handValues(player) > 21) { dealerHidden = false; setMessage('Bust! You Lose!', 'lose'); inRound = false; currentBet = 0; updateUI(); return; } playerStand(); } // EVENTS betBtn.addEventListener('click', startRound); hitBtn.addEventListener('click', playerHit); standBtn.addEventListener('click', playerStand); doubleBtn.addEventListener('click', playerDouble); newRoundBtn.addEventListener('click', () => { if (inRound && !confirm('Masih dalam ronde. Reset?')) return; // Do NOT reset balance. Balance persists. currentBet = 0; inRound = false; dealer = []; player = []; deck = []; dealerHidden = true; setMessage('Meja di-reset.', ''); updateUI(); }); // KEYBOARD window.addEventListener('keydown', e => { if (e.key === 'h') playerHit(); if (e.key === 's') playerStand(); if (e.key === 'd') playerDouble(); if (e.key === 'Enter') startRound(); }); updateUI(); // TOP UP FEATURE // Tambahkan variabel global untuk top up let topUpAmount = 0; let topUpHistory = []; // DOM elements untuk top up const topUpBtn = document.getElementById('top-up-btn'); const topUpModal = document.getElementById('top-up-modal'); const topUpClose = document.getElementById('top-up-close'); const topUpInput = document.getElementById('top-up-input'); const topUpConfirm = document.getElementById('top-up-confirm'); const topUpHistoryEl = document.getElementById('top-up-history'); const topUpBalanceEl = document.getElementById('top-up-balance'); // Fungsi untuk menampilkan modal top up function showTopUpModal() { topUpModal.style.display = 'block'; topUpInput.value = ''; updateTopUpHistory(); } // Fungsi untuk menyembunyikan modal top up function hideTopUpModal() { topUpModal.style.display = 'none'; } // Fungsi untuk memproses top up function processTopUp() { const amount = Number(topUpInput.value) || 0; if (amount <= 0) { alert('Masukkan jumlah top up yang valid!'); return; } if (amount > 1000000) { alert('Maksimal top up adalah 1.000.000!'); return; } // Simulasi proses top up (dalam implementasi nyata, ini akan terhubung ke payment gateway) balance += amount; updateBalanceToServer(balance); // Update to server topUpAmount += amount; // Tambahkan ke riwayat top up topUpHistory.push({ amount: amount, date: new Date().toLocaleString('id-ID'), balanceAfter: balance }); // Update UI updateUI(); updateTopUpHistory(); // Tampilkan pesan sukses setMessage(`Top up berhasil! +${amount.toLocaleString('id-ID')}`, 'win'); // Sembunyikan modal hideTopUpModal(); } // Fungsi untuk memperbarui riwayat top up function updateTopUpHistory() { if (!topUpHistoryEl) return; topUpHistoryEl.innerHTML = ''; if (topUpHistory.length === 0) { topUpHistoryEl.innerHTML = '

Belum ada riwayat top up

'; return; } // Tampilkan maksimal 5 riwayat terbaru const recentHistory = topUpHistory.slice(-5).reverse(); recentHistory.forEach(record => { const historyItem = document.createElement('div'); historyItem.className = 'history-item'; historyItem.innerHTML = `
+${record.amount.toLocaleString('id-ID')}
${record.date}
Saldo: ${record.balanceAfter.toLocaleString('id-ID')}
`; topUpHistoryEl.appendChild(historyItem); }); } // Fungsi untuk memperbarui tampilan saldo top up function updateTopUpBalance() { if (topUpBalanceEl) { topUpBalanceEl.textContent = `Total Top Up: ${topUpAmount.toLocaleString('id-ID')}`; } } // Event listeners untuk top up if (topUpBtn) { topUpBtn.addEventListener('click', showTopUpModal); } if (topUpClose) { topUpClose.addEventListener('click', hideTopUpModal); } if (topUpConfirm) { topUpConfirm.addEventListener('click', processTopUp); } // Tutup modal jika klik di luar modal window.addEventListener('click', (e) => { if (e.target === topUpModal) { hideTopUpModal(); } }); // Keyboard shortcut untuk top up (Ctrl+T) window.addEventListener('keydown', e => { if (e.ctrlKey && e.key === 't') { e.preventDefault(); showTopUpModal(); } }); // Modifikasi fungsi updateUI untuk menampilkan informasi top up const originalUpdateUI = updateUI; updateUI = function () { originalUpdateUI(); ` []` updateTopUpBalance(); }; // Modifikasi fungsi newRound untuk reset saldo yang tidak mempengaruhi riwayat top up const originalNewRound = newRoundBtn.onclick; newRoundBtn.onclick = function () { if (inRound && !confirm('Masih dalam ronde. Reset?')) return; // Reset game tapi jangan reset balance currentBet = 0; inRound = false; dealer = []; player = []; deck = []; dealerHidden = true; setMessage('Bank di-reset.', ''); updateUI(); }; // Inisialisasi updateTopUpHistory(); updateTopUpBalance();