dok/public/js/buildings/mine.js
2026-04-08 14:07:53 +01:00

370 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 = `<div class="mine-loading">Lade Mineninfo...</div>`;
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 = "<p class='mine-error'>" + data.error + "</p>";
return;
}
actionsTab.innerHTML =
"<div class='mine-panel'>" +
renderHeader(data) +
renderDivider() +
renderResourceSelector(data, buildingId) +
(data.selected_resource ? renderProductionSection(data) : "") +
(data.selected_resource ? renderDivider() : "") +
(data.selected_resource ? renderLoopSection(data, buildingId) : "") +
(data.selected_resource ? renderDivider() : "") +
(data.selected_resource ? renderCollectSection(data, buildingId) : "") +
"</div>";
if (data.selected_resource) {
startCountdown(buildingId, data);
}
} catch (err) {
console.error("Mine Fehler:", err);
actionsTab.innerHTML =
"<p class='mine-error'>Fehler beim Laden der Mineninfo.</p>";
}
}
/* ─────────────────────────────────────────────────
Abschnitt: Header (Level + Zyklusinfo)
───────────────────────────────────────────────── */
function renderHeader(data) {
let cycleText = "Keine Ressource gewählt";
if (data.selected_resource) {
if (data.is_full) {
cycleText = "Voll bitte abholen!";
} else if (data.cycles > 0) {
cycleText = data.cycles + "x Zyklus abgeschlossen";
} else {
cycleText = "Läuft...";
}
}
return (
"<div class='mine-header-row'>" +
"<span class='mine-level-badge'>Level " + data.level + "</span>" +
"<span class='mine-cycles'>" + cycleText + "</span>" +
"</div>"
);
}
/* ─────────────────────────────────────────────────
Abschnitt: Ressourcen-Auswahl
───────────────────────────────────────────────── */
function renderResourceSelector(data, buildingId) {
const resources = data.production; // [{resource, amount}]
const buttons = resources.map(r => {
const isSelected = data.selected_resource === r.resource;
return (
"<button class='mine-res-btn" +
(isSelected ? " mine-res-btn-active" : "") +
"' data-resource='" + r.resource +
"' data-building='" + buildingId + "'>" +
"<span class='mine-res-btn-icon'>" + resourceIcon(r.resource) + "</span>" +
"<span class='mine-res-btn-name'>" + resourceLabel(r.resource) + "</span>" +
"<span class='mine-res-btn-amount'>+" + r.amount + "/Zyklus</span>" +
"</button>"
);
}).join("");
return (
"<p class='mine-section-title'>Ressource wählen</p>" +
"<div class='mine-res-selector'>" +
buttons +
"</div>"
);
}
/* ─────────────────────────────────────────────────
Abschnitt: Aktuelle Produktion
───────────────────────────────────────────────── */
function renderProductionSection(data) {
const minutesLeft = Math.floor(data.next_cycle_in_seconds / 60);
const secondsLeft = data.next_cycle_in_seconds % 60;
const maxHoursDisplay = data.max_hours + "h";
const progressPercent = Math.min(
100,
Math.round((data.cycles / data.max_cycles) * 100)
);
return (
renderDivider() +
"<p class='mine-section-title'>Aktuelle Produktion</p>" +
"<div class='mine-resource-row" + (data.ready ? " mine-resource-ready" : "") + "'>" +
"<span class='mine-resource-icon'>" + resourceIcon(data.selected_resource) + "</span>" +
"<span class='mine-resource-label'>" + resourceLabel(data.selected_resource) + "</span>" +
"<span class='mine-resource-amount'>" + data.available_amount + "</span>" +
"</div>" +
"<div class='mine-progress-wrap'>" +
"<div class='mine-progress-bar' style='width:" + progressPercent + "%'></div>" +
"</div>" +
"<div class='mine-timer-row'>" +
"<span class='mine-timer-label'>" +
(data.is_full
? "Maximale Zeit erreicht (" + maxHoursDisplay + ")"
: "Nächster Zyklus in") +
"</span>" +
(data.is_full
? "<span class='mine-timer mine-timer-full'>VOLL</span>"
: "<span class='mine-timer' id='mine-countdown' data-seconds='" +
data.next_cycle_in_seconds + "'>" +
minutesLeft + "m " + secondsLeft + "s</span>") +
"</div>"
);
}
/* ─────────────────────────────────────────────────
Abschnitt: Schleifen (Loops)
───────────────────────────────────────────────── */
function renderLoopSection(data, buildingId) {
const loopDots = [];
for (let i = 0; i < 4; i++) {
loopDots.push(
"<span class='mine-loop-dot" +
(i < data.loops_purchased ? " mine-loop-dot-active" : "") +
"'></span>"
);
}
const canBuy = data.loops_available > 0 && data.can_afford_loop;
const maxReached = data.loops_available === 0;
return (
"<p class='mine-section-title'>Schleifen</p>" +
"<div class='mine-loop-row'>" +
"<div class='mine-loop-dots'>" + loopDots.join("") + "</div>" +
"<span class='mine-loop-info'>" +
data.max_hours + "h max" +
(maxReached ? " <span class='mine-loop-maxed'>(Max)</span>" : "") +
"</span>" +
"</div>" +
(!maxReached
? "<button class='mine-btn-loop" + (canBuy ? "" : " mine-btn-disabled") + "'" +
" id='mine-loop-btn'" +
" data-building='" + buildingId + "'" +
(canBuy ? "" : " disabled") + ">" +
"<span class='mine-loop-gem-icon'>💎</span>" +
"10 Juwelen → +5h" +
(data.can_afford_loop ? "" : " <span class='mine-loop-no-gems'>(" + data.player_gems + " verfügbar)</span>") +
"</button>"
: ""
)
);
}
/* ─────────────────────────────────────────────────
Abschnitt: Abholen-Button
───────────────────────────────────────────────── */
function renderCollectSection(data, buildingId) {
return (
"<div class='mine-actions'>" +
"<button class='mine-btn-collect" + (data.ready ? "" : " mine-btn-disabled") + "'" +
" id='mine-collect-btn'" +
" data-building='" + buildingId + "'" +
(data.ready ? "" : " disabled") + ">" +
(data.ready ? "Abholen" : "Noch nicht bereit") +
"</button>" +
"</div>"
);
}
function renderDivider() {
return "<div class='mine-divider'></div>";
}
/* ─────────────────────────────────────────────────
Event-Delegation: Ressource wählen
───────────────────────────────────────────────── */
document.addEventListener("click", async (e) => {
const btn = e.target.closest(".mine-res-btn");
if (!btn || btn.classList.contains("mine-res-btn-active")) return;
const resource = btn.dataset.resource;
const buildingId = btn.dataset.building;
// Alle Buttons kurz deaktivieren
document.querySelectorAll(".mine-res-btn").forEach(b => b.disabled = true);
try {
const res = await fetch("/api/mine/" + buildingId + "/select", {
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;
}
showNotification(
resourceLabel(resource) + " ausgewählt.\nTimer wurde zurückgesetzt.",
"Mine", "⛏️"
);
await renderMineStatus(buildingId);
} catch (err) {
console.error("Ressource wählen Fehler:", err);
await renderMineStatus(buildingId);
}
});
/* ─────────────────────────────────────────────────
Event-Delegation: Schleife kaufen
───────────────────────────────────────────────── */
document.addEventListener("click", async (e) => {
const btn = e.target.closest("#mine-loop-btn");
if (!btn || btn.disabled) return;
const buildingId = btn.dataset.building;
btn.disabled = true;
btn.textContent = "Kaufe...";
try {
const res = await fetch("/api/mine/" + buildingId + "/loop", {
method: "POST",
});
if (!res.ok) throw new Error("API Fehler");
const data = await res.json();
if (data.error) {
showNotification(data.error, "Mine", "⛏️");
await renderMineStatus(buildingId);
return;
}
showNotification(
"Schleife aktiviert! +" + 5 + "h Abbauzeit.\n" +
"Noch " + data.loops_available + " Schleife(n) verfügbar.",
"Mine", "💎"
);
await renderMineStatus(buildingId);
await refreshHud();
} catch (err) {
console.error("Schleife kaufen Fehler:", err);
await renderMineStatus(buildingId);
}
});
/* ─────────────────────────────────────────────────
Event-Delegation: Ressource 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;
showNotification(
"Abgeholt!\n" + resourceLabel(c.resource) + ": +" + c.amount,
"Mine", "⛏️"
);
await renderMineStatus(buildingId);
await refreshHud();
} catch (err) {
console.error("Abholen Fehler:", err);
showNotification("Fehler beim Abholen. Bitte erneut versuchen.", "Fehler", "⚠️");
await renderMineStatus(buildingId);
}
});
/* ─────────────────────────────────────────────────
Countdown-Timer
───────────────────────────────────────────────── */
let countdownInterval = null;
function startCountdown(buildingId, data) {
if (countdownInterval) clearInterval(countdownInterval);
if (data.is_full) return;
countdownInterval = setInterval(() => {
const el = document.getElementById("mine-countdown");
if (!el) { clearInterval(countdownInterval); 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(countdownInterval);
renderMineStatus(buildingId);
}
}, 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 (
"<span class='mine-resource-icon-" + resource + "'>" +
"<img src='" + imgMap[resource] + "' alt=''>" +
"</span>"
);
}
return "📦";
}
function resourceLabel(resource) {
const map = {
gold: "Gold",
iron: "Eisen",
stone: "Stein",
wood: "Holz",
};
return map[resource] || resource;
}