import { showNotification } from "../notification.js"; import { refreshHud } from "../hud.js"; /* ── Einstiegspunkt ─────────────────────────────── */ export async function loadMine(buildingId) { const actionsTab = document.getElementById("tab-actions"); if (!actionsTab) return; actionsTab.innerHTML = `
Lade Mineninfo...
`; await renderMineStatus(buildingId); } /* ───────────────────────────────────────────────── Haupt-Render-Funktion ───────────────────────────────────────────────── */ async function renderMineStatus(buildingId) { const actionsTab = document.getElementById("tab-actions"); try { const res = await fetch("/api/mine/" + buildingId + "/status"); if (!res.ok) throw new Error("API Fehler"); const data = await res.json(); if (data.error) { actionsTab.innerHTML = "

" + data.error + "

"; return; } actionsTab.innerHTML = "
" + renderHeader(data) + renderDivider() + (!data.selected_resource ? renderResourceSelector(data, buildingId) : renderActiveSession(data, buildingId) ) + "
"; if (data.selected_resource) { startSessionCountdown(buildingId, data); } } catch (err) { console.error("Mine Fehler:", err); actionsTab.innerHTML = "

Fehler beim Laden der Mineninfo.

"; } } /* ───────────────────────────────────────────────── Header ───────────────────────────────────────────────── */ function renderHeader(data) { let cycleText = "Keine Ressource gewählt"; if (data.selected_resource) { if (data.is_full) cycleText = "Session beendet – bitte abholen!"; else if (data.cycles > 0) cycleText = data.cycles + "x Zyklus bereit"; else cycleText = "Läuft..."; } return ( "
" + "Level " + data.level + "" + "" + cycleText + "" + "
" ); } /* ───────────────────────────────────────────────── Startscreen (keine aktive Session) ───────────────────────────────────────────────── */ function renderResourceSelector(data, buildingId) { return ( "

Ressource wählen

" + "

Wähle eine Ressource für die nächsten " + data.session_hours + "h.

" + renderResourceGrid(data.production, null, buildingId, "select") ); } /* ───────────────────────────────────────────────── Aktive Session ───────────────────────────────────────────────── */ function renderActiveSession(data, buildingId) { return ( renderCurrentProduction(data) + renderDivider() + renderQueueSection(data, buildingId) + renderDivider() + renderCollectSection(data, buildingId) ); } /* ───────────────────────────────────────────────── Aktuelle Produktion Zwei Timer: 1. Session-Countdown → wie lange läuft die 5h noch? 2. Zyklus-Countdown → wann ist der nächste Zyklus fertig? ───────────────────────────────────────────────── */ function renderCurrentProduction(data) { const sessionMin = Math.floor(data.session_seconds_left / 60); const sessionSec = data.session_seconds_left % 60; const cycleMin = Math.floor(data.next_cycle_in_seconds / 60); const cycleSec = data.next_cycle_in_seconds % 60; /* Fortschritt: wieviele Zyklen von max wurden in der Session erreicht */ const progressPct = Math.min(100, Math.round((data.cycles / data.max_cycles) * 100)); return ( "

Aktuelle Session – " + data.session_hours + "h

" + "
" + "" + resourceIcon(data.selected_resource) + "" + "" + resourceLabel(data.selected_resource) + "" + "" + data.available_amount + "" + "
" + /* Fortschrittsbalken */ "
" + "
" + "
" + /* Session-Timer (läuft immer durch) */ "
" + "Session endet in" + (data.is_full ? "FERTIG" : "" + sessionMin + "m " + sessionSec + "s" ) + "
" + /* Zyklus-Timer (nur wenn Session noch läuft und noch Zyklen kommen) */ (!data.is_full ? "
" + "Nächster Zyklus in" + "" + cycleMin + "m " + cycleSec + "s" + "
" : "" ) ); } /* ───────────────────────────────────────────────── Warteschlange ───────────────────────────────────────────────── */ function renderQueueSection(data, buildingId) { const { loop_queue, loop_slots_free, loop_slots_used, loop_cost_gems, can_afford_loop, player_gems } = data; let html = "

Warteschlange" + " (" + loop_slots_used + "/4)

"; loop_queue.forEach((res, i) => { html += "
" + "" + (i + 1) + "." + "" + resourceIcon(res) + "" + "" + resourceLabel(res) + "" + "" + data.session_hours + "h" + "
"; }); if (loop_slots_free > 0) { const nextPos = loop_slots_used + 1; html += "
" + "" + "" + "
"; } if (loop_slots_free === 0) { html += "

Warteschlange voll – 4 Schleifen aktiv.

"; } return html; } /* ───────────────────────────────────────────────── Ressourcen-Raster ───────────────────────────────────────────────── */ function renderResourceGrid(production, activeResource, buildingId, mode) { const buttons = production.map(r => { const isActive = r.resource === activeResource; return ( "" ); }).join(""); return "
" + buttons + "
"; } /* ───────────────────────────────────────────────── Collect-Button ───────────────────────────────────────────────── */ function renderCollectSection(data, buildingId) { return ( "
" + "" + "
" ); } function renderDivider() { return "
"; } /* ───────────────────────────────────────────────── Event: Loop-Picker togglen ───────────────────────────────────────────────── */ document.addEventListener("click", (e) => { const btn = e.target.closest("#mine-queue-toggle"); if (!btn || btn.disabled) return; const picker = document.getElementById("mine-loop-picker"); if (!picker) return; const isOpen = picker.style.display !== "none"; picker.style.display = isOpen ? "none" : "block"; btn.classList.toggle("mine-btn-add-loop-open", !isOpen); }); /* ───────────────────────────────────────────────── Event: Ressource wählen / Schleife buchen ───────────────────────────────────────────────── */ document.addEventListener("click", async (e) => { const btn = e.target.closest(".mine-res-btn"); if (!btn || btn.disabled || btn.classList.contains("mine-res-btn-active")) return; const resource = btn.dataset.resource; const buildingId = btn.dataset.building; const mode = btn.dataset.mode; document.querySelectorAll(".mine-res-btn").forEach(b => (b.disabled = true)); const endpoint = mode === "loop" ? "/api/mine/" + buildingId + "/loop" : "/api/mine/" + buildingId + "/select"; try { const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ resource }), }); if (!res.ok) throw new Error("API Fehler"); const data = await res.json(); if (data.error) { showNotification(data.error, "Mine", "⛏️"); await renderMineStatus(buildingId); return; } if (mode === "loop") { showNotification( "Schleife hinzugefügt!\n" + resourceLabel(resource) + " – 5h\n" + "Noch " + data.loop_slots_free + " Slot(s) frei.", "Mine", "💎" ); } else { showNotification( resourceLabel(resource) + " ausgewählt.\n5h Session startet jetzt.", "Mine", "⛏️" ); } await renderMineStatus(buildingId); if (mode === "loop") await refreshHud(); } catch (err) { console.error("Mine Fehler:", err); await renderMineStatus(buildingId); } }); /* ───────────────────────────────────────────────── Event: Abholen ───────────────────────────────────────────────── */ document.addEventListener("click", async (e) => { const btn = e.target.closest("#mine-collect-btn"); if (!btn || btn.disabled) return; const buildingId = btn.dataset.building; btn.disabled = true; btn.textContent = "Wird abgeholt..."; try { const res = await fetch("/api/mine/" + buildingId + "/collect", { method: "POST", }); if (!res.ok) throw new Error("API Fehler"); const data = await res.json(); if (data.error) { showNotification( data.ready_in_display ? "Noch nicht bereit.\nBereit in: " + data.ready_in_display : data.error, "Mine", "⛏️" ); await renderMineStatus(buildingId); return; } const c = data.collected; let msg = "Abgeholt!\n" + resourceLabel(c.resource) + ": +" + c.amount; if (data.session_ended) { msg += data.next_resource ? "\n\nNächste Session: " + resourceLabel(data.next_resource) + " (5h)" : "\n\nKeine weiteren Schleifen – neue Ressource wählen."; } /* Session läuft noch → kein Hinweis nötig */ showNotification(msg, "Mine", "⛏️"); await renderMineStatus(buildingId); await refreshHud(); } catch (err) { console.error("Abholen Fehler:", err); showNotification("Fehler beim Abholen. Bitte erneut versuchen.", "Fehler", "⚠️"); await renderMineStatus(buildingId); } }); /* ───────────────────────────────────────────────── Zwei parallele Countdowns: 1. Session-Countdown (mine-session-countdown) 2. Zyklus-Countdown (mine-cycle-countdown) ───────────────────────────────────────────────── */ let sessionInterval = null; let cycleInterval = null; function startSessionCountdown(buildingId, data) { if (sessionInterval) clearInterval(sessionInterval); if (cycleInterval) clearInterval(cycleInterval); if (data.is_full) return; /* Session-Timer */ sessionInterval = setInterval(() => { const el = document.getElementById("mine-session-countdown"); if (!el) { clearInterval(sessionInterval); return; } let secs = parseInt(el.dataset.seconds, 10) - 1; if (secs < 0) secs = 0; el.dataset.seconds = secs; el.textContent = Math.floor(secs / 60) + "m " + (secs % 60) + "s"; if (secs === 0) { clearInterval(sessionInterval); clearInterval(cycleInterval); renderMineStatus(buildingId); // Session abgelaufen → neu rendern } }, 1000); /* Zyklus-Timer */ cycleInterval = setInterval(() => { const el = document.getElementById("mine-cycle-countdown"); if (!el) { clearInterval(cycleInterval); return; } let secs = parseInt(el.dataset.seconds, 10) - 1; if (secs < 0) secs = 0; el.dataset.seconds = secs; el.textContent = Math.floor(secs / 60) + "m " + (secs % 60) + "s"; if (secs === 0) { clearInterval(cycleInterval); renderMineStatus(buildingId); // Neuer Zyklus → Menge aktualisieren } }, 1000); } /* ───────────────────────────────────────────────── Icons & Labels ───────────────────────────────────────────────── */ function resourceIcon(resource) { const imgMap = { iron: "/images/items/eisen.png", gold: "/images/items/goldmuenze.png", wood: "/images/items/holz.png", stone: "/images/items/stein.png", }; if (imgMap[resource]) { return ( "" + "" + "" ); } return "📦"; } function resourceLabel(resource) { const map = { gold: "Gold", iron: "Eisen", stone: "Stein", wood: "Holz" }; return map[resource] || resource; }