/
chewy
/
BDZ_GenAI
Обзор
Документация
Войти
/
chewy
/
BDZ_GenAI
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
scripts/language.js
132 строки
6 KB
pichugin.sa
Раскидал все по папкам, чтобы нормально выглядел репозиторий
16 ноя 2025, 21:55
16 ноя 2025, 21:55
bd854ee
Код
Авторство
О чём код?
// language.js - LanguageSystem gesture mini-game (moved from ui.js) import * as NOTIF from './notify.js'; import { RuleEngine } from './hud.js'; export const LanguageSystem = { learnedPhrases: [], open:false, ui: null, symbols: ['✦','☀','★','◆','✿'], currentTarget: [], currentSelection: [], currentNpc: null, successCount: {}, lastClickAt: 0, clickInterval: 200, // Codex structure: key -> { icon, desc, confidence(0-100), learned:boolean } codex: {}, codexTotalAdded: 0, init(){ const modal = document.createElement('div'); modal.className='modal'; modal.style.display='none'; modal.innerHTML = ` <div style="font-weight:700">Диалог — Жесты</div> <div style="font-size:13px;color:var(--muted);margin-top:6px">Повторите показанную последовательность</div> <div style="margin-top:8px;font-size:13px"><span id="npcExample" style="font-weight:700"></span></div> <div class="symbols" id="symbolRow"></div> <div style="display:flex;gap:8px;justify-content:center;margin-top:8px"> <button id="langConfirm" class="small">Подтвердить</button> <button id="langClose" class="small">Отмена</button> </div> <div style="margin-top:8px;font-size:12px;color:var(--muted)">После 3 успешных диалогов фраза попадёт в словарь</div> `; document.body.appendChild(modal); this.ui = modal; modal.querySelector('#langClose').addEventListener('click', ()=> this.close()); modal.querySelector('#langConfirm').addEventListener('click', ()=> this.check()); this.renderSymbols(); }, openFor(npc){ if(!this.ui) this.init(); this.currentNpc = npc; const len = 3 + Math.floor(Math.random()*3); this.currentTarget = []; for(let i=0;i<len;i++) this.currentTarget.push(this.symbols[Math.floor(Math.random()*this.symbols.length)]); // ensure Codex entries exist for each symbol encountered for first time for(const sym of this.currentTarget){ if(!this.codex[sym]){ this.codex[sym] = { icon: sym, desc: 'Новый символ', confidence: 10, learned: false }; this.codexTotalAdded++; // notify UI to update codex panel and persistable state try{ document.dispatchEvent(new CustomEvent('codex:updated',{detail:{symbol:sym}})); }catch(e){} } } this.currentSelection = []; const factionKey = (npc && npc.faction) ? npc.faction : 'MiniTribe'; this.clickInterval = factionKey === 'GiantFolk' ? 600 : 180; const ex = this.ui.querySelector('#npcExample'); ex.textContent = 'Пример: ' + this.currentTarget.join(' '); this.updateUI(); this.ui.style.display='block'; this.open = true; this.successCount[npc && npc.id ? npc.id : ('npc'+(Math.random()*10000|0))] = this.successCount[npc && npc.id ? npc.id : ''] || 0; }, close(){ if(this.ui) this.ui.style.display='none'; this.open=false; this.currentNpc=null; }, renderSymbols(){ if(!this.ui) return; const row = this.ui.querySelector('#symbolRow'); row.innerHTML = ''; this.symbols.forEach(sym=>{ const b = document.createElement('button'); b.className='symbol-btn'; b.textContent = sym; b.addEventListener('click', (ev)=>{ const now = performance.now(); if(now - (LanguageSystem.lastClickAt || 0) < LanguageSystem.clickInterval) { b.animate([{transform:'scale(1)'},{transform:'scale(0.95)'}],{duration:120,iterations:1}); return; } LanguageSystem.lastClickAt = now; if(LanguageSystem.currentSelection.length >= 5) return; LanguageSystem.currentSelection.push(sym); b.classList.add('selected'); LanguageSystem.updateUI(); }); row.appendChild(b); }); }, updateUI(){ if(!this.ui) return; const buttons = this.ui.querySelectorAll('.symbol-btn'); buttons.forEach(btn=> btn.classList.remove('selected')); const rowBtns = Array.from(buttons); this.currentSelection.forEach((sym, idx)=>{ const btn = rowBtns.find(b=>b.textContent === sym && !b.dataset.used); if(btn){ btn.dataset.used='1'; btn.classList.add('selected'); setTimeout(()=> delete btn.dataset.used, 300); } }); }, check(){ if(this.currentSelection.length !== this.currentTarget.length){ NOTIF.notify('Неверная длина последовательности', 'warn'); RuleEngine.changeRep('MiniTribe', -1); return this.close(); } const ok = this.currentSelection.join('') === this.currentTarget.join(''); const npc = this.currentNpc; const id = npc && npc.id ? npc.id : ('npc'+(Math.random()*10000|0)); if(ok){ this.successCount[id] = (this.successCount[id] || 0) + 1; NOTIF.notify('Успех! (' + this.successCount[id] + '/3)', 'success'); // increase confidence on correct application per symbol for(const sym of this.currentTarget){ const card = this.codex[sym] || (this.codex[sym] = {icon:sym,desc:'Новый символ',confidence:10,learned:false}); // add 33..35% per successful use (so 3 successes => ~100) card.confidence = Math.min(100, card.confidence + 34); if(card.confidence >= 100 && !card.learned){ card.learned = true; NOTIF.notify('Новый символ изучен: ' + sym, 'info', 1200); } try{ document.dispatchEvent(new CustomEvent('codex:updated',{detail:{symbol:sym,card}})); }catch(e){} } if(this.successCount[id] >= 3){ const phrase = this.currentTarget.join(' '); this.learnedPhrases.push(phrase); NOTIF.notify('Фраза выучена: ' + phrase, 'info', 1400); const jl = document.getElementById('journalList'); if(jl){ const li = document.createElement('li'); li.textContent = 'Выучено: ' + phrase; jl.appendChild(li); } this.successCount[id] = 0; } } else { NOTIF.notify('Неверно', 'warn'); RuleEngine.changeRep('MiniTribe', -1); } this.currentSelection = []; this.updateUI(); this.close(); return ok; }, // utility to compute completion % completionPercent(){ const keys = Object.keys(this.codex||{}); if(!keys.length) return 0; const learned = keys.filter(k=> this.codex[k].learned).length; return Math.round((learned / keys.length) * 100); } };