212 lines
8.2 KiB
JavaScript
212 lines
8.2 KiB
JavaScript
/* ============================================================
|
||
public/js/buildings/daily.js
|
||
Tagesherausforderung – Karten-Pfad mit 7 Stationen gegen KI
|
||
============================================================ */
|
||
|
||
/* ── Stationen: Position auf dem Bild (% left, % top) ───── */
|
||
const DAILY_STATIONS = [
|
||
{ id: 1, left: 49.5, top: 86.5, label: "1" },
|
||
{ id: 2, left: 37.0, top: 73.0, label: "2" },
|
||
{ id: 3, left: 44.5, top: 62.0, label: "3" },
|
||
{ id: 4, left: 54.5, top: 53.5, label: "4" },
|
||
{ id: 5, left: 49.0, top: 46.0, label: "5" },
|
||
{ id: 6, left: 44.5, top: 37.5, label: "6" },
|
||
{ id: 7, left: 50.0, top: 22.0, label: "7" },
|
||
];
|
||
|
||
let dailyDeckId = null;
|
||
let dailyOverlay = null;
|
||
|
||
/* ── Öffnet den Karten-Pfad ──────────────────────────────── */
|
||
export async function openDailyMap(deckId) {
|
||
dailyDeckId = deckId;
|
||
|
||
// Kein Duplikat
|
||
document.getElementById("daily-map-overlay")?.remove();
|
||
|
||
/* Fortschritt vom Server laden */
|
||
let completed = [];
|
||
try {
|
||
const res = await fetch("/api/himmelstor/daily/progress");
|
||
if (res.ok) {
|
||
const data = await res.json();
|
||
completed = data.completed ?? [];
|
||
}
|
||
} catch (e) { console.error("[Daily] Fortschritt laden:", e); }
|
||
|
||
/* Overlay aufbauen */
|
||
dailyOverlay = document.createElement("div");
|
||
dailyOverlay.id = "daily-map-overlay";
|
||
dailyOverlay.innerHTML = `
|
||
<div id="daily-map-wrap">
|
||
<img id="daily-map-img" src="/images/KI_arena/daily.jpeg"
|
||
onerror="this.src='/images/items/rueckseite.png'" alt="Daily" />
|
||
<div id="daily-map-title">☀️ TAGESHERAUSFORDERUNG</div>
|
||
<button id="daily-map-close" title="Schließen">✕</button>
|
||
${buildCircles(completed)}
|
||
<div id="daily-progress-bar-wrap">
|
||
<div id="daily-progress-text">${completed.length} / 7 Stationen abgeschlossen</div>
|
||
<div id="daily-progress-track">
|
||
<div id="daily-progress-fill" style="width:${Math.round((completed.length / 7) * 100)}%"></div>
|
||
</div>
|
||
</div>
|
||
${completed.length >= 7 ? buildAllDonePanel() : ""}
|
||
</div>`;
|
||
|
||
document.body.appendChild(dailyOverlay);
|
||
|
||
/* Event-Listener */
|
||
document.getElementById("daily-map-close").addEventListener("click", closeDailyMap);
|
||
dailyOverlay.addEventListener("click", e => { if (e.target === dailyOverlay) closeDailyMap(); });
|
||
|
||
/* Klickbare Kreise */
|
||
dailyOverlay.querySelectorAll(".daily-circle.available").forEach(circle => {
|
||
circle.addEventListener("click", () => {
|
||
const station = parseInt(circle.dataset.station, 10);
|
||
startDailyStation(station);
|
||
});
|
||
});
|
||
}
|
||
|
||
/* ── HTML der Kreise ─────────────────────────────────────── */
|
||
function buildCircles(completed) {
|
||
const maxDone = completed.length; // nächster freier = maxDone + 1
|
||
|
||
return DAILY_STATIONS.map(s => {
|
||
const isDone = completed.includes(s.id);
|
||
const isAvailable = !isDone && s.id === maxDone + 1;
|
||
const isLocked = !isDone && !isAvailable;
|
||
|
||
const cls = isDone ? "done" : isAvailable ? "available" : "locked";
|
||
const inner = isDone ? "" : s.label; // done zeigt ✓ per CSS ::after
|
||
|
||
return `<div
|
||
class="daily-circle ${cls}"
|
||
data-station="${s.id}"
|
||
style="left:${s.left}%;top:${s.top}%;"
|
||
title="${isDone ? "Abgeschlossen" : isAvailable ? `Station ${s.id} starten` : "Gesperrt"}"
|
||
>${inner}</div>`;
|
||
}).join("");
|
||
}
|
||
|
||
function buildAllDonePanel() {
|
||
return `
|
||
<div id="daily-all-done">
|
||
<div class="done-icon">🏆</div>
|
||
<div class="done-title">TAGESQUEST ABGESCHLOSSEN!</div>
|
||
<div class="done-sub">Du hast alle 7 Stationen gemeistert.</div>
|
||
<button class="done-btn" onclick="document.getElementById('daily-map-overlay')?.remove()">
|
||
✔ SCHLIESSEN
|
||
</button>
|
||
</div>`;
|
||
}
|
||
|
||
/* ── Station starten ─────────────────────────────────────── */
|
||
function startDailyStation(station) {
|
||
if (!dailyDeckId) {
|
||
alert("Bitte zuerst ein Deck auswählen.");
|
||
return;
|
||
}
|
||
|
||
const socket = window._socket;
|
||
if (!socket) {
|
||
console.error("[Daily] Kein Socket.");
|
||
return;
|
||
}
|
||
|
||
/* Kreis als "lädt" markieren */
|
||
const circle = dailyOverlay.querySelector(`.daily-circle[data-station="${station}"]`);
|
||
if (circle) {
|
||
circle.style.animation = "none";
|
||
circle.style.opacity = "0.5";
|
||
circle.style.cursor = "wait";
|
||
}
|
||
|
||
/* Einmaligen Listener für Match-Gefunden */
|
||
socket.once("ht_daily_match_found", data => {
|
||
closeDailyMap();
|
||
openHtDailyPopup(
|
||
`/himmelstor/daily?match=${encodeURIComponent(data.matchId)}&slot=${encodeURIComponent(data.mySlot)}&deck=${encodeURIComponent(dailyDeckId)}&station=${station}&opponent=${encodeURIComponent("Wächter " + station)}`,
|
||
"Wächter " + station,
|
||
data.matchId
|
||
);
|
||
});
|
||
|
||
socket.once("ht_daily_error", data => {
|
||
if (circle) { circle.style.animation = ""; circle.style.opacity = ""; circle.style.cursor = ""; }
|
||
alert(data.message || "Fehler beim Starten.");
|
||
});
|
||
|
||
socket.emit("ht_join_daily", {
|
||
station,
|
||
deckId: dailyDeckId,
|
||
});
|
||
}
|
||
|
||
/* ── Popup öffnen (Iframe wie bei Arena) ─────────────────── */
|
||
function openHtDailyPopup(src, opponentName, matchId) {
|
||
document.getElementById("ht-daily-backdrop")?.remove();
|
||
document.getElementById("ht-daily-popup")?.remove();
|
||
|
||
const backdrop = document.createElement("div");
|
||
backdrop.id = "ht-daily-backdrop";
|
||
backdrop.style.cssText = "position:fixed;inset:0;background:rgba(0,0,0,.82);backdrop-filter:blur(5px);z-index:9998;";
|
||
|
||
const popup = document.createElement("div");
|
||
popup.id = "ht-daily-popup";
|
||
popup.style.cssText = "position:fixed;inset:50px;z-index:9999;display:flex;flex-direction:column;border-radius:14px;overflow:hidden;box-shadow:0 0 0 1px rgba(80,140,255,.4),0 30px 90px rgba(0,0,0,.85);";
|
||
popup.innerHTML = `
|
||
<div style="display:flex;align-items:center;justify-content:space-between;background:rgba(5,8,20,.95);border-bottom:1px solid rgba(80,140,255,.3);padding:0 16px;height:42px;flex-shrink:0;">
|
||
<span style="font-family:'Cinzel',serif;font-size:13px;letter-spacing:4px;color:rgba(160,200,255,.85);text-transform:uppercase;">☀️ Daily · vs ${opponentName}</span>
|
||
<span style="font-size:11px;color:rgba(255,255,255,.22);">${matchId}</span>
|
||
</div>
|
||
<iframe src="${src}" allowfullscreen style="flex:1;border:none;width:100%;display:block;"></iframe>`;
|
||
|
||
document.body.appendChild(backdrop);
|
||
document.body.appendChild(popup);
|
||
|
||
/* Cleanup wenn Iframe-Spiel beendet → closeToArena ruft parent auf */
|
||
}
|
||
|
||
/* ── Overlay schließen ───────────────────────────────────── */
|
||
function closeDailyMap() {
|
||
document.getElementById("daily-map-overlay")?.remove();
|
||
dailyOverlay = null;
|
||
}
|
||
|
||
/* ── Extern: nach gewonnenem Match Kreis aktualisieren ───── */
|
||
export function markDailyStationDone(station) {
|
||
if (!dailyOverlay) return;
|
||
const circle = dailyOverlay.querySelector(`.daily-circle[data-station="${station}"]`);
|
||
if (!circle) return;
|
||
circle.className = "daily-circle done";
|
||
circle.textContent = "";
|
||
circle.style = "";
|
||
|
||
/* Nächste Station freischalten */
|
||
const next = dailyOverlay.querySelector(`.daily-circle[data-station="${station + 1}"]`);
|
||
if (next) {
|
||
next.className = "daily-circle available";
|
||
next.textContent = String(station + 1);
|
||
next.addEventListener("click", () => startDailyStation(station + 1));
|
||
}
|
||
|
||
/* Fortschrittsbalken updaten */
|
||
const done = dailyOverlay.querySelectorAll(".daily-circle.done").length;
|
||
const pct = Math.round((done / 7) * 100);
|
||
const fill = document.getElementById("daily-progress-fill");
|
||
const text = document.getElementById("daily-progress-text");
|
||
if (fill) fill.style.width = pct + "%";
|
||
if (text) text.textContent = `${done} / 7 Stationen abgeschlossen`;
|
||
|
||
/* Alle 7 fertig? */
|
||
if (done >= 7) {
|
||
const wrap = document.getElementById("daily-map-wrap");
|
||
if (wrap && !document.getElementById("daily-all-done")) {
|
||
const panel = document.createElement("div");
|
||
panel.innerHTML = buildAllDonePanel();
|
||
wrap.appendChild(panel.firstElementChild);
|
||
}
|
||
}
|
||
}
|