AI 6
This commit is contained in:
parent
8fb82cfec8
commit
a8bb5f90e5
@ -238,17 +238,122 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.character-center img {
|
/* ========================
|
||||||
|
Avatar Wrapper
|
||||||
|
======================== */
|
||||||
|
|
||||||
|
.avatar-wrapper {
|
||||||
|
position: relative;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
height: 320px;
|
height: 320px;
|
||||||
object-fit: cover;
|
|
||||||
object-position: top;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 2px solid #8b6a3c;
|
border: 2px solid #8b6a3c;
|
||||||
|
background: radial-gradient(ellipse at center, #2a1f14 0%, #0d0a07 100%);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 20px rgba(0, 0, 0, 0.7),
|
0 0 20px rgba(0, 0, 0, 0.8),
|
||||||
inset 0 0 10px rgba(0, 0, 0, 0.3);
|
inset 0 0 30px rgba(0, 0, 0, 0.5);
|
||||||
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.8));
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-base {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
display: block;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Item Overlays */
|
||||||
|
|
||||||
|
.avatar-overlay {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
display: none;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-overlay.visible {
|
||||||
|
display: block;
|
||||||
|
animation: overlayFadeIn 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-overlay img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
filter: drop-shadow(0 0 4px rgba(255, 200, 80, 0.5))
|
||||||
|
drop-shadow(0 2px 6px rgba(0, 0, 0, 0.9));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes overlayFadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.15);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Positionen der Item-Overlays (180x320px) */
|
||||||
|
|
||||||
|
.avatar-overlay[data-slot="helmet"] {
|
||||||
|
top: 1%;
|
||||||
|
left: 22%;
|
||||||
|
width: 56%;
|
||||||
|
height: 20%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="amulet"] {
|
||||||
|
top: 21%;
|
||||||
|
left: 58%;
|
||||||
|
width: 30%;
|
||||||
|
height: 11%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="shoulder"] {
|
||||||
|
top: 19%;
|
||||||
|
left: 3%;
|
||||||
|
width: 30%;
|
||||||
|
height: 13%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="weapon"] {
|
||||||
|
top: 38%;
|
||||||
|
left: 56%;
|
||||||
|
width: 40%;
|
||||||
|
height: 32%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="gloves"] {
|
||||||
|
top: 54%;
|
||||||
|
left: 2%;
|
||||||
|
width: 30%;
|
||||||
|
height: 13%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="shield"] {
|
||||||
|
top: 36%;
|
||||||
|
left: 4%;
|
||||||
|
width: 36%;
|
||||||
|
height: 30%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="belt"] {
|
||||||
|
top: 51%;
|
||||||
|
left: 18%;
|
||||||
|
width: 64%;
|
||||||
|
height: 11%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="ring"] {
|
||||||
|
top: 67%;
|
||||||
|
left: 3%;
|
||||||
|
width: 24%;
|
||||||
|
height: 9%;
|
||||||
|
}
|
||||||
|
.avatar-overlay[data-slot="boots"] {
|
||||||
|
top: 80%;
|
||||||
|
left: 12%;
|
||||||
|
width: 76%;
|
||||||
|
height: 18%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top-Slots (Helm + Amulett) über dem Avatar */
|
/* Top-Slots (Helm + Amulett) über dem Avatar */
|
||||||
|
|||||||
24
public/images/avatar_silhouette.svg
Normal file
24
public/images/avatar_silhouette.svg
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 320" width="180" height="320">
|
||||||
|
<!-- Kopf -->
|
||||||
|
<ellipse cx="90" cy="38" rx="26" ry="30" fill="#1a1a1a"/>
|
||||||
|
<!-- Hals -->
|
||||||
|
<rect x="80" y="64" width="20" height="16" rx="4" fill="#1a1a1a"/>
|
||||||
|
<!-- Torso -->
|
||||||
|
<path d="M45,80 Q40,100 38,140 L55,145 L55,190 L125,190 L125,145 L142,140 Q140,100 135,80 Z" fill="#1a1a1a"/>
|
||||||
|
<!-- Linker Arm -->
|
||||||
|
<path d="M45,82 Q20,100 15,145 Q18,148 28,145 Q38,110 55,95 Z" fill="#1a1a1a"/>
|
||||||
|
<!-- Linke Hand -->
|
||||||
|
<ellipse cx="20" cy="150" rx="10" ry="13" fill="#1a1a1a"/>
|
||||||
|
<!-- Rechter Arm -->
|
||||||
|
<path d="M135,82 Q160,100 165,145 Q162,148 152,145 Q142,110 125,95 Z" fill="#1a1a1a"/>
|
||||||
|
<!-- Rechte Hand -->
|
||||||
|
<ellipse cx="160" cy="150" rx="10" ry="13" fill="#1a1a1a"/>
|
||||||
|
<!-- Linkes Bein -->
|
||||||
|
<path d="M55,188 Q48,230 46,280 Q52,285 66,280 Q70,235 75,190 Z" fill="#1a1a1a"/>
|
||||||
|
<!-- Linker Fuss -->
|
||||||
|
<ellipse cx="54" cy="284" rx="16" ry="9" fill="#1a1a1a"/>
|
||||||
|
<!-- Rechtes Bein -->
|
||||||
|
<path d="M125,188 Q132,230 134,280 Q128,285 114,280 Q110,235 105,190 Z" fill="#1a1a1a"/>
|
||||||
|
<!-- Rechter Fuss -->
|
||||||
|
<ellipse cx="126" cy="284" rx="16" ry="9" fill="#1a1a1a"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -6,7 +6,6 @@ export async function loadWohnhaus() {
|
|||||||
const ui = document.querySelector(".building-ui");
|
const ui = document.querySelector(".building-ui");
|
||||||
|
|
||||||
ui.innerHTML = `
|
ui.innerHTML = `
|
||||||
<!-- Charakter UI -->
|
|
||||||
<div id="character-ui">
|
<div id="character-ui">
|
||||||
|
|
||||||
<!-- Linke Spalte -->
|
<!-- Linke Spalte -->
|
||||||
@ -22,7 +21,20 @@ export async function loadWohnhaus() {
|
|||||||
<div class="slot" data-slot="helmet"><div class="slot-label">Helm</div></div>
|
<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 class="slot" data-slot="amulet"><div class="slot-label">Amulett</div></div>
|
||||||
</div>
|
</div>
|
||||||
<img src="/images/avatar.png" alt="Avatar">
|
|
||||||
|
<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="ring"><img src="" alt=""></div>
|
||||||
|
<div class="avatar-overlay" data-slot="boots"><img src="" alt=""></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="equip-bottom">
|
<div class="equip-bottom">
|
||||||
<div class="slot" data-slot="belt"><div class="slot-label">Guertel</div></div>
|
<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 class="slot" data-slot="boots"><div class="slot-label">Stiefel</div></div>
|
||||||
@ -38,7 +50,6 @@ export async function loadWohnhaus() {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Inventar -->
|
|
||||||
<div class="inventory-section-title">Inventar</div>
|
<div class="inventory-section-title">Inventar</div>
|
||||||
|
|
||||||
<div id="inventory-wrapper">
|
<div id="inventory-wrapper">
|
||||||
@ -46,22 +57,39 @@ export async function loadWohnhaus() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="inventory-nav">
|
<div id="inventory-nav">
|
||||||
<button id="inv-left">◀</button>
|
<button id="inv-left">◄</button>
|
||||||
<div id="inventory-page"></div>
|
<div id="inventory-page"></div>
|
||||||
<button id="inv-right">▶</button>
|
<button id="inv-right">►</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
await loadInventory();
|
await loadInventory();
|
||||||
await loadEquipment();
|
await loadEquipment();
|
||||||
|
|
||||||
initInventoryButtons();
|
initInventoryButtons();
|
||||||
|
|
||||||
initDrag();
|
initDrag();
|
||||||
initSlotDrag();
|
initSlotDrag();
|
||||||
initDrop();
|
initDrop();
|
||||||
initInventoryDrop();
|
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
|
INVENTAR LADEN
|
||||||
================================ */
|
================================ */
|
||||||
@ -69,7 +97,6 @@ export async function loadWohnhaus() {
|
|||||||
async function loadInventory() {
|
async function loadInventory() {
|
||||||
const res = await fetch("/api/inventory");
|
const res = await fetch("/api/inventory");
|
||||||
inventoryItems = await res.json();
|
inventoryItems = await res.json();
|
||||||
|
|
||||||
renderInventory();
|
renderInventory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +106,6 @@ async function loadInventory() {
|
|||||||
|
|
||||||
function renderInventory() {
|
function renderInventory() {
|
||||||
const grid = document.getElementById("inventory-grid");
|
const grid = document.getElementById("inventory-grid");
|
||||||
|
|
||||||
let html = "";
|
let html = "";
|
||||||
|
|
||||||
const start = inventoryPage * slotsPerPage;
|
const start = inventoryPage * slotsPerPage;
|
||||||
@ -90,32 +116,22 @@ function renderInventory() {
|
|||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
const icon = item.icon || "/images/items/default.png";
|
const icon = item.icon || "/images/items/default.png";
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
<div class="inventory-slot"
|
<div class="inventory-slot"
|
||||||
data-slot="${item.equip_slot || ""}"
|
data-slot="${item.equip_slot || ""}"
|
||||||
data-id="${item.id}"
|
data-id="${item.id}"
|
||||||
data-level="${item.level}"
|
data-level="${item.level}"
|
||||||
draggable="true">
|
draggable="true">
|
||||||
|
<img src="${icon}">
|
||||||
<img src="${icon}">
|
</div>`;
|
||||||
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
} else {
|
} else {
|
||||||
html += `
|
html += `<div class="inventory-slot empty"></div>`;
|
||||||
<div class="inventory-slot empty"></div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grid.innerHTML = html;
|
grid.innerHTML = html;
|
||||||
|
|
||||||
const totalPages = Math.max(
|
const totalPages = Math.max(1, Math.ceil(inventoryItems.length / slotsPerPage));
|
||||||
1,
|
|
||||||
Math.ceil(inventoryItems.length / slotsPerPage),
|
|
||||||
);
|
|
||||||
|
|
||||||
document.getElementById("inventory-page").innerText =
|
document.getElementById("inventory-page").innerText =
|
||||||
"Seite " + (inventoryPage + 1) + " / " + totalPages;
|
"Seite " + (inventoryPage + 1) + " / " + totalPages;
|
||||||
|
|
||||||
@ -135,11 +151,7 @@ function initInventoryButtons() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById("inv-right").onclick = () => {
|
document.getElementById("inv-right").onclick = () => {
|
||||||
const totalPages = Math.max(
|
const totalPages = Math.max(1, Math.ceil(inventoryItems.length / slotsPerPage));
|
||||||
1,
|
|
||||||
Math.ceil(inventoryItems.length / slotsPerPage),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (inventoryPage < totalPages - 1) {
|
if (inventoryPage < totalPages - 1) {
|
||||||
inventoryPage++;
|
inventoryPage++;
|
||||||
renderInventory();
|
renderInventory();
|
||||||
@ -163,16 +175,12 @@ async function loadEquipment() {
|
|||||||
|
|
||||||
const label = slot.querySelector(".slot-label");
|
const label = slot.querySelector(".slot-label");
|
||||||
|
|
||||||
slot.innerHTML = `
|
slot.innerHTML = `<img src="${item.icon}" draggable="true" data-id="${item.item_id}" data-level="${item.item_level_id}">`;
|
||||||
<img src="${item.icon}"
|
|
||||||
draggable="true"
|
|
||||||
data-id="${item.item_id}"
|
|
||||||
data-level="${item.item_level_id}">
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (label) slot.appendChild(label);
|
if (label) slot.appendChild(label);
|
||||||
|
|
||||||
slot.classList.add("has-item");
|
slot.classList.add("has-item");
|
||||||
|
|
||||||
|
// Avatar Overlay aktualisieren
|
||||||
|
updateAvatarOverlay(item.slot, item.icon);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +209,6 @@ function initSlotDrag() {
|
|||||||
|
|
||||||
img.addEventListener("dragstart", (e) => {
|
img.addEventListener("dragstart", (e) => {
|
||||||
const slot = img.closest(".slot");
|
const slot = img.closest(".slot");
|
||||||
|
|
||||||
e.dataTransfer.setData("itemId", img.dataset.id);
|
e.dataTransfer.setData("itemId", img.dataset.id);
|
||||||
e.dataTransfer.setData("itemLevel", img.dataset.level);
|
e.dataTransfer.setData("itemLevel", img.dataset.level);
|
||||||
e.dataTransfer.setData("slot", slot.dataset.slot);
|
e.dataTransfer.setData("slot", slot.dataset.slot);
|
||||||
@ -225,7 +232,6 @@ function initDrop() {
|
|||||||
const itemLevel = e.dataTransfer.getData("itemLevel");
|
const itemLevel = e.dataTransfer.getData("itemLevel");
|
||||||
const itemSlot = e.dataTransfer.getData("slot");
|
const itemSlot = e.dataTransfer.getData("slot");
|
||||||
const source = e.dataTransfer.getData("source");
|
const source = e.dataTransfer.getData("source");
|
||||||
|
|
||||||
const targetSlot = slot.dataset.slot;
|
const targetSlot = slot.dataset.slot;
|
||||||
|
|
||||||
if (!itemSlot || itemSlot !== targetSlot) return;
|
if (!itemSlot || itemSlot !== targetSlot) return;
|
||||||
@ -233,41 +239,27 @@ function initDrop() {
|
|||||||
let icon;
|
let icon;
|
||||||
|
|
||||||
if (source === "inventory") {
|
if (source === "inventory") {
|
||||||
const inventoryItem = document.querySelector(
|
const inventoryItem = document.querySelector('.inventory-slot[data-id="' + itemId + '"]');
|
||||||
'.inventory-slot[data-id="' + itemId + '"]',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!inventoryItem) return;
|
if (!inventoryItem) return;
|
||||||
|
|
||||||
icon = inventoryItem.querySelector("img").src;
|
icon = inventoryItem.querySelector("img").src;
|
||||||
|
|
||||||
inventoryItem.classList.add("empty");
|
inventoryItem.classList.add("empty");
|
||||||
inventoryItem.innerHTML = "";
|
inventoryItem.innerHTML = "";
|
||||||
} else {
|
} else {
|
||||||
const slotItem = document.querySelector(
|
const slotItem = document.querySelector('.slot[data-slot="' + itemSlot + '"] img');
|
||||||
'.slot[data-slot="' + itemSlot + '"] img',
|
|
||||||
);
|
|
||||||
if (!slotItem) return;
|
if (!slotItem) return;
|
||||||
|
|
||||||
icon = slotItem.src;
|
icon = slotItem.src;
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = slot.querySelector(".slot-label");
|
const label = slot.querySelector(".slot-label");
|
||||||
|
slot.innerHTML = `<img src="${icon}" draggable="true" data-id="${itemId}" data-level="${itemLevel}">`;
|
||||||
slot.innerHTML = `
|
|
||||||
<img src="${icon}"
|
|
||||||
draggable="true"
|
|
||||||
data-id="${itemId}"
|
|
||||||
data-level="${itemLevel}">
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (label) slot.appendChild(label);
|
if (label) slot.appendChild(label);
|
||||||
|
|
||||||
slot.classList.add("has-item");
|
slot.classList.add("has-item");
|
||||||
|
|
||||||
|
// Avatar Overlay anzeigen
|
||||||
|
updateAvatarOverlay(targetSlot, icon);
|
||||||
|
|
||||||
initDrag();
|
initDrag();
|
||||||
initSlotDrag();
|
initSlotDrag();
|
||||||
|
|
||||||
saveEquipment(targetSlot, itemId, itemLevel);
|
saveEquipment(targetSlot, itemId, itemLevel);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -286,7 +278,6 @@ function initInventoryDrop() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const source = e.dataTransfer.getData("source");
|
const source = e.dataTransfer.getData("source");
|
||||||
|
|
||||||
if (source !== "slot") return;
|
if (source !== "slot") return;
|
||||||
|
|
||||||
const itemId = e.dataTransfer.getData("itemId");
|
const itemId = e.dataTransfer.getData("itemId");
|
||||||
@ -294,11 +285,9 @@ function initInventoryDrop() {
|
|||||||
const slotName = e.dataTransfer.getData("slot");
|
const slotName = e.dataTransfer.getData("slot");
|
||||||
|
|
||||||
const slot = document.querySelector('.slot[data-slot="' + slotName + '"]');
|
const slot = document.querySelector('.slot[data-slot="' + slotName + '"]');
|
||||||
|
|
||||||
if (!slot) return;
|
if (!slot) return;
|
||||||
|
|
||||||
const img = slot.querySelector("img");
|
const img = slot.querySelector("img");
|
||||||
|
|
||||||
if (!img) return;
|
if (!img) return;
|
||||||
|
|
||||||
inventoryItems.push({
|
inventoryItems.push({
|
||||||
@ -311,14 +300,14 @@ function initInventoryDrop() {
|
|||||||
renderInventory();
|
renderInventory();
|
||||||
|
|
||||||
const label = slot.querySelector(".slot-label");
|
const label = slot.querySelector(".slot-label");
|
||||||
|
|
||||||
slot.innerHTML = "";
|
slot.innerHTML = "";
|
||||||
if (label) slot.appendChild(label);
|
if (label) slot.appendChild(label);
|
||||||
|
|
||||||
slot.classList.remove("has-item");
|
slot.classList.remove("has-item");
|
||||||
|
|
||||||
saveEquipment(slotName, null, null);
|
// Avatar Overlay entfernen
|
||||||
|
updateAvatarOverlay(slotName, null);
|
||||||
|
|
||||||
|
saveEquipment(slotName, null, null);
|
||||||
initDrag();
|
initDrag();
|
||||||
initSlotDrag();
|
initSlotDrag();
|
||||||
});
|
});
|
||||||
@ -332,10 +321,6 @@ async function saveEquipment(slot, itemId, itemLevelId) {
|
|||||||
await fetch("/api/equip", {
|
await fetch("/api/equip", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({ slot, itemId, itemLevelId }),
|
||||||
slot: slot,
|
|
||||||
itemId: itemId,
|
|
||||||
itemLevelId: itemLevelId,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user