diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..ba2a6c0
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "python-envs.defaultEnvManager": "ms-python.python:system",
+ "python-envs.pythonProjects": []
+}
\ No newline at end of file
diff --git a/html.php b/html.php
index 7bec743..1d0c0d9 100644
--- a/html.php
+++ b/html.php
@@ -1,4 +1,76 @@
+
+
+
+
+
+
+
+ Blackjack [21]
+
+
+
+
Signed in as:
+
+
Logout
+
+
+
+
+
+
+
+
session_start();
// If not logged in, redirect to login
if (!isset($_SESSION['username'])) {
diff --git a/loginn.php b/loginn.php
index b1a2137..a30fea7 100644
--- a/loginn.php
+++ b/loginn.php
@@ -3,66 +3,103 @@ include "koneksi.php";
session_start();
$error = '';
-if(isset($_POST['login'])){
- $username = $_POST['username'];
+$success = '';
+
+if(isset($_POST['register'])){
+ $username = mysqli_real_escape_string($conn, $_POST['username']);
$password = $_POST['password'];
-
- $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'";
- $result = mysqli_query($conn, $sql);
-
- if (mysqli_num_rows($result) > 0) {
- $user = mysqli_fetch_assoc($result);
- $_SESSION['username'] = $user['username'];
- // Initialize balance in session (default 1000 if not set)
- $_SESSION['balance'] = isset($user['balance']) ? (int)$user['balance'] : 1000;
- header("Location: html.php");
- exit;
+ $confirm_password = $_POST['confirm_password'];
+
+ // Validasi
+ if(empty($username) || empty($password)) {
+ $error = 'All fields are required.';
+ } elseif($password !== $confirm_password) {
+ $error = 'Passwords do not match.';
+ } elseif(strlen($password) < 6) {
+ $error = 'Password must be at least 6 characters.';
} else {
- $error = 'Invalid username or password.';
+ // Cek username sudah ada
+ $check_sql = "SELECT id FROM users WHERE username = ?";
+ $check_stmt = mysqli_prepare($conn, $check_sql);
+ mysqli_stmt_bind_param($check_stmt, "s", $username);
+ mysqli_stmt_execute($check_stmt);
+ mysqli_stmt_store_result($check_stmt);
+
+ if(mysqli_stmt_num_rows($check_stmt) > 0) {
+ $error = 'Username already exists.';
+ } else {
+ // Password hashing untuk keamanan
+ // UNTUK TESTING: simpan plain text (tidak direkomendasikan)
+ $hashed_password = $password; // HAPUS INI DI PRODUKSI
+
+ // UNTUK PRODUKSI: gunakan password_hash()
+ // $hashed_password = password_hash($password, PASSWORD_DEFAULT);
+
+ // Insert user baru dengan saldo awal
+ $insert_sql = "INSERT INTO users (username, password, balance, created_at)
+ VALUES (?, ?, 1000, NOW())";
+ $insert_stmt = mysqli_prepare($conn, $insert_sql);
+ mysqli_stmt_bind_param($insert_stmt, "ss", $username, $hashed_password);
+
+ if(mysqli_stmt_execute($insert_stmt)) {
+ $success = 'Registration successful! You can now login.';
+ // Auto login setelah register (opsional)
+ $user_id = mysqli_insert_id($conn);
+ $_SESSION['user_id'] = $user_id;
+ $_SESSION['username'] = $username;
+ $_SESSION['balance'] = 1000;
+
+ header("Location: html.php");
+ exit;
+ } else {
+ $error = 'Registration failed. Please try again.';
+ }
+ }
}
}
?>
-
-
+
-
-
-
Login
+
Register
OCAGamingHub
-
Welcome back — sign in to continue
+
Create your account
-
+
-
+
\ No newline at end of file
diff --git a/ody git.js b/ody git.js
index c6efb5b..a525c7b 100644
--- a/ody git.js
+++ b/ody git.js
@@ -1,14 +1,23 @@
-// SET MESSAGE (WIN/LOSE)
+
+// =========================
+// SET MESSAGE
+// =========================
function setMessage(text, status) {
- messageEl.textContent = text;
- messageEl.className = status;
+ if (messageEl) {
+ messageEl.textContent = text;
+ messageEl.className = status;
+ }
}
-// Simple Blackjack implementation
+// =========================
+// KONSTANTA KARTU
+// =========================
const SUITS = ['♠', '♥', '♦', '♣'];
const RANKS = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
-// DOM
+// =========================
+// DOM ELEMENTS
+// =========================
const dealerHandEl = document.getElementById('dealer-hand');
const playerHandEl = document.getElementById('player-hand');
const dealerValueEl = document.getElementById('dealer-value');
@@ -23,16 +32,16 @@ const doubleBtn = document.getElementById('double');
const newRoundBtn = document.getElementById('new-round');
const messageEl = document.getElementById('message');
-// TOP UP DOM Elements - HANDLED IN HTML.PHP
-// 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');
+// TOPUP DOM
+const topupBtn = document.getElementById('topup-btn');
+const topupModal = document.getElementById('topup-modal');
+const topupForm = document.getElementById('topup-form');
+const topupMessage = document.getElementById('topup-message');
+const modalAmount = document.getElementById('modal-amount');
-// Game variables
+// =========================
+// VARIABEL GAME
+// =========================
let deck = [];
let dealer = [];
let player = [];
@@ -41,23 +50,80 @@ let balance = 0;
let currentBet = 0;
let inRound = false;
-// TOP UP variables - HANDLED IN HTML.PHP
-// let topUpAmount = 0;
-// let topUpHistory = [];
+// =========================================
+// AMBIL VALUE DARI PHP (HIDDEN INPUT)
+// =========================================
+let gameBalance = parseInt(document.getElementById('php-balance').value);
+let userId = parseInt(document.getElementById('php-userid').value);
-// Initialize balance from global gameBalance
-if (typeof gameBalance !== 'undefined') {
- balance = gameBalance;
-} else {
- balance = 1000;
+// =========================
+// UPDATE BALANCE DISPLAY
+// =========================
+function updateBalanceDisplay() {
+ if (balanceEl) balanceEl.textContent = gameBalance.toLocaleString('id-ID');
+ const modalBalance = document.getElementById('modal-balance');
+ if (modalBalance) modalBalance.textContent = gameBalance.toLocaleString('id-ID');
}
+// =========================
+// SYNC KE SERVER
+// =========================
+async function syncBalanceToServer() {
+ try {
+ const response = await fetch('update_balance.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ userId, balance: gameBalance })
+ });
+
+ const data = await response.json();
+ return data.success;
+ } catch (err) {
+ console.error("Error:", err);
+ return false;
+ }
+}
+
+// =========================
+// UPDATE SESSION PHP
+// =========================
+async function updateSessionBalance() {
+ try {
+ await fetch('update_session.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ balance: gameBalance })
+ });
+ } catch (err) {
+ console.error("Error:", err);
+ }
+}
+
+// =========================
+// UPDATE BALANCE LOGIC
+// =========================
+function updateGameBalance(amount, type) {
+ if (type === 'win') gameBalance += amount;
+ else if (type === 'loss') gameBalance -= amount;
+ else if (type === 'bet') gameBalance -= amount;
+ else if (type === 'refund') gameBalance += amount;
+
+ updateBalanceDisplay();
+ syncBalanceToServer();
+ updateSessionBalance();
+}
+
+window.updateGameBalance = updateGameBalance;
+window.gameBalance = gameBalance;
+window.userId = userId;
+
+// =========================
+// FUNGSI KARTU
+// =========================
function makeDeck() {
deck = [];
for (const s of SUITS) {
- for (const r of RANKS) {
- deck.push({ suit: s, rank: r });
- }
+ for (const r of RANKS) deck.push({ suit: s, rank: r });
}
}
@@ -69,42 +135,45 @@ function shuffle() {
}
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)];
+ if (card.rank === 'A') return [1, 11];
+ if (['J', 'Q', 'K'].includes(card.rank)) return [10];
+ return [parseInt(card.rank)];
}
function handValues(hand) {
let totals = [0];
- for (const c of hand) {
- const vals = cardValue(c);
+
+ for (const card of hand) {
+ const cv = cardValue(card);
const newTotals = [];
- for (const t of totals) {
- for (const v of vals) { newTotals.push(t + v); }
- }
- totals = Array.from(new Set(newTotals));
+
+ totals.forEach(t => cv.forEach(v => newTotals.push(t + v)));
+
+ totals = [...new Set(newTotals)];
}
+
const valid = totals.filter(t => t <= 21);
- if (valid.length) return Math.max(...valid);
- return Math.min(...totals);
+ return valid.length ? Math.max(...valid) : 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 = 'TERSEMBUNYI';
+ div.textContent = 'HIDE';
} else {
+ div.className = 'card' + ((c.suit === '♥' || c.suit === '♦') ? ' red' : '');
const top = document.createElement('div');
- top.textContent = c.rank + ' ' + c.suit;
const bot = document.createElement('div');
- bot.style.alignSelf = 'flex-end';
+
+ top.textContent = c.rank + ' ' + c.suit;
bot.textContent = c.rank + ' ' + c.suit;
+ bot.style.alignSelf = 'flex-end';
+
div.appendChild(top);
div.appendChild(bot);
}
@@ -113,88 +182,64 @@ function renderHand(el, hand, hideFirst = false) {
});
}
+// =========================
+// UPDATE UI
+// =========================
function updateUI() {
renderHand(dealerHandEl, dealer, dealerHidden);
- renderHand(playerHandEl, player, false);
+ renderHand(playerHandEl, player);
+
dealerValueEl.textContent = dealerHidden ? '??' : 'Nilai: ' + handValues(dealer);
playerValueEl.textContent = 'Nilai: ' + handValues(player);
- balanceEl.textContent = balance.toLocaleString('id-ID');
- currentBetEl.textContent = currentBet.toLocaleString('id-ID');
- // updateTopUpBalance(); // Redundant
-}
-
-function updateBalanceOnServer() {
- fetch('html.php', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- body: 'update_balance=' + balance
- })
- .then(response => {
- if (response.headers.get('content-type')?.includes('application/json')) {
- return response.json();
- }
- return { status: 'success' };
- })
- .then(data => {
- if (data.balance !== undefined) {
- balance = data.balance;
- gameBalance = data.balance;
- }
- })
- .catch(err => console.log('Balance update sent', err));
+ updateBalanceDisplay();
+
+ if (currentBetEl) currentBetEl.textContent = currentBet.toLocaleString('id-ID');
}
+// =========================
+// START ROUND
+// =========================
function startRound() {
if (inRound) return;
- const bet = Number(betInput.value) || 0;
-
- if (bet <= 0 || bet > balance) {
- alert('BANK TIDAK CUKUP!');
- return;
- }
+ const bet = Number(betInput.value);
+ if (bet <= 0) return alert("Masukkan jumlah taruhan!");
+ if (bet > gameBalance) return alert("BANK TIDAK CUKUP!");
currentBet = bet;
- balance -= bet;
- gameBalance = balance;
+ updateGameBalance(bet, 'bet');
inRound = true;
dealerHidden = true;
-
- setMessage('', '');
+ setMessage("", "");
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;
- gameBalance = balance;
- setMessage('Tie (seri).', '');
+ if (handValues(dealer) === 21) {
+ updateGameBalance(currentBet, 'refund');
+ setMessage("Tie!", "");
} else {
- const payout = Math.floor(currentBet * 2.5);
- balance += payout;
- gameBalance = balance;
- setMessage('Blackjack! You Win!', 'win');
+ updateGameBalance(Math.floor(currentBet * 2.5), 'win');
+ setMessage("Blackjack! You win!", "win");
}
inRound = false;
currentBet = 0;
- updateUI();
- updateBalanceOnServer();
}
}
+// =========================
+// HIT
+// =========================
function playerHit() {
if (!inRound) return;
@@ -203,56 +248,49 @@ function playerHit() {
if (handValues(player) > 21) {
dealerHidden = false;
- setMessage('Bust! You Lose!', 'lose');
+ setMessage("Bust! You Lose!", "lose");
inRound = false;
currentBet = 0;
- gameBalance = balance;
- updateUI();
- updateBalanceOnServer();
}
}
+// =========================
+// STAND
+// =========================
function playerStand() {
if (!inRound) return;
dealerHidden = false;
- while (handValues(dealer) < 17) {
- dealer.push(deck.pop());
- }
+ while (handValues(dealer) < 17) dealer.push(deck.pop());
+
+ updateUI();
const pv = handValues(player);
const dv = handValues(dealer);
if (dv > 21 || pv > dv) {
- balance += currentBet * 2;
- gameBalance = balance;
- setMessage('You Win!', 'win');
-
+ updateGameBalance(currentBet * 2, 'win');
+ setMessage("You Win!", "win");
} else if (pv === dv) {
- balance += currentBet;
- gameBalance = balance;
- setMessage('Tie (seri).', '');
-
+ updateGameBalance(currentBet, 'refund');
+ setMessage("Tie!", "");
} else {
- setMessage('You Lose!', 'lose');
+ setMessage("You Lose!", "lose");
}
inRound = false;
currentBet = 0;
- updateUI();
- updateBalanceOnServer();
}
+// =========================
+// DOUBLE
+// =========================
function playerDouble() {
if (!inRound) return;
- if (balance < currentBet) {
- alert('Bank tidak cukup untuk double.');
- return;
- }
+ if (gameBalance < currentBet) return alert("Bank tidak cukup untuk double.");
- balance -= currentBet;
- gameBalance = balance;
+ updateGameBalance(currentBet, 'bet');
currentBet *= 2;
player.push(deck.pop());
@@ -260,151 +298,103 @@ function playerDouble() {
if (handValues(player) > 21) {
dealerHidden = false;
- setMessage('Bust! You Lose!', 'lose');
+ setMessage("Bust! You Lose!", "lose");
inRound = false;
currentBet = 0;
- updateUI();
- updateBalanceOnServer();
return;
}
playerStand();
}
-// TOP UP FUNCTIONS - HANDLED IN HTML.PHP
-/*
-function showTopUpModal() {
- topUpModal.style.display = 'block';
- if(topUpInput) topUpInput.value = '';
- updateTopUpHistory();
-}
-
-function hideTopUpModal() {
- topUpModal.style.display = 'none';
-}
-
-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;
- }
-
- balance += amount;
- gameBalance = balance;
- topUpAmount += amount;
-
- topUpHistory.push({
- amount: amount,
- date: new Date().toLocaleString('id-ID'),
- balanceAfter: balance
- });
-
- updateUI();
- updateTopUpHistory();
-
- setMessage(`Top up berhasil! +${amount.toLocaleString('id-ID')}`, 'win');
-
- hideTopUpModal();
-}
-
-function updateTopUpHistory() {
- if (!topUpHistoryEl) return;
-
- topUpHistoryEl.innerHTML = '';
-
- if (topUpHistory.length === 0) {
- topUpHistoryEl.innerHTML = '
Belum ada riwayat top up
';
- return;
- }
-
- 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);
- });
-}
-
-function updateTopUpBalance() {
- if (topUpBalanceEl) {
- topUpBalanceEl.textContent = `Total Top Up: ${topUpAmount.toLocaleString('id-ID')}`;
- }
-}
-*/
-
-// EVENT LISTENERS
-betBtn.addEventListener('click', function (e) {
- startRound();
+// =========================
+// TOP UP MODAL
+// =========================
+topupBtn.addEventListener('click', () => {
+ topupModal.style.display = 'flex';
+ topupForm.reset();
+ topupMessage.style.display = 'none';
+ updateBalanceDisplay();
});
+function closeTopUpModal() {
+ topupModal.style.display = 'none';
+ topupMessage.style.display = 'none';
+}
+
+window.addEventListener('click', e => {
+ if (e.target === topupModal) closeTopUpModal();
+});
+
+function setModalAmount(amount) {
+ modalAmount.value = amount;
+}
+
+function showTopUpMessage(msg, type) {
+ topupMessage.textContent = msg;
+ topupMessage.className = 'topup-message ' + type;
+ topupMessage.style.display = 'block';
+}
+
+topupForm.addEventListener('submit', e => {
+ e.preventDefault();
+
+ const bankMethod = document.querySelector('input[name="bank_method"]:checked');
+ const amount = parseInt(modalAmount.value);
+
+ if (!bankMethod) return showTopUpMessage("Pilih metode pembayaran!", "error");
+ if (amount <= 0 || amount > 1000000) return showTopUpMessage("Jumlah harus 1–1.000.000", "error");
+
+ const formData = new FormData(topupForm);
+ formData.append('userId', userId);
+
+ fetch('process_topup.php', { method: 'POST', body: formData })
+ .then(res => res.json())
+ .then(data => {
+ if (data.success) {
+ gameBalance = data.new_balance;
+ updateBalanceDisplay();
+ showTopUpMessage("✓ Top up berhasil!", "success");
+ setTimeout(closeTopUpModal, 2000);
+ } else {
+ showTopUpMessage(data.message, "error");
+ }
+ })
+ .catch(() => showTopUpMessage("Terjadi kesalahan.", "error"));
+});
+
+// =========================
+// EVENT LISTENERS
+// =========================
+betBtn.addEventListener('click', startRound);
hitBtn.addEventListener('click', playerHit);
standBtn.addEventListener('click', playerStand);
doubleBtn.addEventListener('click', playerDouble);
-newRoundBtn.addEventListener('click', function () {
- if (inRound && !confirm('Masih dalam ronde. Reset?')) return;
- balance = 1000;
- gameBalance = 1000;
- currentBet = 0;
- inRound = false;
+newRoundBtn.addEventListener('click', () => {
+ if (inRound && !confirm("Masih dalam ronde. Reset?")) return;
+
dealer = [];
player = [];
deck = [];
+ inRound = false;
dealerHidden = true;
- setMessage('Bank di-reset.', '');
+ currentBet = 0;
+
+ setMessage("Game di-reset.", "");
updateUI();
- updateBalanceOnServer();
});
-// TOP UP EVENT LISTENERS - HANDLED IN HTML.PHP
-/*
-if (topUpBtn) {
- topUpBtn.addEventListener('click', showTopUpModal);
-}
-
-if (topUpClose) {
- topUpClose.addEventListener('click', hideTopUpModal);
-}
-
-if (topUpConfirm) {
- topUpConfirm.addEventListener('click', processTopUp);
-}
-
-window.addEventListener('click', (e) => {
- if (e.target === topUpModal) {
- hideTopUpModal();
- }
-});
-*/
-
-// 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();
- /*
- if (e.ctrlKey && e.key === 't') {
- e.preventDefault();
- showTopUpModal();
- }
- */
});
-// INITIALIZATION
-updateUI();
-// updateTopUpHistory();
-// updateTopUpBalance();
+// =========================
+// INIT
+// =========================
+document.addEventListener('DOMContentLoaded', () => {
+ updateBalanceDisplay();
+});
diff --git a/prosestopup.php b/prosestopup.php
new file mode 100644
index 0000000..1bf6fc8
--- /dev/null
+++ b/prosestopup.php
@@ -0,0 +1,54 @@
+ false, 'message' => 'Not logged in']);
+ exit;
+}
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $user_id = $_SESSION['user_id'];
+ $amount = intval($_POST['amount']);
+ $bank_method = $_POST['bank_method'];
+
+ // Validasi
+ if ($amount <= 0 || $amount > 1000000) {
+ echo json_encode(['success' => false, 'message' => 'Invalid amount']);
+ exit;
+ }
+
+ // Update balance di database
+ $sql = "UPDATE users SET balance = balance + ? WHERE id = ?";
+ $stmt = mysqli_prepare($conn, $sql);
+ mysqli_stmt_bind_param($stmt, "ii", $amount, $user_id);
+
+ if (mysqli_stmt_execute($stmt)) {
+ // Get new balance
+ $sql2 = "SELECT balance FROM users WHERE id = ?";
+ $stmt2 = mysqli_prepare($conn, $sql2);
+ mysqli_stmt_bind_param($stmt2, "i", $user_id);
+ mysqli_stmt_execute($stmt2);
+ $result = mysqli_stmt_get_result($stmt2);
+ $user = mysqli_fetch_assoc($result);
+
+ // Update session
+ $_SESSION['balance'] = $user['balance'];
+
+ // Log transaction
+ $log_sql = "INSERT INTO transactions (user_id, type, amount, description)
+ VALUES (?, 'topup', ?, 'Top up via $bank_method')";
+ $log_stmt = mysqli_prepare($conn, $log_sql);
+ mysqli_stmt_bind_param($log_stmt, "ii", $user_id, $amount);
+ mysqli_stmt_execute($log_stmt);
+
+ echo json_encode([
+ 'success' => true,
+ 'new_balance' => $user['balance'],
+ 'message' => 'Top up successful'
+ ]);
+ } else {
+ echo json_encode(['success' => false, 'message' => 'Database error']);
+ }
+}
+?>
\ No newline at end of file
diff --git a/upbalance.php b/upbalance.php
new file mode 100644
index 0000000..d62253f
--- /dev/null
+++ b/upbalance.php
@@ -0,0 +1,27 @@
+ false]);
+ exit;
+}
+
+$data = json_decode(file_get_contents('php://input'), true);
+$user_id = $_SESSION['user_id'];
+$balance = intval($data['balance']);
+
+// Update balance di database
+$sql = "UPDATE users SET balance = ? WHERE id = ?";
+$stmt = mysqli_prepare($conn, $sql);
+mysqli_stmt_bind_param($stmt, "ii", $balance, $user_id);
+
+if (mysqli_stmt_execute($stmt)) {
+ // Update session
+ $_SESSION['balance'] = $balance;
+
+ echo json_encode(['success' => true]);
+} else {
+ echo json_encode(['success' => false]);
+}
+?>
\ No newline at end of file
diff --git a/users.sql b/users.sql
index f264ffd..bdc4f37 100644
--- a/users.sql
+++ b/users.sql
@@ -68,3 +68,23 @@ COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+
+-- Tabel users
+CREATE TABLE users (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ username VARCHAR(50) UNIQUE NOT NULL,
+ password VARCHAR(255) NOT NULL,
+ balance DECIMAL(10,2) DEFAULT 0.00,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Tabel transaction history (opsional)
+CREATE TABLE transactions (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ user_id INT,
+ type ENUM('topup', 'win', 'loss', 'bet'),
+ amount DECIMAL(10,2),
+ description VARCHAR(255),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (user_id) REFERENCES users(id)
+);