/* wizard.js — Schritt-Navigation + Screens 1-3 (Grundinfos, Gestaltung, Regeln) */ /* ══════════════════════════════════════════════ NAVIGATION ══════════════════════════════════════════════ */ function goTo(step){ if(step>cur&&!canLeave(cur))return; save(); const from=document.getElementById('s'+cur); from.classList.remove('active'); from.style.display='none'; setTimeout(()=>{from.style.display='';},50); if(step>cur)ST.highestStep=Math.max(ST.highestStep,step); cur=step; const to=document.getElementById('s'+cur); to.style.display=''; to.classList.add('active','slide-in'); to.addEventListener('animationend',()=>to.classList.remove('slide-in'),{once:true}); const ep=document.getElementById('editorPane');if(ep)ep.scrollTo({top:0,behavior:'smooth'});else window.scrollTo({top:0,behavior:'smooth'}); updatePB(); showSummary(step); if(step===1)s2init(); if(step===2){ s3init(); if(typeof maybeStartTour==='function') maybeStartTour(); } if(step===3)buildQuiz(); if(step===4)buildReview(); showToast('✅ Schritt '+(step+1)+' geöffnet!'); } function pbClick(step){if(step0; if(step===1)return !!(ST.figure&&ST.background) && (ST.playerCount!==2 || (ST.figure2 && ST.figure2!==ST.figure)); if(step===2)return ST.fields.slice(1,ST.fieldCount-1).filter(Boolean).length>0; return true; } function updatePB(){ for(let i=0;i<5;i++){ const d=document.getElementById('pb'+i); d.className='pb-step'+(i===cur?' active':i👋 ${esc(ST.devName)}`;html+=`
🎮 ${esc(ST.name)}
`;if(ST.desc)html+=`
"${esc(ST.desc.slice(0,40))}${ST.desc.length>40?'…':''}"
`;} if(idx===1){const f=FIGURES.find(x=>x.id===ST.figure);const b=BACKGROUNDS.find(x=>x.id===ST.background);if(f)html+=`
${f.e} ${f.n}
`;if(b)html+=`
🌍 ${b.n}
`;} if(idx===2){const filled=ST.fields.slice(1,ST.fieldCount-1).filter(Boolean).length;html+=`
⬛ ${ST.fieldCount} Felder
🕹️ ${filled} Mini-Games
📖 ${ST.storyItems.length} Erzähltexte
`;} if(idx===3){const done=ST.quizData.filter(isQComplete).length;html+=`
❓ ${done}/${ST.quizData.length||0} Quiz-Fragen
`;} chips.innerHTML=html; } function showToast(msg){ const t=document.getElementById('toast');t.textContent=msg;t.classList.add('show'); setTimeout(()=>t.classList.remove('show'),2000); } /* ══════════════════════════════════════════════ STEP 1 — GRUNDINFOS ══════════════════════════════════════════════ */ function s1init(){ document.getElementById('s1devname').value=ST.devName; document.getElementById('s1name').value=ST.name; document.getElementById('s1desc').value=ST.desc; s1update(); } function s1update(){ ST.devName=document.getElementById('s1devname').value.trim(); ST.name=document.getElementById('s1name').value.trim(); ST.desc=document.getElementById('s1desc').value; const nl=document.getElementById('s1name').value.length; const dl=ST.desc.length; document.getElementById('s1nc').textContent=nl+' / 40'; document.getElementById('s1dc').textContent=dl+' / 120'; document.getElementById('s1dc').className='char-row'+(dl>100?' warn':''); const s1dis=!ST.name||!ST.devName; document.getElementById('s1next').disabled=s1dis; const s1hint=document.getElementById('s1hint');if(s1hint)s1hint.style.display=s1dis?'block':'none'; // Persönliche Begrüßung const grEl=document.getElementById('devGreeting'); if(ST.devName){ const greetings=[ 'Hey '+ST.devName+' 👋 Schön, dass du dabei bist!', 'Los geht\'s, '+ST.devName+'! Dein Spiel wartet 🎮', 'Hi '+ST.devName+'! Du wirst ein tolles Spiel bauen ✨', 'Willkommen, '+ST.devName+'! Game on! 🚀', ]; grEl.textContent=greetings[ST.devName.length%greetings.length]; grEl.style.opacity='1'; } else {grEl.style.opacity='0';} // Vorschau const show=ST.name.length>0&&ST.devName.length>0; document.getElementById('s1preview').style.display=show?'':'none'; if(show){ document.getElementById('s1pvname').textContent=ST.name; document.getElementById('s1pvdesc').textContent=ST.desc||'Keine Beschreibung.'; document.getElementById('s1pvdev').textContent='👨‍💻 Entwickelt von '+ST.devName; } } function suggest(txt){document.getElementById('s1name').value=txt;s1update();} /* ══════════════════════════════════════════════ STEP 2 — GESTALTUNG ══════════════════════════════════════════════ */ function buildFigureGrid(gridId, current, blocked, onPick){ const g=document.getElementById(gridId); if(!g) return; g.innerHTML=''; FIGURES.forEach(f=>{ const isBlocked = blocked && blocked===f.id; const c=document.createElement('div'); c.className='sel-card'+(current===f.id?' selected':'')+(isBlocked?' disabled':''); c.innerHTML=`${f.e}
${f.n}
`; if(isBlocked){ c.title='Bereits vom anderen Spieler gewählt'; } else { c.onclick=()=>onPick(f.id); } g.appendChild(c); }); } function setPlayerCount(n){ ST.playerCount = n; if(n===1){ ST.figure2=''; } setCodeFocus('figure'); save(); s2update(); } function s2init(){ buildFigureGrid('figGrid', ST.figure, ST.figure2, id => { ST.figure=id; setCodeFocus('figure'); if(ST.figure2===id) ST.figure2=''; // Konflikt löst sich automatisch s2update(); }); const bg=document.getElementById('bgGrid'); bg.innerHTML=''; BACKGROUNDS.forEach(b=>{ const c=document.createElement('div');c.className='sel-card'+(ST.background===b.id?' selected':''); c.innerHTML=`${b.e}
${b.n}
`; c.onclick=()=>{ST.background=b.id;setCodeFocus('bg');s2update();bg.querySelectorAll('.sel-card').forEach(x=>x.classList.remove('selected'));c.classList.add('selected');}; bg.appendChild(c); }); s2update(); } function s2update(){ // Spielmodus-Karten markieren document.getElementById('pmode1')?.classList.toggle('active', ST.playerCount!==2); document.getElementById('pmode2')?.classList.toggle('active', ST.playerCount===2); // Figur-Karten-Titel anpassen const t = document.getElementById('figCardTitle'); const s = document.getElementById('figCardSub'); if(t){ t.textContent = ST.playerCount===2 ? '👤 Spielfigur Spieler 1' : '👤 Spielfigur'; } if(s){ s.textContent = ST.playerCount===2 ? 'Wer bist du im Spiel?' : 'Das bist du im Spiel!'; } // P2-Karte ein-/ausblenden + Grid neu bauen (für blocked-State) const fig2Card = document.getElementById('fig2Card'); if(fig2Card){ fig2Card.style.display = ST.playerCount===2 ? '' : 'none'; if(ST.playerCount===2){ buildFigureGrid('fig2Grid', ST.figure2, ST.figure, id => { ST.figure2=id; setCodeFocus('figure'); s2update(); }); } } // P1-Grid neu bauen (damit Block-State der gegenüberliegenden Figur stimmt) buildFigureGrid('figGrid', ST.figure, ST.playerCount===2 ? ST.figure2 : '', id => { ST.figure=id; setCodeFocus('figure'); if(ST.figure2===id) ST.figure2=''; s2update(); }); // Combo-Preview const ok = !!(ST.figure&&ST.background) && (ST.playerCount!==2 || (ST.figure2 && ST.figure2!==ST.figure)); document.getElementById('s2next').disabled=!ok; const combo=document.getElementById('s2combo'); if(ST.figure && ST.background){ const f=FIGURES.find(x=>x.id===ST.figure);const b=BACKGROUNDS.find(x=>x.id===ST.background); combo.style.display=''; const f2 = ST.playerCount===2 && ST.figure2 ? FIGURES.find(x=>x.id===ST.figure2) : null; document.getElementById('s2scene').textContent = b.scene + ' ' + f.e + (f2?' vs '+f2.e:''); document.getElementById('s2clabel').textContent = f.n + (f2?' & '+f2.n:'') + ' im '+ b.n; } else { combo.style.display='none'; } } /* ══════════════════════════════════════════════ STEP 3 — SPIELFELD ══════════════════════════════════════════════ */ let selGame=null,dragging=null,epFor=null,dragFromIdx=null; const STORY_MAX=5,MULTI_MAX=3; // unlockSection: Markiert eine Sektion als "gesehen" für den Live-Code-Preview function unlockSection(key){ if(typeof unlocked !== 'undefined') unlocked.add(key); if(typeof setCodeFocus === 'function') setCodeFocus(key); } function s3init(){ unlockSection('movement'); unlockSection('failmode'); unlockSection('fieldcount'); unlockSection('fields'); unlockSection('consequences'); document.getElementById('cntVal').textContent=ST.fieldCount; document.getElementById('cntMinus').disabled=ST.fieldCount<=6; document.getElementById('cntPlus').disabled=ST.fieldCount>=50; applyRuleUI(); buildPalette(); buildBoard(); updateConsequenceUI(); } function selRule(el){ const g=el.dataset.g; document.querySelectorAll(`[data-g="${g}"]`).forEach(x=>x.classList.remove('selected')); el.classList.add('selected');ST.rules[g]=el.dataset.v; // Map data-g to focus keys const fkMap={'movement':'movement','fail':'failmode'}; setCodeFocus(fkMap[g]||g); if(g==='fail'){ const sl = document.getElementById('sub_lives'); const sp = document.getElementById('sub_points'); if(ST.rules.fail==='lives'){ sl.classList.add('visible'); sl.style.display='flex'; sp.classList.remove('visible'); sp.style.display=''; } else { sl.classList.remove('visible'); sl.style.display=''; sp.classList.add('visible'); sp.style.display=''; } } updateConsequenceUI(); } function selSub(el){ const g=el.dataset.g; document.querySelectorAll(`[data-g="${g}"]`).forEach(x=>x.classList.remove('selected')); el.classList.add('selected');ST.rules[g]=el.dataset.v; // lives/pts sub-options setCodeFocus(g==='lives'?'lives':g==='pts'?'pts':'failmode'); } // ── Konsequenz-Funktionen ────────────────────────────────────────────────── function chgLives(delta){ const cur = parseInt(ST.rules.lives) || 3; const next = Math.min(5, Math.max(1, cur + delta)); ST.rules.lives = String(next); document.getElementById('livesDisplay').textContent = next; document.getElementById('livesHearts').textContent = '❤️'.repeat(next); setCodeFocus('lives'); save(); } function selCQ(el,e){ e&&e.stopPropagation&&e.stopPropagation(); const side = el.dataset.cq; const val = el.dataset.cv; document.querySelectorAll(`[data-cq="${side}"]`) .forEach(x=>x.classList.remove('selected')); el.classList.add('selected'); ST.consequences[side] = val; setCodeFocus('consequences'); save(); } function chgCQVal(key, delta, e){ e && e.stopPropagation(); const mins = {winVal:0,loseVal:0,winPts:0,losePts:0}; const maxs = {winVal:6,loseVal:6,winPts:100,losePts:100}; if(!ST.consequences[key]) ST.consequences[key] = key.includes('Pts') ? 10 : 1; let v = (ST.consequences[key]||0) + delta; v = Math.max(mins[key]||0, Math.min(maxs[key]||99, v)); ST.consequences[key] = v; const elId = {winVal:'cqWinVal',loseVal:'cqLoseVal',winPts:'cqWinPts',losePts:'cqLosePts'}[key]; if(elId) document.getElementById(elId).textContent = v; setCodeFocus('consequences'); save(); } function updateConsequenceUI(){ const grid = document.getElementById('consequenceGrid'); if(!grid) return; const isDice = ST.rules.movement === 'dice'; const isLives = ST.rules.fail === 'lives'; const isPts = ST.rules.fail === 'points'; // CSS-Klassen für sichtbare Optionen // Alle Modus-Klassen zuerst entfernen grid.classList.remove('cq-mode-step','cq-mode-lives','cq-mode-pts'); // Dann die passenden setzen if(!isDice) grid.classList.add('cq-mode-step'); if(isLives) grid.classList.add('cq-mode-lives'); if(isPts) grid.classList.add('cq-mode-pts'); // Falls aktuelle Auswahl nicht mehr sichtbar → auf 'nothing' zurücksetzen ['win','lose'].forEach(side=>{ const cur = ST.consequences[side]; const diceOnly = ['forward','back','again','skip']; const livesOnly = ['life']; const ptsOnly = ['points']; let invalid = false; if(diceOnly.includes(cur) && !isDice) invalid = true; if(livesOnly.includes(cur) && !isLives) invalid = true; if(ptsOnly.includes(cur) && !isPts) invalid = true; if(invalid){ ST.consequences[side] = 'nothing'; } // UI aktualisieren document.querySelectorAll(`[data-cq="${side}"]`) .forEach(x=>x.classList.toggle('selected', x.dataset.cv === ST.consequences[side])); }); // Werte anzeigen const c = ST.consequences; const wv = document.getElementById('cqWinVal'); const lv = document.getElementById('cqLoseVal'); const wp = document.getElementById('cqWinPts'); const lp = document.getElementById('cqLosePts'); if(wv) wv.textContent = c.winVal ?? 2; if(lv) lv.textContent = c.loseVal ?? 1; const ld = document.getElementById('livesDisplay'); const lh = document.getElementById('livesHearts'); const ln = parseInt(ST.rules.lives) || 3; if(ld) ld.textContent = ln; if(lh) lh.textContent = '❤️'.repeat(ln); if(wp) wp.textContent = c.winPts ?? 10; if(lp) lp.textContent = c.losePts ?? 5; } function applyRuleUI(){ ['movement','fail'].forEach(g=>document.querySelectorAll(`[data-g="${g}"]`).forEach(x=>x.classList.toggle('selected',x.dataset.v===ST.rules[g]))); document.getElementById('sub_lives').classList.toggle('visible',ST.rules.fail==='lives'); document.getElementById('sub_points').classList.toggle('visible',ST.rules.fail==='points'); ['lives','pts'].forEach(g=>document.querySelectorAll(`[data-g="${g}"]`).forEach(x=>x.classList.toggle('selected',x.dataset.v===ST.rules[g]))); updateConsequenceUI(); } function chgCount(d){ const n=ST.fieldCount+d;if(n<6||n>50)return; ST.fieldCount=n;setCodeFocus('fieldcount');document.getElementById('cntVal').textContent=n; document.getElementById('cntMinus').disabled=n<=6;document.getElementById('cntPlus').disabled=n>=50; while(ST.fields.lengths.fieldIndex