const VERSION_BASE = '29.04.2026.'; const STORAGE_KEY = 'nepastoucherTime'; const GAMEOVER_STORAGE_KEY = 'gameoverTime'; const WARNING_DURATION_MS = 10 * 60 * 1000; const versionEl = document.getElementById('compteur'); const contentEl = document.getElementById('content'); const preventionEl = document.getElementById('prevention'); const choiceButtons = document.querySelectorAll('.nepastoucher'); const counterButton = document.getElementById('compteurplusun'); const buyAutoClickButton = document.getElementById('achatautoclick'); const gameOverButton = document.getElementById('gameover'); const state = { counter: 1, autoClickCount: 0, autoClickAccumulator: 0, versionFlashColor: '', versionFlashExpiry: 0, autoClickInterval: 1000, isGameOver: false, fallingElements: [], baseGravity: 0.0009, bounceDamping: 0.6 }; const formatVersion = () => `Version: ${VERSION_BASE}${state.counter}`; const updateVersionText = () => { versionEl.textContent = formatVersion(); }; const flashVersion = (color, duration = 500) => { state.versionFlashColor = color; state.versionFlashExpiry = performance.now() + duration; versionEl.style.color = color; }; const getAutoClickCost = () => Math.max(1, Math.round(5 * state.autoClickCount)); const applyWarningEffect = () => { contentEl.classList.add('rotated'); preventionEl.classList.remove('hidden'); choiceButtons.forEach(button => button.classList.add('hidden')); }; const saveWarningTime = () => { localStorage.setItem(STORAGE_KEY, Date.now().toString()); }; const loadWarningState = () => { const storedTime = localStorage.getItem(STORAGE_KEY); if (!storedTime) { return; } const elapsed = Date.now() - Number(storedTime); if (elapsed < WARNING_DURATION_MS) { applyWarningEffect(); } else { localStorage.removeItem(STORAGE_KEY); } }; const saveGameOverTime = () => { localStorage.setItem(GAMEOVER_STORAGE_KEY, Date.now().toString()); }; const loadGameOverState = () => { const storedTime = localStorage.getItem(GAMEOVER_STORAGE_KEY); if (!storedTime) { return; } const elapsed = Date.now() - Number(storedTime); if (elapsed < WARNING_DURATION_MS) { state.isGameOver = true; const allButtons = document.querySelectorAll('button'); allButtons.forEach(button => { button.disabled = true; }); prepareFallingElements(); // Move all elements to bottom position immediately state.fallingElements.forEach(entry => { entry.settled = true; entry.velocity = 0; const bottomLimit = window.innerHeight - entry.height; entry.top = bottomLimit; entry.node.style.top = `${entry.top}px`; }); } else { localStorage.removeItem(GAMEOVER_STORAGE_KEY); } }; const prepareFallingElements = () => { const elements = Array.from(document.querySelectorAll('p, button, h1, h2')); // First pass: capture all positions before any DOM changes const elementData = elements.map(node => { const rect = node.getBoundingClientRect(); return { node, left: rect.left, top: rect.top, width: rect.width, height: rect.height }; }); // Second pass: apply positioning and create fall entries elementData.forEach(data => { const { node, left, top, width, height } = data; node.style.position = 'fixed'; node.style.left = `${left}px`; node.style.top = `${top}px`; node.style.width = `${width}px`; node.style.height = `${height}px`; node.style.margin = '0'; node.style.padding = node.style.padding || ''; node.style.boxSizing = 'border-box'; node.style.transition = 'none'; state.fallingElements.push({ node, top, width, height, velocity: (Math.random() - 0.5) * 0.3, gravity: state.baseGravity * (0.5 + Math.random()), bounceDamping: state.bounceDamping * (0.5 + Math.random() * 0.5), settled: false }); }); }; const startGameOverFall = () => { if (state.isGameOver) { return; } state.isGameOver = true; saveGameOverTime(); // Disable all buttons const allButtons = document.querySelectorAll('button'); allButtons.forEach(button => { button.disabled = true; }); prepareFallingElements(); }; const tick = (delta) => { if (state.autoClickCount > 0) { state.autoClickAccumulator += delta; const clicks = Math.floor(state.autoClickAccumulator / state.autoClickInterval) * state.autoClickCount; if (clicks > 0) { state.autoClickAccumulator %= state.autoClickInterval; state.counter += clicks; updateVersionText(); } } if (state.isGameOver) { state.fallingElements.forEach(entry => { // Apply gravity entry.velocity += entry.gravity * delta; entry.top += entry.velocity * delta; const bottomLimit = window.innerHeight - entry.height; // Bounce collision if (entry.top >= bottomLimit) { entry.top = bottomLimit; entry.velocity *= -entry.bounceDamping; // Stop bouncing when velocity is very small if (Math.abs(entry.velocity) < 0.1) { entry.velocity = 0; entry.settled = true; } } entry.node.style.top = `${entry.top}px`; }); } if (state.versionFlashExpiry && performance.now() >= state.versionFlashExpiry) { state.versionFlashColor = ''; state.versionFlashExpiry = 0; versionEl.style.color = ''; } }; const gameLoop = (timestamp) => { if (!gameLoop.lastTime) { gameLoop.lastTime = timestamp; } const delta = timestamp - gameLoop.lastTime; gameLoop.lastTime = timestamp; tick(delta); requestAnimationFrame(gameLoop); }; const init = () => { updateVersionText(); loadWarningState(); loadGameOverState(); choiceButtons.forEach(button => { button.addEventListener('click', () => { saveWarningTime(); applyWarningEffect(); }); }); counterButton.addEventListener('click', () => { state.counter += 1; updateVersionText(); flashVersion('green', 300); }); buyAutoClickButton.addEventListener('click', () => { const cost = getAutoClickCost(); if (state.counter >= cost) { state.counter -= cost; state.autoClickCount += 1; updateVersionText(); flashVersion('yellow', 1000); } else { flashVersion('red', 1000); } }); gameOverButton.addEventListener('click', () => { startGameOverFall(); }); requestAnimationFrame(gameLoop); }; document.addEventListener('DOMContentLoaded', init);