export class FeedbackUI { constructor(parentContainer, game) { this.parentContainer = parentContainer; this.game = game; // Needed for resolving hero names/ids in logs? this.combatLogContainer = null; this.initCombatLogContainer(); } initCombatLogContainer() { this.combatLogContainer = document.createElement('div'); Object.assign(this.combatLogContainer.style, { position: 'absolute', top: '140px', // Below the top status panel left: '50%', transform: 'translateX(-50%)', display: 'flex', flexDirection: 'column', alignItems: 'center', pointerEvents: 'none', width: '100%', maxWidth: '600px', zIndex: '500' // Below modals }); this.parentContainer.appendChild(this.combatLogContainer); } showModal(title, message, onClose) { const overlay = document.createElement('div'); Object.assign(overlay.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.7)', display: 'flex', justifyContent: 'center', alignItems: 'center', pointerEvents: 'auto', zIndex: '1000' }); const content = document.createElement('div'); Object.assign(content.style, { backgroundColor: '#222', border: '2px solid #888', borderRadius: '8px', padding: '20px', width: '300px', textAlign: 'center', color: '#fff', fontFamily: 'sans-serif' }); const titleEl = document.createElement('h2'); titleEl.textContent = title; Object.assign(titleEl.style, { marginTop: '0', color: '#f44' }); content.appendChild(titleEl); const msgEl = document.createElement('p'); msgEl.innerHTML = message; Object.assign(msgEl.style, { fontSize: '16px', lineHeight: '1.5' }); content.appendChild(msgEl); const btn = document.createElement('button'); btn.textContent = 'Entendido'; Object.assign(btn.style, { marginTop: '20px', padding: '10px 20px', fontSize: '16px', cursor: 'pointer', backgroundColor: '#444', color: '#fff', border: '1px solid #888' }); btn.onclick = () => { if (overlay.parentNode /** Checks if attached */) this.parentContainer.removeChild(overlay); if (onClose) onClose(); }; content.appendChild(btn); overlay.appendChild(content); this.parentContainer.appendChild(overlay); } showConfirm(title, message, onConfirm) { const overlay = document.createElement('div'); Object.assign(overlay.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.7)', display: 'flex', justifyContent: 'center', alignItems: 'center', pointerEvents: 'auto', zIndex: '1000' }); const content = document.createElement('div'); Object.assign(content.style, { backgroundColor: '#222', border: '2px solid #888', borderRadius: '8px', padding: '20px', width: '300px', textAlign: 'center', color: '#fff', fontFamily: 'sans-serif' }); const titleEl = document.createElement('h2'); titleEl.textContent = title; Object.assign(titleEl.style, { marginTop: '0', color: '#f44' }); content.appendChild(titleEl); const msgEl = document.createElement('p'); msgEl.innerHTML = message; Object.assign(msgEl.style, { fontSize: '16px', lineHeight: '1.5' }); content.appendChild(msgEl); const buttons = document.createElement('div'); Object.assign(buttons.style, { display: 'flex', justifyContent: 'space-around', marginTop: '20px' }); const cancelBtn = document.createElement('button'); cancelBtn.textContent = 'Cancelar'; Object.assign(cancelBtn.style, { padding: '10px 20px', fontSize: '16px', cursor: 'pointer', backgroundColor: '#555', color: '#fff', border: '1px solid #888' }); cancelBtn.onclick = () => { this.parentContainer.removeChild(overlay); }; buttons.appendChild(cancelBtn); const confirmBtn = document.createElement('button'); confirmBtn.textContent = 'Aceptar'; Object.assign(confirmBtn.style, { padding: '10px 20px', fontSize: '16px', cursor: 'pointer', backgroundColor: '#2a5', color: '#fff', border: '1px solid #888' }); confirmBtn.onclick = () => { if (onConfirm) onConfirm(); this.parentContainer.removeChild(overlay); }; buttons.appendChild(confirmBtn); content.appendChild(buttons); overlay.appendChild(content); this.parentContainer.appendChild(overlay); } showTemporaryMessage(title, message, duration = 2000) { const modal = document.createElement('div'); Object.assign(modal.style, { position: 'absolute', top: '25%', left: '50%', transform: 'translate(-50%, -50%)', backgroundColor: 'rgba(139, 0, 0, 0.9)', color: '#fff', padding: '15px 30px', borderRadius: '8px', border: '2px solid #ff4444', fontFamily: '"Cinzel", serif', fontSize: '20px', textShadow: '2px 2px 4px black', zIndex: '2000', pointerEvents: 'none', opacity: '0', transition: 'opacity 0.5s ease-in-out' }); modal.innerHTML = `

⚠️ ${title}

${message}
`; document.body.appendChild(modal); requestAnimationFrame(() => { modal.style.opacity = '1'; }); setTimeout(() => { modal.style.opacity = '0'; setTimeout(() => { if (modal.parentNode) document.body.removeChild(modal); }, 500); }, duration); } showCombatLog(log) { const isHit = log.hitSuccess; const color = isHit ? '#ff4444' : '#aaaaaa'; let detailHtml = ''; if (isHit) { if (log.woundsCaused > 0) { detailHtml = `
-${log.woundsCaused} HP
`; } else { detailHtml = `
Sin Heridas (Armadura)
`; } } else { detailHtml = `
Esquivado / Fallado
`; } // We create a new log element or update a singleton? // The original logic updated a SINGLE notification area. // Let's create a transient toast style log here, appending to container. const logItem = document.createElement('div'); Object.assign(logItem.style, { backgroundColor: 'rgba(0,0,0,0.9)', padding: '15px', border: `2px solid ${color}`, borderRadius: '5px', textAlign: 'center', minWidth: '250px', marginBottom: '10px', fontFamily: '"Cinzel", serif', opacity: '0', transition: 'opacity 0.3s' }); logItem.innerHTML = `
${log.attackerId.split('_')[0]} ATACA
${detailHtml}
${log.message}
`; // Clear previous logs to act like the single notification area of before, OR stack them? // Original behavior was overwrite `innerHTML`. I should stick to that to avoid spam. // So I will clear `combatLogContainer` before adding. this.combatLogContainer.innerHTML = ''; this.combatLogContainer.appendChild(logItem); // Fade in requestAnimationFrame(() => { logItem.style.opacity = '1'; }); // Fade out setTimeout(() => { logItem.style.opacity = '0'; // We don't remove immediately to avoid layout jumps if another comes in, // but we cleared logic above. }, 3500); } }