197 lines
8.1 KiB
JavaScript
197 lines
8.1 KiB
JavaScript
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 = `
|
|
<h3 style="margin:0; text-align:center; color: #FFD700; text-transform: uppercase;">⚠️ ${title}</h3>
|
|
<div style="margin-top:5px; font-size: 16px;">${message}</div>
|
|
`;
|
|
|
|
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 = `<div style="font-size: 24px; color: #ff0000; font-weight:bold;">-${log.woundsCaused} HP</div>`;
|
|
} else {
|
|
detailHtml = `<div style="font-size: 20px; color: #aaa;">Sin Heridas (Armadura)</div>`;
|
|
}
|
|
} else {
|
|
detailHtml = `<div style="font-size: 18px; color: #888;">Esquivado / Fallado</div>`;
|
|
}
|
|
|
|
// 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 = `
|
|
<div style="font-size: 18px; color: ${color}; margin-bottom: 5px; text-transform:uppercase;">${log.attackerId.split('_')[0]} ATACA</div>
|
|
${detailHtml}
|
|
<div style="font-size: 14px; color: #ccc; margin-top:5px;">${log.message}</div>
|
|
`;
|
|
|
|
// 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);
|
|
}
|
|
}
|