Moje Květina
?
QR Kód s aktuální adresou
Vypěstuj si svou květinu!
Hledám pro tebe unikátní barvy...
Tohle je tvůj tajný kód. Dobře si ho pamatuj!
ZAČÍT HRÁT!
Pozor!
Něčeho máš moc (nebo málo). Běž rychle do Záchranné stanice, jinak kytka zvadne!
Semínko
0 %
50 %
50 %
50 %
Gratulujeme!
Podařilo se ti vypěstovat nádhernou květinu.
VYPĚSTOVAT NOVOU
Upravit obsah stránky
{% extends "templates/base.html" %} {% set game_name = "Moje Květina" %} {% block content %} <div id="appContainer" class="full-screen-app bg-light"> <button id="fsBtn" class="btn btn-outline-secondary position-absolute top-0 end-0 m-3 shadow" style="z-index: 10050;" onclick="toggleFullscreen()"> <i class="fa-solid fa-expand fa-2x"></i> </button> <div id="setupScreen" class="container d-flex flex-column justify-content-center align-items-center h-100"> <h1 class="mb-4 text-center fw-bold">Vypěstuj si svou květinu!</h1> <div id="loadingPin" class="text-center mb-4"> <div class="spinner-border text-primary mb-2" role="status"></div> <h4>Hledám pro tebe unikátní barvy...</h4> </div> <div id="pinReady" class="text-center w-100" style="display: none;"> <h4 class="mb-4">Tohle je tvůj tajný kód. Dobře si ho pamatuj!</h4> <div class="d-flex justify-content-center gap-3 mb-5" id="pinDisplay"> <div class="pin-slot border rounded-circle shadow" style="width: 100px; height: 100px;"></div> <div class="pin-slot border rounded-circle shadow" style="width: 100px; height: 100px;"></div> <div class="pin-slot border rounded-circle shadow" style="width: 100px; height: 100px;"></div> </div> <button id="startBtn" class="btn btn-success btn-lg px-5 py-4 fs-1 shadow fw-bold" onclick="startGame()">ZAČÍT HRÁT!</button> </div> </div> <div id="gameScreen" class="container py-4 flex-column h-100 d-none" style="position: relative;"> <div class="d-flex gap-2 position-absolute top-0 start-0 m-3" id="miniPinDisplay"> <div class="border rounded-circle shadow-sm mini-pin" style="width: 40px; height: 40px;"></div> <div class="border rounded-circle shadow-sm mini-pin" style="width: 40px; height: 40px;"></div> <div class="border rounded-circle shadow-sm mini-pin" style="width: 40px; height: 40px;"></div> </div> <div id="alertBox" class="alert alert-danger text-center mx-auto shadow-lg" style="display: none; max-width: 600px; margin-top: 60px; z-index: 10;"> <h2 id="alertHeading" class="alert-heading fw-bold"><i class="fa-solid fa-triangle-exclamation"></i> Pozor!</h2> <p class="fs-4 mb-0" id="alertReason">Něčeho máš moc (nebo málo). Běž rychle do Záchranné stanice, jinak kytka zvadne!</p> </div> <div class="text-center my-auto position-relative d-flex align-items-center justify-content-center flex-grow-1" style="min-height: 350px;"> <img id="flowerVisual" src="flower_stage1.png" alt="Květina"> <div id="bugContainer" class="position-absolute w-100 h-100 top-0 start-0 pointer-events-none"></div> </div> <div class="text-center mb-4 w-100 px-3"> <h3 class="mb-2 fw-bold"><span id="stageText">Semínko</span></h3> <div class="progress shadow-sm" style="height: 45px; font-size: 1.6rem; border-radius: 25px; border: 2px solid #fff;"> <div id="xpBar" class="progress-bar progress-bar-striped progress-bar-animated bg-success fw-bold" role="progressbar" style="width: 0%;">0 %</div> </div> </div> <div class="row text-center mt-auto w-100 m-0 pb-3"> <div class="col-4 px-2"> <h1 class="text-primary mb-1"><i class="fa-solid fa-droplet"></i></h1> <div class="progress shadow-sm" style="height: 50px; border: 3px solid #ccc; border-radius: 15px;"> <div id="waterBar" class="progress-bar bg-primary fs-4 fw-bold" style="width: 50%;">50 %</div> </div> </div> <div class="col-4 px-2"> <h1 class="text-warning mb-1"><i class="fa-solid fa-sun"></i></h1> <div class="progress shadow-sm" style="height: 50px; border: 3px solid #ccc; border-radius: 15px;"> <div id="sunBar" class="progress-bar bg-warning fs-4 fw-bold text-dark" style="width: 50%;">50 %</div> </div> </div> <div class="col-4 px-2"> <h1 style="color: #8B4513;" class="mb-1"><i class="fa-solid fa-poop"></i></h1> <div class="progress shadow-sm" style="height: 50px; border: 3px solid #ccc; border-radius: 15px;"> <div id="fertBar" class="progress-bar fs-4 fw-bold" style="background-color: #8B4513; width: 50%;">50 %</div> </div> </div> </div> </div> <div id="winScreen" class="container py-4 flex-column h-100 text-center justify-content-center align-items-center d-none"> <h1 class="display-3 fw-bold text-success mb-4"><i class="fa-solid fa-trophy text-warning"></i> Gratulujeme!</h1> <h3 class="mb-5 text-secondary">Podařilo se ti vypěstovat nádhernou květinu.</h3> <img id="winVisual" src="flower_stage4.png" class="pulse-anim mb-5" style="height: 25rem; object-fit: contain;" alt="Vítězná květina"> <button class="btn btn-primary btn-lg px-5 py-4 fs-2 shadow fw-bold" onclick="resetGame()">VYPĚSTOVAT NOVOU</button> </div> </div> <style> .full-screen-app { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999; display: flex; flex-direction: column; overflow: hidden; } body { user-select: none; -webkit-user-select: none; } .pointer-events-none { pointer-events: none; } #flowerVisual { height: 0; /* Fix bliknutí */ object-fit: contain; transition: all 0.4s ease-out; display: block; margin: 0 auto; } .pulse-anim { animation: pulse 2s infinite ease-in-out; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } </style> <script> forrestHubLib = ForrestHubLib.getInstance(true); const varPrefix = "flower_"; const availableColors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange']; let myPin = []; let myId = ""; let myFlower = { status: "ok", water: 50, sun: 50, fertilizer: 50, stage: 1, xp: 0 }; let gameLoop; let bugSpawner; let activeBug = null; document.addEventListener('DOMContentLoaded', generateUniquePin); function toggleFullscreen() { const el = document.documentElement; if (!document.fullscreenElement) { if (el.requestFullscreen) el.requestFullscreen(); else if (el.webkitRequestFullscreen) el.webkitRequestFullscreen(); else if (el.msRequestFullscreen) el.msRequestFullscreen(); } } document.addEventListener('fullscreenchange', () => { document.getElementById('fsBtn').style.display = document.fullscreenElement ? 'none' : 'block'; }); async function generateUniquePin() { try { let isUnique = false; let safetyCounter = 0; while (!isUnique && safetyCounter < 100) { let tempPin = [ availableColors[Math.floor(Math.random() * availableColors.length)], availableColors[Math.floor(Math.random() * availableColors.length)], availableColors[Math.floor(Math.random() * availableColors.length)] ]; let tempId = tempPin.join('_'); let exists = await forrestHubLib.dbVarKeyExists(varPrefix + tempId); if (!exists) { myPin = tempPin; myId = tempId; isUnique = true; } safetyCounter++; } if (!isUnique) { forrestHubLib.uiShowAlert('danger', 'Nepodařilo se vygenerovat PIN.'); return; } document.querySelectorAll('.pin-slot').forEach((slot, index) => { slot.style.backgroundColor = myPin[index]; }); document.getElementById('loadingPin').style.display = 'none'; document.getElementById('pinReady').style.display = 'block'; } catch (error) { console.error(error); } } async function startGame() { await forrestHubLib.dbVarSetKey(varPrefix + myId, myFlower); document.querySelectorAll('.mini-pin').forEach((slot, idx) => { slot.style.backgroundColor = myPin[idx]; }); // OPRAVA: Explicitní přepnutí Bootstrap tříd const setup = document.getElementById('setupScreen'); setup.classList.remove('d-flex'); setup.classList.add('d-none'); const game = document.getElementById('gameScreen'); game.classList.remove('d-none'); game.classList.add('d-flex'); updateUI(); // Okamžitá aktualizace před startem loopu startMainLoop(); } function startMainLoop() { gameLoop = setInterval(async () => { if (myFlower.status === "won") return; try { let serverData = await forrestHubLib.dbVarGetKey(varPrefix + myId); if (serverData) { if (myFlower.status === "sick" && serverData.status === "ok") { myFlower.status = "ok"; myFlower.water = serverData.water; myFlower.sun = serverData.sun; myFlower.fertilizer = serverData.fertilizer; forrestHubLib.uiShowAlert('success', 'Květina byla vyléčena!', 4000); } else if (serverData.status === "busy" && myFlower.status !== "busy") { myFlower.status = "busy"; } else if ((serverData.status === "ok" || serverData.status === "sick") && myFlower.status === "busy") { myFlower.status = serverData.status; myFlower.water = serverData.water; myFlower.sun = serverData.sun; myFlower.fertilizer = serverData.fertilizer; if (serverData.status === "sick") forrestHubLib.uiShowAlert('danger', 'Pozor, na stanici jsi to přehnal!', 3000); } if (myFlower.status !== "busy" && myFlower.status !== "sick") { if (serverData.water > myFlower.water) { myFlower.water = serverData.water; } if (serverData.sun > myFlower.sun) { myFlower.sun = serverData.sun; } if (serverData.fertilizer > myFlower.fertilizer) { myFlower.fertilizer = serverData.fertilizer; } } } } catch(e) {} if (myFlower.status !== "ok") { updateUI(); return; } myFlower.water = Math.max(0, myFlower.water - 1); myFlower.sun = Math.max(0, myFlower.sun - 1); myFlower.fertilizer = Math.max(0, myFlower.fertilizer - 1); if (myFlower.water > 100 || myFlower.sun > 100 || myFlower.fertilizer > 100) { myFlower.status = "sick"; } if (myFlower.status === "ok" && !activeBug) { let isStarving = (myFlower.water < 15 || myFlower.sun < 15 || myFlower.fertilizer < 15); let isVerySlow = !isStarving && (myFlower.water < 30 || myFlower.sun < 30 || myFlower.fertilizer < 30); let isPerfect = (myFlower.water >= 60 && myFlower.water <= 90) && (myFlower.sun >= 60 && myFlower.sun <= 90) && (myFlower.fertilizer >= 60 && myFlower.fertilizer <= 90); if (isStarving) { myFlower.xp -= 1; if (myFlower.xp < 0) { if (myFlower.stage > 1) { myFlower.stage--; myFlower.xp = 90; } else { myFlower.xp = 0; } } } else { let growthSpeed = isVerySlow ? 5 : (isPerfect ? 20 : 10); myFlower.xp += growthSpeed; if (myFlower.xp >= 100) { if (myFlower.stage < 4) { myFlower.stage++; myFlower.xp = 0; } else { myFlower.xp = 100; myFlower.status = "won"; showWinScreen(); } } } } updateUI(); if(myFlower.status !== "won") { await forrestHubLib.dbVarSetKey(varPrefix + myId, myFlower); } }, 2000); bugSpawner = setInterval(() => { if (myFlower.status === "ok" && !activeBug && Math.random() > 0.5) spawnBug(); }, 10000); } function spawnBug() { const container = document.getElementById('bugContainer'); const bug = document.createElement('div'); bug.innerHTML = `<i class="fa-solid fa-bug text-dark"></i>`; bug.className = 'position-absolute text-danger'; bug.style.fontSize = '4.5rem'; bug.style.top = `${Math.floor(Math.random() * 60) + 20}%`; bug.style.left = `${Math.floor(Math.random() * 60) + 20}%`; bug.style.cursor = 'pointer'; bug.style.pointerEvents = 'auto'; bug.onclick = () => { clearTimeout(activeBug.timer); container.innerHTML = ''; activeBug = null; }; container.appendChild(bug); let timer = setTimeout(async () => { if (activeBug && myFlower.status === "ok") { container.innerHTML = ''; activeBug = null; myFlower.water = Math.max(0, myFlower.water - 15); myFlower.sun = Math.max(0, myFlower.sun - 15); myFlower.fertilizer = Math.max(0, myFlower.fertilizer - 15); forrestHubLib.uiShowAlert('danger', 'Au! Brouk tě kousnul! (-15%)', 3000); updateUI(); await forrestHubLib.dbVarSetKey(varPrefix + myId, myFlower); } else { container.innerHTML = ''; activeBug = null; } }, 5000); activeBug = { element: bug, timer: timer }; } function updateUI() { if (myFlower.status === "won") return; document.getElementById('waterBar').style.width = `${Math.min(100, myFlower.water)}%`; document.getElementById('waterBar').innerText = `${myFlower.water} %`; document.getElementById('sunBar').style.width = `${Math.min(100, myFlower.sun)}%`; document.getElementById('sunBar').innerText = `${myFlower.sun} %`; document.getElementById('fertBar').style.width = `${Math.min(100, myFlower.fertilizer)}%`; document.getElementById('fertBar').innerText = `${myFlower.fertilizer} %`; let totalProgress = Math.floor(((myFlower.stage - 1) * 25) + (myFlower.xp / 4)); document.getElementById('xpBar').style.width = `${totalProgress}%`; document.getElementById('xpBar').innerText = `${totalProgress} %`; const visual = document.getElementById('flowerVisual'); const stageText = document.getElementById('stageText'); const alertBox = document.getElementById('alertBox'); let growthRatio = myFlower.xp / 100; let currentHeight = 8; if (myFlower.stage === 1) { currentHeight = 8 + (growthRatio * 4); stageText.innerText = "Semínko"; } else if (myFlower.stage === 2) { currentHeight = 12 + (growthRatio * 4); stageText.innerText = "Klíček"; } else if (myFlower.stage === 3) { currentHeight = 16 + (growthRatio * 4); stageText.innerText = "Rostlinka"; } else if (myFlower.stage === 4) { currentHeight = 20 + (growthRatio * 6); stageText.innerText = "Květina"; } visual.src = `flower_stage${myFlower.stage}.png`; visual.style.height = `${currentHeight}rem`; if (myFlower.status === "busy") { visual.style.filter = "drop-shadow(0 0 20px #0dcaf0) grayscale(30%)"; alertBox.style.display = 'block'; alertBox.className = "alert alert-info text-center mx-auto shadow-lg"; document.getElementById('alertHeading').innerHTML = "<i class='fa-solid fa-pause'></i> Hra pozastavena"; document.getElementById('alertReason').innerHTML = "<i class='fa-solid fa-spinner fa-spin'></i> Pracuješ na stanici..."; } else if (myFlower.status === "sick" || myFlower.water > 100 || myFlower.sun > 100 || myFlower.fertilizer > 100) { visual.style.filter = "drop-shadow(0 0 30px #dc3545) sepia(50%) hue-rotate(-50deg) saturate(150%)"; alertBox.style.display = 'block'; alertBox.className = "alert alert-danger text-center mx-auto shadow-lg"; document.getElementById('alertHeading').innerHTML = "<i class='fa-solid fa-triangle-exclamation'></i> Pozor, kytka je nemocná!"; if (myFlower.water > 100) document.getElementById('alertReason').innerText = "Přelil jsi vodu! Běž do záchranné stanice."; else if (myFlower.sun > 100) document.getElementById('alertReason').innerText = "Kytka je spálená od slunce! Běž do záchranné stanice."; else if (myFlower.fertilizer > 100) document.getElementById('alertReason').innerText = "Přehnojil jsi ji! Běž do záchranné stanice."; else document.getElementById('alertReason').innerText = "Kytka je nemocná. Běž do záchranné stanice."; } else { visual.style.filter = "drop-shadow(0 0 10px rgba(0,0,0,0.1))"; alertBox.style.display = 'none'; } } function showWinScreen() { document.getElementById('gameScreen').classList.remove('d-flex'); document.getElementById('gameScreen').classList.add('d-none'); const win = document.getElementById('winScreen'); win.classList.remove('d-none'); win.classList.add('d-flex'); } async function resetGame() { try { await forrestHubLib.dbVarDeleteKey(varPrefix + myId); } catch(e) {} location.reload(); } </script> {% endblock %}