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:
@@ -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 (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)
|
||||
* ==========================================================================*/
|
||||
(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 (0–100) → 0–5 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);
|
||||
@@ -57,6 +57,13 @@
|
||||
.badge .desc{font-size:.6rem;color:#8a8a8a}
|
||||
.badge.earned{border-color:#4a7c8a;background:linear-gradient(135deg,#f0f8fa,#fff)}
|
||||
.badge.locked-b{opacity:.4}
|
||||
.badge .desc{min-height:1.6em}
|
||||
.sim-coll{margin-bottom:1.1rem}
|
||||
.sim-coll-head{display:flex;align-items:center;gap:.5rem;margin:.5rem 0 .45rem;font-weight:700;font-size:.82rem}
|
||||
.sim-coll-head .sc-ic{font-size:1.3rem}
|
||||
.sim-coll-head .sc-t{flex:1}
|
||||
.sim-coll-head .sc-stars{color:#e0a838;letter-spacing:1px;font-size:.82rem}
|
||||
.sim-coll-head .sc-count{font-size:.68rem;color:#8a8a8a;background:#f0eeea;border-radius:99px;padding:.12rem .55rem;font-weight:700}
|
||||
/* Erfolgs-Liste pro Modul */
|
||||
.ach-summary{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem;margin-bottom:1.2rem}
|
||||
.ach-summary .card{background:#fff;border-radius:10px;padding:.9rem .8rem;text-align:center;border:1.5px solid rgba(0,0,0,.05)}
|
||||
@@ -87,6 +94,7 @@
|
||||
.hidden{display:none}
|
||||
@media(max-width:550px){.mod-grid{grid-template-columns:1fr}.badge-grid{grid-template-columns:repeat(2,1fr)}}
|
||||
</style>
|
||||
<script src="assets/js/badges.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="topbar">
|
||||
@@ -363,6 +371,33 @@ async function renderAchievements() {
|
||||
html += '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
// === Abzeichen-Sammlung pro Simulation (gesperrte = sichtbare Ziele) ===
|
||||
if (typeof GGS_SIMS !== 'undefined') {
|
||||
var progBySim = {};
|
||||
allProgress.forEach(function(p){ progBySim[p.sim_id] = p; });
|
||||
html += '<p style="font-size:.85rem;font-weight:700;color:#4a7c8a;margin:1.3rem 0 .3rem">Abzeichen-Sammlung</p>';
|
||||
html += '<p style="font-size:.68rem;color:#8a8a8a;margin:0 0 .7rem">Jede Simulation hat fünf Abzeichen. Blasse sind noch nicht geschafft — das sind deine Ziele.</p>';
|
||||
GGS_SIMS.forEach(function(sim){
|
||||
var p = progBySim[sim.id] || {plays:0, best_stars:0, level:1};
|
||||
var got = ggsBadgeCount(p);
|
||||
var st = (p.best_stars||0);
|
||||
var stars = '★'.repeat(st) + '☆'.repeat(Math.max(0, 5-st));
|
||||
html += '<div class="sim-coll"><div class="sim-coll-head">'
|
||||
+ '<span class="sc-ic">'+sim.icon+'</span><span class="sc-t">'+sim.title+'</span>'
|
||||
+ '<span class="sc-stars" title="Beste Sterne">'+stars+'</span>'
|
||||
+ '<span class="sc-count">'+got+' / '+GGS_BADGES.length+'</span></div>';
|
||||
html += '<div class="badge-grid">';
|
||||
GGS_BADGES.forEach(function(b){
|
||||
var e = b.cond(p);
|
||||
html += '<div class="badge '+(e?'earned':'locked-b')+'" title="'+(e?'Geschafft!':'Ziel: '+b.desc)+'">'
|
||||
+ '<div class="icon">'+b.icon+'</div><div class="name">'+b.name+'</div>'
|
||||
+ '<div class="desc">'+b.desc+'</div></div>';
|
||||
});
|
||||
html += '</div></div>';
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('tab-achievements').innerHTML = html;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user