Dveře 5
?
QR Kód s aktuální adresou
📺 Fullscreen
Dveře 5
ZAMČENO
↑
←
→
↓
Upravit obsah stránky
{% extends "templates/base.html" %} {% set game_name = "Dveře 5" %} {% block content %} <!-- Fullscreen button --> <button type="button" id="goFullscreen" class="btn btn-light" style="position:fixed; top:8px; right:8px; z-index:2000;">📺 Fullscreen</button> <div class="full-screen"> <!-- Panel with title and state --> <div class="door-panel card text-center p-3 mb-4 d-flex align-items-center justify-content-between"> <div class="flex-shrink-0"></div> <div> <br> <h1 class="mb-1">Dveře 5</h1> <p id="doorStatus" class="h4 mb-1">ZAMČENO</p> <p id="countdown" class="h5 mb-0" style="visibility:hidden;"></p> </div> <div class="flex-shrink-0"></div> </div> <br> <!-- 5×5 Grid --> <div id="grid" class="grid-container mb-3"> {% for row in ['A','B','C','D','E'] %} {% for col in [1,2,3,4,5] %} <div id="cell-{{row}}{{col}}" class="grid-cell"></div> {% endfor %} {% endfor %} </div> <br> <!-- Movement controls --> <div class="d-flex justify-content-center gap-2"> <button type="button" class="btn btn-secondary move-btn" data-dir="up">↑</button> <button type="button" class="btn btn-secondary move-btn" data-dir="left">←</button> <button type="button" class="btn btn-secondary move-btn" data-dir="right">→</button> <button type="button" class="btn btn-secondary move-btn" data-dir="down">↓</button> </div> </div> <style> .full-screen { position: fixed; top:0; left:0; width:100%; height:100%; display:flex; flex-direction:column; align-items:center; background-color:#ff4d4d; padding:2vh 2vw; box-sizing:border-box; overflow:hidden; } .door-panel { width:100%; max-width:600px; background:rgba(255,255,255,0.85); border:2px solid rgba(0,0,0,0.1); border-radius:.5rem; } .grid-container { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; width: 100%; max-width:90vw; flex:1 flex-shrink:0; } /* enforce true square cells with aspect-ratio */ .grid-cell { aspect-ratio: 1 / 1; border:1px solid #333; background:#fff; font-size:2.5rem; display:flex; align-items:center; justify-content:center; padding: 0; /* remove padding hack */ max-width: 100% /* max width for larger screens */ max-height: 80px; /* max height for larger screens */ } .move-btn { width:110px; height:110px; font-size:3rem; font-weight: bold; } body.locked .full-screen { background-color:#ff4d4d; } body.unlocked .full-screen { background-color:#4dff4d; } body.alarm .full-screen { background-color:#660000; } #alarmOverlay { position:absolute; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.9); color:#ff4444; display:flex; align-items:center; justify-content:center; font-size:2rem; text-align:center; z-index:9999; padding:1rem; } @media(max-width:768px) { .move-btn { width:15vw; height:15vw; font-size:2rem; } } </style> <script> document.getElementById('goFullscreen').addEventListener('click', () => { document.getElementById('goFullscreen').style.display = 'none'; const el = document.documentElement; (el.requestFullscreen||el.webkitRequestFullscreen||el.msRequestFullscreen).call(el); }); (async()=>{ const fh = new ForrestHubLib(); const variants = [ { name:'coin', emoji:'🪙', forbidden:['B1','B2','A4','A5','D4'] }, { name:'hat', emoji:'🎩', forbidden:['A2','B2','C2','D2','E4'] }, { name:'spider', emoji:'🕷️', forbidden:['A2','A3','B4','C1','C2','C4','C5'] } ]; const target = 'E5'; let variant, pos, state='locked', countdownTimer, resetTimer; function updateUI() { document.body.classList.remove('locked','unlocked','alarm'); document.body.classList.add(state); document.getElementById('doorStatus').textContent = state==='locked'? 'ZAMČENO' : state==='unlocked'? 'ODEMČENO' : 'ALARM'; } function renderGrid() { document.querySelectorAll('.grid-cell').forEach(cell=>{ cell.textContent = ''; }); document.getElementById('cell-'+pos).textContent = variant.emoji; const tgt = document.getElementById('cell-'+target); tgt.style.backgroundColor = '#cfc'; } async function pickVariant() { const i = Math.floor(Math.random()*variants.length); variant = variants[i]; await fh.dbVarSetKey('doors5Variant', variant.name); } async function lockDoor() { clearInterval(countdownTimer); clearTimeout(resetTimer); state = 'locked'; await pickVariant(); pos = 'A1'; await fh.dbVarSetKey('doors5Pos', pos); await fh.dbVarSetKey('doors5State', state); document.querySelectorAll('.grid-cell').forEach(cell=>{ cell.style.backgroundColor = '#fff'; }); updateUI(); renderGrid(); const cd = document.getElementById('countdown'); cd.style.visibility = 'hidden'; } async function unlockDoor() { clearInterval(countdownTimer); clearTimeout(resetTimer); state = 'unlocked'; await fh.dbVarSetKey('doors5State', state); updateUI(); let t = 10; const cd = document.getElementById('countdown'); cd.style.visibility = 'visible'; cd.textContent = t + ' s'; countdownTimer = setInterval(()=>{ if (--t > 0) cd.textContent = t + ' s'; },1000); resetTimer = setTimeout(lockDoor,10000); } async function triggerAlarm() { clearInterval(countdownTimer); clearTimeout(resetTimer); state = 'alarm'; await fh.dbVarSetKey('doors5State','alarm'); updateUI(); const ov = document.createElement('div'); ov.id = 'alarmOverlay'; ov.textContent = '!!!! Chyba !!!! ALARM !!!!'; document.body.appendChild(ov); setTimeout(()=>{ ov.remove(); lockDoor(); },10000); } function move(dir) { if (state !== 'locked') return; const row = pos[0], col = Number(pos[1]); const rows = ['A','B','C','D','E']; let r = rows.indexOf(row), c = col - 1; if (dir==='up' && r>0) r--; if (dir==='down' && r<4) r++; if (dir==='left' && c>0) c--; if (dir==='right' && c<4) c++; pos = rows[r] + (c+1); fh.dbVarSetKey('doors5Pos', pos); renderGrid(); if (pos === target) unlockDoor(); else if (variant.forbidden.includes(pos)) triggerAlarm(); } await lockDoor(); updateUI(); document.querySelectorAll('.move-btn').forEach(btn=>{ btn.addEventListener('click', ()=> move(btn.dataset.dir)); }); })(); </script> {% endblock %}