room center: GATE VIEW supersedes SCAN SIGS / CAST SKY / DRAW SEA / sig overlay when token cost lapses — ROLE pick survives grace — TDD
Phase 3 of the room GATE VIEW + seat-renewal sprint. When the viewer's own FILLED gate-slot cost has lapsed (filled_at past the cost-current window), the center hex shows a GATE VIEW button (→ room gate-view) instead of the phase affordances, so they must renew before advancing. - _role_select_context: adds viewer_cost_current / viewer_in_grace from the viewer's FILLED slot (no slot → current, defensive) - room.html: the ROLE card-stack renders OUTSIDE the cost gate (the gamer's own role pick survives the renewal grace — deposit privilege); GATE VIEW supersedes the rest of .table-center; #id_pick_sigs_wrap (SCAN SIGS, advancing the whole table) is gated on viewer_cost_current; the SIG/SKY/SEA overlays are gated too (they embed their trigger-btn ids in JS, so they must not render alongside GATE VIEW) - per user-spec: only the ROLE pick stays in grace; SCAN SIGS + every later phase get GATE VIEW Tests: RoomCenterSupersessionTest (9) — GATE VIEW supersedes sig overlay / CAST SKY / DRAW SEA / SCAN SIGS when lapsed, normal buttons when current; RoomRoleStackGraceTest (1) — card-stack (eligible) kept alongside GATE VIEW when lapsed. 838 epic+gameboard ITs green. Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,10 @@
|
||||
<div id="id_aperture_fill"></div>
|
||||
<div class="room-shell">
|
||||
<div id="id_game_table" class="room-table">
|
||||
{% if room.table_status == "ROLE_SELECT" %}
|
||||
{# SCAN SIGS advances the whole table past role-select — gated on #}
|
||||
{# the viewer's token cost being current (a lapsed gamer gets GATE #}
|
||||
{# VIEW in the center instead; only their own ROLE pick survives). #}
|
||||
{% if room.table_status == "ROLE_SELECT" and viewer_cost_current %}
|
||||
<div id="id_pick_sigs_wrap"{% if starter_roles|length < 6 %} style="display:none"{% endif %}>
|
||||
<form method="POST" action="{% url 'epic:pick_sigs' room.id %}">
|
||||
{% csrf_token %}
|
||||
@@ -22,29 +25,45 @@
|
||||
<div class="table-hex-border">
|
||||
<div class="table-hex">
|
||||
<div class="table-center">
|
||||
{% if room.table_status == "ROLE_SELECT" %}
|
||||
{% if card_stack_state %}
|
||||
<div class="card-stack" data-state="{{ card_stack_state }}"
|
||||
data-starter-roles="{{ starter_roles|join:',' }}"
|
||||
data-user-slots="{{ user_slots|join:',' }}"
|
||||
data-active-slot="{{ active_slot }}"
|
||||
data-equipped-deck="{{ equipped_deck_id|default:'' }}">
|
||||
{% if card_stack_state == "ineligible" %}
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{# ROLE card-stack — the gamer's own role pick stays #}
|
||||
{# available even when their token cost has lapsed #}
|
||||
{# (deposit-privilege grace, 7d), so it renders OUTSIDE #}
|
||||
{# the cost gate below. #}
|
||||
{% if room.table_status == "ROLE_SELECT" and card_stack_state %}
|
||||
<div class="card-stack" data-state="{{ card_stack_state }}"
|
||||
data-starter-roles="{{ starter_roles|join:',' }}"
|
||||
data-user-slots="{{ user_slots|join:',' }}"
|
||||
data-active-slot="{{ active_slot }}"
|
||||
data-equipped-deck="{{ equipped_deck_id|default:'' }}">
|
||||
{% if card_stack_state == "ineligible" %}
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if room.table_status == "SKY_SELECT" %}
|
||||
{% if sky_confirmed %}
|
||||
<button id="id_pick_sea_btn" class="btn btn-primary">DRAW<br>SEA</button>
|
||||
{% else %}
|
||||
<button id="id_pick_sky_btn" class="btn btn-primary">CAST<br>SKY</button>
|
||||
{% endif %}
|
||||
{% elif room.table_status == "SIG_SELECT" %}
|
||||
<button id="id_pick_sky_btn" class="btn btn-primary" style="display:none">CAST<br>SKY</button>
|
||||
{% if polarity_done %}
|
||||
<p id="id_hex_waiting_msg">{% if user_polarity == "levity" %}Gravity settling . . .{% else %}Levity appraising . . .{% endif %}</p>
|
||||
{% if not viewer_cost_current %}
|
||||
{# Token cost lapsed → GATE VIEW supersedes SCAN SIGS #}
|
||||
{# / CAST SKY / DRAW SEA / the sig waiting msg. The #}
|
||||
{# gamer keeps their seat through the renewal grace; #}
|
||||
{# GATE VIEW routes to the renewal gate-view. Only #}
|
||||
{# the ROLE pick (above) survives. `<button>` + #}
|
||||
{# onclick (not `<a>`) — `.btn` doesn't reset serif #}
|
||||
{# font on anchors. [[feedback-btn-vs-anchor-font- #}
|
||||
{# family]] #}
|
||||
<button id="id_room_gate_view_btn" type="button"
|
||||
class="btn btn-primary"
|
||||
onclick="window.location.href='{% url 'epic:room_gate' room.id %}'">GATE<br>VIEW</button>
|
||||
{% else %}
|
||||
{% if room.table_status == "SKY_SELECT" %}
|
||||
{% if sky_confirmed %}
|
||||
<button id="id_pick_sea_btn" class="btn btn-primary">DRAW<br>SEA</button>
|
||||
{% else %}
|
||||
<button id="id_pick_sky_btn" class="btn btn-primary">CAST<br>SKY</button>
|
||||
{% endif %}
|
||||
{% elif room.table_status == "SIG_SELECT" %}
|
||||
<button id="id_pick_sky_btn" class="btn btn-primary" style="display:none">CAST<br>SKY</button>
|
||||
{% if polarity_done %}
|
||||
<p id="id_hex_waiting_msg">{% if user_polarity == "levity" %}Gravity settling . . .{% else %}Levity appraising . . .{% endif %}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -67,23 +86,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Phase overlays are gated on `viewer_cost_current` too: a lapsed gamer #}
|
||||
{# gets GATE VIEW in the center, so the SIG/SKY/SEA modals (which embed #}
|
||||
{# their trigger-btn ids in JS) must not render alongside it. #}
|
||||
{# Sig Select overlay — suppressed once this gamer's polarity sigs are assigned #}
|
||||
{% if room.table_status == "SIG_SELECT" and user_polarity and not polarity_done %}
|
||||
{% if room.table_status == "SIG_SELECT" and user_polarity and not polarity_done and viewer_cost_current %}
|
||||
{% include "apps/gameboard/_partials/_sig_select_overlay.html" %}
|
||||
{% endif %}
|
||||
|
||||
{# Sky (Pick Sky) overlay — natal chart entry #}
|
||||
{% if room.table_status == "SKY_SELECT" and not sky_confirmed %}
|
||||
{% if room.table_status == "SKY_SELECT" and not sky_confirmed and viewer_cost_current %}
|
||||
{% include "apps/gameboard/_partials/_sky_overlay.html" %}
|
||||
{% endif %}
|
||||
{# Sky tooltip: sibling of .sky-overlay, not inside .sky-modal-wrap (which has transform) #}
|
||||
{% if room.table_status == "SKY_SELECT" and not sky_confirmed %}
|
||||
{% if room.table_status == "SKY_SELECT" and not sky_confirmed and viewer_cost_current %}
|
||||
<div id="id_sky_tooltip" class="tt" style="display:none;"></div>
|
||||
<div id="id_sky_tooltip_2" class="tt" style="display:none;"></div>
|
||||
{% endif %}
|
||||
|
||||
{# Sea (Pick Sea) overlay — Celtic Cross spread entry #}
|
||||
{% if room.table_status == "SKY_SELECT" and sky_confirmed %}
|
||||
{% if room.table_status == "SKY_SELECT" and sky_confirmed and viewer_cost_current %}
|
||||
{% include "apps/gameboard/_partials/_sea_overlay.html" %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user