This commit is contained in:
cay 2026-04-07 14:52:07 +01:00
parent 1ad2b2a25b
commit f68ff01825
2 changed files with 163 additions and 199 deletions

View File

@ -1,4 +1,5 @@
export async function loadArena() {
export async function loadArena(options = {}) {
const { dailyOnly = false, onMatchComplete = null } = options;
const ui = document.querySelector(".building-ui");
ui.innerHTML = `
@ -15,6 +16,7 @@ export async function loadArena() {
<div class="arena-mode-desc">Einzelkampf Beweis deine Stärke im Duell</div>
</div>
${!dailyOnly ? `
<div class="arena-mode-card" data-mode="2v2">
<div class="arena-mode-icon"></div>
<div class="arena-mode-label">2v2</div>
@ -26,6 +28,7 @@ export async function loadArena() {
<div class="arena-mode-label">4v4</div>
<div class="arena-mode-desc">Schlachtruf Führe deine Truppe zum Sieg</div>
</div>
` : ''}
</div>
@ -36,7 +39,7 @@ export async function loadArena() {
`;
injectArenaStyles();
initArenaModes();
initArenaModes({ onMatchComplete });
}
/* ── Styles ────────────────────────────────────────────────────────────────── */
@ -225,13 +228,13 @@ function getSocket() {
}
/* ── Klick-Handler initialisieren ─────────────────────────────────────────── */
function initArenaModes() {
function initArenaModes({ onMatchComplete = null } = {}) {
document.querySelectorAll(".arena-mode-card").forEach((card) => {
card.addEventListener("click", () => {
const mode = card.dataset.mode;
if (mode === "1v1") {
handle1v1Click(card);
handle1v1Click(card, onMatchComplete);
} else {
console.log("Arena Modus gewählt:", mode);
// Platzhalter für 2v2 / 4v4
@ -241,7 +244,7 @@ function initArenaModes() {
}
/* ── 1v1: Hauptlogik ───────────────────────────────────────────────────────── */
async function handle1v1Click(card) {
async function handle1v1Click(card, onMatchComplete = null) {
const socket = getSocket();
if (!socket) {
showArenaError("Keine Verbindung zum Server. Bitte Seite neu laden.");
@ -287,6 +290,9 @@ async function handle1v1Click(card) {
setCardSearching(card, false);
hideQueueStatus();
// Daily als erledigt markieren
if (typeof onMatchComplete === "function") onMatchComplete();
showMatchFoundOverlay(me.name, data.opponent.name, () => {
openArenaPopup(
`/arena/1v1?match=${encodeURIComponent(data.matchId)}&slot=${encodeURIComponent(data.mySlot)}`,

View File

@ -20,22 +20,19 @@ function rarityImgs(rarity, size = 13) {
}
function cardHTML(card, isFront = true) {
if (!isFront)
return `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
if (!isFront) return `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
// image zuerst, dann icon als Fallback
const imgFile = card?.image || card?.icon || null;
const img = imgFile
? `/images/cards/${imgFile}`
: "/images/items/rueckseite.png";
const img = imgFile ? `/images/cards/${imgFile}` : "/images/items/rueckseite.png";
return `
<img class="booster-slot-img" src="${img}" alt="${card?.name || ""}" draggable="false"
<img class="booster-slot-img" src="${img}" alt="${card?.name || ''}" draggable="false"
onerror="this.src='/images/items/rueckseite.png'">
${card?.attack != null ? `<span class="bs-stat-atk">${card.attack}</span>` : ""}
${card?.defends != null ? `<span class="bs-stat-def">${card.defends}</span>` : ""}
${card?.cooldown != null ? `<span class="bs-stat-cd">${card.cooldown}</span>` : ""}
${card?.cooldown!= null ? `<span class="bs-stat-cd">${card.cooldown}</span>` : ""}
${card?.rarity ? `<div class="bs-rarity">${rarityImgs(card.rarity, 11)}</div>` : ""}
<div class="bs-card-name">${card?.name || ""}</div>
<div class="bs-card-name">${card?.name || ''}</div>
`;
}
@ -54,28 +51,11 @@ export async function loadEvents() {
}
const events = [
{
id: 1,
img: "/images/items/runenhaufen.png",
label: "Booster Öffnen",
type: "booster",
},
{ id: 2, img: "/images/items/1v1.png", label: "1v1" },
{ id: 3, img: "/images/items/2v2.png", label: "2v2" },
{
id: 4,
img: "/images/items/holz.png",
label: "Holz Spenden",
type: "wood",
woodCost: 100,
},
{
id: 5,
img: "/images/items/goldmuenze.png",
label: "Gold Spenden",
type: "gold",
goldCost: 100,
},
{ id: 1, img: "/images/items/runenhaufen.png", label: "Booster Öffnen", type: "booster" },
{ id: 2, img: "/images/items/runenhaufen.png", label: "1v1 Duell", type: "arena" },
{ id: 3, img: "/images/items/runenhaufen.png", label: "Textzeile 3" },
{ id: 4, img: "/images/items/holz.png", label: "Holz Spenden", type: "wood", woodCost: 100 },
{ id: 5, img: "/images/items/gold.png", label: "Gold Spenden", type: "gold", goldCost: 100 },
];
// Täglichen Status + Holz-Bestand parallel laden
@ -99,30 +79,24 @@ export async function loadEvents() {
body.innerHTML = `
<div class="events-grid" id="events-grid">
${events
.map((ev) => {
${events.map(ev => {
const done = completedToday.includes(ev.id);
const locked =
!done &&
((ev.woodCost && playerWood < ev.woodCost) ||
(ev.goldCost && playerGold < ev.goldCost));
const costLabel = ev.woodCost
? `🪵 ${ev.woodCost} Holz`
: ev.goldCost
? `🪙 ${ev.goldCost} Gold`
: "";
const cls = done ? " event-done" : locked ? " event-locked" : "";
const locked = !done && (
(ev.woodCost && playerWood < ev.woodCost) ||
(ev.goldCost && playerGold < ev.goldCost)
);
const costLabel = ev.woodCost ? `🪵 ${ev.woodCost} Holz` : ev.goldCost ? `🪙 ${ev.goldCost} Gold` : '';
const cls = done ? ' event-done' : locked ? ' event-locked' : '';
return `
<div class="event-card${cls}" data-event-id="${ev.id}" data-type="${ev.type || ""}" data-done="${done}" data-locked="${locked}">
<div class="event-card${cls}" data-event-id="${ev.id}" data-type="${ev.type || ''}" data-done="${done}" data-locked="${locked}">
<div class="event-card-img-wrap">
<img src="${ev.img}" alt="${ev.label}" draggable="false">
${done ? `<div class="event-done-overlay"></div>` : ""}
${locked ? `<div class="event-locked-overlay"><span>${costLabel}<br>benötigt</span></div>` : ""}
${done ? `<div class="event-done-overlay"></div>` : ''}
${locked ? `<div class="event-locked-overlay"><span>${costLabel}<br>benötigt</span></div>` : ''}
</div>
<span class="event-card-label">${ev.label}</span>
</div>`;
})
.join("")}
}).join("")}
</div>
<!-- Booster UI -->
@ -134,15 +108,12 @@ export async function loadEvents() {
<span class="booster-stapel-hint" id="booster-hint">Klicken zum Öffnen</span>
</div>
<div class="booster-slots" id="booster-slots">
${Array.from(
{ length: 5 },
(_, i) => `
${Array.from({length: 5}, (_, i) => `
<div class="booster-slot" id="booster-slot-${i}">
<div class="booster-slot-inner">
<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">
</div>
</div>`,
).join("")}
</div>`).join("")}
</div>
</div>
</div>
@ -174,7 +145,7 @@ export async function loadEvents() {
<div class="booster-stage">
<div class="booster-left">
<div class="wood-btn-wrap">
<img id="gold-btn" src="/images/items/goldmuenze.png" alt="Gold Spenden" draggable="false" class="booster-stapel-img">
<img id="gold-btn" src="/images/items/gold.png" alt="Gold Spenden" draggable="false" class="booster-stapel-img">
<div class="gold-stamp" id="gold-stamp">Bitte Spenden</div>
</div>
<span class="booster-stapel-hint" id="gold-hint">100 Gold spenden</span>
@ -210,7 +181,7 @@ export async function loadEvents() {
const eventsGrid = body.querySelector("#events-grid");
/* ── Event-Karten ── */
body.querySelectorAll(".event-card").forEach((card) => {
body.querySelectorAll(".event-card").forEach(card => {
card.addEventListener("click", () => {
if (card.dataset.done === "true") return;
if (card.dataset.locked === "true") return;
@ -221,6 +192,16 @@ export async function loadEvents() {
resetBooster();
return;
}
if (card.dataset.type === "arena") {
// Arena-Popup öffnen nur 1v1, Daily-Callback mitgeben
import("/js/quickmenu/arena.js").then(mod => {
mod.loadArena({
dailyOnly: true,
onMatchComplete: () => markDailyComplete(2),
});
});
return;
}
if (card.dataset.type === "gold") {
eventsGrid.style.display = "none";
goldUi.style.display = "flex";
@ -234,7 +215,7 @@ export async function loadEvents() {
return;
}
const id = Number(card.dataset.eventId);
const ev = events.find((e) => e.id === id);
const ev = events.find(e => e.id === id);
if (!ev) return;
edpImg.src = ev.img;
edpImg.alt = ev.label;
@ -253,24 +234,16 @@ export async function loadEvents() {
body: JSON.stringify({ eventId }),
});
// Karte visuell als erledigt markieren
const card = body.querySelector(
`.event-card[data-event-id="${eventId}"]`,
);
const card = body.querySelector(`.event-card[data-event-id="${eventId}"]`);
if (card) {
card.dataset.done = "true";
card.classList.add("event-done");
const wrap = card.querySelector(".event-card-img-wrap");
if (wrap && !wrap.querySelector(".event-done-overlay")) {
wrap.insertAdjacentHTML(
"beforeend",
`<div class="event-done-overlay">✓</div>`,
);
wrap.insertAdjacentHTML("beforeend", `<div class="event-done-overlay">✓</div>`);
}
if (!card.querySelector(".event-done-label")) {
card.insertAdjacentHTML(
"beforeend",
`<span class="event-done-label">Bereits erledigt</span>`,
);
card.insertAdjacentHTML("beforeend", `<span class="event-done-label">Bereits erledigt</span>`);
}
}
} catch (e) {
@ -278,12 +251,8 @@ export async function loadEvents() {
}
}
body
.querySelector("#edp-close-btn")
.addEventListener("click", () => overlay.classList.remove("active"));
overlay.addEventListener("click", (e) => {
if (e.target === overlay) overlay.classList.remove("active");
});
body.querySelector("#edp-close-btn").addEventListener("click", () => overlay.classList.remove("active"));
overlay.addEventListener("click", e => { if (e.target === overlay) overlay.classList.remove("active"); });
body.querySelector("#booster-back-btn").addEventListener("click", () => {
if (isSpinning) return;
@ -327,7 +296,7 @@ export async function loadEvents() {
let slotLocked = {}; // { index: true } → verhindert Überschreiben nach reveal
function clearAllIntervals() {
Object.values(spinIntervals).forEach((id) => clearInterval(id));
Object.values(spinIntervals).forEach(id => clearInterval(id));
spinIntervals = {};
slotLocked = {};
}
@ -349,13 +318,9 @@ export async function loadEvents() {
allRevealed = false;
for (let i = 0; i < 5; i++) {
const inner = body.querySelector(
`#booster-slot-${i} .booster-slot-inner`,
);
const inner = body.querySelector(`#booster-slot-${i} .booster-slot-inner`);
inner.innerHTML = `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
body
.querySelector(`#booster-slot-${i}`)
.classList.remove("revealed", "spinning");
body.querySelector(`#booster-slot-${i}`).classList.remove("revealed", "spinning");
}
const stapel = body.querySelector("#booster-stapel");
@ -444,15 +409,13 @@ export async function loadEvents() {
setTimeout(() => revealSlot(i, drawnCards[i]), (i + 1) * 5000);
}
setTimeout(
async () => {
body.querySelector("#booster-hint").textContent =
"Karten werden gespeichert...";
setTimeout(async () => {
body.querySelector("#booster-hint").textContent = "Karten werden gespeichert...";
isSpinning = false;
// Karten in user_cards speichern
try {
const cardIds = drawnCards.map((c) => c.id);
const cardIds = drawnCards.map(c => c.id);
const saveRes = await fetch("/api/booster/save", {
method: "POST",
headers: { "Content-Type": "application/json" },
@ -467,14 +430,11 @@ export async function loadEvents() {
await markDailyComplete(1);
allRevealed = true;
body.querySelector("#booster-hint").textContent =
"Alle Karten erhalten! ✓";
body.querySelector("#booster-hint").textContent = "Alle Karten erhalten! ✓";
const backBtn = body.querySelector("#booster-back-btn");
backBtn.style.opacity = "1";
backBtn.style.cursor = "pointer";
},
5 * 5000 + 500,
);
}, 5 * 5000 + 500);
});
preloadCards();
@ -494,7 +454,7 @@ export async function loadEvents() {
const res = await fetch("/api/booster/cards");
if (!res.ok) throw new Error(res.status);
const all = await res.json();
rarity3Cards = all.filter((c) => parseInt(c.rarity) === 3);
rarity3Cards = all.filter(c => parseInt(c.rarity) === 3);
// Fallback: wenn keine rarity-3 vorhanden alle nehmen
if (!rarity3Cards.length) rarity3Cards = all;
} catch (e) {
@ -503,7 +463,7 @@ export async function loadEvents() {
}
function clearWoodIntervals() {
Object.values(woodIntervals).forEach((id) => clearInterval(id));
Object.values(woodIntervals).forEach(id => clearInterval(id));
woodIntervals = {};
woodLocked = {};
}
@ -553,8 +513,7 @@ export async function loadEvents() {
slot.classList.add("revealed");
inner.innerHTML = cardHTML(card, true);
setTimeout(() => {
if (slot.classList.contains("revealed"))
inner.innerHTML = cardHTML(card, true);
if (slot.classList.contains("revealed")) inner.innerHTML = cardHTML(card, true);
}, 100);
}
@ -628,7 +587,7 @@ export async function loadEvents() {
let goldLocked = {};
function clearGoldIntervals() {
Object.values(goldIntervals).forEach((id) => clearInterval(id));
Object.values(goldIntervals).forEach(id => clearInterval(id));
goldIntervals = {};
goldLocked = {};
}
@ -678,8 +637,7 @@ export async function loadEvents() {
slot.classList.add("revealed");
inner.innerHTML = cardHTML(card, true);
setTimeout(() => {
if (slot.classList.contains("revealed"))
inner.innerHTML = cardHTML(card, true);
if (slot.classList.contains("revealed")) inner.innerHTML = cardHTML(card, true);
}, 100);
}