268 lines
10 KiB
JavaScript
268 lines
10 KiB
JavaScript
/* ================================
|
||
HUD – Charakter & Währungsanzeige
|
||
================================ */
|
||
|
||
async function fetchHud() {
|
||
const res = await fetch("/api/hud");
|
||
if (!res.ok) throw new Error("HUD API Fehler");
|
||
return await res.json();
|
||
}
|
||
|
||
function applyHudData(data) {
|
||
const set = (id, val) => {
|
||
const el = document.getElementById(id);
|
||
if (el) el.textContent = formatNumber(val);
|
||
};
|
||
|
||
const nameEl = document.getElementById("hud-name");
|
||
if (nameEl) nameEl.textContent = data.name;
|
||
|
||
set("hud-gems", data.gems);
|
||
set("hud-gold", data.gold);
|
||
set("hud-wood", data.wood);
|
||
set("hud-stone", data.stone);
|
||
|
||
/* ── Energie anzeigen ────────────────────────────── */
|
||
const energy = data.energy ?? 40;
|
||
const energyMax = data.energy_max ?? 40;
|
||
const energyEl = document.getElementById("hud-energy-value");
|
||
if (energyEl) energyEl.textContent = energy + " / " + energyMax;
|
||
|
||
/* Farbe je nach Stand */
|
||
if (energyEl) {
|
||
energyEl.style.color =
|
||
energy <= 0 ? "#e74c3c" // leer → rot
|
||
: energy <= 10 ? "#e67e22" // niedrig → orange
|
||
: energy < energyMax ? "#f0d9a6" // teilweise → normal
|
||
: "#7de87d"; // voll → grün
|
||
}
|
||
}
|
||
|
||
export async function loadHud() {
|
||
try {
|
||
const data = await fetchHud();
|
||
applyHudData(data);
|
||
// Auto-Refresh alle 30 Sekunden
|
||
setInterval(async () => {
|
||
try {
|
||
const d = await fetchHud();
|
||
applyHudData(d);
|
||
} catch {}
|
||
}, 30000);
|
||
} catch (err) {
|
||
console.error("HUD Fehler:", err);
|
||
}
|
||
}
|
||
|
||
export async function refreshHud() {
|
||
try {
|
||
const data = await fetchHud();
|
||
applyHudData(data);
|
||
} catch (err) {
|
||
console.error("HUD Refresh Fehler:", err);
|
||
}
|
||
}
|
||
|
||
function formatNumber(n) {
|
||
if (n === undefined || n === null) return "0";
|
||
return Number(n).toLocaleString("de-DE");
|
||
}
|
||
|
||
/* ════════════════════════════════════════════
|
||
Energie kaufen – Popup beim + Klick
|
||
════════════════════════════════════════════ */
|
||
|
||
document.getElementById("hud-energy-plus")?.addEventListener("click", openEnergyBuyPopup);
|
||
|
||
async function openEnergyBuyPopup() {
|
||
/* Aktuellen Stand laden */
|
||
let hud, energyStatus;
|
||
try {
|
||
[hud, energyStatus] = await Promise.all([
|
||
fetch("/api/hud").then(r => r.json()),
|
||
fetch("/api/energy").then(r => r.json()),
|
||
]);
|
||
} catch {
|
||
return;
|
||
}
|
||
|
||
/* Altes Popup entfernen */
|
||
document.getElementById("energy-buy-overlay")?.remove();
|
||
|
||
const alreadyBought = energyStatus.bought_today;
|
||
const energyFull = (energyStatus.energy ?? 0) >= (energyStatus.energy_max ?? 40);
|
||
const canGems = hud.gems >= 10;
|
||
const canGold = hud.gold >= 200;
|
||
|
||
const overlay = document.createElement("div");
|
||
overlay.id = "energy-buy-overlay";
|
||
overlay.style.cssText = `
|
||
position:fixed; inset:0; z-index:99999;
|
||
background:rgba(0,0,0,.75);
|
||
display:flex; align-items:center; justify-content:center;`;
|
||
|
||
/* ── Inhalt je nach Status ── */
|
||
let body = "";
|
||
|
||
if (alreadyBought) {
|
||
body = `
|
||
<div style="font-size:36px;margin-bottom:12px;">⏳</div>
|
||
<div style="font-family:'Cinzel',serif;font-size:16px;color:#f0d060;
|
||
letter-spacing:2px;margin-bottom:10px;">BEREITS AUFGEFÜLLT</div>
|
||
<p style="font-family:'Cinzel',serif;font-size:12px;color:#a08060;
|
||
line-height:1.8;margin:0 0 20px;">
|
||
Du hast heute bereits Energie dazugekauft.<br>
|
||
<strong style="color:#f0d060;">Morgen wieder verfügbar.</strong>
|
||
</p>`;
|
||
} else if (energyFull) {
|
||
body = `
|
||
<div style="font-size:36px;margin-bottom:12px;">⚡</div>
|
||
<div style="font-family:'Cinzel',serif;font-size:16px;color:#7de87d;
|
||
letter-spacing:2px;margin-bottom:10px;">ENERGIE VOLL</div>
|
||
<p style="font-family:'Cinzel',serif;font-size:12px;color:#a08060;
|
||
line-height:1.8;margin:0 0 20px;">
|
||
Deine Energie ist bereits auf dem Maximum.
|
||
</p>`;
|
||
} else {
|
||
const gemBtn = canGems
|
||
? `<button class="ebtn" data-pay="gems"
|
||
style="background:linear-gradient(#1a2a4a,#0a1a3a);border:2px solid #4a7acc;
|
||
border-radius:9px;color:#a0c8ff;font-family:'Cinzel',serif;
|
||
font-size:12px;padding:12px 20px;cursor:pointer;flex:1;transition:.15s;">
|
||
<div style="font-size:22px;margin-bottom:5px;">💠</div>
|
||
<div style="font-weight:700;font-size:14px;margin-bottom:3px;">10 Gems</div>
|
||
<div style="font-size:10px;color:#6090c0;">Verfügbar: ${formatNum(hud.gems)}</div>
|
||
</button>`
|
||
: `<button disabled style="background:rgba(20,20,30,.6);border:2px solid rgba(80,100,140,.3);
|
||
border-radius:9px;color:rgba(100,130,180,.4);font-family:'Cinzel',serif;
|
||
font-size:12px;padding:12px 20px;flex:1;cursor:not-allowed;">
|
||
<div style="font-size:22px;margin-bottom:5px;">💠</div>
|
||
<div style="font-weight:700;font-size:14px;margin-bottom:3px;">10 Gems</div>
|
||
<div style="font-size:10px;">Zu wenig Gems</div>
|
||
</button>`;
|
||
|
||
const goldBtn = canGold
|
||
? `<button class="ebtn" data-pay="gold"
|
||
style="background:linear-gradient(#2a1a04,#1a0f02);border:2px solid #c8960c;
|
||
border-radius:9px;color:#f0d060;font-family:'Cinzel',serif;
|
||
font-size:12px;padding:12px 20px;cursor:pointer;flex:1;transition:.15s;">
|
||
<div style="font-size:22px;margin-bottom:5px;">🪙</div>
|
||
<div style="font-weight:700;font-size:14px;margin-bottom:3px;">200 Gold</div>
|
||
<div style="font-size:10px;color:#a08040;">Verfügbar: ${formatNum(hud.gold)}</div>
|
||
</button>`
|
||
: `<button disabled style="background:rgba(20,15,5,.6);border:2px solid rgba(140,100,20,.3);
|
||
border-radius:9px;color:rgba(180,140,40,.4);font-family:'Cinzel',serif;
|
||
font-size:12px;padding:12px 20px;flex:1;cursor:not-allowed;">
|
||
<div style="font-size:22px;margin-bottom:5px;">🪙</div>
|
||
<div style="font-weight:700;font-size:14px;margin-bottom:3px;">200 Gold</div>
|
||
<div style="font-size:10px;">Zu wenig Gold</div>
|
||
</button>`;
|
||
|
||
body = `
|
||
<div style="font-size:36px;margin-bottom:10px;">⚡</div>
|
||
<div style="font-family:'Cinzel',serif;font-size:16px;color:#f0d060;
|
||
letter-spacing:2px;margin-bottom:6px;">ENERGIE AUFFÜLLEN</div>
|
||
<p style="font-family:'Cinzel',serif;font-size:11px;color:#a08060;
|
||
margin:0 0 18px;line-height:1.7;">
|
||
+10 Energie · max. 1× täglich
|
||
</p>
|
||
<div style="display:flex;gap:12px;width:100%;">${gemBtn}${goldBtn}</div>
|
||
${!canGems && !canGold
|
||
? `<p style="font-family:'Cinzel',serif;font-size:11px;color:#e74c3c;
|
||
margin:12px 0 0;">Weder genug Gems noch Gold vorhanden.</p>`
|
||
: ""}`;
|
||
}
|
||
|
||
overlay.innerHTML = `
|
||
<div style="
|
||
background:linear-gradient(135deg,#1a0f04,#0a0803);
|
||
border:2px solid #c8960c; border-radius:14px;
|
||
padding:28px 32px; max-width:360px; width:90%;
|
||
text-align:center;
|
||
box-shadow:0 20px 60px rgba(0,0,0,.9);
|
||
font-family:'Cinzel',serif;">
|
||
${body}
|
||
<button id="ebtn-close"
|
||
style="margin-top:16px;background:none;border:1px solid rgba(200,150,60,.35);
|
||
border-radius:7px;color:#806040;font-family:'Cinzel',serif;
|
||
font-size:11px;padding:7px 22px;cursor:pointer;transition:.15s;">
|
||
Schließen
|
||
</button>
|
||
</div>`;
|
||
|
||
document.body.appendChild(overlay);
|
||
|
||
/* Schließen */
|
||
document.getElementById("ebtn-close").addEventListener("click", () => overlay.remove());
|
||
overlay.addEventListener("click", e => { if (e.target === overlay) overlay.remove(); });
|
||
|
||
/* Kauf-Buttons */
|
||
overlay.querySelectorAll(".ebtn").forEach(btn => {
|
||
btn.addEventListener("mouseenter", () => { btn.style.transform = "translateY(-2px)"; btn.style.opacity = ".9"; });
|
||
btn.addEventListener("mouseleave", () => { btn.style.transform = ""; btn.style.opacity = ""; });
|
||
btn.addEventListener("click", () => buyEnergy(btn.dataset.pay, overlay));
|
||
});
|
||
}
|
||
|
||
async function buyEnergy(payWith, overlay) {
|
||
/* Buttons deaktivieren während Kauf */
|
||
overlay.querySelectorAll(".ebtn").forEach(b => { b.disabled = true; b.style.opacity = ".5"; });
|
||
|
||
try {
|
||
const res = await fetch("/api/energy/buy", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ currency: payWith }),
|
||
});
|
||
const data = await res.json();
|
||
|
||
if (!res.ok) {
|
||
overlay.querySelector("div > div:last-of-type").insertAdjacentHTML(
|
||
"beforebegin",
|
||
`<p style="font-family:'Cinzel',serif;font-size:11px;color:#e74c3c;
|
||
margin:8px 0 0;">${data.error || "Fehler beim Kauf."}</p>`
|
||
);
|
||
overlay.querySelectorAll(".ebtn").forEach(b => { b.disabled = false; b.style.opacity = ""; });
|
||
return;
|
||
}
|
||
|
||
/* Erfolg: HUD aktualisieren + Popup mit Bestätigung */
|
||
await refreshHud();
|
||
overlay.remove();
|
||
|
||
const confirm = document.createElement("div");
|
||
confirm.style.cssText = `
|
||
position:fixed; inset:0; z-index:99999;
|
||
background:rgba(0,0,0,.75);
|
||
display:flex; align-items:center; justify-content:center;`;
|
||
confirm.innerHTML = `
|
||
<div style="background:linear-gradient(135deg,#0a1a08,#041004);
|
||
border:2px solid #4a8a3c; border-radius:14px;
|
||
padding:28px 36px; text-align:center; max-width:300px;
|
||
box-shadow:0 20px 60px rgba(0,0,0,.9); font-family:'Cinzel',serif;">
|
||
<div style="font-size:44px;margin-bottom:10px;">⚡</div>
|
||
<div style="font-size:16px;color:#7de87d;letter-spacing:2px;margin-bottom:8px;">
|
||
+10 ENERGIE
|
||
</div>
|
||
<p style="font-size:12px;color:#a0c890;margin:0 0 18px;">
|
||
Energie aufgefüllt auf ${data.energy} / ${data.energy_max}
|
||
</p>
|
||
<button onclick="this.closest('div[style]').remove()"
|
||
style="background:linear-gradient(#1a4a18,#0f2a0e);border:2px solid #4a8a3c;
|
||
border-radius:7px;color:#a0e090;font-family:'Cinzel',serif;
|
||
font-size:12px;padding:8px 24px;cursor:pointer;">
|
||
✔ OK
|
||
</button>
|
||
</div>`;
|
||
document.body.appendChild(confirm);
|
||
setTimeout(() => confirm.remove(), 3000);
|
||
|
||
} catch {
|
||
overlay.querySelectorAll(".ebtn").forEach(b => { b.disabled = false; b.style.opacity = ""; });
|
||
}
|
||
}
|
||
|
||
function formatNum(n) {
|
||
return Number(n || 0).toLocaleString("de-DE");
|
||
}
|