Abzeichen: gemeinsame Bibliothek + Sammlung im Erfolge-Tab

Neue badges.js: 5 einheitliche Abzeichen pro Sim (Einstieg/Fortgeschritten/
Könner/Meister/Ausdauer), Bedingungen aus allgemeinen Leistungsdaten (plays/
best_stars/level) → gelten sofort für ALLE Sims. Gesperrte Abzeichen sichtbar
als Ziele. ggsErfolgToStars() für Sterne aus normiertem Erfolg. Erfolge-Tab in
schueler.html zeigt die Sammlung pro Simulation (auch ungespielte = Ziele).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 14:24:55 +02:00
parent 3d1b8e49a3
commit 65ca8692cb
2 changed files with 111 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
/* ============================================================================
* 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.
*
* 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 (0100) auf
* 05 Sterne ab.
*
* Verwendung (Client):
* GGS_BADGES.forEach(b => { var earned = b.cond(progressObj); ... });
* progressObj = { plays, best_stars, level } (pro Sim)
* ==========================================================================*/
(function (root) {
'use strict';
// Fünf Abzeichen-Typen, für alle Sims identisch. cond(p) wird pro Sim geprüft.
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; } }
];
// 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: '🗺️' },
{ id: 'kofferdetektiv', title: 'Kofferdetektiv', icon: '🧳' },
{ id: 'busfahrt', title: 'Busfahrt', icon: '🚌' },
{ id: 'logistik', title: 'Logistik Europa', icon: '🚚' },
{ id: 'weltkueche', title: 'Weltküche', icon: '🍽️' },
{ id: 'farmer', title: 'Landwirtschaft', icon: '🌾' },
{ id: 'klima', title: 'Klimawächter', icon: '🌍' },
{ id: 'klima-3d', title: 'Klimawächter 3D', icon: '🌊' },
{ id: 'fluss', title: 'Flussmanagement', icon: '🏞️' },
{ id: 'energiemanager', title: 'Energiemanager', icon: '⚡' },
{ id: 'heli', title: 'Heli-Navigation', icon: '🚁' },
{ id: 'sonnensystem', title: 'Sonnensystem', icon: '🪐' },
{ id: 'eu-werkstatt', title: 'EU-Werkstatt', icon: '🏛️' }
];
// Normierter Erfolg (0100) → 05 Sterne. Ein Rechenweg für alle Sims.
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;
})(typeof window !== 'undefined' ? window : this);