document.addEventListener('DOMContentLoaded', () => { const slapImage = document.getElementById('slap-image'); const hand = document.getElementById('hand'); const fist = document.getElementById('fist'); const slapSound = document.getElementById('slap-sound'); const punchSound = document.getElementById('punch-sound'); const scoreDisplay = document.getElementById('score'); const saveScoreBtn = document.getElementById('save-score'); const leaderboard = document.getElementById('leaderboard'); const modalOverlay = document.getElementById('modal-overlay'); const modal = document.getElementById('modal'); const nameInput = document.getElementById('name-input'); const submitScoreBtn = document.getElementById('submit-score'); const cancelScoreBtn = document.getElementById('cancel-score'); let score = 0; let pressTimer = null; const initialHandRight = 20; const initialFistRight = 20; hand.style.right = `${initialHandRight}px`; fist.style.right = `${initialFistRight}px`; /* * Slap Ryan with the hand or fist. */ function doAction(emoji, x, y) { console.log('doAction called'); emoji.style.right = 'auto'; /* Unset right property. */ emoji.style.left = `${x - emoji.offsetWidth / 2}px`; emoji.style.top = `${y - emoji.offsetHeight / 2}px`; if (emoji === hand) { slapSound.currentTime = 0; slapSound.play(); } else { punchSound.currentTime = 0; punchSound.play(); } score++; scoreDisplay.textContent = score; console.log('Score:', score); /* Move the emoji back to a ready position. */ setTimeout(() => { console.log('Moving emoji back'); emoji.style.left = 'auto'; /* Unset left property. */ if (emoji === hand) { emoji.style.right = `${initialHandRight}px`; emoji.style.top = '50%'; } else { emoji.style.right = `${initialFistRight}px`; emoji.style.top = 'calc(50% + 150px)'; } }, 500); } /* * Handle mouse events. */ slapImage.addEventListener('mousedown', (event) => { if (event.button === 0) { // Left mouse button /* Start a timer to detect a long press. */ pressTimer = setTimeout(() => { doAction(fist, event.clientX, event.clientY); pressTimer = null; }, 500); } else if (event.button === 2) { // Right mouse button doAction(fist, event.clientX, event.clientY); } }); slapImage.addEventListener('mouseup', (event) => { if (pressTimer && event.button === 0) { /* If the timer is still running, it was a short press. */ clearTimeout(pressTimer); doAction(hand, event.clientX, event.clientY); } }); /* Prevent the context menu on right-click. */ slapImage.addEventListener('contextmenu', (event) => { event.preventDefault(); }); /* * Handle touch events. */ slapImage.addEventListener('touchstart', (event) => { /* Start a timer to detect a long press. */ pressTimer = setTimeout(() => { doAction(fist, event.touches[0].clientX, event.touches[0].clientY); pressTimer = null; }, 500); }); slapImage.addEventListener('touchend', (event) => { if (pressTimer) { /* If the timer is still running, it was a short press. */ clearTimeout(pressTimer); doAction(hand, event.changedTouches[0].clientX, event.changedTouches[0].clientY); } }); slapImage.addEventListener('touchmove', (event) => { /* Cancel the long press if the user moves their finger. */ clearTimeout(pressTimer); }); const fetchScores = async () => { try { console.log('Fetching scores...'); const response = await fetch('/api/scores'); console.log('Scores response:', response); const scores = await response.json(); console.log('Scores data:', scores); leaderboard.innerHTML = ''; scores.forEach(score => { const li = document.createElement('li'); li.textContent = `${score.name}: ${score.score}`; leaderboard.appendChild(li); }); } catch (error) { console.error('Error fetching scores:', error); } }; saveScoreBtn.addEventListener('click', () => { modalOverlay.style.display = 'flex'; }); submitScoreBtn.addEventListener('click', async () => { const name = nameInput.value; if (name) { try { const response = await fetch('/api/scores', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, score }) }); if (response.ok) { score = 0; scoreDisplay.textContent = score; fetchScores(); } modalOverlay.style.display = 'none'; nameInput.value = ''; } catch (error) { console.error('Error saving score:', error); } } }); cancelScoreBtn.addEventListener('click', () => { modalOverlay.style.display = 'none'; nameInput.value = ''; }); fetchScores(); });