"""
return kopf + inhalt + fuss
@app.route("/")
def start():
# Fortschritt für einen frischen Durchlauf zurücksetzen
for key in [k for k in list(session.keys())
if k.startswith("raum_") or k.startswith("chal_")
or k.startswith("fs40")]:
session.pop(key, None)
inhalt = """
LEGO • Geheimmission
Einbruch im Octan-Tower 🧱
Präsident Business hortet ganz oben in seinem Wolkenkratzer
das Kragle – und will damit die ganze Welt für immer festkleben.
Nur du kannst ihn stoppen! Kämpf dich Etage für Etage nach oben: vorbei an
Haien 🦈, Lasern 🔴 und – natürlich –
Laserhaien 🦈⚡.
Jede Etage ist ein Gang, der sich gabelt. Lies die
Hinweise genau! Der sichere Prüf-Weg stellt dir ein paar
thematische Fragen und führt gemütlich eine Etage höher. Der andere Weg ist eine
riskante Abkürzung: Dort wartet jemand mit einem Deal – schaffst
du seine Fragen gegen die Uhr, springst du weit nach oben. Ein
Fehler oder zu langsam? Mission vorbei. Ganz oben wartet die
letzte Frage zu Präsident Business.
"""
return adventure_seite(inhalt)
@app.route("/frage")
def frage():
return redirect("/app/")
# ─── Adventure-Helfer: Sieg / Game Over / Challenge ──────────────────────────
def _clear_challenge(rid):
"""Timer- und Fortschritts-Keys einer Challenge aus der Session entfernen."""
session.pop("chal_%d_deadline" % rid, None)
session.pop("chal_%d_idx" % rid, None)
session.modified = True
def sieg_screen(text=None):
body = text or ("Du hast Präsident Business gestoppt und das Kragle gesichert. "
"Die Welt bleibt frei – und kreativ!")
inhalt = ("""
""" % esc(grund))
return adventure_seite(inhalt, akzent="#f87171")
def challenge_raum(db, r):
"""Risk/Reward-Abkürzung mit Zeitlimit (Biologe, Elektriker, Cyborgs)."""
rid = r["id"]
limit = int(r["zeit_limit"] or 40)
ziel = int(r["ziel_anzahl"] or 10)
erfolg_raum = r["erfolg_raum"] or 0
erfolg_text = r["erfolg_text"] or ""
dl_key = "chal_%d_deadline" % rid
idx_key = "chal_%d_idx" % rid
fragen = db.execute(
"SELECT * FROM fragen WHERE raum_id=? ORDER BY id", (rid,)
).fetchall()
back = db.execute(
"SELECT nach_raum FROM ausgaenge WHERE von_raum=? ORDER BY rowid LIMIT 1",
(rid,)
).fetchone()
db.close()
back_raum = back["nach_raum"] if back else 1
gesamt = min(ziel, len(fragen)) if fragen else ziel
now = time.time()
# ── Noch nicht gestartet → Intro (die Entscheidung: Risk vs. Reward) ──
if dl_key not in session:
if request.args.get("start") == "1" and fragen:
session[dl_key] = now + limit
session[idx_key] = 0
session.modified = True
return redirect("/app/raum/%d" % rid)
reward = ("🏆 Bei Erfolg: sofort gewonnen!" if not erfolg_raum
else "🏆 Bei Erfolg: Express ganz nach oben")
inhalt = ("""
⚠️ Risiko-Abkürzung · Etage %d
%s
%s
🎯 %d Fragen richtig⏱️ %d Sekunden%s💀 Ein Fehler = Aus
""" % (esc(erfolg_text), erfolg_raum))
return adventure_seite(inhalt)
return sieg_screen(erfolg_text)
return redirect("/app/raum/%d" % rid)
# falsche Antwort → sofortiges Game Over
_clear_challenge(rid)
return gameover_screen(
"❌ Falsch! Dein Gegenüber durchschaut dich sofort und schlägt Alarm. "
"So knapp – aber der riskante Weg verzeiht keinen einzigen Fehler.")
# GET → aktuelle Frage mit Countdown zeigen
if idx >= len(fragen):
_clear_challenge(rid)
return sieg_screen(erfolg_text)
aktuelle = fragen[idx]
remaining = deadline - now
buttons = ""
for opt in aktuelle["optionen"].split("|"):
buttons += (''
% (esc(opt), esc(opt)))
tpl = """
⏱️ Risiko-Challenge · __NAME__
__NAME__
__REMAIN__ s
Frage __NR__ von __GES__ · schon richtig: __IDX__
__FRAGE__
"""
html = (tpl
.replace("__NAME__", esc(r["name"]))
.replace("__REMAINMS__", str(int(max(0.0, remaining) * 1000)))
.replace("__REMAIN__", "%.1f" % max(0.0, remaining))
.replace("__LIMIT__", str(limit))
.replace("__NR__", str(idx + 1))
.replace("__GES__", str(gesamt))
.replace("__IDX__", str(idx))
.replace("__FRAGE__", esc(aktuelle["frage"]))
.replace("__BTN__", buttons)
.replace("__ID__", str(rid)))
return adventure_seite(html, akzent="#f87171")
# ─── Polizei-Führerschein-Kontrolle vor dem Lord-Business-Finale (U18) ────────
# Die drei Aufgaben stammen aus der deutschen Führerschein-Theorieprüfung.
# "richtig" = Menge der (1-basierten) anzukreuzenden Optionen. Mehrfachauswahl!
FS_FRAGEN = [
{
"frage": "Welches Verhalten ist richtig?",
"bild": "/fs_frage1.png",
"optionen": ["erst nach dem Bus abbiegen",
"vor dem Motorrad abbiegen",
"als Erster abbiegen"],
"richtig": {3},
},
{
"frage": "Wann kann es hier zu einer gefährlichen Situation kommen?",
"bild": "/fs_frage2.png",
"optionen": ["Wenn der Radfahrer am Ende des Radweges anhält",
"Wenn ich unvermindert weiterfahre",
"Wenn der Radfahrer auf meine Fahrbahn wechselt"],
"richtig": {2, 3},
},
{
"frage": "Warum ist man nach dem Konsum der Droge „Crystal Meth“ fahruntauglich?",
"bild": None,
"optionen": ["Weil plötzliche Erschöpfung eintreten kann",
"Weil Wahnvorstellungen auftreten können",
"Weil die eigene Leistungsfähigkeit überschätzt werden kann"],
"richtig": {1, 2, 3},
},
]
FS_IDX_KEY = "fs40_idx"
FS_DONE_KEY = "fs40_done"
def _blaulicht_intro():
"""Grelles deutsches Blaulicht + Polizei-Ansage vor der Kontrolle."""
inhalt = """
🚨
🚔 POLIZEI · VERKEHRSKONTROLLE
Anhalten – Fahrzeugkontrolle!
Kurz vor dem Kragle-Tresor stoppt dich eine Streife.
Die Beamten mustern deinen Führerschein misstrauisch:
„Diesen Lappen haben Sie doch nie im Leben ehrlich bestanden!
Wenn er echt ist, beweisen Sie es: Lösen Sie diese drei Aufgaben
aus der Theorieprüfung – dann dürfen Sie weiter.“
🚦 Achtung: Bei manchen Fragen ist
mehr als eine Antwort richtig. Kreuze alle
zutreffenden an – ein falsches Kreuz und du fällst durch.
Mehrfachauswahl möglich – kreuze alle richtigen Antworten an.
"""
html = (inhalt
.replace("__NR__", str(idx + 1))
.replace("__GES__", str(len(FS_FRAGEN)))
.replace("__FB__", fb)
.replace("__FRAGE__", esc(f["frage"]))
.replace("__BILD__", bild_html)
.replace("__CHECKS__", checks))
return adventure_seite(html, akzent="#6b8e23")
def fuehrerschein_kontrolle():
"""Steuert die dreiteilige Polizei-Führerschein-Kontrolle vor dem Finale."""
# Noch nicht gestartet → Blaulicht-Intro (oder Start per ?fs=1)
if FS_IDX_KEY not in session:
if request.args.get("fs") == "1":
session[FS_IDX_KEY] = 0
session.modified = True
return redirect("/app/raum/40")
return _blaulicht_intro()
idx = session.get(FS_IDX_KEY, 0)
feedback = ""
if request.method == "POST" and idx < len(FS_FRAGEN):
gewaehlt = set()
for i in range(1, len(FS_FRAGEN[idx]["optionen"]) + 1):
if request.form.get("opt%d" % i):
gewaehlt.add(i)
if gewaehlt == FS_FRAGEN[idx]["richtig"]:
idx += 1
session[FS_IDX_KEY] = idx
session.modified = True
elif not gewaehlt:
feedback = ("🚨 Kein Kreuz gesetzt! „So kommen Sie hier nicht durch.“ "
"Kreuze alle richtigen Antworten an.")
else:
feedback = ("🚨 Durchgefallen bei dieser Aufgabe! Die Beamten schütteln "
"den Kopf: „Nochmal – und diesmal richtig.“")
if idx >= len(FS_FRAGEN):
session[FS_DONE_KEY] = True
session.modified = True
return redirect("/app/raum/40")
return _fs_frage_screen(idx, feedback)
@app.route("/raum/", methods=["GET", "POST"])
def raum(id):
db = get_db()
r = db.execute("SELECT * FROM raeume WHERE id=?", (id,)).fetchone()
if r is None:
db.close()
return adventure_seite(
'
')
typ = r["typ"]
# ═══ Risk/Reward-Abkürzung mit Timer (Biologe / Elektriker / Cyborgs) ═══
if typ == "challenge":
return challenge_raum(db, r)
# ═══ Räume mit Fragen: thema (Prüf-Weg) · ziel (Finale) ═══
if typ in ("thema", "ziel"):
# ── Polizei-Führerschein-Kontrolle vor dem Lord-Business-Finale ──
if typ == "ziel" and id == 40 and not session.get(FS_DONE_KEY):
db.close()
return fuehrerschein_kontrolle()
fragen = db.execute(
"SELECT * FROM fragen WHERE raum_id=? ORDER BY id", (id,)
).fetchall()
prog_key = "raum_%d_idx" % id
idx = session.get(prog_key, 0)
# ── Noch offene Fragen → nächste Frage zeigen ──
if fragen and idx < len(fragen):
aktuelle = fragen[idx]
feedback = ""
if request.method == "POST":
gewaehlt = request.form.get("antwort", "").strip()
if gewaehlt.lower() == aktuelle["antwort"].strip().lower():
session[prog_key] = idx + 1
session.modified = True
db.close()
return redirect("/app/raum/%d" % id)
feedback = ('
🚨 Alarm! Falsche Antwort – '
'die Wächter werden fast auf dich aufmerksam. Nochmal!
')
optionen = aktuelle["optionen"].split("|")
db.close()
buttons = ""
for opt in optionen:
buttons += (''
% (esc(opt), esc(opt)))
if typ == "ziel":
label = "🧱 FINALE · %s" % esc(r["name"])
else:
label = "🔐 Sicherheitsprüfung · %s" % esc(r["name"])
inhalt = ("""
%s
%s
%s
Frage %d von %d
%s
%s
""" % (label, esc(r["name"]), esc(r["beschreibung"]),
idx + 1, len(fragen), feedback,
esc(aktuelle["frage"]), buttons))
return adventure_seite(inhalt)
# ── Alle Fragen dieses Raums beantwortet ──
ausgaenge = db.execute(
"SELECT richtung, nach_raum, hinweis FROM ausgaenge "
"WHERE von_raum=? ORDER BY rowid", (id,)
).fetchall()
db.close()
# ZIEL erreicht → Sieg
if typ == "ziel":
inhalt = ("""