// hud.js : maj des elements html du hud (hp, cd, vagues, upgrades, end game) import { UPGRADE_CATALOG, ABILITY_COOLDOWNS, DISPLACEMENT_COOLDOWNS, SCORE_PER_KILL, SCORE_PER_SOUL, SCORE_VICTORY, SCORE_PER_WAVE } from './constants.js'; import { showEndGameForm } from './leaderboard.js'; import { send } from './network.js'; import { setInputBlocked } from './input.js'; const BUFF_LABELS = { invulnerable: 'Invulnerable', casting: 'Incantation', flying: 'Vol', intangible: 'Intangible', combat_buff: 'Buff combat', damage_mult: 'Degats x3', }; const WAVE_STATES = { combat: 'Combat', preparation: 'Preparation', boss: 'Boss', victory: 'Victoire', }; export function updatePlayerHud(local) { document.getElementById('hud-class-name').textContent = (local.class ?? '').toUpperCase(); document.getElementById('hud-souls').textContent = 'Ames : ' + (local.souls ?? 0); const hpPct = local.max_hp > 0 ? Math.max(0, local.hp / local.max_hp * 100) : 0; document.getElementById('hud-hp-fill').style.width = hpPct + '%'; document.getElementById('hud-hp-text').textContent = local.hp + ' / ' + local.max_hp; _updateSkillCooldowns(local); _updateBuffTags(local); } function _updateSkillCooldowns(local) { const cds = local.cooldowns ?? {}; const abMaxes = ABILITY_COOLDOWNS[local.class] ?? [8, 12]; [['hud-s1', 0], ['hud-s2', 1]].forEach(([id, i]) => { const el = document.getElementById(id); const cd = cds['ability_' + (i + 1)] ?? 0; const maxCd = abMaxes[i]; const fill = cd <= 0 ? 100 : (1 - cd / maxCd) * 100; el.querySelector('.cd-fill').style.height = fill + '%'; el.classList.toggle('ready', cd <= 0); el.classList.remove('locked'); }); const elE = document.getElementById('hud-se'); const cdE = cds['displacement'] ?? 0; const maxCdE = DISPLACEMENT_COOLDOWNS[local.class] ?? 6; const fillE = cdE <= 0 ? 100 : (1 - cdE / maxCdE) * 100; elE.querySelector('.cd-fill').style.height = fillE + '%'; elE.classList.toggle('ready', cdE <= 0); elE.classList.remove('locked', 'divine-ready'); } function _updateBuffTags(local) { const buffsEl = document.getElementById('hud-buffs'); buffsEl.innerHTML = ''; for (const b of (local.buffs ?? [])) { const label = BUFF_LABELS[b.type]; if (!label) continue; const tag = document.createElement('span'); tag.className = 'buff-tag ' + b.type; tag.textContent = label; buffsEl.appendChild(tag); } } export function updateSoulgateBar(sg) { if (!sg) return; const pct = sg.max_hp > 0 ? Math.max(0, sg.hp / sg.max_hp * 100) : 0; document.getElementById('sg-fill').style.width = pct + '%'; document.getElementById('sg-hp-text').textContent = sg.hp + ' / ' + sg.max_hp; } export function updateWaveInfo(wave) { if (!wave) return; document.getElementById('wave-label').textContent = 'Vague ' + wave.number + ' / 3'; document.getElementById('wave-state-label').textContent = WAVE_STATES[wave.state] ?? wave.state; document.getElementById('wave-enemies').textContent = 'Ennemis : ' + (wave.enemies_remaining ?? 0); } export function updateBossBar(wave) { const isBoss = wave.state === 'boss' && wave.boss_max_hp > 0; document.getElementById('boss-bar').classList.toggle('hidden', !isBoss); if (isBoss) { document.getElementById('boss-bar-name').textContent = wave.boss_name.toUpperCase(); const pct = Math.max(0, wave.boss_hp / wave.boss_max_hp * 100); document.getElementById('boss-bar-fill').style.width = pct + '%'; document.getElementById('boss-bar-hp').textContent = wave.boss_hp + ' / ' + wave.boss_max_hp; } } export function updateUpgradePanel(wave, local) { const inPrep = wave.state === 'preparation'; document.getElementById('upgrade-panel').classList.toggle('hidden', !inPrep); // pendant la prep on bloque les inputs pour focus sur le menu setInputBlocked(inPrep || gameOver); if (inPrep) { document.getElementById('prep-timer').textContent = Math.ceil(wave.prep_timer); const souls = local?.souls ?? 0; document.getElementById('soul-count').textContent = souls; _updateUpgradeList(souls, local?.upgrades ?? {}); } } let _upgradeListBuilt = false; let _upgradeClickBound = false; function _updateUpgradeList(souls, upgrades) { // on construit la liste 1 seule fois et on met juste a jour les stacks/disabled apres // sinon on detruit les boutons pendant qu'on clique dessus const list = document.getElementById('upgrade-list'); if (!_upgradeListBuilt) { list.innerHTML = ''; for (const [id, spec] of Object.entries(UPGRADE_CATALOG)) { const item = document.createElement('div'); item.className = 'upgrade-item'; item.dataset.id = id; item.innerHTML = `