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.
60 lines
2.4 KiB
Twig
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 %}
|