feat(ui): implement tie & trump menu, fixed some critical bugs #52

Merged
Janis merged 3 commits from rework/43-ui-improvements into main 2025-11-13 08:20:31 +01:00
11 changed files with 398 additions and 118 deletions
Showing only changes of commit ca1c7bd2ac - Show all commits

View File

@@ -320,7 +320,7 @@ class IngameController @Inject()(
val session = g.getUserSession(request.user.id) val session = g.getUserSession(request.user.id)
optSession = Some(session) optSession = Some(session)
session.lock.lock() session.lock.lock()
g.selectTie(g.getUserSession(request.user.id), tie.toInt) g.selectTie(g.getUserSession(request.user.id), tie.toInt - 1)
} }
optSession.foreach(_.lock.unlock()) optSession.foreach(_.lock.unlock())
if (result.isSuccess) { if (result.isSuccess) {

View File

@@ -157,6 +157,9 @@ class GameLobby private(
*/ */
def selectTie(userSession: UserSession, tieNumber: Int): Unit = { def selectTie(userSession: UserSession, tieNumber: Int): Unit = {
val player = getPlayerInteractable(userSession, InteractionType.TieChoice) val player = getPlayerInteractable(userSession, InteractionType.TieChoice)
val highestNumber = logic.playerTieLogic.highestAllowedNumber()
if (tieNumber < 0 || tieNumber > highestNumber)
throw new IllegalArgumentException(s"Selected number $tieNumber is out of allowed range (0 to $highestNumber)")
userSession.resetCanInteract() userSession.resetCanInteract()
logic.playerTieLogic.receivedTieBreakerCard(tieNumber) logic.playerTieLogic.receivedTieBreakerCard(tieNumber)
} }

View File

@@ -5,7 +5,7 @@
<div class="ingame-stage blur-sides"> <div class="ingame-stage blur-sides">
<div class="container py-4"> <div class="container py-4">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-12 col-md-10 col-lg-8"> <div class="col-12">
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-header text-center"> <div class="card-header text-center">
<h3 class="mb-0">Select Trump Suit</h3> <h3 class="mb-0">Select Trump Suit</h3>
@@ -16,66 +16,50 @@
You (@player.toString) won the last round. Choose the trump suit for the next round. You (@player.toString) won the last round. Choose the trump suit for the next round.
</div> </div>
<form method="post" action="@routes.IngameController.playTrump(gameId)"> <div class="row justify-content-center col-auto mb-5">
<div class="row row-cols-2 row-cols-sm-4 g-3"> <div class="col-auto handcard">
<div class="col"> <form action="@routes.IngameController.playTrump(gameId)" method="post">
<button class="btn btn-outline-dark w-100 h-100 py-3" type="submit" name="trump" value="0" aria-label="Spades"> <input type="hidden" name="cardId" value="0" />
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Spades)) <button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none" name="trump" value="0" style="border-radius: 6px">
<div class="mt-2">Spades</div> @util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Spades)) width="120px" style="border-radius: 6px"/>
</button> </button>
</div>
<div class="col">
<button class="btn btn-outline-danger w-100 h-100 py-3" type="submit" name="trumpSuit" value="1" aria-label="Hearts">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Hearts))
<div class="mt-2">Hearts</div>
</button>
</div>
<div class="col">
<button class="btn btn-outline-warning w-100 h-100 py-3" type="submit" name="trumpSuit" value="2" aria-label="Diamonds">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Diamonds))
<div class="mt-2">Diamonds</div>
</button>
</div>
<div class="col">
<button class="btn btn-outline-secondary w-100 h-100 py-3" type="submit" name="trumpSuit" value="3" aria-label="Clubs">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Clubs))
<div class="mt-2">Clubs</div>
</button>
</div>
</div>
</form> </form>
</div>
<div class="col-auto handcard">
<form action="@routes.IngameController.playTrump(gameId)" method="post">
<input type="hidden" name="cardId" value="1" />
<button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none" name="trump" value="1" style="border-radius: 6px">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Hearts)) width="120px" style="border-radius: 6px"/>
</button>
</form>
</div>
<div class="col-auto handcard">
<form action="@routes.IngameController.playTrump(gameId)" method="post">
<input type="hidden" name="cardId" value="2" />
<button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none" name="trump" value="2" style="border-radius: 6px">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Diamonds)) width="120px" style="border-radius: 6px"/>
</button>
</form>
</div>
<div class="col-auto handcard">
<form action="@routes.IngameController.playTrump(gameId)" method="post">
<input type="hidden" name="cardId" value="3" />
<button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none" name="trump" value="3" style="border-radius: 6px">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Clubs)) width="120px" style="border-radius: 6px"/>
</button>
</form>
</div>
</div>
<div class="row justify-content-center" id="card-slide">
@for(i <- player.currentHand().get.cards.indices) {
<div class="col-auto" style="border-radius: 6px">
@util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px" style="border-radius: 6px"/>
</div>
}
</div>
} else { } else {
<div class="alert alert-warning" role="alert" aria-live="polite"> <div class="alert alert-warning" role="alert" aria-live="polite">
@player.toString is choosing a trumpsuit. The new round will start once a suit is picked. @logic.getCurrentMatch.get.roundlist.last.winner.get.name is choosing a trumpsuit. The new round will start once a suit is picked.
</div>
<div class="text-center">
<div class="row row-cols-2 row-cols-sm-4 g-3">
<div class="col">
<div class="btn btn-outline-dark disabled w-100 h-100 py-3" aria-disabled="true">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Spades))
<div class="mt-2">Spades</div>
</div>
</div>
<div class="col">
<div class="btn btn-outline-danger disabled w-100 h-100 py-3" aria-disabled="true">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Hearts))
<div class="mt-2">Hearts</div>
</div>
</div>
<div class="col">
<div class="btn btn-outline-warning disabled w-100 h-100 py-3" aria-disabled="true">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Diamonds))
<div class="mt-2">Diamonds</div>
</div>
</div>
<div class="col">
<div class="btn btn-outline-secondary disabled w-100 h-100 py-3" aria-disabled="true">
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Clubs))
<div class="mt-2">Clubs</div>
</div>
</div>
</div>
</div> </div>
} }
</div> </div>

View File

@@ -12,7 +12,6 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="mb-3"> <div class="mb-3">
<h5 class="card-title">Knockout Whist</h5>
<p class="card-text"> <p class="card-text">
The last round was tied between: The last round was tied between:
<span class="ms-1"> <span class="ms-1">
@@ -26,7 +25,7 @@
@if(player.equals(logic.playerTieLogic.currentTiePlayer())) { @if(player.equals(logic.playerTieLogic.currentTiePlayer())) {
@defining(logic.playerTieLogic.highestAllowedNumber()) { maxNum => @defining(logic.playerTieLogic.highestAllowedNumber()) { maxNum =>
<div class="alert alert-info" role="alert" aria-live="polite"> <div class="alert alert-info" role="alert" aria-live="polite">
Pick a number between 1 and @maxNum. The resulting card will be your card for the cut. Pick a number between 1 and @{maxNum + 1}. The resulting card will be your card for the cut.
</div> </div>
<form class="row g-2 align-items-center" method="post" action="@routes.IngameController.playTie(gameId)"> <form class="row g-2 align-items-center" method="post" action="@routes.IngameController.playTie(gameId)">
@@ -34,29 +33,66 @@
<label for="tieNumber" class="col-form-label">Your number</label> <label for="tieNumber" class="col-form-label">Your number</label>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<input type="number" id="tieNumber" class="form-control" name="tie" min="1" max="@maxNum" placeholder="1" required> <input type="number" id="tieNumber" class="form-control" name="tie" min="1" max="@{maxNum + 1}" placeholder="1" required>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<button type="submit" class="btn btn-primary">Confirm</button> <button type="submit" class="btn btn-primary">Confirm</button>
</div> </div>
</form> </form>
<h6 class="mt-4 mb-3">Currently Picked Cards</h6>
<div id="cardsplayed" class="row g-3 justify-content-center">
@if(logic.playerTieLogic.getSelectedCard.nonEmpty) {
@for((player, card) <- logic.playerTieLogic.getSelectedCard) {
<div class="col-6">
<div class="card shadow-sm border-0 h-100 text-center">
<div class="card-body d-flex flex-column justify-content-between">
<p class="card-text fw-semibold mb-2 text-primary">@player</p>
<div class="card-img-top">
@util.WebUIUtils.cardtoImage(card)
</div>
</div>
</div>
</div>
}
} else {
<div class="col-12">
<div class="alert alert-info text-center" role="alert">
<i class="bi bi-info-circle me-2"></i>
No cards have been selected yet.
</div>
</div>
}
</div>
} }
} else { } else {
<div class="alert alert-warning" role="alert" aria-live="polite"> <div class="alert alert-warning" role="alert" aria-live="polite">
<strong>@logic.playerTieLogic.currentTiePlayer()</strong> is currently picking a number for the cut. <strong>@logic.playerTieLogic.currentTiePlayer()</strong> is currently picking a number for the cut.
</div> </div>
<h6 class="mt-3">Currently picked cards</h6> <h6 class="mt-4 mb-3">Currently Picked Cards</h6>
<div id="cardsplayed" class="row row-cols-2 row-cols-sm-3 row-cols-md-4 g-3 mt-1">
<div id="cardsplayed" class="row g-3 justify-content-center">
@if(logic.playerTieLogic.getSelectedCard.nonEmpty) {
@for((player, card) <- logic.playerTieLogic.getSelectedCard) { @for((player, card) <- logic.playerTieLogic.getSelectedCard) {
<div class="col"> <div class="col-6 col-sm-4 col-md-3 col-lg-2">
<div class="card h-100 text-center"> <div class="card shadow-sm border-0 h-100 text-center">
<div class="card-body"> <div class="card-body d-flex flex-column justify-content-between">
<p class="card-text fw-semibold mb-2">@player</p> <p class="card-text fw-semibold mb-2 text-primary">@player</p>
<div class="card-img-top">
@util.WebUIUtils.cardtoImage(card) @util.WebUIUtils.cardtoImage(card)
</div> </div>
</div> </div>
</div> </div>
</div>
}
} else {
<div class="col-12">
<div class="alert alert-info text-center" role="alert">
<i class="bi bi-info-circle me-2"></i>
No cards have been selected yet.
</div>
</div>
} }
</div> </div>
} }