diff --git a/App/assets/img/badges/bg-ausdauer.webp b/App/assets/img/badges/bg-ausdauer.webp new file mode 100644 index 0000000..7a62b64 Binary files /dev/null and b/App/assets/img/badges/bg-ausdauer.webp differ diff --git a/App/assets/img/badges/bg-einstieg.webp b/App/assets/img/badges/bg-einstieg.webp new file mode 100644 index 0000000..06f3b6f Binary files /dev/null and b/App/assets/img/badges/bg-einstieg.webp differ diff --git a/App/assets/img/badges/bg-fortgeschritten.webp b/App/assets/img/badges/bg-fortgeschritten.webp new file mode 100644 index 0000000..b9dd867 Binary files /dev/null and b/App/assets/img/badges/bg-fortgeschritten.webp differ diff --git a/App/assets/img/badges/bg-koenner.webp b/App/assets/img/badges/bg-koenner.webp new file mode 100644 index 0000000..49c9c31 Binary files /dev/null and b/App/assets/img/badges/bg-koenner.webp differ diff --git a/App/assets/img/badges/bg-meister.webp b/App/assets/img/badges/bg-meister.webp new file mode 100644 index 0000000..3874898 Binary files /dev/null and b/App/assets/img/badges/bg-meister.webp differ diff --git a/App/assets/img/badges/th-busfahrt.webp b/App/assets/img/badges/th-busfahrt.webp new file mode 100644 index 0000000..d409f9a Binary files /dev/null and b/App/assets/img/badges/th-busfahrt.webp differ diff --git a/App/assets/img/badges/th-energiemanager.webp b/App/assets/img/badges/th-energiemanager.webp new file mode 100644 index 0000000..83af315 Binary files /dev/null and b/App/assets/img/badges/th-energiemanager.webp differ diff --git a/App/assets/img/badges/th-eu-werkstatt.webp b/App/assets/img/badges/th-eu-werkstatt.webp new file mode 100644 index 0000000..6d4770e Binary files /dev/null and b/App/assets/img/badges/th-eu-werkstatt.webp differ diff --git a/App/assets/img/badges/th-farmer.webp b/App/assets/img/badges/th-farmer.webp new file mode 100644 index 0000000..c68ad4d Binary files /dev/null and b/App/assets/img/badges/th-farmer.webp differ diff --git a/App/assets/img/badges/th-fluss.webp b/App/assets/img/badges/th-fluss.webp new file mode 100644 index 0000000..9bb1533 Binary files /dev/null and b/App/assets/img/badges/th-fluss.webp differ diff --git a/App/assets/img/badges/th-heli.webp b/App/assets/img/badges/th-heli.webp new file mode 100644 index 0000000..df3e22d Binary files /dev/null and b/App/assets/img/badges/th-heli.webp differ diff --git a/App/assets/img/badges/th-klima-3d.webp b/App/assets/img/badges/th-klima-3d.webp new file mode 100644 index 0000000..a5a2e9f Binary files /dev/null and b/App/assets/img/badges/th-klima-3d.webp differ diff --git a/App/assets/img/badges/th-klima.webp b/App/assets/img/badges/th-klima.webp new file mode 100644 index 0000000..61e2a6f Binary files /dev/null and b/App/assets/img/badges/th-klima.webp differ diff --git a/App/assets/img/badges/th-kofferdetektiv.webp b/App/assets/img/badges/th-kofferdetektiv.webp new file mode 100644 index 0000000..293317c Binary files /dev/null and b/App/assets/img/badges/th-kofferdetektiv.webp differ diff --git a/App/assets/img/badges/th-logistik.webp b/App/assets/img/badges/th-logistik.webp new file mode 100644 index 0000000..a152664 Binary files /dev/null and b/App/assets/img/badges/th-logistik.webp differ diff --git a/App/assets/img/badges/th-sonnensystem.webp b/App/assets/img/badges/th-sonnensystem.webp new file mode 100644 index 0000000..67f180b Binary files /dev/null and b/App/assets/img/badges/th-sonnensystem.webp differ diff --git a/App/assets/img/badges/th-tourismusregion.webp b/App/assets/img/badges/th-tourismusregion.webp new file mode 100644 index 0000000..c18afa4 Binary files /dev/null and b/App/assets/img/badges/th-tourismusregion.webp differ diff --git a/App/assets/img/badges/th-tourismustal.webp b/App/assets/img/badges/th-tourismustal.webp new file mode 100644 index 0000000..005477b Binary files /dev/null and b/App/assets/img/badges/th-tourismustal.webp differ diff --git a/App/assets/img/badges/th-weltkueche.webp b/App/assets/img/badges/th-weltkueche.webp new file mode 100644 index 0000000..6c3fed6 Binary files /dev/null and b/App/assets/img/badges/th-weltkueche.webp differ diff --git a/App/assets/js/badges.js b/App/assets/js/badges.js index 411f57e..eb17c26 100644 --- a/App/assets/js/badges.js +++ b/App/assets/js/badges.js @@ -1,44 +1,63 @@ /* ============================================================================ * GeoGraSim — gemeinsame Abzeichen-Bibliothek * ---------------------------------------------------------------------------- - * Ein einheitliches Set von 5 Abzeichen pro Simulation, dessen Freischalt- - * Bedingungen sich aus den ALLGEMEINEN Leistungsdaten (plays, best_stars, - * level) berechnen. Dadurch gelten die Abzeichen SOFORT für JEDE Sim — auch - * für die ohne eigenen Achievement-Code — und sind über alle Sims vergleichbar. + * Zwei Ebenen, für alle Sims einheitlich strukturiert: + * 1) BASIS — 5 Abzeichen, in jeder Sim identisch, Bedingung aus allgemeinen + * Leistungsdaten (plays / best_stars / level) → gelten sofort für JEDE Sim. + * 2) THEMATISCH — je Sim ein eigenes, thematisch benanntes Abzeichen. * - * Abzeichen sind bewusst auch im GESPERRTEN Zustand sichtbar (Zielvorstellung), - * die Beschreibung ist zugleich das Ziel. Sterne laufen parallel (Qualität pro - * Durchlauf); ggsErfolgToStars() bildet den normierten Erfolg (0–100) auf - * 0–5 Sterne ab. + * Icons sind sauber generierte Emblems (Flat-Scandinavian, keine Emojis) unter + * assets/img/badges/. Gesperrte Abzeichen bleiben sichtbar (Zielvorstellung), + * die Beschreibung ist das Ziel. Sterne laufen parallel; ggsErfolgToStars() + * bildet den normierten Erfolg (0–100) auf 0–5 Sterne ab. * - * Verwendung (Client): - * GGS_BADGES.forEach(b => { var earned = b.cond(progressObj); ... }); - * progressObj = { plays, best_stars, level } (pro Sim) + * progressObj (pro Sim): { plays, best_stars, level } * ==========================================================================*/ (function (root) { 'use strict'; + var IMG = 'assets/img/badges/'; - // Fünf Abzeichen-Typen, für alle Sims identisch. cond(p) wird pro Sim geprüft. + // 1) BASIS — 5 Abzeichen, überall gleich. var GGS_BADGES = [ - { id: 'einstieg', icon: '🌱', name: 'Einstieg', - desc: 'Ersten Durchlauf geschafft', - cond: function (p) { return (p && p.plays || 0) >= 1; } }, - { id: 'fortgeschritten', icon: '📈', name: 'Fortgeschritten', - desc: 'Level 2 erreicht', - cond: function (p) { return (p && p.level || 1) >= 2; } }, - { id: 'koenner', icon: '⭐', name: 'Könner', - desc: 'Vier Sterne geschafft', - cond: function (p) { return (p && p.best_stars || 0) >= 4; } }, - { id: 'meister', icon: '🏆', name: 'Meister', - desc: 'Fünf Sterne — Bestleistung', - cond: function (p) { return (p && p.best_stars || 0) >= 5; } }, - { id: 'ausdauer', icon: '🔥', name: 'Ausdauer', - desc: 'Acht Durchläufe', - cond: function (p) { return (p && p.plays || 0) >= 8; } } + { id: 'einstieg', icon: IMG + 'bg-einstieg.webp', name: 'Einstieg', + desc: 'Ersten Durchlauf geschafft', cond: function (p) { return (p && p.plays || 0) >= 1; } }, + { id: 'fortgeschritten', icon: IMG + 'bg-fortgeschritten.webp', name: 'Fortgeschritten', + desc: 'Level 2 erreicht', cond: function (p) { return (p && p.level || 1) >= 2; } }, + { id: 'koenner', icon: IMG + 'bg-koenner.webp', name: 'Könner', + desc: 'Vier Sterne geschafft', cond: function (p) { return (p && p.best_stars || 0) >= 4; } }, + { id: 'meister', icon: IMG + 'bg-meister.webp', name: 'Meister', + desc: 'Fünf Sterne — Bestleistung', cond: function (p) { return (p && p.best_stars || 0) >= 5; } }, + { id: 'ausdauer', icon: IMG + 'bg-ausdauer.webp', name: 'Ausdauer', + desc: 'Acht Durchläufe', cond: function (p) { return (p && p.plays || 0) >= 8; } } ]; + // Bedingungs-Bausteine für thematische Abzeichen + function lvl3(p) { return (p && p.level || 1) >= 3; } + function star5(p) { return (p && p.best_stars || 0) >= 5; } + function played6(p) { return (p && p.plays || 0) >= 6; } + function b(sim, name, desc, cond) { + return { id: 'th-' + sim, icon: IMG + 'th-' + sim + '.webp', name: name, desc: desc, cond: cond, thematic: true }; + } + + // 2) THEMATISCH — je Sim ein eigenes Abzeichen (Name/Icon sim-spezifisch). + var GGS_SIM_BADGES = { + 'tourismustal': b('tourismustal', 'Vier-Jahreszeiten', 'Level 3 im Tourismustal', lvl3), + 'tourismusregion': b('tourismusregion', 'Regionen-Meister', 'Fünf Sterne in der Region', star5), + 'kofferdetektiv': b('kofferdetektiv', 'Welt-Detektiv', 'Sechs Fälle gelöst', played6), + 'busfahrt': b('busfahrt', 'Europa-Kenner', 'Fünf Sterne auf der Tour', star5), + 'logistik': b('logistik', 'Lieferketten-Profi','Level 3 in der Logistik', lvl3), + 'weltkueche': b('weltkueche', 'Sterne-Koch', 'Fünf Sterne in der Weltküche', star5), + 'farmer': b('farmer', 'Ernte-Meister', 'Sechs Ernten eingefahren', played6), + 'klima': b('klima', '1,5-Grad-Held', 'Fünf Sterne im Klimaschutz', star5), + 'klima-3d': b('klima-3d', 'Küstenwächter', 'Level 3 im Küstenschutz', lvl3), + 'fluss': b('fluss', 'Renaturierer', 'Fünf Sterne am Fluss', star5), + 'energiemanager': b('energiemanager', 'Grundlast-Profi', 'Level 3 im Energienetz', lvl3), + 'heli': b('heli', 'Alpen-Pilot', 'Sechs Einsätze geflogen', played6), + 'sonnensystem': b('sonnensystem', 'Astronom', 'Fünf Sterne am Himmel', star5), + 'eu-werkstatt': b('eu-werkstatt', 'Gesetzgeber:in', 'Level 3 in der EU-Werkstatt', lvl3) + }; + // Spielbare Simulationen (aktiv/beta) — Reihenfolge wie im Schulbuch. - // Auch ungespielte erscheinen in der Sammlung: alle 5 Abzeichen gesperrt = Ziel. var GGS_SIMS = [ { id: 'tourismustal', title: 'Tourismustal', icon: '🏔️' }, { id: 'tourismusregion', title: 'Tourismusregion', icon: '🗺️' }, @@ -56,21 +75,26 @@ { id: 'eu-werkstatt', title: 'EU-Werkstatt', icon: '🏛️' } ]; - // Normierter Erfolg (0–100) → 0–5 Sterne. Ein Rechenweg für alle Sims. + // Alle Abzeichen einer Sim = 5 Basis + (falls vorhanden) 1 thematisches. + function ggsSimBadges(simId) { + var out = GGS_BADGES.slice(); + if (GGS_SIM_BADGES[simId]) out.push(GGS_SIM_BADGES[simId]); + return out; + } + function ggsBadgeCount(p, simId) { + var list = simId ? ggsSimBadges(simId) : GGS_BADGES, n = 0; + for (var i = 0; i < list.length; i++) if (list[i].cond(p)) n++; + return n; + } function ggsErfolgToStars(pct) { if (pct == null || isNaN(pct)) return 0; return Math.max(0, Math.min(5, Math.round(pct / 20))); } - // Wie viele der 5 Abzeichen sind für ein Progress-Objekt freigeschaltet? - function ggsBadgeCount(p) { - var n = 0; - for (var i = 0; i < GGS_BADGES.length; i++) if (GGS_BADGES[i].cond(p)) n++; - return n; - } - - root.GGS_BADGES = GGS_BADGES; - root.GGS_SIMS = GGS_SIMS; - root.ggsErfolgToStars = ggsErfolgToStars; - root.ggsBadgeCount = ggsBadgeCount; + root.GGS_BADGES = GGS_BADGES; + root.GGS_SIM_BADGES = GGS_SIM_BADGES; + root.GGS_SIMS = GGS_SIMS; + root.ggsSimBadges = ggsSimBadges; + root.ggsBadgeCount = ggsBadgeCount; + root.ggsErfolgToStars = ggsErfolgToStars; })(typeof window !== 'undefined' ? window : this); diff --git a/App/schueler.html b/App/schueler.html index ca5d7da..e377bc0 100644 --- a/App/schueler.html +++ b/App/schueler.html @@ -53,6 +53,8 @@ .badge-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:.6rem} .badge{background:#fff;border-radius:10px;padding:.8rem;text-align:center;border:1.5px solid rgba(0,0,0,.04)} .badge .icon{font-size:2rem;margin-bottom:.3rem} + .badge .icon img{width:48px;height:48px;object-fit:contain;display:block;margin:0 auto} + .badge.locked-b .icon img{filter:grayscale(.9)} .badge .name{font-size:.72rem;font-weight:700} .badge .desc{font-size:.6rem;color:#8a8a8a} .badge.earned{border-color:#4a7c8a;background:linear-gradient(135deg,#f0f8fa,#fff)} @@ -359,19 +361,6 @@ async function renderAchievements() { html += ''; } - // Auszeichnungen / Badges - html += '

Auszeichnungen

'; - html += '
'; - BADGES.forEach(function(b) { - var isEarned = earned.indexOf(b.id) !== -1; - html += '
'; - html += '
'+b.icon+'
'; - html += '
'+b.name+'
'; - html += '
'+b.desc+'
'; - html += '
'; - }); - html += '
'; - // === Abzeichen-Sammlung pro Simulation (gesperrte = sichtbare Ziele) === if (typeof GGS_SIMS !== 'undefined') { var progBySim = {}; @@ -380,18 +369,20 @@ async function renderAchievements() { html += '

Jede Simulation hat fünf Abzeichen. Blasse sind noch nicht geschafft — das sind deine Ziele.

'; GGS_SIMS.forEach(function(sim){ var p = progBySim[sim.id] || {plays:0, best_stars:0, level:1}; - var got = ggsBadgeCount(p); + var list = ggsSimBadges(sim.id); + var got = ggsBadgeCount(p, sim.id); var st = (p.best_stars||0); var stars = '★'.repeat(st) + '☆'.repeat(Math.max(0, 5-st)); html += '
' + ''+sim.icon+''+sim.title+'' + ''+stars+'' - + ''+got+' / '+GGS_BADGES.length+'
'; + + ''+got+' / '+list.length+'
'; html += '
'; - GGS_BADGES.forEach(function(b){ + list.forEach(function(b){ var e = b.cond(p); - html += '
' - + '
'+b.icon+'
'+b.name+'
' + html += '
' + + '
' + + '
'+b.name+'
' + '
'+b.desc+'
'; }); html += '
'; diff --git a/App/teacher.html b/App/teacher.html index 7a53bba..a003f43 100644 --- a/App/teacher.html +++ b/App/teacher.html @@ -412,6 +412,7 @@ schueler01,Max M.,,,,, +