194 lines
6.5 KiB
Python
194 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from fupogfakta.models import GameSession, RoundQuestion
|
|
from lobby.i18n import i18n_locale_config
|
|
|
|
from .models import PhaseVoiceLine, QuestionVoiceLine
|
|
|
|
VOICE_GAME_KEY = "fupogfakta"
|
|
|
|
DEFAULT_PHASE_LINES: dict[str, dict[str, str]] = {
|
|
"en": {
|
|
"intro": (
|
|
"Welcome to Fup og Fakta. Invent a believable lie, spot the real answer, "
|
|
"and score points when other players believe your bluff."
|
|
),
|
|
"lobby": "Players are joining the session. Get ready to start the round.",
|
|
"lie": "The question is live. Players, write one believable lie before time runs out.",
|
|
"guess": "The answers are mixed. Pick the answer you believe is true.",
|
|
"reveal": "Time to reveal the lies, the guesses, and the correct answer.",
|
|
"scoreboard": "Here comes the scoreboard for this round.",
|
|
"finished": "The game is finished. Here is the final result.",
|
|
},
|
|
"da": {
|
|
"intro": (
|
|
"Velkommen til Fup og Fakta. Find på en troværdig løgn, gennemsku det rigtige svar, "
|
|
"og få point når andre hopper på dit bluff."
|
|
),
|
|
"lobby": "Spillerne er ved at joine sessionen. Gør klar til at starte runden.",
|
|
"lie": "Spørgsmålet er live. Spillere, skriv en troværdig løgn før tiden løber ud.",
|
|
"guess": "Svarene er blandet. Vælg det svar du tror er rigtigt.",
|
|
"reveal": "Nu afslører vi løgnene, gættene og det rigtige svar.",
|
|
"scoreboard": "Her kommer scoreboardet for denne runde.",
|
|
"finished": "Spillet er slut. Her er det endelige resultat.",
|
|
},
|
|
}
|
|
|
|
|
|
def _default_question_prompt(locale: str, prompt: str) -> str:
|
|
if locale == "da":
|
|
return f"Spørgsmålet lyder: {prompt}"
|
|
return f"The question is: {prompt}"
|
|
|
|
|
|
def _default_question_reveal(locale: str, correct_answer: str) -> str:
|
|
if locale == "da":
|
|
return f"Det rigtige svar er: {correct_answer}"
|
|
return f"The correct answer is: {correct_answer}"
|
|
|
|
|
|
def _supported_locales() -> tuple[str, tuple[str, ...]]:
|
|
return i18n_locale_config()
|
|
|
|
|
|
def _default_phase_line(cue_key: str, locale: str) -> str:
|
|
default_locale, _locales = _supported_locales()
|
|
localized_lines = DEFAULT_PHASE_LINES.get(locale) or DEFAULT_PHASE_LINES.get(default_locale) or {}
|
|
return localized_lines.get(cue_key, cue_key)
|
|
|
|
|
|
def _resolve_audio_url(audio_field: Any) -> str | None:
|
|
if not audio_field:
|
|
return None
|
|
try:
|
|
return str(audio_field.url)
|
|
except ValueError:
|
|
return None
|
|
|
|
|
|
def _resolve_phase_content(*, cue_key: str, locale: str) -> tuple[str, str | None, str]:
|
|
custom = (
|
|
PhaseVoiceLine.objects.filter(
|
|
game_key=VOICE_GAME_KEY,
|
|
cue_key=cue_key,
|
|
locale=locale,
|
|
is_active=True,
|
|
)
|
|
.first()
|
|
)
|
|
if custom:
|
|
return custom.text, _resolve_audio_url(custom.audio_file), "custom"
|
|
return _default_phase_line(cue_key, locale), None, "default"
|
|
|
|
|
|
def _resolve_question_content(
|
|
*,
|
|
cue_key: str,
|
|
locale: str,
|
|
round_question: RoundQuestion,
|
|
) -> tuple[str, str | None, str]:
|
|
custom = (
|
|
QuestionVoiceLine.objects.filter(
|
|
question=round_question.question,
|
|
cue_key=cue_key,
|
|
locale=locale,
|
|
is_active=True,
|
|
)
|
|
.first()
|
|
)
|
|
if custom:
|
|
return custom.text, _resolve_audio_url(custom.audio_file), "custom"
|
|
|
|
if cue_key == QuestionVoiceLine.CueKey.QUESTION_REVEAL:
|
|
return _default_question_reveal(locale, round_question.correct_answer), None, "default"
|
|
return _default_question_prompt(locale, round_question.question.prompt), None, "default"
|
|
|
|
|
|
def _build_cue_payload(
|
|
*,
|
|
cue_key: str,
|
|
text_by_locale: dict[str, str],
|
|
audio_urls: dict[str, str],
|
|
source: str,
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"cue": cue_key,
|
|
"translations": text_by_locale,
|
|
"audio_urls": audio_urls,
|
|
"source": source,
|
|
}
|
|
|
|
|
|
def resolve_session_voice_cues(
|
|
session: GameSession,
|
|
*,
|
|
current_round_question: RoundQuestion | None,
|
|
) -> dict[str, Any]:
|
|
default_locale, supported_locales = _supported_locales()
|
|
|
|
def collect_phase(cue_key: str) -> dict[str, Any]:
|
|
translations: dict[str, str] = {}
|
|
audio_urls: dict[str, str] = {}
|
|
source = "default"
|
|
for locale in supported_locales:
|
|
text, audio_url, line_source = _resolve_phase_content(cue_key=cue_key, locale=locale)
|
|
translations[locale] = text
|
|
if audio_url:
|
|
audio_urls[locale] = audio_url
|
|
if line_source == "custom":
|
|
source = "custom"
|
|
return _build_cue_payload(
|
|
cue_key=cue_key,
|
|
text_by_locale=translations,
|
|
audio_urls=audio_urls,
|
|
source=source,
|
|
)
|
|
|
|
def collect_question(cue_key: str) -> dict[str, Any] | None:
|
|
if current_round_question is None:
|
|
return None
|
|
|
|
translations: dict[str, str] = {}
|
|
audio_urls: dict[str, str] = {}
|
|
source = "default"
|
|
for locale in supported_locales:
|
|
text, audio_url, line_source = _resolve_question_content(
|
|
cue_key=cue_key,
|
|
locale=locale,
|
|
round_question=current_round_question,
|
|
)
|
|
translations[locale] = text
|
|
if audio_url:
|
|
audio_urls[locale] = audio_url
|
|
if line_source == "custom":
|
|
source = "custom"
|
|
return _build_cue_payload(
|
|
cue_key=cue_key,
|
|
text_by_locale=translations,
|
|
audio_urls=audio_urls,
|
|
source=source,
|
|
)
|
|
|
|
phase_cue_key = session.status if session.status in {
|
|
GameSession.Status.LOBBY,
|
|
GameSession.Status.LIE,
|
|
GameSession.Status.GUESS,
|
|
GameSession.Status.REVEAL,
|
|
GameSession.Status.SCOREBOARD,
|
|
GameSession.Status.FINISHED,
|
|
} else GameSession.Status.LOBBY
|
|
|
|
return {
|
|
"default_locale": default_locale,
|
|
"intro": collect_phase(PhaseVoiceLine.CueKey.INTRO),
|
|
"phase": collect_phase(phase_cue_key),
|
|
"question_prompt": collect_question(QuestionVoiceLine.CueKey.QUESTION_PROMPT)
|
|
if session.status in {GameSession.Status.LIE, GameSession.Status.GUESS}
|
|
else None,
|
|
"question_reveal": collect_question(QuestionVoiceLine.CueKey.QUESTION_REVEAL)
|
|
if session.status in {GameSession.Status.REVEAL, GameSession.Status.SCOREBOARD, GameSession.Status.FINISHED}
|
|
else None,
|
|
}
|