dok/public/js/map-ui.js
2026-04-11 14:40:23 +01:00

335 lines
11 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 { loadArena } from "./buildings/arena.js?v=4";
import { loadCharacterHouse } from "./buildings/character-house.js?v=2";
import { loadBlackmarket } from "./buildings/blackmarket.js?v=2";
import { loadMine } from "./buildings/mine.js?v=2";
import { loadGlucksspiel } from "./gaststaette/glucksspiel.js";
import { loadBazaar } from "./buildings/bazaar.js";
const popup = document.getElementById("building-popup");
const title = document.getElementById("popup-title");
const tooltip = document.getElementById("map-tooltip");
const tooltipCache = {};
/* ================================
Gaststätte Popup
================================ */
const gaststaettePopup = document.getElementById("gaststaette-popup");
const qmOverlay = document.getElementById("qm-overlay");
document.querySelectorAll(".gaststaette-tab").forEach((tab) => {
tab.addEventListener("click", () => {
document.querySelectorAll(".gaststaette-tab").forEach((t) => t.classList.remove("active"));
document.querySelectorAll(".gaststaette-tab-content").forEach((c) => c.classList.remove("active"));
tab.classList.add("active");
document.getElementById(tab.dataset.tab).classList.add("active");
if (tab.dataset.tab === "gs-tab1") loadGlucksspiel();
});
});
// Tooltip verstecken wenn Maus über Quickmenu, Popup oder QM-Popups fährt
document
.getElementById("quickmenu-panel")
?.addEventListener("mouseenter", () => {
tooltip.style.display = "none";
});
document
.getElementById("building-popup")
?.addEventListener("mouseenter", () => {
tooltip.style.display = "none";
});
document.querySelectorAll(".qm-popup").forEach((p) => {
p.addEventListener("mouseenter", () => {
tooltip.style.display = "none";
});
});
document.getElementById("qm-overlay")?.addEventListener("mouseenter", () => {
tooltip.style.display = "none";
});
const buildingModules = {
1: loadArena, // Arena eigenes UI, Tabs ausblenden
10: loadMine, // Mine Tabs bleiben sichtbar
11: loadCharacterHouse, // Charakterhaus eigenes UI, Tabs ausblenden
12: loadBlackmarket, // Schwarzmarkt eigenes UI, Tabs ausblenden
};
// Gebäude die ihre eigenen Tabs behalten sollen
const keepTabsVisible = new Set([10]);
/* ================================
Tabs zurücksetzen
================================ */
function resetTabs() {
document
.querySelectorAll(".tab")
.forEach((t) => t.classList.remove("active"));
document
.querySelectorAll(".tab-content")
.forEach((c) => c.classList.remove("active"));
const firstTab = document.querySelector(".tab");
const firstContent = document.querySelector(".tab-content");
if (firstTab) firstTab.classList.add("active");
if (firstContent) firstContent.classList.add("active");
}
/* ================================
Gebäude Popup öffnen (Funktion)
================================ */
async function openBuildingPopup(url) {
title.innerText = "Lädt...";
popup.style.left = "50%";
popup.style.top = "50%";
popup.classList.add("active");
resetTabs();
try {
const res = await fetch("/api" + url);
if (!res.ok) throw new Error("API Fehler");
const data = await res.json();
title.innerText = data.name;
const infoTab = document.getElementById("tab-info");
const tabs = document.querySelector(".popup-tabs");
infoTab.innerHTML = `
<div class="popup-info-title">${data.name}</div>
<div class="popup-stat-row"><span class="popup-stat-key">Level</span><span class="popup-stat-val">${data.level}</span></div>
<div class="popup-stat-row"><span class="popup-stat-key">Punkte</span><span class="popup-stat-val">${data.points} / ${data.nextLevelPoints}</span></div>
<p class="popup-desc" style="color:#cccccc !important;font-size:13px;line-height:1.8;">${data.description}</p>
<div class="popup-xp-wrap">
<div class="popup-xp-label">Fortschritt zum nächsten Level</div>
<div class="popup-xp-track">
<div class="popup-xp-fill" style="width:${Math.min((data.points / data.nextLevelPoints) * 100, 100)}%">
<div class="popup-xp-shimmer"></div>
</div>
</div>
</div>
<div class="popup-divider">✦ · ✦ · ✦</div>
`;
tabs.style.display = "flex";
const buildingType = Number(data.type);
if (buildingModules[buildingType]) {
if (keepTabsVisible.has(buildingType)) {
tabs.style.display = "flex";
} else {
tabs.style.display = "none";
infoTab.innerHTML = `<div class="building-ui"></div>`;
}
buildingModules[buildingType](url.split("/").pop());
}
// Punkte-Check: Upgrade nur möglich wenn genug Punkte vorhanden
const hasEnoughPoints =
data.upgradeRequiredPoints === null ||
data.points >= data.upgradeRequiredPoints;
const canUpgrade = data.upgradeWood !== null && hasEnoughPoints;
const pointsPct = data.upgradeRequiredPoints
? Math.min((data.points / data.upgradeRequiredPoints) * 100, 100)
: 100;
const barColor = hasEnoughPoints ? "#88ff88" : "#e8a020";
document.getElementById("tab-upgrade").innerHTML = `
<div class="popup-info-title">Upgrade</div>
<div class="popup-stat-row"><span class="popup-stat-key">Holz</span><span class="popup-stat-val">${data.upgradeWood ?? ""}</span></div>
<div class="popup-stat-row"><span class="popup-stat-key">Stein</span><span class="popup-stat-val">${data.upgradeStone ?? ""}</span></div>
<div class="popup-stat-row"><span class="popup-stat-key">Gold</span><span class="popup-stat-val">${data.upgradeGold ?? ""}</span></div>
<div class="popup-xp-wrap" style="margin-top:14px;">
<div class="popup-xp-label" style="display:flex;justify-content:space-between;">
<span>Punkte für Upgrade</span>
<span style="color:${barColor}">${data.points} / ${data.upgradeRequiredPoints ?? ""}</span>
</div>
<div class="popup-xp-track">
<div class="popup-xp-fill" style="width:${pointsPct}%;background:${barColor};">
<div class="popup-xp-shimmer"></div>
</div>
</div>
</div>
<button class="popup-upgrade-btn" id="upgrade-btn" data-building="${url.split("/").pop()}"
${!canUpgrade ? 'disabled style="opacity:0.4;cursor:not-allowed;"' : ""}>
⚒ UPGRADE STARTEN ⚒
</button>
${!hasEnoughPoints ? `<p style="color:#ff6666;font-size:12px;margin-top:8px;text-align:center;">Noch ${data.upgradeRequiredPoints - data.points} Punkte bis zum Upgrade.</p>` : ""}
`;
} catch (error) {
console.error("Gebäude konnte nicht geladen werden:", error);
}
}
/* ================================
Gebäude Popup per Klick öffnen
================================ */
document.querySelectorAll(".building").forEach((building) => {
building.addEventListener("click", async (e) => {
e.preventDefault();
const url = building.getAttribute("href");
// Gebäude 6 → Gaststätte eigenes Popup
if (url === "/building/6") {
gaststaettePopup.style.left = "50%";
gaststaettePopup.style.top = "50%";
gaststaettePopup.style.transform = "translate(-50%, -50%) scale(1)";
gaststaettePopup.classList.add("active");
qmOverlay.classList.add("active");
loadGlucksspiel();
return;
}
// Gebäude 8 → Bazaar eigenes Popup
if (url === "/building/8") {
loadBazaar();
return;
}
await openBuildingPopup(url);
});
});
/* ================================
Upgrade Button
================================ */
document.addEventListener("click", async (e) => {
const btn = e.target.closest("#upgrade-btn");
if (!btn || btn.disabled) return;
const buildingId = btn.dataset.building;
btn.disabled = true;
btn.textContent = "Wird durchgeführt...";
try {
const res = await fetch("/api/building/" + buildingId + "/upgrade", {
method: "POST",
});
const data = await res.json();
if (!res.ok || data.error) {
window.showNotification(
data.error || "Upgrade fehlgeschlagen.",
"Upgrade",
"⚒️",
);
btn.disabled = false;
btn.textContent = "⚒ UPGRADE STARTEN ⚒";
return;
}
window.showNotification(
`Upgrade erfolgreich!\nNeues Level: ${data.newLevel}\n\nKosten: ${data.cost.wood} Holz, ${data.cost.stone} Stein, ${data.cost.gold} Gold`,
"Upgrade",
"⚒️",
);
// Popup mit frischen Daten neu laden
await openBuildingPopup("/building/" + buildingId);
// HUD aktualisieren
import("/js/hud.js").then(({ loadHud }) => loadHud());
} catch (err) {
console.error("Upgrade Fehler:", err);
window.showNotification(
"Fehler beim Upgrade. Bitte erneut versuchen.",
"Fehler",
"⚠️",
);
btn.disabled = false;
btn.textContent = "⚒ UPGRADE STARTEN ⚒";
}
});
/* ================================
Tabs wechseln
================================ */
document.querySelectorAll(".tab").forEach((tab) => {
tab.addEventListener("click", () => {
document
.querySelectorAll(".tab")
.forEach((t) => t.classList.remove("active"));
tab.classList.add("active");
document
.querySelectorAll(".tab-content")
.forEach((c) => c.classList.remove("active"));
document.getElementById("tab-" + tab.dataset.tab).classList.add("active");
});
});
/* ================================
Popup schließen
================================ */
document.querySelector(".popup-close").onclick = () => {
popup.classList.remove("active");
};
/* ================================
Tooltip
================================ */
document.querySelectorAll(".building").forEach((building) => {
building.addEventListener("mouseenter", async (e) => {
try {
// data-id bevorzugen, sonst ID aus href extrahieren (z.B. "/building/5" → "5")
const id = building.dataset.id || building.getAttribute("href")?.split("/").pop();
if (!id) return;
if (!tooltipCache[id]) {
const res = await fetch("/api/building/" + id);
if (!res.ok) throw new Error("API Fehler");
tooltipCache[id] = await res.json();
}
const data = tooltipCache[id];
tooltip.innerHTML = `
<strong>${data.name}</strong><br>
Level ${data.level}<br>
Punkte ${data.points}/${data.nextLevelPoints}<br>
<hr>
Upgrade Kosten:<br>
${data.upgradeCost}
`;
tooltip.style.display = "block";
} catch (err) {
console.error("Tooltip Fehler:", err);
}
});
building.addEventListener("mousemove", (e) => {
// Tooltip erst rendern lassen damit offsetWidth korrekt ist
const tw = tooltip.offsetWidth;
const th = tooltip.offsetHeight;
let x = e.clientX + 15;
let y = e.clientY + 15;
// Rechter Rand Tooltip links vom Cursor anzeigen
if (x + tw > window.innerWidth - 10) x = e.clientX - tw - 10;
// Unterer Rand Tooltip über dem Cursor anzeigen
if (y + th > window.innerHeight - 10) y = e.clientY - th - 10;
tooltip.style.left = x + "px";
tooltip.style.top = y + "px";
});
building.addEventListener("mouseleave", () => {
tooltip.style.display = "none";
});
});