SystemEscape mit zufälligen Runs und Raumpool erweitern
mindflux-ci / build (push) Successful in 22s
mindflux-ci / build (push) Successful in 22s
This commit is contained in:
@@ -3,7 +3,7 @@ const api=(url,opt)=>fetch('/api/codeescape'+url,{headers:{'Content-Type':'appli
|
||||
function esc(s){return String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));}function post(url,data){return api(url,{method:'POST',body:JSON.stringify(data)});}function seconds(){return Math.max(1,Math.round((Date.now()-start)/1000));}
|
||||
function startTimer(){clearInterval(tickId);start=Date.now();tickId=setInterval(()=>{let left=session.timeLimitSeconds-seconds();timerEl.textContent=(left<0?'+':'')+fmt(Math.abs(left));timerEl.classList.toggle('alarm',left<=0);},1000);}function fmt(s){return String(Math.floor(s/60)).padStart(2,'0')+':'+String(s%60).padStart(2,'0');}
|
||||
function loadCatalog(){api('/scenarios').then(d=>{catalog=d.scenarios;renderLobby();}).catch(error);}
|
||||
function renderLobby(){timerEl.textContent='--:--';view.innerHTML='<div class="esc-hero"><span class="esc-eyebrow">FACILITY ARCHIVE // 03 SZENARIEN</span><h1>Wähle deinen Fluchtweg</h1><p>Jeder Raum enthält IT-Rätsel. Sichere die Code-Fragmente, öffne die Schleusen und entkomme, bevor der Zeitbonus verfällt.</p></div><div class="esc-grid">'+catalog.map(s=>`<article class="esc-card"><span class="esc-eyebrow">${esc(s.examScope)} · ${esc(s.difficulty)}</span><h2>${esc(s.title)}</h2><p>${esc(s.description)}</p><div class="esc-meta"><span class="esc-chip">${s.roomCount} Räume</span><span class="esc-chip">${Math.round(s.timeLimitSeconds/60)} Minuten</span></div><button class="esc-btn" data-start="${esc(s.slug)}">FACILITY BETRETEN</button></article>`).join('')+'</div>';view.querySelectorAll('[data-start]').forEach(b=>b.onclick=()=>begin(b.dataset.start));}
|
||||
function renderLobby(){timerEl.textContent='--:--';view.innerHTML='<div class="esc-hero"><span class="esc-eyebrow">FACILITY ARCHIVE // VARIABLE RUNS</span><h1>Wähle deinen Fluchtweg</h1><p>Jeder Run stellt vier Räume neu aus einem größeren Pool zusammen. Löse IT-Rätsel, sichere Fragmente und entkomme – der nächste Durchlauf wird anders.</p></div><div class="esc-grid">'+catalog.map(s=>`<article class="esc-card"><span class="esc-eyebrow">${esc(s.examScope)} · ${esc(s.difficulty)}</span><h2>${esc(s.title)}</h2><p>${esc(s.description)}</p><div class="esc-meta"><span class="esc-chip">${s.roomCount} Räume pro Run</span><span class="esc-chip">${s.poolSize} im Pool</span><span class="esc-chip">${Math.round(s.timeLimitSeconds/60)} Minuten</span></div><button class="esc-btn" data-start="${esc(s.slug)}">NEUEN RUN GENERIEREN</button></article>`).join('')+'</div>';view.querySelectorAll('[data-start]').forEach(b=>b.onclick=()=>begin(b.dataset.start));}
|
||||
function begin(slug){api('/session/'+encodeURIComponent(slug)).then(d=>{session=d;roomIndex=0;answers.clear();fragments.clear();startTimer();renderRoom();}).catch(error);}
|
||||
function renderRoom(){const r=session.rooms[roomIndex],complete=r.puzzles.every(p=>answers.has(p.puzzleId));view.innerHTML=`<div class="esc-room-head"><div><span class="esc-eyebrow">RAUM ${roomIndex+1} / ${session.rooms.length} · ${esc(session.examScope)}</span><h1>${esc(r.title)}</h1><p>${esc(r.intro)}</p></div><div class="esc-progress">${'● '.repeat(roomIndex+1)}${'○ '.repeat(session.rooms.length-roomIndex-1)}</div></div><div class="esc-how"><div class="${complete?'done':''}"><b>1</b><span><strong>Rätsel lösen</strong><small>Die Rätsel sind frei wählbar.</small></span></div><div class="${complete?'done':''}"><b>2</b><span><strong>Fragmente sammeln</strong><small>Ihre Reihenfolge ist links → rechts.</small></span></div><div class="${complete?'active':''}"><b>3</b><span><strong>Türcode bilden</strong><small>Ohne Leerzeichen zusammensetzen.</small></span></div></div><div class="esc-puzzles">${r.puzzles.map((p,i)=>`<button class="esc-puzzle ${answers.has(p.puzzleId)?'done':''}" data-puzzle="${p.puzzleId}"><span class="esc-eyebrow">RÄTSEL ${i+1} · ${esc(p.type)}</span><h3>${esc(p.prompt)}</h3><div class="status">${answers.has(p.puzzleId)?'✓ FRAGMENT GESICHERT':'ANKLICKEN UND LÖSEN →'}</div></button>`).join('')}</div><div class="esc-inventory ${complete?'complete':''}"><span class="esc-eyebrow">2 · FRAGMENTE VON LINKS NACH RECHTS</span><div class="esc-fragments">${r.puzzles.map((p,i)=>`<span class="esc-fragment"><small>${i+1}</small>${fragments.has(p.puzzleId)?esc(fragments.get(p.puzzleId)):'•••'}</span>`).join('')}</div>${complete?'<p class="esc-ready">✓ Alle Fragmente gesichert. Bilde jetzt unten den Türcode.</p>':''}</div><div class="esc-door ${complete?'ready':''}"><div class="esc-door-title"><span class="esc-eyebrow">3 · TÜRTERMINAL</span><strong>${complete?'Schleuse bereit':'Noch nicht verfügbar'}</strong></div><label>${complete?esc(r.doorPrompt):'Löse zuerst alle Rätsel, um das Terminal freizuschalten.'}<input class="esc-input" id="doorCode" autocomplete="off" spellcheck="false" ${complete?'':'disabled'}></label>${complete?'<button class="esc-btn" id="assembleBtn">FRAGMENTE EINSETZEN</button>':''}<button class="esc-btn primary" id="doorBtn" ${complete?'':'disabled'}>CODE PRÜFEN & ÖFFNEN</button><button class="esc-btn danger" id="quitBtn">AUFGEBEN</button><div class="esc-door-feedback" id="doorFeedback" role="status" aria-live="polite"></div></div>`;view.querySelectorAll('[data-puzzle]').forEach(b=>b.onclick=()=>openPuzzle(r.puzzles.find(p=>p.puzzleId==b.dataset.puzzle)));if(complete){document.getElementById('assembleBtn').onclick=()=>{document.getElementById('doorCode').value=r.puzzles.map(p=>fragments.get(p.puzzleId)).join('');document.getElementById('doorCode').focus();doorMessage('Fragmente eingesetzt. Prüfe den Code und öffne die Schleuse.','ok');};document.getElementById('doorCode').onkeydown=e=>{if(e.key==='Enter')openDoor(r);};}document.getElementById('doorBtn').onclick=()=>openDoor(r);document.getElementById('quitBtn').onclick=()=>finish(false);}
|
||||
function control(p){if(p.type==='code')return `<input class="esc-input" id="answer" placeholder="${esc(p.placeholder||'Antwort')}">`;if(p.type==='choice')return `<div class="esc-options">${p.options.map(x=>`<button class="esc-option" data-value="${esc(x)}">${esc(x)}</button>`).join('')}</div>`;if(p.type==='order')return `<div class="esc-options">${p.items.map((x,i)=>`<label>${i+1}.<select class="esc-select order">${p.items.map(y=>`<option>${esc(y)}</option>`).join('')}</select></label>`).join('')}</div>`;if(p.type==='match')return `<div class="esc-pairs">${p.left.map(x=>`<label>${esc(x)}<select class="esc-select pair" data-left="${esc(x)}">${p.right.map(y=>`<option>${esc(y)}</option>`).join('')}</select></label>`).join('')}</div>`;return'';}
|
||||
|
||||
Reference in New Issue
Block a user