Navigátor - Taktická Mapa
?
QR Kód s aktuální adresou
Navigace
Čas:
05:00
SEVERNÍ PÓL (CÍL)
Radar oslepen!
Krize: Mlha na radaru
Hlaste Skladníkovi:
"Potřebuji Radar (QR-02)!"
Nařídit nový kurz
-30° (Levá)
-15°
0° (Přímo)
+15°
+30° (Pravá)
Varování: Každá změna kurzu vyžaduje okamžitou reakci Kapitána na kormidle!
Upravit obsah stránky
{% extends "templates/base.html" %} {% set game_name = "Navigátor - Taktická Mapa" %} {% block content %} <style> /* Stylování radaru */ .radar-box { background-color: #051605; border: 4px solid #00ff00; border-radius: 10px; position: relative; height: 55vh; overflow: hidden; box-shadow: inset 0 0 40px rgba(0, 255, 0, 0.2), 0 0 15px rgba(0, 255, 0, 0.5); } /* Mřížka radaru */ .radar-grid { position: absolute; width: 100%; height: 100%; background-image: linear-gradient(rgba(0, 255, 0, 0.2) 1px, transparent 1px), linear-gradient(90deg, rgba(0, 255, 0, 0.2) 1px, transparent 1px); background-size: 10% 10%; } /* Skenovací čára */ .radar-scanner { position: absolute; width: 100%; height: 10%; background: linear-gradient(to bottom, transparent, rgba(0, 255, 0, 0.5)); border-bottom: 2px solid #00ff00; animation: scan 4s linear infinite; z-index: 2; } @keyframes scan { 0% { top: -10%; } 100% { top: 100%; } } /* Ikonka lodi */ .ship-icon { position: absolute; bottom: 0%; left: 50%; transform: translateX(-50%) rotate(0deg); color: #00ff00; font-size: 2rem; /* Odebrali jsme transition pro transform a left, protože je budeme plynule animovat přes JS (30 FPS) */ transition: bottom 1s linear; z-index: 5; text-shadow: 0 0 10px #00ff00; } /* Cíl - Severní pól */ .north-pole { position: absolute; top: 0; left: 0; width: 100%; text-align: center; color: #00ff00; font-weight: bold; background: rgba(0, 255, 0, 0.2); border-bottom: 2px dashed #00ff00; padding: 5px 0; z-index: 1; } /* Překážky na mapě */ .obstacle { position: absolute; color: #ff3333; font-size: 1.5rem; transform: translateX(-50%); z-index: 4; text-shadow: 0 0 10px #ff3333; } /* Efekt mlhy */ .fog-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(200, 200, 200, 0.9); backdrop-filter: blur(10px); z-index: 10; display: none; /* Skryto ve výchozím stavu */ flex-direction: column; justify-content: center; align-items: center; text-align: center; } .fog-overlay h2 { color: #d9534f; font-weight: 900; text-transform: uppercase; letter-spacing: 2px; text-shadow: 2px 2px 0px #fff; } </style> <div class="container py-3"> <div class="d-flex justify-content-between align-items-center mb-3"> <h3 class="text-success mb-0"><i class="fa-solid fa-satellite-dish"></i> Navigace</h3> <div class="bg-dark text-white p-2 rounded border border-secondary"> <i class="fa-solid fa-clock"></i> Čas: <span id="uiTimeLeft" class="text-warning fw-bold">05:00</span> </div> </div> <!-- Taktický Radar --> <div class="radar-box mb-4"> <div class="radar-grid"></div> <div class="radar-scanner"></div> <div class="north-pole"><i class="fa-solid fa-flag"></i> SEVERNÍ PÓL (CÍL)</div> <!-- Pevně dané vizuální překážky na trase --> <i class="fa-solid fa-mountain obstacle" style="bottom: 20%; left: 30%;"></i> <i class="fa-solid fa-cloud-bolt obstacle" style="bottom: 50%; left: 70%;"></i> <i class="fa-solid fa-mountain obstacle" style="bottom: 80%; left: 40%;"></i> <!-- Naše vzducholoď --> <i class="fa-solid fa-location-arrow ship-icon" id="shipIcon"></i> <!-- Překryvná vrstva: MLHA --> <div class="fog-overlay" id="fogOverlay"> <i class="fa-solid fa-triangle-exclamation display-1 text-danger mb-3"></i> <h2>Radar oslepen!</h2> <p class="fs-4 text-dark fw-bold">Krize: Mlha na radaru</p> <div class="alert alert-danger shadow-sm"> <strong>Hlaste Skladníkovi:</strong> "Potřebuji Radar (QR-02)!" </div> </div> </div> <!-- Ovládací panel kurzu --> <div class="card bg-dark border-secondary"> <div class="card-body text-center"> <h5 class="text-light mb-3"><i class="fa-solid fa-compass"></i> Nařídit nový kurz</h5> <div class="btn-group w-100" role="group"> <button type="button" class="btn btn-outline-info course-btn" id="btn-course--30" onclick="setCourse(-30)">-30° (Levá)</button> <button type="button" class="btn btn-outline-info course-btn" id="btn-course--15" onclick="setCourse(-15)">-15°</button> <button type="button" class="btn btn-info course-btn active" id="btn-course-0" onclick="setCourse(0)">0° (Přímo)</button> <button type="button" class="btn btn-outline-info course-btn" id="btn-course-15" onclick="setCourse(15)">+15°</button> <button type="button" class="btn btn-outline-info course-btn" id="btn-course-30" onclick="setCourse(30)">+30° (Pravá)</button> </div> <small class="text-muted mt-2 d-block">Varování: Každá změna kurzu vyžaduje okamžitou reakci Kapitána na kormidle!</small> </div> </div> </div> <script> const forrestHubLib = ForrestHubLib.getInstance(true); let currentCourse = 0; // Globální proměnné pro vizualizaci pohybu let shipX = 50; // Začínáme uprostřed radaru (50 %) const DRIFT_SPEED = 0.15; // Rychlost posunu do stran // --- OVLÁDÁNÍ KURZU --- async function setCourse(degree) { currentCourse = degree; // 1. Odeslání do DB pro Kapitána await forrestHubLib.dbVarSetKey('targetHeading', degree); // 2. Úprava tlačítek v UI document.querySelectorAll('.course-btn').forEach(btn => { btn.classList.remove('active', 'btn-info'); btn.classList.add('btn-outline-info'); }); const activeBtn = document.getElementById(`btn-course-${degree}`); if(activeBtn) { activeBtn.classList.remove('btn-outline-info'); activeBtn.classList.add('active', 'btn-info'); } forrestHubLib.uiShowAlert('success', `Kurz změněn na ${degree}°`, 1500); } // --- HERNÍ SMYČKA LOKÁLNÍHO VYKRESLOVÁNÍ (30 FPS) --- // Zajišťuje plynulý přesun lodě do stran podle kurzu setInterval(() => { // Vypočítáme drift: maximum je při 30 a -30 stupních let driftAmount = (currentCourse / 30) * DRIFT_SPEED; shipX += driftAmount; // Omezení, aby loď nevyletěla mimo radar (např. držíme se mezi 5 % a 95 %) shipX = Math.max(5, Math.min(95, shipX)); // Aplikace na ikonu const shipIcon = document.getElementById('shipIcon'); shipIcon.style.left = `${shipX}%`; shipIcon.style.transform = `translateX(-50%) rotate(${currentCourse}deg)`; }, 1000 / 30); // --- SYNCHRONIZAČNÍ SMYČKA S DATABÁZÍ (1 FPS) --- // Čte globální stav hry (čas, postup vpřed, eventy) setInterval(async () => { try { // --- 1. Čtení Pozice (postup k pólu) a Času --- let pos = await forrestHubLib.dbVarGetKey('position'); if (pos !== null && pos !== undefined) { // Přepočítáme 0-100 na vizuální výšku (zastavíme na 95%, aby to nevylétlo ven z divu) let visualPos = Math.min(parseFloat(pos), 95); document.getElementById('shipIcon').style.bottom = `${visualPos}%`; } let time = await forrestHubLib.dbVarGetKey('timeLeft'); if (time !== null && time !== undefined) { let parsedTime = parseInt(time); let mins = Math.floor(Math.max(0, parsedTime) / 60); let secs = Math.ceil(Math.max(0, parsedTime) % 60); document.getElementById('uiTimeLeft').innerText = `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } // --- 2. Kontrola Krizí (Mlha) --- let eventsDict = await forrestHubLib.dbArrayFetchAllRecords('activeEvents'); let isFogActive = false; if (eventsDict) { // Projdeme aktivní eventy, jestli je tam mlha Object.values(eventsDict).forEach(ev => { if (ev.id && ev.id.toLowerCase().includes("mlha")) { isFogActive = true; } }); } // Aplikace nebo zrušení mlhy const fogUI = document.getElementById('fogOverlay'); if (isFogActive) { fogUI.style.display = 'flex'; } else { fogUI.style.display = 'none'; } } catch (err) { console.warn("Chyba při čtení dat Navigátora: ", err); } }, 1000); // Inicializace výchozího kurzu při načtení document.addEventListener('DOMContentLoaded', () => { setCourse(0); }); </script> {% endblock %}