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!
Zpráva...
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-fluid flex-column h-100 d-none p-0" style="position: relative; overflow: hidden;"> <div class="d-flex gap-2 position-absolute top-0 start-0 m-3" style="z-index: 20;"> <div class="border rounded-circle shadow-sm mini-pin" style="width: 35px; height: 35px;"></div> <div class="border rounded-circle shadow-sm mini-pin" style="width: 35px; height: 35px;"></div> <div class="border rounded-circle shadow-sm mini-pin" style="width: 35px; height: 35px;"></div> </div> <div id="alertBox" class="alert text-center shadow-lg position-absolute start-50 translate-middle-x" style="display: none; top: 10vh; width: 90%; max-width: 500px; z-index: 100;"> <h2 id="alertHeading" class="alert-heading fw-bold fs-3">Pozor!</h2> <p class="fs-5 mb-0" id="alertReason">Zpráva...</p> </div> <div class="d-flex flex-column align-items-center justify-content-end flex-grow-1 pb-3" style="min-height: 0;"> <div class="position-relative d-flex justify-content-center align-items-end" style="flex-grow: 1; min-height: 0;"> <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 w-100 px-4 mt-3 flex-shrink-0"> <h3 class="mb-2 fw-bold"><span id="stageText">Semínko</span></h3> <div class="progress shadow-sm" style="height: 35px; font-size: 1.3rem; border-radius: 20px; 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> <div class="row text-center w-100 m-0 pb-3 pt-2 bg-white border-top shadow-sm flex-shrink-0"> <div class="col-4 px-2"> <i class="fa-solid fa-droplet text-primary fs-2 mb-1"></i> <div class="progress shadow-sm" style="height: 35px; border: 2px solid #eee; border-radius: 10px;"> <div id="waterBar" class="progress-bar bg-primary fs-6 fw-bold" style="width: 50%;">50 %</div> </div> </div> <div class="col-4 px-2"> <i class="fa-solid fa-sun text-warning fs-2 mb-1"></i> <div class="progress shadow-sm" style="height: 35px; border: 2px solid #eee; border-radius: 10px;"> <div id="sunBar" class="progress-bar bg-warning fs-6 fw-bold text-dark" style="width: 50%;">50 %</div> </div> </div> <div class="col-4 px-2"> <i class="fa-solid fa-poop fs-2 mb-1" style="color: #8B4513;"></i> <div class="progress shadow-sm" style="height: 35px; border: 2px solid #eee; border-radius: 10px;"> <div id="fertBar" class="progress-bar fs-6 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-3"><i class="fa-solid fa-trophy text-warning"></i> Gratulujeme!</h1> <h3 class="mb-4 text-secondary">Podařilo se ti vypěstovat nádhernou květinu.</h3> <img id="winVisual" src="flower_stage4.png" class="pulse-anim mb-4" style="max-height: 40vh; object-fit: contain;" alt="Výhra"> <button class="btn btn-primary btn-lg px-5 py-3 fs-2 shadow fw-bold mt-2" 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; max-width: 90vw; 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 }; // NENASTAVENÉ VÝCHOZÍ RYCHLOSTI RŮSTU let globalSettings = { speedSlow: 1, speedNormal: 2, speedPerfect: 4 }; 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(); } } async function generateUniquePin() { try { let isUnique = false; let safetyCounter = 0; while (!isUnique && safetyCounter < 50) { 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++; } 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]; }); document.getElementById('setupScreen').classList.add('d-none'); document.getElementById('setupScreen').classList.remove('d-flex'); document.getElementById('gameScreen').classList.remove('d-none'); document.getElementById('gameScreen').classList.add('d-flex'); updateUI(); startMainLoop(); } function startMainLoop() { gameLoop = setInterval(async () => { if (myFlower.status === "won") return; try { // 1. NAČTENÍ GLOBÁLNÍCH NASTAVENÍ (Z Admin.html) let settingsData = await forrestHubLib.dbVarGetKey("global_flower_settings"); if (settingsData) { globalSettings = settingsData; } // 2. NAČTENÍ STAVU KVĚTINY (Zalévání, léčení) 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; } 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 (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; } // Úbytek 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 { // DYNAMICKÁ RYCHLOST Z ADMIN PANELU let growthSpeed = isVerySlow ? globalSettings.speedSlow : (isPerfect ? globalSettings.speedPerfect : globalSettings.speedNormal); 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() * 50) + 20}%`; bug.style.left = `${Math.floor(Math.random() * 50) + 20}%`; bug.style.cursor = 'pointer'; bug.style.pointerEvents = 'auto'; bug.onclick = () => { 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); 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 alertBox = document.getElementById('alertBox'); let growthRatio = myFlower.xp / 100; let currentHeight = 15; if (myFlower.stage === 1) { currentHeight = 15 + (growthRatio * 5); document.getElementById('stageText').innerText = "Semínko"; } else if (myFlower.stage === 2) { currentHeight = 20 + (growthRatio * 10); document.getElementById('stageText').innerText = "Klíček"; } else if (myFlower.stage === 3) { currentHeight = 30 + (growthRatio * 10); document.getElementById('stageText').innerText = "Rostlinka"; } else if (myFlower.stage === 4) { currentHeight = 40 + (growthRatio * 10); document.getElementById('stageText').innerText = "Květina"; } visual.src = `flower_stage${myFlower.stage}.png`; visual.style.height = `${currentHeight}vh`; 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 shadow-lg position-absolute start-50 translate-middle-x"; document.getElementById('alertHeading').innerHTML = "<i class='fa-solid fa-pause'></i> Hra pozastavena"; document.getElementById('alertReason').innerHTML = "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%)"; alertBox.style.display = 'block'; alertBox.className = "alert alert-danger text-center shadow-lg position-absolute start-50 translate-middle-x"; document.getElementById('alertHeading').innerHTML = "<i class='fa-solid fa-triangle-exclamation'></i> Pozor, kytka je nemocná!"; document.getElementById('alertReason').innerText = myFlower.water > 100 ? "Přelil jsi vodu!" : "Běž do záchranné stanice."; } else { visual.style.filter = "none"; alertBox.style.display = 'none'; } } function showWinScreen() { document.getElementById('gameScreen').classList.add('d-none'); document.getElementById('gameScreen').classList.remove('d-flex'); document.getElementById('winScreen').classList.remove('d-none'); document.getElementById('winScreen').classList.add('d-flex'); } async function resetGame() { try { await forrestHubLib.dbVarDeleteKey(varPrefix + myId); } catch(e) {} location.reload(); } </script> {% endblock %}