Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Lucky Spin Slot Machine</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
@keyframes spin { | |
0% { transform: translateY(0); } | |
100% { transform: translateY(-1000px); } | |
} | |
@keyframes bounce { | |
0%, 100% { transform: translateY(0); } | |
50% { transform: translateY(-20px); } | |
} | |
@keyframes winPulse { | |
0% { transform: scale(1); } | |
50% { transform: scale(1.1); } | |
100% { transform: scale(1); } | |
} | |
.slot-reel { | |
height: 100px; | |
overflow: hidden; | |
position: relative; | |
} | |
.slot-item { | |
height: 100px; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 3rem; | |
} | |
.spinning { | |
animation: spin 0.1s linear infinite; | |
} | |
.win-animation { | |
animation: winPulse 0.5s ease infinite; | |
} | |
.jackpot { | |
animation: bounce 0.5s ease infinite, winPulse 0.5s ease infinite; | |
} | |
.machine-body { | |
background: linear-gradient(145deg, #d10000, #8a0000); | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); | |
} | |
.lever { | |
transition: all 0.3s ease; | |
} | |
.lever.pulled { | |
transform: rotate(-30deg); | |
} | |
.coin { | |
transition: all 0.3s ease; | |
} | |
.coin.inserted { | |
transform: translateY(50px) scale(0); | |
} | |
.auto-spin-active { | |
background-color: #10b981 ; | |
box-shadow: 0 0 10px #10b981; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-900 min-h-screen flex items-center justify-center p-4"> | |
<div class="relative"> | |
<!-- Slot Machine --> | |
<div class="machine-body rounded-2xl p-8 relative overflow-hidden"> | |
<!-- Decorative elements --> | |
<div class="absolute top-0 left-0 w-full h-4 bg-yellow-400"></div> | |
<div class="absolute bottom-0 left-0 w-full h-4 bg-yellow-400"></div> | |
<div class="absolute top-4 left-4 right-4 bottom-4 border-4 border-yellow-400 rounded-xl opacity-20"></div> | |
<!-- Machine header --> | |
<div class="text-center mb-6"> | |
<h1 class="text-yellow-400 text-4xl font-bold mb-2">LUCKY SPIN</h1> | |
<div class="bg-black bg-opacity-50 rounded-full py-2 px-6 inline-block"> | |
<span class="text-white font-mono text-xl">SLOT MACHINE</span> | |
</div> | |
</div> | |
<!-- Reels container --> | |
<div class="flex justify-center items-center mb-8"> | |
<!-- Lever --> | |
<div class="h-48 w-16 bg-gray-700 rounded-lg mr-4 flex flex-col items-center justify-end relative"> | |
<div class="w-16 h-8 bg-gray-800 rounded-t-lg"></div> | |
<div id="lever" class="lever w-12 h-32 bg-red-700 rounded-t-lg absolute top-0 cursor-pointer z-10"></div> | |
</div> | |
<!-- Reels --> | |
<div class="flex bg-black bg-opacity-70 rounded-xl p-4"> | |
<div class="slot-reel w-24 bg-white rounded-lg mx-2 relative overflow-hidden" id="reel1"> | |
<div class="slot-items" id="items1"> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-purple-500">π</div> | |
<div class="slot-item text-yellow-500">π</div> | |
<div class="slot-item text-green-500">π</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-yellow-500">π°</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
</div> | |
</div> | |
<div class="slot-reel w-24 bg-white rounded-lg mx-2 relative overflow-hidden" id="reel2"> | |
<div class="slot-items" id="items2"> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-purple-500">π</div> | |
<div class="slot-item text-yellow-500">π</div> | |
<div class="slot-item text-green-500">π</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-yellow-500">π°</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-purple-500">π</div> | |
</div> | |
</div> | |
<div class="slot-reel w-24 bg-white rounded-lg mx-2 relative overflow-hidden" id="reel3"> | |
<div class="slot-items" id="items3"> | |
<div class="slot-item text-purple-500">π</div> | |
<div class="slot-item text-yellow-500">π</div> | |
<div class="slot-item text-green-500">π</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-yellow-500">π°</div> | |
<div class="slot-item text-red-500">π</div> | |
<div class="slot-item text-blue-500">π</div> | |
<div class="slot-item text-purple-500">π</div> | |
<div class="slot-item text-yellow-500">π</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Coin slot and controls --> | |
<div class="flex justify-between items-center"> | |
<div class="relative"> | |
<div class="w-24 h-12 bg-gray-700 rounded-lg flex items-center justify-center"> | |
<div class="w-16 h-2 bg-gray-800 rounded-full"></div> | |
</div> | |
<div id="coin" class="coin absolute top-0 left-1/2 transform -translate-x-1/2 w-8 h-8 bg-yellow-400 rounded-full shadow-lg"> | |
<div class="absolute inset-0 rounded-full bg-yellow-300 opacity-50"></div> | |
</div> | |
</div> | |
<div class="text-center"> | |
<div class="bg-black bg-opacity-70 rounded-lg p-3 inline-block"> | |
<div class="text-white mb-2">CREDIT: <span id="credit" class="text-yellow-400 font-bold">100</span></div> | |
<div class="text-white">WIN: <span id="win" class="text-green-400 font-bold">0</span></div> | |
</div> | |
</div> | |
<div class="flex space-x-2"> | |
<button id="auto-spin-btn" class="bg-gray-700 hover:bg-gray-600 text-white font-bold py-3 px-4 rounded-lg shadow-lg transition-all transform hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed"> | |
<i class="fas fa-sync-alt mr-2"></i>AUTO | |
</button> | |
<button id="spin-btn" class="bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-3 px-6 rounded-lg shadow-lg transition-all transform hover:scale-105 disabled:opacity-50 disabled:cursor-not-allowed"> | |
SPIN | |
</button> | |
</div> | |
</div> | |
<!-- Auto-spin options --> | |
<div id="auto-spin-options" class="hidden mt-4 bg-black bg-opacity-50 rounded-lg p-3"> | |
<div class="flex justify-between items-center mb-2"> | |
<span class="text-white">Auto-spin count:</span> | |
<select id="auto-spin-count" class="bg-gray-700 text-white rounded px-2 py-1"> | |
<option value="10">10</option> | |
<option value="25">25</option> | |
<option value="50">50</option> | |
<option value="100">100</option> | |
<option value="0">Until stop</option> | |
</select> | |
</div> | |
<div class="flex justify-between items-center"> | |
<span class="text-white">Stop if credit below:</span> | |
<select id="auto-spin-limit" class="bg-gray-700 text-white rounded px-2 py-1"> | |
<option value="10">10</option> | |
<option value="25">25</option> | |
<option value="50">50</option> | |
<option value="100">100</option> | |
<option value="0">Never stop</option> | |
</select> | |
</div> | |
<div class="flex justify-center mt-3 space-x-2"> | |
<button id="start-auto-spin" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded"> | |
Start | |
</button> | |
<button id="stop-auto-spin" class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded"> | |
Stop | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- Paytable --> | |
<div class="mt-8 bg-gray-800 bg-opacity-70 rounded-xl p-6 text-white max-w-md mx-auto"> | |
<h2 class="text-2xl font-bold text-yellow-400 mb-4 text-center">PAYTABLE</h2> | |
<div class="grid grid-cols-2 gap-4"> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">πππ</span> | |
<span class="font-bold">x50</span> | |
</div> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">π°π°π°</span> | |
<span class="font-bold">x100</span> | |
</div> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">πππ</span> | |
<span class="font-bold">x20</span> | |
</div> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">πππ</span> | |
<span class="font-bold">x30</span> | |
</div> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">πππ</span> | |
<span class="font-bold">x15</span> | |
</div> | |
<div class="flex items-center"> | |
<span class="text-3xl mr-2">πππ</span> | |
<span class="font-bold">x10</span> | |
</div> | |
</div> | |
</div> | |
<!-- Win message --> | |
<div id="win-message" class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-70 z-50 hidden"> | |
<div class="bg-gradient-to-br from-yellow-400 to-yellow-600 p-8 rounded-xl text-center max-w-md"> | |
<h2 class="text-4xl font-bold mb-4">YOU WIN!</h2> | |
<p id="win-amount" class="text-5xl font-bold mb-6">0</p> | |
<button id="close-win" class="bg-black text-white px-6 py-3 rounded-lg font-bold hover:bg-gray-800 transition">COLLECT</button> | |
</div> | |
</div> | |
<!-- Auto-spin status --> | |
<div id="auto-spin-status" class="fixed bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-70 text-white px-4 py-2 rounded-lg hidden"> | |
<span id="auto-spin-countdown">Auto-spin: 10 remaining</span> | |
</div> | |
</div> | |
<!-- Audio elements --> | |
<audio id="spinSound" src="https://assets.mixkit.co/sfx/preview/mixkit-slot-machine-spin-1930.mp3" preload="auto"></audio> | |
<audio id="winSound" src="https://assets.mixkit.co/sfx/preview/mixkit-winning-chimes-2015.mp3" preload="auto"></audio> | |
<audio id="coinSound" src="https://assets.mixkit.co/sfx/preview/mixkit-coin-win-notification-919.mp3" preload="auto"></audio> | |
<audio id="leverSound" src="https://assets.mixkit.co/sfx/preview/mixkit-retro-arcade-game-lever-1083.mp3" preload="auto"></audio> | |
<audio id="jackpotSound" src="https://assets.mixkit.co/sfx/preview/mixkit-emergency-alert-alarm-1007.mp3" preload="auto"></audio> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// Game state | |
let credit = 100; | |
let winAmount = 0; | |
let isSpinning = false; | |
let isAutoSpinning = false; | |
let autoSpinCount = 0; | |
let autoSpinLimit = 0; | |
let remainingAutoSpins = 0; | |
// DOM elements | |
const spinBtn = document.getElementById('spin-btn'); | |
const autoSpinBtn = document.getElementById('auto-spin-btn'); | |
const autoSpinOptions = document.getElementById('auto-spin-options'); | |
const startAutoSpinBtn = document.getElementById('start-auto-spin'); | |
const stopAutoSpinBtn = document.getElementById('stop-auto-spin'); | |
const autoSpinCountSelect = document.getElementById('auto-spin-count'); | |
const autoSpinLimitSelect = document.getElementById('auto-spin-limit'); | |
const autoSpinStatus = document.getElementById('auto-spin-status'); | |
const autoSpinCountdown = document.getElementById('auto-spin-countdown'); | |
const lever = document.getElementById('lever'); | |
const coin = document.getElementById('coin'); | |
const creditDisplay = document.getElementById('credit'); | |
const winDisplay = document.getElementById('win'); | |
const winMessage = document.getElementById('win-message'); | |
const winAmountDisplay = document.getElementById('win-amount'); | |
const closeWinBtn = document.getElementById('close-win'); | |
const reels = [document.getElementById('reel1'), document.getElementById('reel2'), document.getElementById('reel3')]; | |
const items = [document.getElementById('items1'), document.getElementById('items2'), document.getElementById('items3')]; | |
// Audio elements | |
const spinSound = document.getElementById('spinSound'); | |
const winSound = document.getElementById('winSound'); | |
const coinSound = document.getElementById('coinSound'); | |
const leverSound = document.getElementById('leverSound'); | |
const jackpotSound = document.getElementById('jackpotSound'); | |
// Paytable | |
const paytable = { | |
'πππ': 50, | |
'π°π°π°': 100, | |
'πππ': 20, | |
'πππ': 30, | |
'πππ': 15, | |
'πππ': 10 | |
}; | |
// Initialize the game | |
function init() { | |
// Set initial positions | |
items.forEach(item => { | |
item.style.transform = 'translateY(0)'; | |
}); | |
updateDisplay(); | |
// Event listeners for auto-spin | |
autoSpinBtn.addEventListener('click', toggleAutoSpinOptions); | |
startAutoSpinBtn.addEventListener('click', startAutoSpin); | |
stopAutoSpinBtn.addEventListener('click', stopAutoSpin); | |
} | |
// Update display | |
function updateDisplay() { | |
creditDisplay.textContent = credit; | |
winDisplay.textContent = winAmount; | |
// Disable spin button if no credit | |
spinBtn.disabled = credit <= 0 || isSpinning; | |
autoSpinBtn.disabled = credit <= 0 || isSpinning; | |
} | |
// Insert coin animation | |
function insertCoin() { | |
if (isSpinning) return; | |
coin.classList.add('inserted'); | |
coinSound.currentTime = 0; | |
coinSound.play(); | |
setTimeout(() => { | |
coin.classList.remove('inserted'); | |
coin.style.display = 'block'; | |
}, 300); | |
} | |
// Pull lever animation | |
function pullLever() { | |
lever.classList.add('pulled'); | |
leverSound.currentTime = 0; | |
leverSound.play(); | |
setTimeout(() => { | |
lever.classList.remove('pulled'); | |
}, 300); | |
} | |
// Toggle auto-spin options | |
function toggleAutoSpinOptions() { | |
if (autoSpinOptions.classList.contains('hidden')) { | |
autoSpinOptions.classList.remove('hidden'); | |
} else { | |
autoSpinOptions.classList.add('hidden'); | |
} | |
} | |
// Start auto-spin | |
function startAutoSpin() { | |
autoSpinCount = parseInt(autoSpinCountSelect.value); | |
autoSpinLimit = parseInt(autoSpinLimitSelect.value); | |
if (autoSpinCount === 0) { | |
remainingAutoSpins = Infinity; | |
} else { | |
remainingAutoSpins = autoSpinCount; | |
} | |
isAutoSpinning = true; | |
autoSpinBtn.classList.add('auto-spin-active'); | |
autoSpinOptions.classList.add('hidden'); | |
autoSpinStatus.classList.remove('hidden'); | |
updateAutoSpinStatus(); | |
// Start the first spin | |
if (!isSpinning) { | |
spin(); | |
} | |
} | |
// Stop auto-spin | |
function stopAutoSpin() { | |
isAutoSpinning = false; | |
autoSpinBtn.classList.remove('auto-spin-active'); | |
autoSpinOptions.classList.add('hidden'); | |
autoSpinStatus.classList.add('hidden'); | |
} | |
// Update auto-spin status display | |
function updateAutoSpinStatus() { | |
if (isAutoSpinning) { | |
if (remainingAutoSpins === Infinity) { | |
autoSpinCountdown.textContent = "Auto-spin: Unlimited"; | |
} else { | |
autoSpinCountdown.textContent = `Auto-spin: ${remainingAutoSpins} remaining`; | |
} | |
} | |
} | |
// Spin the reels | |
function spin() { | |
if (isSpinning || credit <= 0) return; | |
// Check auto-spin stop conditions | |
if (isAutoSpinning) { | |
if (autoSpinLimit > 0 && credit < autoSpinLimit) { | |
stopAutoSpin(); | |
return; | |
} | |
if (remainingAutoSpins !== Infinity) { | |
remainingAutoSpins--; | |
updateAutoSpinStatus(); | |
if (remainingAutoSpins <= 0) { | |
stopAutoSpin(); | |
} | |
} | |
} | |
// Deduct credit | |
credit--; | |
updateDisplay(); | |
// Play sounds | |
spinSound.currentTime = 0; | |
spinSound.play(); | |
// Pull lever animation | |
pullLever(); | |
insertCoin(); | |
isSpinning = true; | |
winAmount = 0; | |
updateDisplay(); | |
// Start spinning animation | |
reels.forEach(reel => { | |
reel.querySelector('.slot-items').classList.add('spinning'); | |
}); | |
// Stop reels at different times | |
setTimeout(() => stopReel(0), 1000 + Math.random() * 500); | |
setTimeout(() => stopReel(1), 1500 + Math.random() * 500); | |
setTimeout(() => stopReel(2), 2000 + Math.random() * 500); | |
} | |
// Stop a single reel | |
function stopReel(reelIndex) { | |
const reel = reels[reelIndex]; | |
const itemsContainer = items[reelIndex]; | |
// Remove spinning class | |
itemsContainer.classList.remove('spinning'); | |
// Calculate random position | |
const itemHeight = 100; // height of each item | |
const itemCount = itemsContainer.children.length; | |
const randomPosition = Math.floor(Math.random() * itemCount) * -itemHeight; | |
// Set final position | |
itemsContainer.style.transform = `translateY(${randomPosition}px)`; | |
// If this is the last reel, check for win | |
if (reelIndex === 2) { | |
setTimeout(checkWin, 500); | |
} | |
} | |
// Check for winning combination | |
function checkWin() { | |
isSpinning = false; | |
// Get the symbols from each reel | |
const symbols = []; | |
for (let i = 0; i < 3; i++) { | |
const itemsContainer = items[i]; | |
const position = parseInt(itemsContainer.style.transform.split('(')[1].split('px)')[0]); | |
const itemIndex = Math.abs(position / 100) % itemsContainer.children.length; | |
symbols.push(itemsContainer.children[itemIndex].textContent); | |
} | |
// Check for matches | |
const combination = symbols.join(''); | |
if (paytable[combination]) { | |
winAmount = paytable[combination]; | |
// Special handling for jackpot | |
if (combination === 'π°π°π°') { | |
jackpotWin(); | |
} else { | |
regularWin(); | |
} | |
} else { | |
updateDisplay(); | |
// If auto-spinning and not showing win message, start next spin | |
if (isAutoSpinning && !winMessage.classList.contains('hidden') === false) { | |
setTimeout(() => { | |
if (credit > 0 && !isSpinning) { | |
spin(); | |
} | |
}, 500); | |
} | |
} | |
} | |
// Regular win | |
function regularWin() { | |
credit += winAmount; | |
updateDisplay(); | |
// Add win animation to reels | |
reels.forEach(reel => { | |
reel.classList.add('win-animation'); | |
}); | |
// Play win sound | |
winSound.currentTime = 0; | |
winSound.play(); | |
// Show win message | |
winAmountDisplay.textContent = winAmount; | |
winMessage.classList.remove('hidden'); | |
// Remove animation after delay | |
setTimeout(() => { | |
reels.forEach(reel => { | |
reel.classList.remove('win-animation'); | |
}); | |
// If auto-spinning, continue after win | |
if (isAutoSpinning) { | |
setTimeout(() => { | |
if (credit > 0 && !isSpinning) { | |
spin(); | |
} | |
}, 1000); | |
} | |
}, 2000); | |
} | |
// Jackpot win | |
function jackpotWin() { | |
credit += winAmount; | |
updateDisplay(); | |
// Add jackpot animation to reels | |
reels.forEach(reel => { | |
reel.classList.add('jackpot'); | |
}); | |
// Play jackpot sound | |
jackpotSound.currentTime = 0; | |
jackpotSound.play(); | |
// Show win message | |
winAmountDisplay.textContent = winAmount; | |
winMessage.classList.remove('hidden'); | |
// Remove animation after delay | |
setTimeout(() => { | |
reels.forEach(reel => { | |
reel.classList.remove('jackpot'); | |
}); | |
// If auto-spinning, continue after win | |
if (isAutoSpinning) { | |
setTimeout(() => { | |
if (credit > 0 && !isSpinning) { | |
spin(); | |
} | |
}, 1000); | |
} | |
}, 3000); | |
} | |
// Event listeners | |
spinBtn.addEventListener('click', spin); | |
lever.addEventListener('mousedown', function() { | |
if (!isSpinning && credit > 0) { | |
pullLever(); | |
spin(); | |
} | |
}); | |
coin.addEventListener('click', insertCoin); | |
closeWinBtn.addEventListener('click', function() { | |
winMessage.classList.add('hidden'); | |
updateDisplay(); | |
// If auto-spinning, continue after closing win message | |
if (isAutoSpinning && credit > 0 && !isSpinning) { | |
setTimeout(spin, 500); | |
} | |
}); | |
// Keyboard support | |
document.addEventListener('keydown', function(e) { | |
if (e.code === 'Space' && !isSpinning && credit > 0) { | |
spin(); | |
} | |
}); | |
// Initialize the game | |
init(); | |
}); | |
</script> | |
</body> | |
</html> |