Feature: Integrate all four Hogwarts mini-games (Duel, Potion Brewing, Cryptex Lock, Cornish Pixies)
This commit is contained in:
+165
-3
@@ -56,6 +56,30 @@ ALL_ITEMS = {
|
||||
"action": "spark_wand",
|
||||
"action_label": "Funkenregen sprühen ⚡"
|
||||
},
|
||||
"felix_felicis": {
|
||||
"id": "felix_felicis",
|
||||
"name": "Felix Felicis",
|
||||
"icon": "🧪",
|
||||
"desc": "Ein Tropfen flüssiges Gold! Verleiht dir unerschütterliches Glück bei deinen magischen Taten.",
|
||||
"action": "lucky_aura",
|
||||
"action_label": "Glücks-Aura aktivieren 🍀"
|
||||
},
|
||||
"cryptex_key": {
|
||||
"id": "cryptex_key",
|
||||
"name": "Schlüssel der Gründer",
|
||||
"icon": "🗝️",
|
||||
"desc": "Ein schwerer, mit uralten Runen gravierter Messingschlüssel aus dem Tresor von Hogwarts.",
|
||||
"action": "inspect_key",
|
||||
"action_label": "Runen betrachten 🔍"
|
||||
},
|
||||
"pixie_jar": {
|
||||
"id": "pixie_jar",
|
||||
"name": "Wichtelglas",
|
||||
"icon": "🧚",
|
||||
"desc": "Ein dickbauchiges Glas mit einem gebannten blauen Wichtel. Er schneidet lustige Fratzen!",
|
||||
"action": "poke_jar",
|
||||
"action_label": "Glas antippen ⚡"
|
||||
},
|
||||
"snape_scroll": {
|
||||
"id": "snape_scroll",
|
||||
"name": "Snapes Logik-Rolle",
|
||||
@@ -81,6 +105,8 @@ HOUSES = {
|
||||
"hufflepuff": {"id": "hufflepuff", "name": "Hufflepuff", "icon": "🦡", "color": "#ecb939", "accent": "#372e29"}
|
||||
}
|
||||
|
||||
CRYPTEX_SOLUTION = ["🦁", "🌙", "🔥", "🪄"]
|
||||
|
||||
def get_session_state(request: Request) -> dict:
|
||||
if "escape" not in request.session:
|
||||
request.session["escape"] = {
|
||||
@@ -91,6 +117,9 @@ def get_session_state(request: Request) -> dict:
|
||||
"broom_score": 0,
|
||||
"broom_time": 0,
|
||||
"duel_solved": False,
|
||||
"brew_solved": False,
|
||||
"cryptex_solved": False,
|
||||
"pixies_solved": False,
|
||||
"bottles_solved": False,
|
||||
"sliding_solved": False,
|
||||
"started_at": datetime.datetime.utcnow().isoformat(),
|
||||
@@ -101,14 +130,26 @@ 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("duel_solved"):
|
||||
if state.get("duel_solved") and "duel_badge" not in state["inventory"]:
|
||||
state["inventory"].append("duel_badge")
|
||||
if state.get("bottles_solved"):
|
||||
if state.get("brew_solved") and "felix_felicis" not in state["inventory"]:
|
||||
state["inventory"].append("felix_felicis")
|
||||
if state.get("cryptex_solved") and "cryptex_key" not in state["inventory"]:
|
||||
state["inventory"].append("cryptex_key")
|
||||
if state.get("pixies_solved") and "pixie_jar" not in state["inventory"]:
|
||||
state["inventory"].append("pixie_jar")
|
||||
if state.get("bottles_solved") and "philosophers_stone" not in state["inventory"]:
|
||||
state["inventory"].append("philosophers_stone")
|
||||
if "house" not in state:
|
||||
state["house"] = "gryffindor"
|
||||
if "duel_solved" not in state:
|
||||
state["duel_solved"] = False
|
||||
if "brew_solved" not in state:
|
||||
state["brew_solved"] = False
|
||||
if "cryptex_solved" not in state:
|
||||
state["cryptex_solved"] = False
|
||||
if "pixies_solved" not in state:
|
||||
state["pixies_solved"] = False
|
||||
request.session["escape"] = state
|
||||
return request.session["escape"]
|
||||
|
||||
@@ -161,6 +202,42 @@ async def page_duel(request: Request):
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/brew", response_class=HTMLResponse)
|
||||
async def page_brew(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="brew.html",
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/cryptex", response_class=HTMLResponse)
|
||||
async def page_cryptex(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="cryptex.html",
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/pixies", response_class=HTMLResponse)
|
||||
async def page_pixies(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="pixies.html",
|
||||
context=get_template_context(request, state, lang)
|
||||
)
|
||||
|
||||
@app.get("/chess")
|
||||
async def redirect_chess():
|
||||
# Graceful redirect for old links
|
||||
@@ -219,6 +296,9 @@ async def api_get_inventory(request: Request):
|
||||
"score": state.get("broom_score", 0),
|
||||
"broom_solved": state.get("broom_solved", False),
|
||||
"duel_solved": state.get("duel_solved", False),
|
||||
"brew_solved": state.get("brew_solved", False),
|
||||
"cryptex_solved": state.get("cryptex_solved", False),
|
||||
"pixies_solved": state.get("pixies_solved", False),
|
||||
"bottles_solved": state.get("bottles_solved", False),
|
||||
"sliding_solved": state.get("sliding_solved", False)
|
||||
})
|
||||
@@ -247,6 +327,9 @@ async def api_reset_state(request: Request):
|
||||
"broom_score": 0,
|
||||
"broom_time": 0,
|
||||
"duel_solved": False,
|
||||
"brew_solved": False,
|
||||
"cryptex_solved": False,
|
||||
"pixies_solved": False,
|
||||
"bottles_solved": False,
|
||||
"sliding_solved": False,
|
||||
"started_at": datetime.datetime.utcnow().isoformat(),
|
||||
@@ -283,11 +366,90 @@ async def api_duel_complete(request: Request):
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Zauberspruch-Duell gewonnen! Die Pforte zur Flammenkammer steht weit offen!",
|
||||
"message": "Zauberspruch-Duell gewonnen! Die Pforte zur Brauküche steht weit offen!",
|
||||
"new_item": ALL_ITEMS["duel_badge"],
|
||||
"state": state
|
||||
})
|
||||
|
||||
@app.post("/api/brew/complete")
|
||||
async def api_brew_complete(request: Request):
|
||||
state = get_session_state(request)
|
||||
state["brew_solved"] = True
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if "felix_felicis" not in state["inventory"]:
|
||||
state["inventory"].append("felix_felicis")
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Goldener Glanz erfüllt den Kessel! Felix Felicis ist meisterhaft gebraut.",
|
||||
"new_item": ALL_ITEMS["felix_felicis"],
|
||||
"state": state
|
||||
})
|
||||
|
||||
@app.post("/api/cryptex/unlock")
|
||||
async def api_cryptex_unlock(request: Request):
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
combo = data.get("combination", [])
|
||||
|
||||
# Check match against CRYPTEX_SOLUTION ["🦁", "🌙", "🔥", "🪄"]
|
||||
is_correct = False
|
||||
if combo == CRYPTEX_SOLUTION:
|
||||
is_correct = True
|
||||
elif combo == [0, 1, 0, 1]:
|
||||
is_correct = True
|
||||
elif combo == ["lion", "moon", "fire", "wand"]:
|
||||
is_correct = True
|
||||
|
||||
if not is_correct:
|
||||
return JSONResponse({
|
||||
"success": False,
|
||||
"message": "Die Runenzylinder rasten nicht ein. Die Gravur bleibt verschlossen!"
|
||||
})
|
||||
|
||||
state = get_session_state(request)
|
||||
state["cryptex_solved"] = True
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if "cryptex_key" not in state["inventory"]:
|
||||
state["inventory"].append("cryptex_key")
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Das Runenschloss springt mit einem goldenen Glühen auf! Der Schlüssel der Gründer gehört dir.",
|
||||
"new_item": ALL_ITEMS["cryptex_key"],
|
||||
"state": state
|
||||
})
|
||||
|
||||
@app.post("/api/pixies/complete")
|
||||
async def api_pixies_complete(request: Request):
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
caught = int(data.get("caught", 0))
|
||||
if caught < 10:
|
||||
return JSONResponse({
|
||||
"success": False,
|
||||
"message": f"Du hast erst {caught}/10 Wichtel gebannt. Halte durch!"
|
||||
})
|
||||
state = get_session_state(request)
|
||||
state["pixies_solved"] = True
|
||||
if "inventory" not in state:
|
||||
state["inventory"] = ["wand", "broom", "snape_scroll"]
|
||||
if "pixie_jar" not in state["inventory"]:
|
||||
state["inventory"].append("pixie_jar")
|
||||
request.session["escape"] = state
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"message": "Alle frechen Wichtel mit Immobilus gebannt! Das Wichtelglas wandert in deinen Beutel.",
|
||||
"new_item": ALL_ITEMS["pixie_jar"],
|
||||
"state": state
|
||||
})
|
||||
|
||||
@app.post("/api/bottles/drink")
|
||||
async def api_bottles_drink(request: Request):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user