diff --git a/App/sims/weltkueche/game.html b/App/sims/weltkueche/game.html
index b441fc6..0e5b378 100644
--- a/App/sims/weltkueche/game.html
+++ b/App/sims/weltkueche/game.html
@@ -170,6 +170,15 @@
.modal .big-emoji{font-size:3.4rem}
.modal h2{font-size:1.6rem;font-weight:800;margin:8px 0}
.modal .scoreline{font-size:1.05rem;color:var(--green-d);font-weight:700;margin:4px 0 14px}
+ /* Live-Punkte-Feedback (schwebt kurz auf und verblasst) */
+ .wk-float{position:fixed;left:50%;top:20%;transform:translateX(-50%);z-index:9999;pointer-events:none;
+ font-weight:800;font-size:1.5rem;padding:.4rem 1rem;border-radius:14px;color:#fff;
+ box-shadow:0 10px 30px rgba(0,0,0,.28);animation:wkFloatAnim 1.4s ease-out forwards;white-space:nowrap}
+ .wk-float.pos{background:#4a7c4e}
+ .wk-float.neg{background:#c0674f;font-size:1rem}
+ @keyframes wkFloatAnim{0%{opacity:0;transform:translate(-50%,12px) scale(.9)}
+ 15%{opacity:1;transform:translate(-50%,0) scale(1)}70%{opacity:1;transform:translate(-50%,-6px) scale(1)}
+ 100%{opacity:0;transform:translate(-50%,-34px) scale(1)}}
.fact{background:var(--gold-soft);border-radius:14px;padding:14px;font-size:.92rem;text-align:left;margin-bottom:14px}
.fact b{color:#8a6516}
.earned-badges{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-bottom:14px}
@@ -612,7 +621,7 @@ const BADGES = [
{id:"perfect",icon:"đŻ",name:"Volltreffer-Koch", desc:"Ein Gericht ganz ohne Fehlklick gelĂśst."},
{id:"dish", icon:"đ˝ď¸",name:"Weltkoch", desc:"Dein erstes Gericht abgeschlossen."},
{id:"landlk", icon:"đşď¸",name:"Geografie-Genie", desc:"Erkannt: Binnenland hat kein Meer (Nori)."},
- {id:"trade", icon:"đ",name:"Welthandels-Profi",desc:"Ăber 3000 Punkte gesammelt."},
+ {id:"trade", icon:"đ",name:"Welthandels-Profi",desc:"Ăber 2000 Punkte gesammelt."},
{id:"explorer",icon:"đ",name:"Kontinent-Hopper",desc:"5 Gerichte abgeschlossen."},
{id:"star", icon:"â",name:"Sterne-Koch", desc:"Alle Gerichte abgeschlossen."},
];
@@ -703,7 +712,7 @@ function buildTutorialSteps() {
+ 'Manche Länder produzieren viel, sind bei uns aber nicht im Regal â etwa weil sie alles selbst verbrauchen oder weil der Transport zu lang ist.' },
{ img: imgBase + 'punkte.webp',
title: 'Punkte & Abzeichen',
- html: 'Jedes richtig zugeordnete Land bringt Punkte. Doppel-Treffer (zweites Herkunftsland) zählen extra.
'
+ html: 'Jedes richtige Herkunftsland bringt Punkte â und je frĂźher du es findest, desto mehr. Jeder Fehlversuch senkt die erreichbaren Punkte.
'
+ 'Es gibt 10 Abzeichen zum Sammeln â z. B. Volltreffer-Koch (Gericht ohne Fehler), Geografie-Genie (erkennen, dass ein Binnenland kein Meer hat) oder Sterne-Koch (alle 30 Gerichte).' },
{ img: imgBase + 'klima.webp',
title: 'Klimabilanz im Blick',
@@ -1154,7 +1163,7 @@ function buildTaskFor(ingKey) {
// 2-4 Distraktoren: 1-2 aus climate_possible (fĂźr didaktisches Feedback),
// Rest aus klar-unmĂśglichen
- const distrCount = 2 + Math.floor(Math.random() * 3); // 2 bis 4
+ const distrCount = 3; // NORM: immer 3 Distraktoren â 5 Karten (2 richtig + 3 falsch), faire & vergleichbare Punkte
const possiblePool = climatePossible.filter(c => !correct.includes(c));
const possiblePicks = [...possiblePool];
shuffleInPlace(possiblePicks);
@@ -1247,18 +1256,16 @@ function loadIngredient(){
// deterministisch: Heimat-Regel bzw. echte Hauptlieferanten nach Menge.
delete _taskCache[ingKey];
const task = buildTaskFor(ingKey);
- current.found=[]; current.wrongHere=0; current.wrongStreak=0; current.attempted=new Set();
+ current.found=[]; current.wrongHere=0; current.wrongStreak=0; current.attempted=new Set(); current.ingPts=0;
const two = task && task.correct.length > 1;
const frage = two
? 'finde die zwei Herkunftsländer aus dieser Auswahl'
: (task && task.signature
? 'aus welchem Land stammt diese Zutat in diesem Gericht?'
: 'aus welchem Land kommt diese Zutat häufig zu uns auf den Markt?');
- const _nd = Math.max(1, task ? (task.choices.length - task.correct.length) : 4);
- const _per = Math.round(100 / _nd);
document.getElementById('taskBanner').innerHTML=
`đ Suche: ${ing.nm} â ${frage}`
- + ` ¡ richtig +100, jeder Fehlklick â${_per} (alle falsch zuerst = 0)`;
+ + ` ¡ je frĂźher du richtig liegst, desto mehr Punkte â Fehlversuche senken sie`;
document.getElementById('resultCard').className="result-card";
drawMarkers(ing); renderIngList();
}
@@ -1284,6 +1291,15 @@ function drawMarkers(ing){
}
function btnFor(key){const m=current.markers[key];return(m&&m.getElement())?m.getElement().querySelector('.country-btn'):null;}
+// Kurzes schwebendes Punkte-Feedback (Live) bei jedem Klick.
+function wkFloat(txt, kind){
+ const el=document.createElement('div');
+ el.className='wk-float '+(kind==='neg'?'neg':'pos');
+ el.textContent=txt;
+ document.body.appendChild(el);
+ setTimeout(()=>{ el.remove(); }, 1400);
+}
+
function guess(key){
const b=btnFor(key); if(!b||b.disabled) return;
const ingKey = current.dish.ings[current.idx];
@@ -1294,23 +1310,25 @@ function guess(key){
if (current.attempted) current.attempted.add(key);
playSfx('click-country');
if (cls === 'correct') {
+ if (current.found.includes(key)) return; // schon gefunden â nicht doppelt zählen
b.classList.add('correct');
- // Strafe pro Fehlklick so, dass âalle Falschen zuerst" IMMER 0 ergibt:
- // 100 á Anzahl Distraktoren. Bei 4 Distraktoren = â25 (Âź), bei 2 = â50.
- const numDistr = Math.max(1, task ? (task.choices.length - task.correct.length) : 4);
- const pts = Math.max(0, Math.round(100 - (100 / numDistr) * (current.wrongHere || 0)));
- state.score+=pts; current.dishScore+=pts;
+ // Punkte pro richtigem Klick = 25 Ă noch verbleibende FALSCHE Optionen.
+ // Je frĂźher gefunden, desto mehr; jeder Fehlklick vorher senkt den Wert.
+ // Bei 3 Distraktoren: max 2Ă75 = 150 pro Zutat; âalle falsch zuerst" = 0.
+ const totalWrong = task ? (task.choices.length - task.correct.length) : 3;
+ const pts = 25 * Math.max(0, totalWrong - (current.wrongHere || 0));
+ state.score+=pts; current.dishScore+=pts; current.ingPts+=pts;
+ wkFloat('+' + pts, 'pos');
state.totalCorrect++; current.wrongStreak=0; current.found.push(key);
map.flyTo([c.lat,c.lng],3,{duration:.7});
const targetCount = task.correct.length;
if(current.found.length >= targetCount){
- let bonus=0;
- if(targetCount > 1){ bonus=50; state.score+=bonus; current.dishScore+=bonus; awardLive(['pair']); }
+ if(targetCount > 1){ awardLive(['pair']); } // Doppel-Treffer-Abzeichen (kein Extra-Punkt: 150 = 75+75)
if(current.wrongHere===0) state.cleanIngredients++;
current.solved.push(current.idx);
Object.keys(current.markers).forEach(k=>{const x=btnFor(k);if(x)x.disabled=true;});
checkLiveBadges(ing,key);
- showSolved(ing,pts,bonus);
+ showSolved(ing,current.ingPts,0);
// Sound nach dem korrekten Render-Frame, damit click-country abgeklungen ist
setTimeout(()=>playSfx('ingredient-solved'), 120);
} else {
@@ -1323,6 +1341,7 @@ function guess(key){
} else {
b.classList.add('wrong'); b.disabled=true;
current.wrongStreak++; current.wrongHere++; current.mistakesInDish++; state.totalWrong++;
+ wkFloat('Fehlversuch â erreichbare Punkte sinken', 'neg');
showWrong(key, cls, ingKey);
setTimeout(()=>playSfx('ingredient-wrong'), 120);
}
@@ -1503,7 +1522,7 @@ function showInterim(ing,key,pts,remaining){
card.innerHTML=`