multicard improvement

This commit is contained in:
Michal Vrba
2026-08-28 14:37:21 +02:00
parent 6abf0f91a0
commit 4803bc22a6
2 changed files with 86 additions and 20 deletions
+74 -23
View File
@@ -4,9 +4,8 @@
@if (SelectedCards.Count > 0 && IsMyTurn)
{
var firstSelected = SelectedCards[0];
var lastSelected = SelectedCards[SelectedCards.Count - 1];
var matchingHandCards = Player.Hand.Where(c => c.Rank == firstSelected.Rank).ToList();
var canPlayCombo = CanPlayCards(SelectedCards);
var canPlayCombo = CanPlayCards(SelectedCards) && CanPlayCard(firstSelected);
<div class="hand-combo-action-bar animate-pop">
<!-- Poradie vykladania kariet -->
@@ -44,11 +43,11 @@
else
{
<div class="combo-invalid-badge">
<span>Nemožno zahrať na stôl</span>
<span>⚠️ Prvá karta (@firstSelected.SuitName) nesedí na stôl</span>
</div>
}
<!-- Možnosť otočiť poradie kariet -->
<!-- Možnosť otočiť poradie kariet (ak je otočenie tiež legálne) -->
@if (SelectedCards.Count > 1)
{
<button class="btn btn-dark btn-combo-reverse" @onclick="ReverseSelectionOrder" title="Otočiť poradie kariet (zmení vrchnú kartu na stole)">
@@ -77,7 +76,13 @@
var card = Player.Hand[i];
var selectedIdx = SelectedCards.IndexOf(card);
var isSelected = selectedIdx >= 0;
var isPlayable = IsMyTurn && (CanPlayCard(card) || (SelectedCards.Count > 0 && SelectedCards[0].Rank == card.Rank && CanPlayCards(new List<Card> { card })));
var isSameRankAsSelected = SelectedCards.Count > 0 && SelectedCards[0].Rank == card.Rank;
// Karta je hrateľná ako 1. na stôl, ALEBO patrí do aktívneho comba rovnakej hodnoty
var isPlayable = IsMyTurn && (
(SelectedCards.Count == 0 && CanPlayCard(card)) ||
(SelectedCards.Count > 0 && isSameRankAsSelected)
);
// Výpočet vejárovitého natočenia kariet v ruke
int total = Player.Hand.Count;
@@ -87,10 +92,17 @@
double yOffset = Math.Abs(offset) * 4.0;
double xOffset = offset * (total > 8 ? 26 : 38);
string fanSlotStyle = $"transform: translateX({xOffset}px) translateY({yOffset}px) rotate({angle}deg); z-index: {(isSelected ? 120 + i : i + 1)};";
string selectedClass = isSelected ? "card-selected-combo" : "";
// Ak patrí do aktívnej skupiny rovnakej hodnoty, vysunieme ju
string slotClasses = "hand-card-slot";
if (isSameRankAsSelected && !isSelected)
{
slotClasses += " rank-group-lifted";
}
<div class="hand-card-slot" style="@fanSlotStyle">
string fanSlotStyle = $"transform: translateX({xOffset}px) translateY({yOffset}px) rotate({angle}deg); z-index: {(isSelected ? 140 + i : (isSameRankAsSelected ? 110 + i : i + 1))};";
string selectedClass = isSelected ? "card-selected-combo" : (isSameRankAsSelected ? "card-group-active" : "");
<div class="@slotClasses" style="@fanSlotStyle">
<CardView Card="card"
Deck="@Deck"
IsInteractive="@IsMyTurn"
@@ -140,30 +152,68 @@
var rankCount = Player.Hand.Count(c => c.Rank == card.Rank);
// Ak už máme vybraté karty inej hodnoty, zresetujeme výber
if (SelectedCards.Count > 0 && SelectedCards[0].Rank != card.Rank)
// 1. Ak ešte nie je nič vybraté:
if (SelectedCards.Count == 0)
{
SelectedCards.Clear();
}
// Ak má hráč v ruke len 1 kartu danej hodnoty a žiadna nie je vybratá:
if (rankCount == 1 && SelectedCards.Count == 0)
// Prvá karta MUSÍ legálne sedieť na stôl!
if (!CanPlayCard(card))
{
if (CanPlayCard(card))
{
await OnPlayCards.InvokeAsync(new List<Card> { card });
}
// Karta nemôže ísť ako prvá (napr. Žaluď na Červeň) -> nedovolíme začať s ňou
return;
}
// Ak je už karta v zozname vybratých -> odoberieme ju (deselect)
// Ak má hráč v ruke len 1 kartu danej hodnoty -> okamžite zahrať
if (rankCount == 1)
{
await OnPlayCards.InvokeAsync(new List<Card> { card });
return;
}
// Ak má viac kariet rovnakej hodnoty -> označíme túto ako 1. a vysunú sa všetky karty danej hodnoty!
SelectedCards.Add(card);
StateHasChanged();
return;
}
// 2. Ak už máme niečo vybraté z INEJ hodnoty:
if (SelectedCards[0].Rank != card.Rank)
{
// Môže táto nová karta ísť legálne na stôl ako prvá?
if (!CanPlayCard(card))
{
return;
}
SelectedCards.Clear();
if (rankCount == 1)
{
await OnPlayCards.InvokeAsync(new List<Card> { card });
return;
}
SelectedCards.Add(card);
StateHasChanged();
return;
}
// 3. Ak klikáme na kartu ROVNAKEJ hodnoty:
if (SelectedCards.Contains(card))
{
SelectedCards.Remove(card);
// Ak je to prvá a jediná vybratá karta, kliknutie ju odznačí a zruší combo
if (SelectedCards.Count == 1 && SelectedCards[0] == card)
{
SelectedCards.Clear();
}
else
{
// Pridáme na koniec zoznamu ako ďalšiu v poradí
// Odznačíme kartu zo zoznamu
SelectedCards.Remove(card);
}
}
else
{
// Pridáme do poradia ako 2., 3., 4. kartu
SelectedCards.Add(card);
}
@@ -172,6 +222,7 @@
private void ReverseSelectionOrder()
{
if (SelectedCards.Count <= 1) return;
SelectedCards.Reverse();
StateHasChanged();
}
@@ -198,7 +249,7 @@
private async Task PlaySelected()
{
if (SelectedCards.Count > 0 && CanPlayCards(SelectedCards))
if (SelectedCards.Count > 0 && CanPlayCards(SelectedCards) && CanPlayCard(SelectedCards[0]))
{
var cardsToPlay = new List<Card>(SelectedCards);
SelectedCards.Clear();
+15
View File
@@ -641,6 +641,21 @@ body, html {
filter: brightness(1.1);
}
/* Všetky karty rovnakej hodnoty sa automaticky vysunú pri otvorení comba */
.hand-card-slot.rank-group-lifted .game-card {
transform: translateY(-18px) scale(1.04);
border-color: rgba(245, 176, 65, 0.8) !important;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.6), 0 0 18px rgba(245, 176, 65, 0.6) !important;
filter: brightness(1.05);
cursor: pointer;
}
.hand-card-slot.rank-group-lifted:hover .game-card {
transform: translateY(-28px) scale(1.08);
border-color: #ffd700 !important;
box-shadow: 0 14px 32px rgba(0, 0, 0, 0.7), 0 0 22px rgba(245, 176, 65, 0.95) !important;
}
/* COMBO ACTION BAR */
.hand-combo-action-bar {
position: absolute;