/
chewy
/
BDZ_GenAI
Обзор
Документация
Войти
/
chewy
/
BDZ_GenAI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
scripts/ui.modals.js
245 строк
15 KB
pichugin.sa
Раскидал все по папкам, чтобы нормально выглядел репозиторий
16 ноя 2025, 21:55
16 ноя 2025, 21:55
bd854ee
Код
Авторство
О чём код?
// ui.modals.js - modal UIs extracted from ui.js (Manual, Contracts, Codex, Options wiring) import * as HUD from '../hud.js'; import * as NOTIF from './notify.js'; import * as LANG from './language.js'; import * as E from './engine.js'; // Manual modal export function initManual(){ if(document.getElementById('__manualModal')) return; const overlay = document.createElement('div'); overlay.className = 'manual-overlay'; overlay.id = '__manualOverlay'; overlay.style.display='none'; const modal = document.createElement('div'); modal.className='modal manual-modal'; modal.id='__manualModal'; modal.innerHTML = ` <div class="manual-header"> <div class="manual-accent"></div> <div class="manual-title"><span class="manual-icon">📖</span> Manual — How to Play</div> </div> <div id="__manualBody" class="manual-body" style="margin-top:8px"></div> <div class="manual-actions" style="margin-top:12px;text-align:right"> <button id="__manualCloseBtn" class="small manual-close">Закрыть</button> </div> `; overlay.appendChild(modal); const sceneEl = document.querySelector('.scene') || document.body; sceneEl.appendChild(overlay); if(sceneEl && sceneEl.classList && sceneEl.classList.contains('scene')){ overlay.style.position = 'absolute'; overlay.style.left = '0'; overlay.style.top = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.zIndex = 1300; } overlay.addEventListener('click', (e)=>{ if(e.target === overlay) closeManual(); }); modal.querySelector('#__manualCloseBtn').addEventListener('click', ()=> closeManual()); } export function openManual(){ initManual(); const overlay = document.getElementById('__manualOverlay'); const modal = document.getElementById('__manualModal'); const body = document.getElementById('__manualBody'); const parts = Array.from(document.querySelectorAll('.manual-content')); body.innerHTML = ''; parts.forEach(p=>{ const c = document.createElement('div'); c.style.marginBottom = '10px'; c.innerHTML = p.innerHTML; body.appendChild(c); }); overlay.style.display = 'flex'; requestAnimationFrame(()=> { overlay.classList.add('show'); modal.classList.add('show'); }); window.__paused = true; document.querySelector('.hud') && document.querySelector('.hud').classList.add('dimmed'); } export function closeManual(){ const overlay = document.getElementById('__manualOverlay'); const modal = document.getElementById('__manualModal'); if(overlay){ overlay.classList.remove('show'); if(modal) modal.classList.remove('show'); setTimeout(()=> { overlay.style.display='none'; }, 420); } window.__paused = false; document.querySelector('.hud') && document.querySelector('.hud').classList.remove('dimmed'); } // Contracts UI export function initContractsUI(){ if(document.getElementById('__contractsModal')) return; const overlay = document.createElement('div'); overlay.className='manual-overlay'; overlay.id='__contractsOverlay'; overlay.style.display='none'; const modal = document.createElement('div'); modal.className='modal manual-modal'; modal.id='__contractsModal'; modal.innerHTML = ` <div class="manual-header"> <div class="manual-accent"></div> <div class="manual-title"><span class="manual-icon">📜</span> Contracts Board</div> </div> <div id="__contractsBody" class="manual-body"></div> <div style="margin-top:12px;text-align:right"><button id="__contractsClose" class="small manual-close">Закрыть</button></div> `; overlay.appendChild(modal); document.body.appendChild(overlay); overlay.addEventListener('click', (ev)=>{ if(ev.target===overlay) closeContracts(); }); modal.querySelector('#__contractsClose').addEventListener('click', ()=> closeContracts()); } export function openContracts(){ initContractsUI(); const overlay = document.getElementById('__contractsOverlay'); const modal = document.getElementById('__contractsModal'); const body = document.getElementById('__contractsBody'); body.innerHTML = ''; const list = (window.__contracts || []); list.forEach(c=>{ const wrap = document.createElement('div'); wrap.style.marginBottom='10px'; wrap.style.borderBottom='1px solid rgba(255,255,255,0.04)'; wrap.style.paddingBottom='8px'; const title = document.createElement('div'); title.style.fontWeight='700'; title.textContent = c.title + (c.status==='accepted' ? ' — Accepted' : (c.status==='completed'?' — Completed':'')); wrap.appendChild(title); const prog = document.createElement('div'); prog.style.fontSize='13px'; prog.style.color='var(--muted)'; prog.id = 'cprog_'+c.id; prog.textContent = 'Progress: '+(c.progress||0)+' / '+c.goal; wrap.appendChild(prog); const btn = document.createElement('button'); btn.className='small'; btn.style.marginTop='8px'; btn.textContent = (c.status==='accepted') ? 'Abandon' : ((c.status==='completed') ? 'Completed' : 'Accept'); btn.addEventListener('click', ()=>{ if(c.status==='accepted'){ c.status='available'; c.progress=0; NOTIF.notify('Контракт отменён', 'warn'); } else if(c.status==='completed'){ NOTIF.notify('Контракт уже завершён', 'info'); } else { c.status='accepted'; NOTIF.notify('Контракт принят: '+c.title, 'success'); } window.__contracts = (window.__contracts || []).map(cc=> cc.id===c.id ? c : cc); localStorage.setItem('rogue_proto_contracts', JSON.stringify(window.__contracts)); openContracts(); hudUpdate(); }); wrap.appendChild(btn); body.appendChild(wrap); }); overlay.style.display='flex'; requestAnimationFrame(()=> { overlay.classList.add('show'); modal.classList.add('show'); }); window.__paused = true; document.querySelector('.hud') && document.querySelector('.hud').classList.add('dimmed'); } export function closeContracts(){ const overlay = document.getElementById('__contractsOverlay'), modal = document.getElementById('__contractsModal'); if(overlay){ overlay.classList.remove('show'); modal && modal.classList.remove('show'); setTimeout(()=> overlay.style.display='none',420); } window.__paused = false; document.querySelector('.hud') && document.querySelector('.hud').classList.remove('dimmed'); } function hudUpdate(){ try{ const upd = document.querySelector && (window.updateHUD || window.__updateHUD); if(typeof upd === 'function') upd(); }catch(e){} } // Codex UI export function initCodexUI(){ if(document.getElementById('__codexModal')) return; const overlay = document.createElement('div'); overlay.className='manual-overlay'; overlay.id='__codexOverlay'; overlay.style.display='none'; const modal = document.createElement('div'); modal.className='modal manual-modal'; modal.id='__codexModal'; modal.innerHTML = ` <div class="manual-header"> <div class="manual-accent"></div> <div class="manual-title"><span class="manual-icon">📚</span> Codex</div> </div> <div id="__codexBody" class="manual-body"></div> <div style="margin-top:12px;text-align:right"><button id="__codexClose" class="small manual-close">Закрыть</button></div> `; overlay.appendChild(modal); document.body.appendChild(overlay); overlay.addEventListener('click', (ev)=>{ if(ev.target===overlay) closeCodex(); }); modal.querySelector('#__codexClose').addEventListener('click', ()=> closeCodex()); document.addEventListener('codex:updated', (ev)=> { try{ renderCodexPanel(); }catch(e){} }); } export function openCodex(){ initCodexUI(); const overlay = document.getElementById('__codexOverlay'); const modal = document.getElementById('__codexModal'); const body = document.getElementById('__codexBody'); body.innerHTML = ''; const codex = (window.__LanguageSystem && window.__LanguageSystem.codex) || {}; const keys = Object.keys(codex); if(!keys.length){ body.innerHTML = '<div style="color:var(--muted)">Codex пуст</div>'; } keys.sort().forEach(k=>{ const c = codex[k]; const row = document.createElement('div'); row.style.display='flex'; row.style.gap='12px'; row.style.alignItems='center'; row.style.marginBottom='8px'; const icon = document.createElement('div'); icon.style.width='48px'; icon.style.height='48px'; icon.style.borderRadius='8px'; icon.style.display='flex'; icon.style.alignItems='center'; icon.style.justifyContent='center'; icon.style.fontSize='20px'; icon.style.background='rgba(255,255,255,0.04)'; icon.textContent = c.icon; const meta = document.createElement('div'); meta.style.flex='1'; const title = document.createElement('div'); title.style.fontWeight='700'; title.textContent = c.icon + ' — ' + (c.learned? 'Изучено' : (c.desc||'Символ')); const sub = document.createElement('div'); sub.style.fontSize='13px'; sub.style.color='var(--muted)'; sub.textContent = (c.desc || '') + ' — Уверенность: ' + (c.confidence||0) + '%'; meta.appendChild(title); meta.appendChild(sub); row.appendChild(icon); row.appendChild(meta); body.appendChild(row); }); overlay.style.display='flex'; requestAnimationFrame(()=> { overlay.classList.add('show'); modal.classList.add('show'); }); window.__paused = true; document.querySelector('.hud') && document.querySelector('.hud').classList.add('dimmed'); } export function closeCodex(){ const overlay = document.getElementById('__codexOverlay'), modal = document.getElementById('__codexModal'); if(overlay){ overlay.classList.remove('show'); modal && modal.classList.remove('show'); setTimeout(()=> overlay.style.display='none',420); } window.__paused = false; document.querySelector('.hud') && document.querySelector('.hud').classList.remove('dimmed'); } export function renderCodexPanel(){ let box = document.getElementById('__codexMini'); if(!box){ box = document.createElement('div'); box.id='__codexMini'; box.style.fontSize='13px'; box.style.marginTop='6px'; box.style.pointerEvents='auto'; const parent = document.querySelector('.manual-content') || document.querySelector('.hud .panel'); if(parent) parent.appendChild(box); } const codex = (window.__LanguageSystem && window.__LanguageSystem.codex) || {}; const total = Object.keys(codex).length; const learned = Object.keys(codex).filter(k=> codex[k].learned).length; box.innerHTML = `Codex: ${learned}/${total} (${ (total? Math.round((learned/total)*100):0) }%) <button id="__openCodexBtn" class="small" style="margin-left:8px">Open</button>`; const openBtn = document.getElementById('__openCodexBtn'); if(openBtn) openBtn.addEventListener('click', ()=> openCodex()); } // Options modal & general DOM wiring moved here (Save/Load/Reset, Options toggles) export function initOptionsAndBindings(){ // wire Save / Load / Reset and Options modal UI once if(document.getElementById('__optionsOverlay')) return; const overlay = document.createElement('div'); overlay.id='__optionsOverlay'; overlay.style.display='none'; overlay.className='manual-overlay'; const modal = document.createElement('div'); modal.id='__optionsModal'; modal.className='manual-modal'; modal.innerHTML = ` <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px"><div style="font-weight:700">Options</div><button id="optsClose" class="small">Close</button></div> <div style="margin-bottom:8px"><label><input type="checkbox" id="optFov" /> Show NPC FOV (debug)</label></div> <div style="margin-bottom:8px"><label><input type="checkbox" id="optAmbient" checked /> Enable Ambient Sound</label></div> <div style="margin-bottom:8px"><label>Ambient Volume <input id="optVolume" type="range" min="0" max="1" step="0.01" value="0.12" /></label></div> <div style="margin-top:10px;font-size:13px;color:var(--muted)"><strong>Bindings</strong><div style="margin-top:6px">Move: WASD • Interact: E • Sneak: Shift • Manual: M • Scale: 1/2/3</div></div> `; overlay.appendChild(modal); document.body.appendChild(overlay); overlay.addEventListener('click', (e)=>{ if(e.target === overlay) { overlay.classList.remove('show'); setTimeout(()=> overlay.style.display='none',320); window.__paused=false; document.querySelector('.hud') && document.querySelector('.hud').classList.remove('dimmed'); } }); modal.querySelector('#optsClose').addEventListener('click', ()=> { overlay.classList.remove('show'); setTimeout(()=> overlay.style.display='none',320); window.__paused=false; document.querySelector('.hud') && document.querySelector('.hud').classList.remove('dimmed'); }); modal.querySelector('#optFov').addEventListener('change', (ev)=> { window.__showNpcFOV = !!ev.target.checked; }); modal.querySelector('#optAmbient').addEventListener('change', (ev)=> { window.__ambientEnabled = !!ev.target.checked; if(!window.__ambientEnabled){ try{ if(window.ambient && window.ambient.wind) { window.ambient.wind.pause(); window.ambient.rain && window.ambient.rain.pause(); } }catch(e){} } else { try{ if(window.ambient && window.ambient.wind) window.ambient.wind.play().catch(()=>{}); }catch(e){} } }); modal.querySelector('#optVolume').addEventListener('input', (ev)=>{ const v = parseFloat(ev.target.value); try{ if(window.ambient && window.ambient.wind) { window.ambient.wind.volume = v; window.ambient.rain && (window.ambient.rain.volume = Math.min(0.12, v * 0.6)); } }catch(e){} }); // open Options button wiring const openOptsBtn = document.getElementById('openOptions'); if(openOptsBtn) openOptsBtn.addEventListener('click', ()=>{ const overlay = document.getElementById('__optionsOverlay'); if(overlay){ overlay.style.display='flex'; requestAnimationFrame(()=> overlay.classList.add('show')); window.__paused=true; document.querySelector('.hud') && document.querySelector('.hud').classList.add('dimmed'); } }); // Save / Load / Reset wiring (from manual-content) const saveBtn = document.getElementById('saveGame'); if(saveBtn) saveBtn.addEventListener('click', ()=> { NOTIF.saveGame(); }); const loadBtn = document.getElementById('loadGame'); if(loadBtn) loadBtn.addEventListener('click', ()=> { NOTIF.loadGame(); }); const resetBtn = document.getElementById('resetGame'); if(resetBtn) resetBtn.addEventListener('click', ()=>{ if(confirm('Сбросить прогресс в localStorage?')){ localStorage.removeItem('ScaleShift_save_v1'); localStorage.removeItem('rogue_proto_save'); localStorage.removeItem('rogue_proto_contracts'); NOTIF.notify('Сбросено', 'warn'); } }); } // single init entry to be called from DOMContentLoaded in ui.js or main.js export function initOnDOMContentLoaded(){ renderCodexPanel(); initOptionsAndBindings(); // try autoload on first run if(!localStorage.getItem('ScaleShift_seen_before')){ localStorage.setItem('ScaleShift_seen_before','1'); const raw = localStorage.getItem('ScaleShift_save_v1'); if(raw){ try{ const s = JSON.parse(raw); if(s && s.player){ E.player.x = s.player.x; E.player.y = s.player.y; HUD.scaleSetting = s.scaleSetting || HUD.scaleSetting; NOTIF.notify('Автозагрузка предыдущего состояния','info',900); } }catch(e){} } } }