// Hotbar UI — 3-slot Minecraft-style bottom bar + selected item indicator import { state } from '../core/state.js'; import { BLOCKS } from '../data/blocks.js'; import { ITEMS } from '../data/items.js'; import { TOOLS } from '../data/tools.js'; import { tex, itemTex } from '../render/textures.js'; import { playSound } from '../audio/sound-engine.js'; const HOTBAR_SLOTS = 3; let selectedItemEl = null; export function addToRecentItems(id) { if (!id) return; state.recentItems = state.recentItems.filter(item => item !== id); state.recentItems.unshift(id); state.recentItems = state.recentItems.slice(0, 5); } function renderSlotIcon(el, id) { if (BLOCKS[id] && tex[id]) { el.style.backgroundImage = `url(${tex[id].toDataURL()})`; el.style.backgroundSize = 'cover'; } else if (itemTex[id]) { el.style.backgroundImage = `url(${itemTex[id].toDataURL()})`; el.style.backgroundSize = 'cover'; } else if (ITEMS[id]) { el.textContent = ITEMS[id].icon || '📦'; } else if (TOOLS[id]) { el.textContent = TOOLS[id].icon || '🔧'; } else if (id === 'iron_armor') { el.textContent = '🛡️'; el.style.background = 'linear-gradient(135deg, #95a5a6 0%, #7f8c8d 100%)'; } else { el.textContent = id.charAt(0).toUpperCase(); el.style.background = '#555'; el.style.color = '#fff'; el.style.fontWeight = '700'; el.style.fontSize = '14px'; } } function updateSelectedItem() { if (!selectedItemEl) selectedItemEl = document.getElementById('selectedItem'); if (!selectedItemEl) return; const sel = state.selected; if (!sel || !state.inv[sel] || state.inv[sel] <= 0) { selectedItemEl.style.display = 'none'; return; } selectedItemEl.style.display = 'flex'; // Clear previous content selectedItemEl.textContent = ''; selectedItemEl.style.backgroundImage = ''; selectedItemEl.style.background = 'rgba(0,0,0,0.45)'; // Render icon if (BLOCKS[sel] && tex[sel]) { selectedItemEl.style.backgroundImage = `url(${tex[sel].toDataURL()})`; selectedItemEl.style.backgroundSize = 'cover'; } else if (itemTex[sel]) { selectedItemEl.style.backgroundImage = `url(${itemTex[sel].toDataURL()})`; selectedItemEl.style.backgroundSize = 'cover'; } else if (ITEMS[sel]) { selectedItemEl.textContent = ITEMS[sel].icon || '📦'; } else if (TOOLS[sel]) { selectedItemEl.textContent = TOOLS[sel].icon || '🔧'; } else { selectedItemEl.textContent = sel.charAt(0).toUpperCase(); } } export function rebuildHotbar() { const hotbarEl = state.hotbarEl; const inv = state.inv; const selected = state.selected; const toolDurability = state.toolDurability; hotbarEl.innerHTML = ''; // Get up to 3 recent items with count > 0 const items = state.recentItems.filter(id => inv[id] > 0).slice(0, HOTBAR_SLOTS); // If selected item not in list and has count > 0, push to front if (inv[selected] > 0 && !items.includes(selected)) { items.unshift(selected); if (items.length > HOTBAR_SLOTS) items.pop(); } // Always render HOTBAR_SLOTS slots (fill empties) for (let si = 0; si < HOTBAR_SLOTS; si++) { const id = items[si] || null; const s = document.createElement('div'); s.className = 'slot' + (id && id === selected ? ' sel' : ''); // Slot number indicator (top-left) const numEl = document.createElement('div'); numEl.style.cssText = 'position:absolute;top:1px;left:3px;font-size:10px;color:rgba(255,255,255,0.55);font-weight:700;pointer-events:none;text-shadow:1px 1px 1px rgba(0,0,0,0.7);'; numEl.textContent = (si + 1).toString(); s.appendChild(numEl); if (id) { renderSlotIcon(s, id); const c = document.createElement('div'); c.className = 'count'; c.textContent = inv[id]; s.appendChild(c); s.onclick = () => { playSound('click'); state.selected = id; // Move to front of recentItems state.recentItems = state.recentItems.filter(item => item !== id); state.recentItems.unshift(id); rebuildHotbar(); }; if (id === 'iron_armor' && state.player.equippedArmor === 'iron_armor') { const equipped = document.createElement('div'); equipped.className = 'equipped-indicator'; equipped.textContent = '✓'; s.appendChild(equipped); } // Durability bar if (TOOLS[id] && inv[id] > 0) { let curDur = 0, maxDur = TOOLS[id].durability; for (const [tid, dur] of toolDurability) { if (dur.type === id) { curDur = dur.current; maxDur = dur.max; break; } } if (maxDur > 0) { const bar = document.createElement('div'); bar.style.cssText = `position:absolute;bottom:0;left:0;right:0;height:3px;background:#333;border-radius:0 0 6px 6px;overflow:hidden;`; const fill = document.createElement('div'); const pct = curDur / maxDur; const color = pct > 0.5 ? '#2ecc71' : pct > 0.25 ? '#f39c12' : '#e74c3c'; fill.style.cssText = `width:${pct * 100}%;height:100%;background:${color};`; bar.appendChild(fill); s.appendChild(bar); } } } hotbarEl.appendChild(s); } // Update selected item indicator above hotbar updateSelectedItem(); }