Files
Escapepage/templates/game/index.html.twig
T
Frank 3984a33282 Add win/lose game-ending flow
Removing all 3 locked files while the timer is still running now marks
the session WON immediately (checked right after every successful rm)
and broadcasts a "game_finished" signal over Mercure so every
connected player gets redirected together, not just the one who
removed the last file. A new /won/{session} route + won.html.twig
mirrors the existing lost flow (victory narrative + the same feedback
form).

The existing timer-expiry path already set LOST but always redirected
to lostUrl regardless of actual status; it now picks won/lost based on
the status the server reports.

Also fixes a pre-existing bug on the lost page (and would-be bug on
the new won page): PlayerService::GetCurrentlyActiveAsPlayer() only
matches players in READY/PLAYING sessions, so by the time a session
has ended it always returned null there, silently breaking the
feedback form. Both pages now look the player up directly via
PlayerRepository instead.

Added a navigatingAway flag so the page's "confirm before leaving"
prompt doesn't block our own win/lose redirects.
2026-07-11 21:41:16 +02:00

60 lines
2.4 KiB
Twig

<!DOCTYPE html>
<html lang="{{ app.request.locale|default(app.request.defaultLocale|default('en')) }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ 'game.title'|trans({'%site%': ('site.name'|trans)}) }}</title>
{# Include Game1-specific CSS in addition to the base app assets #}
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{{ encore_entry_link_tags('game1') }}
{% endblock %}
</head>
<body>
<div id="game-container">
<div id="mercure-config"
data-mercure-public-url="{{ mercure_public_url|e('html_attr') }}"
data-topic="/game/hub/{{ session.id|e('html_attr') }}"
data-api-ping-url="{{ path('game_api_ping')|e('html_attr') }}"
data-api-echo-url="{{ path('game_api_message')|e('html_attr') }}"
data-api-check-finished-url="{{ path('game_api_check_finished', {session: session.id})|e('html_attr') }}"
data-lost-url="{{ path('game_lost', {session: session.id})|e('html_attr') }}"
data-won-url="{{ path('game_won', {session: session.id})|e('html_attr') }}"
data-screen="{{ screen|e('html_attr') }}"
{% if lock %}
data-lock-locked-at="{{ lock.lockedAt }}"
data-lock-reveal-at="{{ lock.revealAt }}"
data-lock-unlock-at="{{ lock.unlockAt }}"
{% endif %}
{% if filesRemovalDeadline %}
data-files-removal-deadline="{{ filesRemovalDeadline }}"
{% endif %}
style="display:none">
</div>
<div id="game-timer" data-end-time="{{ session.timer }}">
--:--:--
</div>
<div id="lock-banner" style="display:none">
<div id="lock-banner-text">AI VIRUS: SYSTEM LOCKED</div>
<div id="lock-countdown">--</div>
</div>
<div id="message-container">
</div>
<audio id="message-sound" style="display:none">
<source src="{{ asset('audio/message.mp3') }}" type="audio/mpeg">
</audio>
<div id="input">
<input type="text" disabled id="input-message">
</div>
</div>
</body>
{# Include Game1-specific JS in addition to the base app assets #}
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{{ encore_entry_script_tags('game1') }}
{% endblock %}