Overhaul: Golden ring flight course and magic spell dueling mini-game with mobile gestures
This commit is contained in:
+36
-47
@@ -11,7 +11,7 @@ from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
app = FastAPI(title="Hogwarts Escape Adventure - Die Kammern des Steins der Weisen")
|
||||
app = FastAPI(title="Hogwarts Escape Adventure - Die Prüfungen der Zauberei")
|
||||
|
||||
SECRET_KEY = os.getenv("SECRET_KEY", "alohomora_bootle_potion_secret_2026")
|
||||
app.add_middleware(SessionMiddleware, secret_key=SECRET_KEY, session_cookie="escape_session")
|
||||
@@ -36,7 +36,7 @@ ALL_ITEMS = {
|
||||
"id": "wand",
|
||||
"name": "Zauberstab",
|
||||
"icon": "🪄",
|
||||
"desc": "Stechpalme und Phönixfeder, 11 Zoll. Liegt warm in deiner Hand.",
|
||||
"desc": "Stechpalme und Phönixfeder, 11 Zoll. Liegt warm und vibrationsbereit in deiner Hand.",
|
||||
"action": "lumos",
|
||||
"action_label": "Lumos / Licht 💡"
|
||||
},
|
||||
@@ -44,10 +44,18 @@ ALL_ITEMS = {
|
||||
"id": "broom",
|
||||
"name": "Nimbus 2000",
|
||||
"icon": "🧹",
|
||||
"desc": "Ein pfeilschneller Rennbesen. Perfekt balanciert für Wendemanöver im Schlüsselraum.",
|
||||
"desc": "Ein pfeilschneller Rennbesen. Perfekt für den rasanten Flug durch schwebende Ringe!",
|
||||
"action": "broom_polish",
|
||||
"action_label": "Besen polieren ✨"
|
||||
},
|
||||
"duel_badge": {
|
||||
"id": "duel_badge",
|
||||
"name": "Duellanten-Abzeichen",
|
||||
"icon": "⚡",
|
||||
"desc": "Ein goldenes Abzeichen für meisterhafte Zauberstab-Gesten im Duellier-Club von Hogwarts.",
|
||||
"action": "spark_wand",
|
||||
"action_label": "Funkenregen sprühen ⚡"
|
||||
},
|
||||
"snape_scroll": {
|
||||
"id": "snape_scroll",
|
||||
"name": "Snapes Logik-Rolle",
|
||||
@@ -56,22 +64,6 @@ ALL_ITEMS = {
|
||||
"action": "read_scroll",
|
||||
"action_label": "Rätsel-Verse lesen 📖"
|
||||
},
|
||||
"silver_key": {
|
||||
"id": "silver_key",
|
||||
"name": "Geknickter Silberschlüssel",
|
||||
"icon": "🗝️",
|
||||
"desc": "Der schwere antike Schlüssel aus der Schlüsselkammer. Sein geknickter Flügel verrät ihn.",
|
||||
"action": "examine_key",
|
||||
"action_label": "Schloss prüfen 🔍"
|
||||
},
|
||||
"chess_knight": {
|
||||
"id": "chess_knight",
|
||||
"name": "Schwarzer Springer",
|
||||
"icon": "♟️",
|
||||
"desc": "Ein massiver schwarzer Springer aus McGonagalls verzaubertem Riesenschach. Hat das weiße Heer geschlagen!",
|
||||
"action": "chess_piece",
|
||||
"action_label": "Stein berühren ⚡"
|
||||
},
|
||||
"philosophers_stone": {
|
||||
"id": "philosophers_stone",
|
||||
"name": "Stein der Weisen",
|
||||
@@ -98,7 +90,7 @@ def get_session_state(request: Request) -> dict:
|
||||
"broom_solved": False,
|
||||
"broom_score": 0,
|
||||
"broom_time": 0,
|
||||
"chess_solved": False,
|
||||
"duel_solved": False,
|
||||
"bottles_solved": False,
|
||||
"sliding_solved": False,
|
||||
"started_at": datetime.datetime.utcnow().isoformat(),
|
||||
@@ -109,16 +101,14 @@ def get_session_state(request: Request) -> dict:
|
||||
state = request.session["escape"]
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if state.get("broom_solved"):
|
||||
state["inventory"].append("silver_key")
|
||||
if state.get("chess_solved"):
|
||||
state["inventory"].append("chess_knight")
|
||||
if state.get("duel_solved"):
|
||||
state["inventory"].append("duel_badge")
|
||||
if state.get("bottles_solved"):
|
||||
state["inventory"].append("philosophers_stone")
|
||||
if "house" not in state:
|
||||
state["house"] = "gryffindor"
|
||||
if "chess_solved" not in state:
|
||||
state["chess_solved"] = False
|
||||
if "duel_solved" not in state:
|
||||
state["duel_solved"] = False
|
||||
request.session["escape"] = state
|
||||
return request.session["escape"]
|
||||
|
||||
@@ -159,18 +149,23 @@ async def page_broom(request: Request):
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/chess", response_class=HTMLResponse)
|
||||
async def page_chess(request: Request):
|
||||
@app.get("/duel", response_class=HTMLResponse)
|
||||
async def page_duel(request: Request):
|
||||
state = get_session_state(request)
|
||||
lang = request.query_params.get("lang", state.get("lang", "de"))
|
||||
state["lang"] = lang
|
||||
request.session["escape"] = state
|
||||
return templates.TemplateResponse(
|
||||
request=request,
|
||||
name="chess.html",
|
||||
name="duel.html",
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/chess")
|
||||
async def redirect_chess():
|
||||
# Graceful redirect for old links
|
||||
return RedirectResponse(url="/duel", status_code=302)
|
||||
|
||||
@app.get("/bottles", response_class=HTMLResponse)
|
||||
async def page_bottles(request: Request):
|
||||
state = get_session_state(request)
|
||||
@@ -223,7 +218,7 @@ async def api_get_inventory(request: Request):
|
||||
"house": house_info,
|
||||
"score": state.get("broom_score", 0),
|
||||
"broom_solved": state.get("broom_solved", False),
|
||||
"chess_solved": state.get("chess_solved", False),
|
||||
"duel_solved": state.get("duel_solved", False),
|
||||
"bottles_solved": state.get("bottles_solved", False),
|
||||
"sliding_solved": state.get("sliding_solved", False)
|
||||
})
|
||||
@@ -251,7 +246,7 @@ async def api_reset_state(request: Request):
|
||||
"broom_solved": False,
|
||||
"broom_score": 0,
|
||||
"broom_time": 0,
|
||||
"chess_solved": False,
|
||||
"duel_solved": False,
|
||||
"bottles_solved": False,
|
||||
"sliding_solved": False,
|
||||
"started_at": datetime.datetime.utcnow().isoformat(),
|
||||
@@ -270,32 +265,26 @@ async def api_broom_complete(request: Request):
|
||||
state["broom_solved"] = True
|
||||
state["broom_score"] = int(data.get("score", 100))
|
||||
state["broom_time"] = int(data.get("time_taken", 30))
|
||||
# Add Silver Key to Inventory
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if "silver_key" not in state["inventory"]:
|
||||
state["inventory"].append("silver_key")
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Der Schlüssel passt ins Schloss! Die Tür zu McGonagalls Zauberschach steht offen!",
|
||||
"new_item": ALL_ITEMS["silver_key"],
|
||||
"message": "Parcours gemeistert! Die Tür zum Zauberspruch-Duell steht offen!",
|
||||
"state": state
|
||||
})
|
||||
|
||||
@app.post("/api/chess/complete")
|
||||
async def api_chess_complete(request: Request):
|
||||
@app.post("/api/duel/complete")
|
||||
async def api_duel_complete(request: Request):
|
||||
state = get_session_state(request)
|
||||
state["chess_solved"] = True
|
||||
state["duel_solved"] = True
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if "chess_knight" not in state["inventory"]:
|
||||
state["inventory"].append("chess_knight")
|
||||
if "duel_badge" not in state["inventory"]:
|
||||
state["inventory"].append("duel_badge")
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Schachmatt! Die weiße Königin senkt ihr Schwert. Der Weg zur Flammenkammer ist frei!",
|
||||
"new_item": ALL_ITEMS["chess_knight"],
|
||||
"message": "Zauberspruch-Duell gewonnen! Die Pforte zur Flammenkammer steht weit offen!",
|
||||
"new_item": ALL_ITEMS["duel_badge"],
|
||||
"state": state
|
||||
})
|
||||
|
||||
@@ -318,7 +307,7 @@ async def api_bottles_drink(request: Request):
|
||||
if content == "ahead":
|
||||
if target_gate == "ahead":
|
||||
state["bottles_solved"] = True
|
||||
if state.get("broom_solved"):
|
||||
if state.get("broom_solved") or state.get("duel_solved"):
|
||||
state["completed_at"] = datetime.datetime.utcnow().isoformat()
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
@@ -349,7 +338,7 @@ async def api_bottles_drink(request: Request):
|
||||
"result": "success_back",
|
||||
"content": content,
|
||||
"message": msg_de if lang == "de" else msg_en,
|
||||
"next_url": "/chess"
|
||||
"next_url": "/duel"
|
||||
})
|
||||
else:
|
||||
msg_de = "Dieser Trank schützt vor den violetten Flammen, führt dich aber nicht vorwärts durch das schwarze Feuer!"
|
||||
|
||||
Reference in New Issue
Block a user