deck contribution sprint 2 + Carte Blanche safeguards — TDD
Sprint 2 UI (game kit applet): - _applet-game-kit.html: in-use deck → two disabled × buttons, .tt-deck-game-name; in-use Carte Blanche → two disabled × buttons, data-current-room-name, .tt-token-room-name; tooltip content mirrors kit bag panel (Default, card count, description, Stock version) - gameboard.js buildMiniContent: 'In-Use' for tokens w. data-current-room-name set - _kit_bag_panel.html: Deck section always renders (placeholder when unequipped) View safeguards: - select_role: look up existing deck from prior seat in same room before equipped_deck (Carte Blanche multi-seat); only unequip when using equipped_deck - drop_token Carte: reject 409 if token.current_room is a different room; unequip from equipped_trinket on drop ITs: SelectRoleMultiSeatTest (2), DropTokenViewTest +3 (carte drop, unequip, lock) Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -405,8 +405,13 @@ def drop_token(request, room_id):
|
||||
if token.token_type == Token.CARTE:
|
||||
# CARTE enters the machine without reserving a slot — all slots
|
||||
# become individually claimable via .drop-token-btn
|
||||
if token.current_room_id and token.current_room_id != room.id:
|
||||
return HttpResponse(status=409)
|
||||
token.current_room = room
|
||||
token.save()
|
||||
if request.user.equipped_trinket_id == token.pk:
|
||||
request.user.equipped_trinket = None
|
||||
request.user.save(update_fields=["equipped_trinket"])
|
||||
request.session["kit_token_id"] = str(token.id)
|
||||
_notify_gate_update(room_id)
|
||||
return redirect("epic:gatekeeper", room_id=room_id)
|
||||
@@ -566,6 +571,7 @@ def select_role(request, room_id):
|
||||
valid_roles = [code for code, _ in TableSeat.ROLE_CHOICES]
|
||||
if not role or role not in valid_roles:
|
||||
return redirect("epic:room", room_id=room_id)
|
||||
existing = None
|
||||
with transaction.atomic():
|
||||
active_seat = room.table_seats.select_for_update().filter(
|
||||
role__isnull=True
|
||||
@@ -575,8 +581,16 @@ def select_role(request, room_id):
|
||||
if room.table_seats.filter(role=role).exists():
|
||||
return HttpResponse(status=409)
|
||||
active_seat.role = role
|
||||
active_seat.deck_variant = request.user.equipped_deck
|
||||
existing = room.table_seats.filter(
|
||||
gamer=request.user, deck_variant__isnull=False,
|
||||
).exclude(pk=active_seat.pk).first()
|
||||
active_seat.deck_variant = (
|
||||
existing.deck_variant if existing else request.user.equipped_deck
|
||||
)
|
||||
active_seat.save()
|
||||
if not existing and request.user.equipped_deck:
|
||||
request.user.equipped_deck = None
|
||||
request.user.save(update_fields=["equipped_deck"])
|
||||
record(room, GameEvent.ROLE_SELECTED, actor=request.user,
|
||||
role=role, slot_number=active_seat.slot_number,
|
||||
role_display=dict(TableSeat.ROLE_CHOICES).get(role, role))
|
||||
|
||||
Reference in New Issue
Block a user