add Carte Blanche trinket: equip system, gatekeeper multi-slot, mini tooltip portal; new token type Token.CARTE ('carte') with fa-money-check icon; migrations 0010-0012:
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

CARTE type, User.equipped_trinket FK, Token.slots_claimed field; post_save signal sets
equipped_trinket=COIN for new users, PASS for staff; kit bag now shows only the equipped
trinket in Trinkets section; Game Kit applet mini tooltip portal shows Equipped or Equip
Trinket per token; AJAX POST equip-trinket id updates equippedId in-place; equip btn
now works for COIN, PASS, and CARTE (data-token-id added to all three); Gatekeeper CARTE
flow: drop_token sets current_room (no slot reserved); each empty slot up to
slots_claimed+1 gets a drop-token-btn; slots_claimed high-water mark advances on fill,
never decrements; highest CARTE-filled slot gets NVM (release_slot); token_return_btn
resets current_room + slots_claimed + un-fills all CARTE slots; gate_status always returns
full template so launch-game-btn persists via HTMX when gate_status == OPEN; room.html
includes gatekeeper when GATHERING or OPEN; new FT test_trinket_carte_blanche.py (2
tests, both passing); 299 tests green
This commit is contained in:
Disco DeDisco
2026-03-16 00:07:52 -04:00
parent b49218b45b
commit 4239245902
26 changed files with 842 additions and 105 deletions

View File

@@ -3,32 +3,49 @@
style="--applet-cols: {{ entry.applet.grid_cols }}; --applet-rows: {{ entry.applet.grid_rows }};"
>
<h2>Game Kit</h2>
<div id="id_game_kit">
<div id="id_game_kit" data-equipped-id="{{ equipped_trinket_id }}">
{% if pass_token %}
<div id="id_kit_pass_token" class="token">
<div id="id_kit_pass" class="token" data-token-id="{{ pass_token.pk }}">
<i class="fa-solid fa-clipboard"></i>
<div class="token-tooltip">
<h4>{{ pass_token.tooltip_name }}</h4>
<p>{{ pass_token.tooltip_description }}</p>
{% if pass_token.tooltip_shoptalk %}
<small><em>{{ pass_token.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ pass_token.tooltip_expiry }}</p>
<div class="token-tooltip-body">
<h4>{{ pass_token.tooltip_name }}</h4>
<p>{{ pass_token.tooltip_description }}</p>
{% if pass_token.tooltip_shoptalk %}
<small><em>{{ pass_token.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ pass_token.tooltip_expiry }}</p>
</div>
</div>
</div>
{% endif %}
{% if carte %}
<div id="id_kit_carte_blanche" class="token" data-token-id="{{ carte.pk }}">
<i class="fa-solid fa-money-check"></i>
<div class="token-tooltip">
<div class="token-tooltip-body">
<h4>{{ carte.tooltip_name }}</h4>
<p>{{ carte.tooltip_description }}</p>
{% if carte.tooltip_shoptalk %}
<small><em>{{ carte.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ carte.tooltip_expiry }}</p>
</div>
</div>
</div>
{% endif %}
{% if coin %}
<div id="id_kit_coin_on_a_string" class="token">
<div id="id_kit_coin_on_a_string" class="token" data-token-id="{{ coin.pk }}">
<i class="fa-solid fa-medal"></i>
<div class="token-tooltip">
<h4>{{ coin.tooltip_name }}</h4>
<p>
{{ coin.tooltip_description }}
</p>
{% if coin.tooltip_shoptalk %}
<small><em>{{ coin.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ coin.tooltip_expiry }}</p>
<div class="token-tooltip-body">
<h4>{{ coin.tooltip_name }}</h4>
<p>{{ coin.tooltip_description }}</p>
{% if coin.tooltip_shoptalk %}
<small><em>{{ coin.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ coin.tooltip_expiry }}</p>
</div>
</div>
</div>
{% endif %}
@@ -37,9 +54,14 @@
<div id="id_kit_free_token" class="token">
<i class="fa-solid fa-coins"></i>
<div class="token-tooltip">
<h4>{{ token.tooltip_name }}{% if free_count > 1 %} <span class="token-count">(×{{ free_count }})</span>{% endif %}</h4>
<p>{{ token.tooltip_description }}</p>
<p class="expiry">{{ token.tooltip_expiry }}</p>
<div class="token-tooltip-body">
<h4>{{ token.tooltip_name }}{% if free_count > 1 %} <span class="token-count">(×{{ free_count }})</span>{% endif %}</h4>
<p>{{ token.tooltip_description }}</p>
{% if token.tooltip_shoptalk %}
<small><em>{{ token.tooltip_shoptalk }}</em></small>
{% endif %}
<p class="expiry">{{ token.tooltip_expiry }}</p>
</div>
</div>
</div>
{% endwith %}
@@ -47,4 +69,4 @@
<div id="id_kit_card_deck" class="kit-item"><i class="fa-regular fa-id-badge"></i></div>
<div id="id_kit_dice_set" class="kit-item"><i class="fa-solid fa-dice"></i></div>
</div>
</section>
</section>

View File

@@ -0,0 +1 @@
<button class="equip-trinket-btn" data-token-id="{{ token.pk }}">Equip Trinket?</button>

View File

@@ -17,7 +17,7 @@
</div>
</header>
<div class="token-slot{% if can_drop %} active{% elif user_reserved_slot %} pending{% elif user_filled_slot %} claimed{% elif token_depleted %} depleted{% else %} locked{% endif %}">
<div class="token-slot{% if can_drop %} active{% elif user_reserved_slot %} pending{% elif user_filled_slot or carte_active %} claimed{% elif token_depleted %} depleted{% else %} locked{% endif %}">
{% if can_drop %}
<form method="POST" action="{% url 'epic:drop_token' room.id %}" style="display:contents">
{% csrf_token %}
@@ -66,10 +66,25 @@
<button type="submit" class="btn btn-confirm">OK</button>
{% endif %}
</form>
{% elif carte_active and slot.status == 'EMPTY' and slot.slot_number <= carte_slots_claimed|add:1 %}
<form method="POST" action="{% url 'epic:confirm_token' room.id %}">
{% csrf_token %}
<input type="hidden" name="slot_number" value="{{ slot.slot_number }}">
<button type="submit" class="drop-token-btn" aria-label="Fill slot {{ slot.slot_number }}"></button>
</form>
{% elif carte_active and slot.status == 'FILLED' and slot.slot_number == carte_nvm_slot_number %}
<form method="POST" action="{% url 'epic:release_slot' room.id %}">
{% csrf_token %}
<input type="hidden" name="slot_number" value="{{ slot.slot_number }}">
<button type="submit" class="slot-release-btn btn btn-cancel">NVM</button>
</form>
{% endif %}
</div>
{% endfor %}
</div>
{% if room.gate_status == 'OPEN' %}
<button class="launch-game-btn">Launch</button>
{% endif %}
{% if request.user == room.owner %}
<div class="form-container">

View File

@@ -10,6 +10,7 @@
{% include "apps/gameboard/_partials/_applets.html" %}
</div>
<div id="id_tooltip_portal" class="token-tooltip"></div>
<div id="id_mini_tooltip_portal" class="token-tooltip token-tooltip--mini"></div>
{% endblock content %}
{% block scripts %}

View File

@@ -10,7 +10,7 @@
<div class="room-table"></div>
</div>
{% if room.gate_status == "GATHERING" %}
{% if room.gate_status == "GATHERING" or room.gate_status == "OPEN" %}
{% include "apps/gameboard/_partials/_gatekeeper.html" %}
{% endif %}
{% include "apps/gameboard/_partials/_room_gear.html" %}