improvements
This commit is contained in:
+213
-27
@@ -31,6 +31,10 @@ else
|
||||
</span>
|
||||
</div>
|
||||
<div class="game-controls">
|
||||
<!-- Rýchly prepínač rýchlosti hry (5 úrovní) -->
|
||||
<button class="btn-game-icon btn-speed-control" title="Rýchlosť hry: @GetSpeedDescription(Engine.State.Rules.SpeedLevel) (Klikni pre zmenu)" @onclick="CycleSpeed">
|
||||
@GetSpeedButtonText(Engine.State.Rules.SpeedLevel)
|
||||
</button>
|
||||
<!-- Rýchly prepínač balíčka kariet -->
|
||||
<button class="btn-game-icon" title="Zmeniť balíček kariet (@Engine.State.Rules.SelectedDeck)" @onclick="ToggleDeck">
|
||||
@GetDeckIcon(Engine.State.Rules.SelectedDeck)
|
||||
@@ -49,8 +53,14 @@ else
|
||||
<!-- Súperi na stole -->
|
||||
@foreach (var opp in GetOpponents())
|
||||
{
|
||||
var isOppFrozen = Engine.State.PendingSkip && Engine.State.CurrentPlayer == opp.Player;
|
||||
var canOppBeRevived = Engine.State.Rules.RedSevenRevives && Engine.State.LastFinishedPlayer == opp.Player && Engine.State.ReviveTurnsRemaining > 0;
|
||||
<PlayerSlot Player="@opp.Player"
|
||||
IsCurrentTurn="@(Engine.State.CurrentPlayer == opp.Player)"
|
||||
IsFrozen="@isOppFrozen"
|
||||
CanBeRevived="@canOppBeRevived"
|
||||
ReviveRoundsRemaining="@Engine.State.ReviveRoundsRemaining"
|
||||
ReviveTurnsRemaining="@Engine.State.ReviveTurnsRemaining"
|
||||
IsOlympicMode="@Engine.State.Rules.OlympicMode"
|
||||
PositionClass="@opp.PositionClass" />
|
||||
}
|
||||
@@ -74,6 +84,14 @@ else
|
||||
CustomStyle="box-shadow: 0 10px 25px rgba(0,0,0,0.7);" />
|
||||
}
|
||||
|
||||
<!-- Indikátor zmrazenia z Esa -->
|
||||
@if (Engine.State.PendingSkip)
|
||||
{
|
||||
<div class="ace-freeze-badge">
|
||||
❄️ ESO: ZMRAZENIE!
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Indikátor trestu zo sedmy -->
|
||||
@if (Engine.State.PendingDrawCount > 0)
|
||||
{
|
||||
@@ -94,23 +112,56 @@ else
|
||||
<span>@dummy.SuitName</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Indikátor Zeleného dolníka (univerzálna karta) -->
|
||||
@if (Engine.State.TopCard != null && Engine.State.TopCard.IsGreenUnderKnave && Engine.State.Rules.GreenUnderKnaveMode == GreenUnderKnaveMode.UniversalWildcard)
|
||||
{
|
||||
<div class="green-wildcard-badge">
|
||||
🍃 ZELENÝ DOLNÍK: Daj čokoľvek!
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Spodný slot: Aktívny hráč v zobrazení -->
|
||||
<div class="slot-bottom @(IsViewingPlayerTurn ? "active-turn-slot" : "")">
|
||||
<div class="avatar-badge @(IsViewingPlayerTurn ? "active-turn" : "") @(ViewingPlayer.IsSkipped ? "is-skipped" : "")"
|
||||
@{
|
||||
var isBottomFrozen = Engine.State.PendingSkip && IsViewingPlayerActiveTurn;
|
||||
var canBottomBeRevived = Engine.State.Rules.RedSevenRevives && Engine.State.LastFinishedPlayer == ViewingPlayer && Engine.State.ReviveTurnsRemaining > 0;
|
||||
}
|
||||
<div class="slot-bottom @(isBottomFrozen ? "frozen-slot" : (IsViewingPlayerActiveTurn ? "active-turn-slot" : ""))">
|
||||
<div class="avatar-badge @(isBottomFrozen ? "is-frozen" : (IsViewingPlayerActiveTurn ? "active-turn" : "")) @(ViewingPlayer.HasFinished ? "is-finished" : "") @(canBottomBeRevived && ViewingPlayer.HasFinished ? "can-be-revived" : "")"
|
||||
style="margin-bottom: 8px;">
|
||||
@if (IsViewingPlayerTurn && !ViewingPlayer.HasFinished && !ViewingPlayer.IsEliminated)
|
||||
@if (isBottomFrozen && !ViewingPlayer.HasFinished && !ViewingPlayer.IsEliminated)
|
||||
{
|
||||
<div class="frozen-indicator-badge">
|
||||
<span class="frozen-indicator-dot"></span>
|
||||
<span class="frozen-indicator-text">@(ViewingPlayer.Type == PlayerType.Human ? "❄️ STOJÍŠ TOTO KOLO" : "❄️ ZMRAZENÝ")</span>
|
||||
</div>
|
||||
}
|
||||
else if (IsViewingPlayerActiveTurn && !ViewingPlayer.HasFinished && !ViewingPlayer.IsEliminated)
|
||||
{
|
||||
<div class="turn-indicator-badge">
|
||||
<span class="turn-indicator-dot"></span>
|
||||
<span class="turn-indicator-text">SI NA ŤAHU</span>
|
||||
<span class="turn-indicator-text">@(ViewingPlayer.Type == PlayerType.Human ? "SI NA ŤAHU" : "NA ŤAHU")</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (ViewingPlayer.HasFinished)
|
||||
{
|
||||
<div class="badge-finished-pos">
|
||||
@ViewingPlayer.FinishedPosition
|
||||
</div>
|
||||
}
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 8px;">
|
||||
<span class="avatar-icon">@ViewingPlayer.Avatar</span>
|
||||
<span class="avatar-name">@ViewingPlayer.Name</span>
|
||||
<span class="avatar-name">
|
||||
@ViewingPlayer.Name
|
||||
@if (ViewingPlayer.Type == PlayerType.AI)
|
||||
{
|
||||
<span style="font-size: 0.7rem; opacity: 0.8;">(AI)</span>
|
||||
}
|
||||
</span>
|
||||
<span class="avatar-card-count">(@ViewingPlayer.Hand.Count @(ViewingPlayer.Hand.Count == 1 ? "karta" : (ViewingPlayer.Hand.Count < 5 ? "karty" : "kariet")))</span>
|
||||
@if (Engine.State.Rules.OlympicMode)
|
||||
{
|
||||
@@ -119,6 +170,29 @@ else
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (isBottomFrozen && !ViewingPlayer.HasFinished && !ViewingPlayer.IsEliminated)
|
||||
{
|
||||
<div class="icicles-row">
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
<span class="icicle"></span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (canBottomBeRevived && ViewingPlayer.HasFinished)
|
||||
{
|
||||
<div class="revive-countdown-badge" title="Tento hráč môže byť vrátený do hry Červenou sedmou!">
|
||||
<span class="heartbeat-icon">❤️</span>
|
||||
<span>
|
||||
@(Engine.State.ReviveRoundsRemaining > 1 ? $"Oživenie: {Engine.State.ReviveRoundsRemaining} kolá" : (Engine.State.ReviveTurnsRemaining <= 1 ? "Oživenie: 1 ťah" : "Oživenie: 1 kolo"))
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- Interaktívna ruka hráča -->
|
||||
@@ -232,17 +306,24 @@ else
|
||||
return Engine.State.CurrentPlayer;
|
||||
}
|
||||
|
||||
// Inak primárne prvého živého hráča v hre
|
||||
// Inak primárne prvého živého človeka v hre
|
||||
var firstHuman = Engine.State.Players.FirstOrDefault(p => p.Type == PlayerType.Human);
|
||||
return firstHuman ?? Engine.State.CurrentPlayer;
|
||||
if (firstHuman != null) return firstHuman;
|
||||
|
||||
// Ak sú všetci hráči AI, spodný hráč je PEVNE prvý hráč (Players[0]), aby sa stôl a rozmiestnenie nemenili
|
||||
return Engine.State.Players[0];
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsViewingPlayerTurn =>
|
||||
private bool IsViewingPlayerActiveTurn =>
|
||||
Engine != null &&
|
||||
Engine.State.TurnState == TurnState.Playing &&
|
||||
Engine.State.CurrentPlayer == ViewingPlayer;
|
||||
|
||||
private bool IsViewingPlayerTurn =>
|
||||
IsViewingPlayerActiveTurn &&
|
||||
ViewingPlayer.Type == PlayerType.Human;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
@@ -269,6 +350,7 @@ else
|
||||
Engine.StartGame(gamePlayers, ConfiguredRules);
|
||||
|
||||
_previousTurnPlayer = Engine.State.CurrentPlayer;
|
||||
_ = Fx.SetSpeedLevelAsync(Engine.State.Rules.SpeedLevel);
|
||||
IsInLobby = false;
|
||||
LastEventMessage = "Hra začala! Veľa šťastia.";
|
||||
|
||||
@@ -294,9 +376,29 @@ else
|
||||
await Fx.PlaySevenStackAsync(Math.Max(1, e.ExtraData / 3));
|
||||
await Fx.TriggerDopamineBannerAsync($"🔥 +{e.ExtraData} KARIET!", "Trestná reťaz sediem", "triple");
|
||||
break;
|
||||
case GameEventType.SevenCanceled:
|
||||
await Fx.PlayLeafShieldAsync();
|
||||
await Fx.TriggerDopamineBannerAsync("🍃 TREST ZRUŠENÝ!", $"{e.SourcePlayer?.Name ?? "Hráč"} zrušil trest Zeleným dolníkom!", "triple");
|
||||
break;
|
||||
case GameEventType.AceSkipped:
|
||||
if (e.Message.Contains("stojí toto kolo"))
|
||||
{
|
||||
if (e.SourcePlayer != null)
|
||||
{
|
||||
await Fx.TriggerIceShatterAsync(GetPlayerPosition(e.SourcePlayer));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await Fx.TriggerFreezeEffectAsync();
|
||||
}
|
||||
break;
|
||||
case GameEventType.AceCountered:
|
||||
await Fx.TriggerFreezeEffectAsync();
|
||||
if (e.SourcePlayer != null)
|
||||
{
|
||||
await Fx.TriggerIceShatterAsync(GetPlayerPosition(e.SourcePlayer));
|
||||
await Fx.TriggerDopamineBannerAsync("⚡ ROZMRAZENÝ!", $"{e.SourcePlayer.Name} prebil Eso vlastným Esom!", "revive");
|
||||
}
|
||||
break;
|
||||
case GameEventType.PlayerRevived:
|
||||
await Fx.TriggerReviveEffectAsync(e.TargetPlayer?.Name ?? e.SourcePlayer?.Name ?? "Hráč");
|
||||
@@ -353,6 +455,44 @@ else
|
||||
|
||||
private static readonly string[] AvailableDecks = new[] { "original", "janosik", "spongebob", "cyberpunk", "fantasy", "egypt", "pets", "pixel" };
|
||||
|
||||
private int MultiCardDelayMs => Engine?.State.Rules.SpeedLevel switch
|
||||
{
|
||||
1 => 130,
|
||||
2 => 105,
|
||||
4 => 50,
|
||||
5 => 25,
|
||||
_ => 80
|
||||
};
|
||||
|
||||
private async Task CycleSpeed()
|
||||
{
|
||||
if (Engine == null) return;
|
||||
int next = (Engine.State.Rules.SpeedLevel % 5) + 1;
|
||||
Engine.State.Rules.SpeedLevel = next;
|
||||
await Fx.SetSpeedLevelAsync(next);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string GetSpeedButtonText(int level) => level switch
|
||||
{
|
||||
1 => "🐢 0.5x",
|
||||
2 => "🚶 0.75x",
|
||||
3 => "⚡ 1x",
|
||||
4 => "🔥 1.5x",
|
||||
5 => "🚀 2.5x",
|
||||
_ => "⚡ 1x"
|
||||
};
|
||||
|
||||
private string GetSpeedDescription(int level) => level switch
|
||||
{
|
||||
1 => "0.5x (Pomalá)",
|
||||
2 => "0.75x (Pokojná)",
|
||||
3 => "1x (Normálna - stredná)",
|
||||
4 => "1.5x (Rýchla)",
|
||||
5 => "2.5x (Turbo / Blesková)",
|
||||
_ => "1x (Normálna)"
|
||||
};
|
||||
|
||||
private void ToggleDeck()
|
||||
{
|
||||
if (Engine == null) return;
|
||||
@@ -393,10 +533,17 @@ else
|
||||
_ = Fx.TriggerComboSlamAsync(4, "👑 KVADRA / MEGA COMBO!");
|
||||
}
|
||||
|
||||
foreach (var card in cards)
|
||||
for (int i = 0; i < cards.Count; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, card, deck);
|
||||
if (cards.Count > 1) await Task.Delay(90);
|
||||
if (i == cards.Count - 1)
|
||||
{
|
||||
await Fx.AnimateCardPlayAsync(pos, cards[i], deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, cards[i], deck);
|
||||
await Task.Delay(MultiCardDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
Engine.PlayCards(ViewingPlayer, cards);
|
||||
@@ -412,10 +559,19 @@ else
|
||||
|
||||
if (Engine.State.PendingDrawCount > 0)
|
||||
{
|
||||
for (int i = 0; i < Math.Min(Engine.State.PendingDrawCount, 4); i++)
|
||||
int drawCount = Engine.State.PendingDrawCount;
|
||||
int staggerDelay = Math.Max(25, (int)(MultiCardDelayMs * 0.75));
|
||||
for (int i = 0; i < drawCount; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardDrawAsync(pos, deck);
|
||||
await Task.Delay(90);
|
||||
if (i == drawCount - 1)
|
||||
{
|
||||
await Fx.AnimateCardDrawAsync(pos, deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardDrawAsync(pos, deck);
|
||||
await Task.Delay(staggerDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!Engine.State.PendingSkip)
|
||||
@@ -460,10 +616,17 @@ else
|
||||
{
|
||||
string pos = GetPlayerPosition(ViewingPlayer);
|
||||
string deck = Engine.State.Rules.SelectedDeck;
|
||||
foreach (var c in cards)
|
||||
for (int i = 0; i < cards.Count; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, c, deck);
|
||||
await Task.Delay(75);
|
||||
if (i == cards.Count - 1)
|
||||
{
|
||||
await Fx.AnimateCardPlayAsync(pos, cards[i], deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, cards[i], deck);
|
||||
await Task.Delay(MultiCardDelayMs);
|
||||
}
|
||||
}
|
||||
Engine.BurnCards(ViewingPlayer, cards);
|
||||
StateHasChanged();
|
||||
@@ -523,20 +686,34 @@ else
|
||||
_ = Fx.TriggerComboSlamAsync(4, $"👑 {aiPlayer.Name}: KVADRA!");
|
||||
}
|
||||
|
||||
foreach (var c in cardsToPlay)
|
||||
for (int i = 0; i < cardsToPlay.Count; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, c, deck);
|
||||
if (cardsToPlay.Count > 1) await Task.Delay(85);
|
||||
if (i == cardsToPlay.Count - 1)
|
||||
{
|
||||
await Fx.AnimateCardPlayAsync(pos, cardsToPlay[i], deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, cardsToPlay[i], deck);
|
||||
await Task.Delay(MultiCardDelayMs);
|
||||
}
|
||||
}
|
||||
Engine.PlayCards(aiPlayer, cardsToPlay, decision.ChosenSuit);
|
||||
}
|
||||
}
|
||||
else if (decision.Type == AIDecisionType.BurnCards && decision.Cards != null)
|
||||
{
|
||||
foreach (var c in decision.Cards)
|
||||
for (int i = 0; i < decision.Cards.Count; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, c, deck);
|
||||
await Task.Delay(75);
|
||||
if (i == decision.Cards.Count - 1)
|
||||
{
|
||||
await Fx.AnimateCardPlayAsync(pos, decision.Cards[i], deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardPlayAsync(pos, decision.Cards[i], deck);
|
||||
await Task.Delay(MultiCardDelayMs);
|
||||
}
|
||||
}
|
||||
Engine.BurnCards(aiPlayer, decision.Cards);
|
||||
}
|
||||
@@ -544,10 +721,19 @@ else
|
||||
{
|
||||
if (Engine.State.PendingDrawCount > 0)
|
||||
{
|
||||
for (int i = 0; i < Math.Min(Engine.State.PendingDrawCount, 4); i++)
|
||||
int drawCount = Engine.State.PendingDrawCount;
|
||||
int staggerDelay = Math.Max(25, (int)(MultiCardDelayMs * 0.75));
|
||||
for (int i = 0; i < drawCount; i++)
|
||||
{
|
||||
_ = Fx.AnimateCardDrawAsync(pos, deck);
|
||||
await Task.Delay(90);
|
||||
if (i == drawCount - 1)
|
||||
{
|
||||
await Fx.AnimateCardDrawAsync(pos, deck);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = Fx.AnimateCardDrawAsync(pos, deck);
|
||||
await Task.Delay(staggerDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!Engine.State.PendingSkip)
|
||||
|
||||
Reference in New Issue
Block a user