375 lines
11 KiB
JavaScript
375 lines
11 KiB
JavaScript
let inventoryPage = 0;
|
|
const slotsPerPage = 32;
|
|
let inventoryItems = [];
|
|
let totalInventoryPages = 1;
|
|
|
|
export async function loadCharacterHouse() {
|
|
const ui = document.querySelector(".building-ui");
|
|
|
|
ui.innerHTML = `
|
|
<div id="character-ui">
|
|
|
|
<!-- Linke Spalte -->
|
|
<div class="equip-col">
|
|
<div class="slot" data-slot="shoulder"><div class="slot-label">Schulter</div></div>
|
|
<div class="slot" data-slot="gloves"><div class="slot-label">Handschuhe</div></div>
|
|
<div class="slot" data-slot="ring1"><div class="slot-label">Ring 1</div></div>
|
|
</div>
|
|
|
|
<!-- Avatar Mitte -->
|
|
<div class="character-center">
|
|
<div class="equip-top">
|
|
<div class="slot" data-slot="helmet"><div class="slot-label">Helm</div></div>
|
|
<div class="slot" data-slot="amulet"><div class="slot-label">Amulett</div></div>
|
|
</div>
|
|
|
|
<div class="avatar-wrapper">
|
|
<img class="avatar-base" src="/images/avatar_silhouette.svg" alt="Avatar">
|
|
<div class="avatar-overlay" data-slot="helmet"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="amulet"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="shoulder"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="weapon"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="gloves"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="shield"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="belt"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="ring1"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="ring2"><img src="" alt=""></div>
|
|
<div class="avatar-overlay" data-slot="boots"><img src="" alt=""></div>
|
|
</div>
|
|
|
|
<div class="equip-bottom">
|
|
<div class="slot" data-slot="belt"><div class="slot-label">Guertel</div></div>
|
|
<div class="slot" data-slot="boots"><div class="slot-label">Stiefel</div></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rechte Spalte -->
|
|
<div class="equip-col">
|
|
<div class="slot" data-slot="weapon"><div class="slot-label">Waffe</div></div>
|
|
<div class="slot" data-slot="shield"><div class="slot-label">Schild</div></div>
|
|
<div class="slot" data-slot="ring2"><div class="slot-label">Ring 2</div></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="inventory-section-title">Inventar</div>
|
|
|
|
<div id="inventory-wrapper">
|
|
<div id="inventory-grid"></div>
|
|
</div>
|
|
|
|
<div id="inventory-nav">
|
|
<button id="inv-left">◄</button>
|
|
<div id="inventory-page"></div>
|
|
<button id="inv-right">►</button>
|
|
</div>`;
|
|
|
|
// Variablen zurücksetzen beim Öffnen
|
|
inventoryPage = 0;
|
|
totalInventoryPages = 1;
|
|
inventoryItems = [];
|
|
|
|
// Buttons zuerst initialisieren
|
|
initInventoryButtons();
|
|
|
|
await loadInventory();
|
|
await loadEquipment();
|
|
initDrag();
|
|
initSlotDrag();
|
|
initDrop();
|
|
initInventoryDrop();
|
|
}
|
|
|
|
/* ================================
|
|
AVATAR OVERLAY AKTUALISIEREN
|
|
================================ */
|
|
|
|
function updateAvatarOverlay(slotName, iconSrc) {
|
|
const overlay = document.querySelector(
|
|
`.avatar-overlay[data-slot="${slotName}"]`,
|
|
);
|
|
if (!overlay) return;
|
|
|
|
const img = overlay.querySelector("img");
|
|
|
|
if (iconSrc) {
|
|
img.src = iconSrc;
|
|
overlay.classList.add("visible");
|
|
} else {
|
|
overlay.classList.remove("visible");
|
|
setTimeout(() => {
|
|
img.src = "";
|
|
}, 250);
|
|
}
|
|
}
|
|
|
|
/* ================================
|
|
INVENTAR LADEN
|
|
================================ */
|
|
|
|
async function loadInventory() {
|
|
const res = await fetch("/api/inventory");
|
|
const data = await res.json();
|
|
|
|
inventoryItems = data.items;
|
|
totalInventoryPages = data.totalPages;
|
|
|
|
renderInventory();
|
|
}
|
|
|
|
/* ================================
|
|
INVENTAR RENDERN
|
|
================================ */
|
|
|
|
function renderInventory() {
|
|
const grid = document.getElementById("inventory-grid");
|
|
let html = "";
|
|
|
|
const start = inventoryPage * slotsPerPage;
|
|
const end = start + slotsPerPage;
|
|
|
|
for (let i = start; i < end; i++) {
|
|
const item = inventoryItems[i];
|
|
|
|
if (item) {
|
|
const icon = item.icon || "/images/items/default.png";
|
|
html += `
|
|
<div class="inventory-slot"
|
|
data-slot="${item.equip_slot || ""}"
|
|
data-id="${item.id}"
|
|
data-level="${item.level}"
|
|
draggable="true">
|
|
<img src="${icon}">
|
|
</div>`;
|
|
} else {
|
|
html += `<div class="inventory-slot empty"></div>`;
|
|
}
|
|
}
|
|
|
|
grid.innerHTML = html;
|
|
|
|
document.getElementById("inventory-page").innerText =
|
|
"Seite " + (inventoryPage + 1) + " / " + totalInventoryPages;
|
|
|
|
// Buttons aktivieren/deaktivieren
|
|
const btnLeft = document.getElementById("inv-left");
|
|
const btnRight = document.getElementById("inv-right");
|
|
|
|
if (btnLeft) btnLeft.disabled = inventoryPage === 0;
|
|
if (btnRight) btnRight.disabled = inventoryPage >= totalInventoryPages - 1;
|
|
|
|
initDrag();
|
|
}
|
|
|
|
/* ================================
|
|
INVENTAR BUTTONS
|
|
================================ */
|
|
|
|
function initInventoryButtons() {
|
|
document.getElementById("inv-left").onclick = () => {
|
|
if (inventoryPage > 0) {
|
|
inventoryPage--;
|
|
renderInventory();
|
|
}
|
|
};
|
|
|
|
document.getElementById("inv-right").onclick = () => {
|
|
if (inventoryPage < totalInventoryPages - 1) {
|
|
inventoryPage++;
|
|
renderInventory();
|
|
}
|
|
};
|
|
}
|
|
|
|
/* ================================
|
|
EQUIPMENT LADEN
|
|
================================ */
|
|
|
|
async function loadEquipment() {
|
|
const res = await fetch("/api/equipment");
|
|
const equipment = await res.json();
|
|
|
|
equipment.forEach((item) => {
|
|
if (!item.item_id) return;
|
|
|
|
const slot = document.querySelector('.slot[data-slot="' + item.slot + '"]');
|
|
if (!slot) return;
|
|
|
|
const label = slot.querySelector(".slot-label");
|
|
|
|
slot.innerHTML = `<img src="${item.icon}" draggable="true" data-id="${item.item_id}" data-level="${item.item_level_id}">`;
|
|
if (label) slot.appendChild(label);
|
|
slot.classList.add("has-item");
|
|
|
|
// Avatar Overlay aktualisieren
|
|
updateAvatarOverlay(item.slot, item.icon);
|
|
});
|
|
}
|
|
|
|
/* ================================
|
|
DRAG INVENTAR
|
|
================================ */
|
|
|
|
function initDrag() {
|
|
document.querySelectorAll(".inventory-slot:not(.empty)").forEach((item) => {
|
|
item.addEventListener("dragstart", (e) => {
|
|
e.dataTransfer.setData("itemId", item.dataset.id);
|
|
e.dataTransfer.setData("itemLevel", item.dataset.level);
|
|
e.dataTransfer.setData("slot", item.dataset.slot);
|
|
e.dataTransfer.setData("source", "inventory");
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ================================
|
|
SLOT DRAG
|
|
================================ */
|
|
|
|
function initSlotDrag() {
|
|
document.querySelectorAll(".slot img").forEach((img) => {
|
|
img.setAttribute("draggable", "true");
|
|
|
|
img.addEventListener("dragstart", (e) => {
|
|
const slot = img.closest(".slot");
|
|
e.dataTransfer.setData("itemId", img.dataset.id);
|
|
e.dataTransfer.setData("itemLevel", img.dataset.level);
|
|
e.dataTransfer.setData("slot", slot.dataset.slot);
|
|
e.dataTransfer.setData("source", "slot");
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ================================
|
|
SLOT KOMPATIBILITÄT PRÜFEN
|
|
Ring-Items (equip_slot="ring") passen in ring1 und ring2
|
|
================================ */
|
|
|
|
function isSlotCompatible(itemSlot, targetSlot) {
|
|
if (itemSlot === targetSlot) return true;
|
|
if (itemSlot === "ring" && (targetSlot === "ring1" || targetSlot === "ring2"))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/* ================================
|
|
SLOT DROP
|
|
================================ */
|
|
|
|
function initDrop() {
|
|
document.querySelectorAll(".slot").forEach((slot) => {
|
|
slot.addEventListener("dragover", (e) => e.preventDefault());
|
|
|
|
slot.addEventListener("drop", (e) => {
|
|
e.preventDefault();
|
|
|
|
const itemId = e.dataTransfer.getData("itemId");
|
|
const itemLevel = e.dataTransfer.getData("itemLevel");
|
|
const itemSlot = e.dataTransfer.getData("slot");
|
|
const source = e.dataTransfer.getData("source");
|
|
const targetSlot = slot.dataset.slot;
|
|
|
|
if (!itemSlot || !isSlotCompatible(itemSlot, targetSlot)) return;
|
|
|
|
let icon;
|
|
|
|
if (source === "inventory") {
|
|
const inventoryItem = document.querySelector(
|
|
'.inventory-slot[data-id="' + itemId + '"]',
|
|
);
|
|
if (!inventoryItem) return;
|
|
icon = inventoryItem.querySelector("img").src;
|
|
|
|
// Item aus dem Array entfernen damit es sich nicht verdoppelt
|
|
inventoryItems = inventoryItems.filter(
|
|
(item) => String(item.id) !== String(itemId),
|
|
);
|
|
|
|
inventoryItem.classList.add("empty");
|
|
inventoryItem.innerHTML = "";
|
|
} else {
|
|
const slotItem = document.querySelector(
|
|
'.slot[data-slot="' + itemSlot + '"] img',
|
|
);
|
|
if (!slotItem) return;
|
|
icon = slotItem.src;
|
|
}
|
|
|
|
const label = slot.querySelector(".slot-label");
|
|
slot.innerHTML = `<img src="${icon}" draggable="true" data-id="${itemId}" data-level="${itemLevel}">`;
|
|
if (label) slot.appendChild(label);
|
|
slot.classList.add("has-item");
|
|
|
|
// Avatar Overlay anzeigen
|
|
updateAvatarOverlay(targetSlot, icon);
|
|
|
|
initDrag();
|
|
initSlotDrag();
|
|
saveEquipment(targetSlot, itemId, itemLevel);
|
|
});
|
|
});
|
|
}
|
|
|
|
/* ================================
|
|
INVENTAR DROP
|
|
================================ */
|
|
|
|
function initInventoryDrop() {
|
|
const grid = document.getElementById("inventory-grid");
|
|
|
|
grid.addEventListener("dragover", (e) => e.preventDefault());
|
|
|
|
grid.addEventListener("drop", (e) => {
|
|
e.preventDefault();
|
|
|
|
const source = e.dataTransfer.getData("source");
|
|
if (source !== "slot") return;
|
|
|
|
const itemId = e.dataTransfer.getData("itemId");
|
|
const itemLevel = e.dataTransfer.getData("itemLevel");
|
|
const slotName = e.dataTransfer.getData("slot");
|
|
|
|
const slot = document.querySelector('.slot[data-slot="' + slotName + '"]');
|
|
if (!slot) return;
|
|
|
|
const img = slot.querySelector("img");
|
|
if (!img) return;
|
|
|
|
// Ring-Slots normalisiert als "ring" im Inventar speichern
|
|
const normalizedSlot =
|
|
slotName === "ring1" || slotName === "ring2" ? "ring" : slotName;
|
|
|
|
inventoryItems.push({
|
|
id: itemId,
|
|
level: itemLevel,
|
|
equip_slot: normalizedSlot,
|
|
icon: img.src,
|
|
});
|
|
|
|
renderInventory();
|
|
|
|
const label = slot.querySelector(".slot-label");
|
|
slot.innerHTML = "";
|
|
if (label) slot.appendChild(label);
|
|
slot.classList.remove("has-item");
|
|
|
|
// Avatar Overlay entfernen
|
|
updateAvatarOverlay(slotName, null);
|
|
|
|
saveEquipment(slotName, null, null);
|
|
initDrag();
|
|
initSlotDrag();
|
|
});
|
|
}
|
|
|
|
/* ================================
|
|
DB SPEICHERN
|
|
================================ */
|
|
|
|
async function saveEquipment(slot, itemId, itemLevelId) {
|
|
await fetch("/api/equip", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ slot, itemId, itemLevelId }),
|
|
});
|
|
}
|