776 lines
25 KiB
C#
776 lines
25 KiB
C#
namespace Faraon.Core.Engine;
|
|
|
|
using Faraon.Core.Models;
|
|
|
|
public class GameEngine
|
|
{
|
|
private readonly Deck _deckManager;
|
|
public GameState State { get; }
|
|
|
|
public event Action<GameEvent>? OnGameEvent;
|
|
|
|
public GameEngine(int? seed = null)
|
|
{
|
|
_deckManager = new Deck(seed);
|
|
State = new GameState();
|
|
}
|
|
|
|
public void StartGame(List<Player> players, RuleOptions rules)
|
|
{
|
|
if (players.Count < 2 || players.Count > 4)
|
|
{
|
|
throw new ArgumentException("Hra Faraón vyžaduje 2 až 4 hráčov.", nameof(players));
|
|
}
|
|
|
|
State.Players = players;
|
|
State.Rules = rules;
|
|
State.IsGameOver = false;
|
|
State.IsMatchOver = false;
|
|
State.IsRoundOver = false;
|
|
State.MatchWinner = null;
|
|
State.RoundLoser = null;
|
|
State.RoundNumber = 1;
|
|
State.LastFinishedPlayer = null;
|
|
State.ReviveTurnsRemaining = 0;
|
|
State.ReviveRoundsRemaining = 0;
|
|
State.ReviveWindowInitialTurns = 0;
|
|
State.TurnCount = 1;
|
|
State.PendingDrawCount = 0;
|
|
State.PendingSkip = false;
|
|
State.ActiveSuit = null;
|
|
State.PendingHornikPlayer = null;
|
|
State.TurnState = TurnState.Playing;
|
|
|
|
foreach (var player in State.Players)
|
|
{
|
|
player.OlympicCardsCount = State.Rules.InitialCardCount;
|
|
player.Reset();
|
|
}
|
|
|
|
// Vytvorenie a zamiešanie balíčka
|
|
State.DrawDeck = _deckManager.CreateShuffledDeck();
|
|
State.DiscardPile.Clear();
|
|
|
|
// Rozdanie kariet každému aktívnemu hráčovi podľa jeho OlympicCardsCount
|
|
foreach (var player in State.ActiveTournamentPlayers)
|
|
{
|
|
for (int i = 0; i < player.OlympicCardsCount; i++)
|
|
{
|
|
if (State.DrawDeck.Count > 0)
|
|
{
|
|
var card = State.DrawDeck[0];
|
|
State.DrawDeck.RemoveAt(0);
|
|
player.Hand.Add(card);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otočenie prvej karty na odhadzovaciu kôpku
|
|
var startCard = State.DrawDeck[0];
|
|
State.DrawDeck.RemoveAt(0);
|
|
State.DiscardPile.Add(startCard);
|
|
|
|
State.CurrentPlayerIndex = 0;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.GameStarted,
|
|
State.CurrentPlayer,
|
|
Card: startCard,
|
|
Message: "Hra sa začala!"
|
|
));
|
|
}
|
|
|
|
public bool CanPlayCard(Player player, Card card)
|
|
{
|
|
if (State.IsGameOver || State.TurnState != TurnState.Playing) return false;
|
|
if (player != State.CurrentPlayer) return false;
|
|
if (!player.Hand.Contains(card)) return false;
|
|
|
|
return ActionValidator.CanPlayCard(
|
|
card,
|
|
State.TopCard,
|
|
State.ActiveSuit,
|
|
State.PendingDrawCount,
|
|
State.PendingSkip,
|
|
State.Rules
|
|
);
|
|
}
|
|
|
|
public bool CanBurnCards(Player player, List<Card> cards)
|
|
{
|
|
if (State.IsGameOver || State.TurnState != TurnState.Playing) return false;
|
|
if (player != State.CurrentPlayer) return false;
|
|
if (cards.Any(c => !player.Hand.Contains(c))) return false;
|
|
|
|
return ActionValidator.CanBurnCards(
|
|
cards,
|
|
State.PendingDrawCount,
|
|
State.PendingSkip,
|
|
State.Rules
|
|
);
|
|
}
|
|
|
|
public bool CanPlayCards(Player player, List<Card> cards)
|
|
{
|
|
if (State.IsGameOver || State.TurnState != TurnState.Playing) return false;
|
|
if (player != State.CurrentPlayer) return false;
|
|
if (cards == null || cards.Count == 0) return false;
|
|
if (cards.Any(c => !player.Hand.Contains(c))) return false;
|
|
|
|
return ActionValidator.CanPlayCards(
|
|
cards,
|
|
State.TopCard,
|
|
State.ActiveSuit,
|
|
State.PendingDrawCount,
|
|
State.PendingSkip,
|
|
State.Rules
|
|
);
|
|
}
|
|
|
|
public bool PlayCards(Player player, List<Card> cards, Suit? chosenSuit = null)
|
|
{
|
|
if (!CanPlayCards(player, cards)) return false;
|
|
|
|
if (cards.Count == 1)
|
|
{
|
|
return PlayCard(player, cards[0], chosenSuit);
|
|
}
|
|
|
|
// 4 rovnaké karty pri pravidle spálenia
|
|
if (cards.Count == 4 && State.Rules.FourOfAKindBurns && State.PendingDrawCount == 0 && !State.PendingSkip)
|
|
{
|
|
return BurnCards(player, cards);
|
|
}
|
|
|
|
// Zoradíme karty tak, aby prvá vyložená karta legálne sadla na stôl a posledná ostala na vrchu
|
|
List<Card> orderedCards;
|
|
if (ActionValidator.CanPlayCard(cards[0], State.TopCard, State.ActiveSuit, State.PendingDrawCount, State.PendingSkip, State.Rules))
|
|
{
|
|
// Prvá karta zvolená hráčom priamo sedí na stôl -> zachováme presné poradie hráča
|
|
orderedCards = new List<Card>(cards);
|
|
}
|
|
else
|
|
{
|
|
// Nájdeme kartu, ktorá legálne viaže combo na stôl, a dáme ju na začiatok
|
|
var matching = cards.FirstOrDefault(c => ActionValidator.CanPlayCard(
|
|
c, State.TopCard, State.ActiveSuit, State.PendingDrawCount, State.PendingSkip, State.Rules)) ?? cards[0];
|
|
|
|
orderedCards = new List<Card> { matching };
|
|
foreach (var c in cards)
|
|
{
|
|
if (c != matching)
|
|
{
|
|
orderedCards.Add(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var c in orderedCards)
|
|
{
|
|
player.Hand.Remove(c);
|
|
State.DiscardPile.Add(c);
|
|
}
|
|
|
|
var firstRank = cards[0].Rank;
|
|
State.ActiveSuit = null;
|
|
|
|
// Efekt Horníkov
|
|
if (firstRank == Rank.OverKnave)
|
|
{
|
|
if (chosenSuit.HasValue)
|
|
{
|
|
State.ActiveSuit = chosenSuit.Value;
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SuitChanged,
|
|
player,
|
|
Cards: cards,
|
|
ChosenSuit: chosenSuit.Value,
|
|
Message: $"{player.Name} zahral {cards.Count}x Horníka a zmenil farbu!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
State.TurnState = TurnState.SelectingSuit;
|
|
State.PendingHornikPlayer = player;
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardPlayed,
|
|
player,
|
|
Cards: cards,
|
|
Message: $"{player.Name} zahral {cards.Count}x Horníka a vyberá farbu..."
|
|
));
|
|
return true;
|
|
}
|
|
}
|
|
// Efekt Sediem
|
|
else if (firstRank == Rank.Seven)
|
|
{
|
|
int addedPenalty = cards.Count * 3;
|
|
State.PendingDrawCount += addedPenalty;
|
|
|
|
var redSeven = cards.FirstOrDefault(c => c.IsRedSeven);
|
|
if (redSeven != null && State.Rules.RedSevenRevives && State.LastFinishedPlayer != null && State.LastFinishedPlayer != player && State.ReviveTurnsRemaining > 0)
|
|
{
|
|
var revived = State.LastFinishedPlayer;
|
|
revived.FinishedPosition = null;
|
|
State.LastFinishedPlayer = null;
|
|
State.ReviveTurnsRemaining = 0;
|
|
State.ReviveRoundsRemaining = 0;
|
|
DrawCardsForPlayer(revived, 3);
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.PlayerRevived,
|
|
player,
|
|
TargetPlayer: revived,
|
|
Cards: cards,
|
|
ExtraData: 3,
|
|
Message: $"🔥 {player.Name} zahral combo {cards.Count}x Sedma a vrátil hráča {revived.Name} späť do hry!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SevenStacked,
|
|
player,
|
|
Cards: cards,
|
|
ExtraData: State.PendingDrawCount,
|
|
Message: $"⚡ COMBO {cards.Count}x Sedma! Trest stúpol na {State.PendingDrawCount} kariet!"
|
|
));
|
|
}
|
|
}
|
|
// Efekt Es
|
|
else if (firstRank == Rank.Ace)
|
|
{
|
|
bool wasPending = State.PendingSkip;
|
|
State.PendingSkip = true;
|
|
|
|
if (wasPending)
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.AceCountered,
|
|
player,
|
|
Cards: cards,
|
|
Message: $"❄️ {player.Name} prebil Eso {cards.Count}x Esom!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.AceSkipped,
|
|
player,
|
|
Cards: cards,
|
|
Message: $"❄️ COMBO {cards.Count}x Eso! Ďalší hráč stojí."
|
|
));
|
|
}
|
|
}
|
|
// Efekt Zeleného dolníka (rušenie sediem)
|
|
else if (firstRank == Rank.UnderKnave && cards.Any(c => c.IsGreenUnderKnave) && State.Rules.GreenUnderKnaveCancelsSevens && State.PendingDrawCount > 0)
|
|
{
|
|
int canceled = State.PendingDrawCount;
|
|
State.PendingDrawCount = 0;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SevenCanceled,
|
|
player,
|
|
Cards: cards,
|
|
ExtraData: canceled,
|
|
Message: $"🍃 {player.Name} zahral Zeleného dolníka a ZRUŠIL trest {canceled} kariet!"
|
|
));
|
|
}
|
|
// Ostatné karty
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardPlayed,
|
|
player,
|
|
Cards: cards,
|
|
Message: $"{player.Name} zahral combo {cards.Count}x {cards[0].RankName}!"
|
|
));
|
|
}
|
|
|
|
CheckPlayerFinish(player);
|
|
AdvanceTurn();
|
|
return true;
|
|
}
|
|
|
|
public bool PlayCard(Player player, Card card, Suit? chosenSuit = null)
|
|
{
|
|
if (!CanPlayCard(player, card)) return false;
|
|
|
|
// Odstránenie z ruky
|
|
player.Hand.Remove(card);
|
|
State.DiscardPile.Add(card);
|
|
|
|
// Ak bola predtým zmenená farba, zrušíme ju (alebo prepíšeme novým horníkom)
|
|
State.ActiveSuit = null;
|
|
|
|
// Efekt Horníka
|
|
if (card.IsHornik)
|
|
{
|
|
if (chosenSuit.HasValue)
|
|
{
|
|
State.ActiveSuit = chosenSuit.Value;
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SuitChanged,
|
|
player,
|
|
Card: card,
|
|
ChosenSuit: chosenSuit.Value,
|
|
Message: $"{player.Name} zahral Horníka a zmenil farbu na {card.SuitName}!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
// Čakáme na výber farby
|
|
State.TurnState = TurnState.SelectingSuit;
|
|
State.PendingHornikPlayer = player;
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardPlayed,
|
|
player,
|
|
Card: card,
|
|
Message: $"{player.Name} zahral Horníka a vyberá farbu..."
|
|
));
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardPlayed,
|
|
player,
|
|
Card: card,
|
|
Message: $"{player.Name} zahral {card.Name}."
|
|
));
|
|
}
|
|
|
|
// Efekt Sedmy
|
|
if (card.IsSeven)
|
|
{
|
|
State.PendingDrawCount += 3;
|
|
|
|
// Červená sedma vracia do hry
|
|
if (card.IsRedSeven && State.Rules.RedSevenRevives && State.LastFinishedPlayer != null && State.LastFinishedPlayer != player && State.ReviveTurnsRemaining > 0)
|
|
{
|
|
var revived = State.LastFinishedPlayer;
|
|
revived.FinishedPosition = null;
|
|
State.LastFinishedPlayer = null;
|
|
State.ReviveTurnsRemaining = 0;
|
|
State.ReviveRoundsRemaining = 0;
|
|
|
|
// Doberie 3 karty
|
|
DrawCardsForPlayer(revived, 3);
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.PlayerRevived,
|
|
player,
|
|
TargetPlayer: revived,
|
|
Card: card,
|
|
ExtraData: 3,
|
|
Message: $"🔥 {player.Name} zahral Červenú sedmu a vrátil hráča {revived.Name} späť do hry!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SevenStacked,
|
|
player,
|
|
Card: card,
|
|
ExtraData: State.PendingDrawCount,
|
|
Message: $"⚡ Sedma! Ďalší hráč berie {State.PendingDrawCount} {(State.PendingDrawCount < 5 ? "karty" : "kariet")}."
|
|
));
|
|
}
|
|
}
|
|
|
|
// Efekt Esa
|
|
if (card.IsAce)
|
|
{
|
|
if (State.PendingSkip)
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.AceCountered,
|
|
player,
|
|
Card: card,
|
|
Message: $"❄️ {player.Name} prebil Eso vlastným Esom!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.AceSkipped,
|
|
player,
|
|
Card: card,
|
|
Message: $"❄️ Eso! Ďalší hráč jedno kolo stojí."
|
|
));
|
|
}
|
|
State.PendingSkip = true;
|
|
}
|
|
|
|
// Efekt Zeleného dolníka (rušenie sediem)
|
|
if (card.IsGreenUnderKnave && State.Rules.GreenUnderKnaveCancelsSevens && State.PendingDrawCount > 0)
|
|
{
|
|
int canceled = State.PendingDrawCount;
|
|
State.PendingDrawCount = 0;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SevenCanceled,
|
|
player,
|
|
Card: card,
|
|
ExtraData: canceled,
|
|
Message: $"🍃 {player.Name} zahral Zeleného dolníka a ZRUŠIL trest {canceled} kariet!"
|
|
));
|
|
}
|
|
|
|
// Kontrola, či hráč vyhral / skončil
|
|
CheckPlayerFinish(player);
|
|
|
|
// Posun na ďalšieho hráča
|
|
AdvanceTurn();
|
|
return true;
|
|
}
|
|
|
|
public bool ChooseSuit(Player player, Suit suit)
|
|
{
|
|
if (State.TurnState != TurnState.SelectingSuit || State.PendingHornikPlayer != player)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
State.ActiveSuit = suit;
|
|
State.TurnState = TurnState.Playing;
|
|
State.PendingHornikPlayer = null;
|
|
|
|
var dummyCard = new Card(suit, Rank.OverKnave);
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.SuitChanged,
|
|
player,
|
|
ChosenSuit: suit,
|
|
Message: $"{player.Name} zmenil farbu na {dummyCard.SuitName} ({dummyCard.SuitSymbol})!"
|
|
));
|
|
|
|
// Kontrola, či hráč vyhodením Horníka skončil
|
|
CheckPlayerFinish(player);
|
|
|
|
AdvanceTurn();
|
|
return true;
|
|
}
|
|
|
|
public bool BurnCards(Player player, List<Card> cards)
|
|
{
|
|
if (!CanBurnCards(player, cards)) return false;
|
|
|
|
var rank = cards[0].Rank;
|
|
foreach (var c in cards)
|
|
{
|
|
player.Hand.Remove(c);
|
|
State.DiscardPile.Add(c);
|
|
}
|
|
|
|
State.ActiveSuit = null;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardsBurned,
|
|
player,
|
|
Cards: cards,
|
|
Message: $"💥 SPÁLENIE! {player.Name} spálil 4x {cards[0].RankName} a hrá znova!"
|
|
));
|
|
|
|
CheckPlayerFinish(player);
|
|
|
|
// Pri spálení hráč pokračuje vo svojom ťahu (nevolá sa AdvanceTurn)
|
|
return true;
|
|
}
|
|
|
|
public void DrawOrAcknowledge(Player player)
|
|
{
|
|
if (State.IsGameOver || State.TurnState != TurnState.Playing) return;
|
|
if (player != State.CurrentPlayer) return;
|
|
|
|
if (State.PendingDrawCount > 0)
|
|
{
|
|
int count = State.PendingDrawCount;
|
|
State.PendingDrawCount = 0;
|
|
DrawCardsForPlayer(player, count);
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardDrawn,
|
|
player,
|
|
ExtraData: count,
|
|
Message: $"{player.Name} si potiahol {count} trestné karty zo sedmy."
|
|
));
|
|
AdvanceTurn();
|
|
}
|
|
else if (State.PendingSkip)
|
|
{
|
|
State.PendingSkip = false;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.AceSkipped,
|
|
player,
|
|
Message: $"{player.Name} stojí toto kolo kvôli Esu."
|
|
));
|
|
AdvanceTurn();
|
|
}
|
|
else
|
|
{
|
|
// Bežné potiahnutie 1 karty
|
|
DrawCardsForPlayer(player, 1);
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.CardDrawn,
|
|
player,
|
|
ExtraData: 1,
|
|
Message: $"{player.Name} si potiahol kartu z balíčka."
|
|
));
|
|
AdvanceTurn();
|
|
}
|
|
}
|
|
|
|
public void ContinueFromPassScreen()
|
|
{
|
|
if (State.TurnState == TurnState.PassScreen)
|
|
{
|
|
State.TurnState = TurnState.Playing;
|
|
}
|
|
}
|
|
|
|
private void DrawCardsForPlayer(Player player, int count)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
EnsureDrawDeckHasCards();
|
|
if (State.DrawDeck.Count > 0)
|
|
{
|
|
var card = State.DrawDeck[0];
|
|
State.DrawDeck.RemoveAt(0);
|
|
player.Hand.Add(card);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureDrawDeckHasCards()
|
|
{
|
|
if (State.DrawDeck.Count > 0) return;
|
|
|
|
// Ak je balíček prázdny, vezmeme odhadzovaciu kôpku okrem vrchnej karty
|
|
if (State.DiscardPile.Count > 1)
|
|
{
|
|
var topCard = State.DiscardPile[^1];
|
|
var cardsToRecycle = State.DiscardPile.Take(State.DiscardPile.Count - 1).ToList();
|
|
State.DiscardPile.Clear();
|
|
State.DiscardPile.Add(topCard);
|
|
|
|
_deckManager.Shuffle(cardsToRecycle);
|
|
State.DrawDeck.AddRange(cardsToRecycle);
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.DeckReshuffled,
|
|
null,
|
|
Message: "Lízací balíček bol premiešaný z odhadzovacej kôpky."
|
|
));
|
|
}
|
|
}
|
|
|
|
private void CheckPlayerFinish(Player player)
|
|
{
|
|
if (player.Hand.Count == 0 && !player.HasFinished)
|
|
{
|
|
int nextPos = State.Players.Count(p => p.HasFinished) + 1;
|
|
player.FinishedPosition = nextPos;
|
|
|
|
if (State.Rules.RedSevenRevives)
|
|
{
|
|
State.LastFinishedPlayer = player;
|
|
int maxRounds = State.Rules.RedSevenMode == RedSevenMode.ColorOrSevenThreeRounds ? 3 : 1;
|
|
int activeCount = Math.Max(1, State.ActivePlayersCount);
|
|
State.ReviveRoundsRemaining = maxRounds;
|
|
State.ReviveTurnsRemaining = maxRounds * activeCount;
|
|
State.ReviveWindowInitialTurns = State.ReviveTurnsRemaining;
|
|
}
|
|
else
|
|
{
|
|
State.LastFinishedPlayer = null;
|
|
State.ReviveRoundsRemaining = 0;
|
|
State.ReviveTurnsRemaining = 0;
|
|
}
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.PlayerFinished,
|
|
player,
|
|
ExtraData: nextPos,
|
|
Message: $"🏆 {player.Name} sa zbavil všetkých kariet a obsadil {nextPos}. miesto!"
|
|
));
|
|
|
|
CheckGameOver();
|
|
}
|
|
}
|
|
|
|
private void CheckGameOver()
|
|
{
|
|
int remaining = State.ActivePlayersCount;
|
|
if (remaining <= 1)
|
|
{
|
|
// Zostávajúci hráč, ktorému ostali karty (porazený tohto kola)
|
|
var lastPlayer = State.ActiveTournamentPlayers.FirstOrDefault(p => !p.HasFinished);
|
|
if (lastPlayer != null)
|
|
{
|
|
lastPlayer.FinishedPosition = State.ActiveTournamentPlayers.Count;
|
|
State.RoundLoser = lastPlayer;
|
|
}
|
|
|
|
if (State.Rules.OlympicMode)
|
|
{
|
|
if (lastPlayer != null)
|
|
{
|
|
lastPlayer.OlympicCardsCount--;
|
|
if (lastPlayer.IsEliminated)
|
|
{
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.PlayerEliminated,
|
|
lastPlayer,
|
|
Message: $"☠️ {lastPlayer.Name} stratil všetky karty a vypadáva z Olympijského turnaja!"
|
|
));
|
|
}
|
|
}
|
|
|
|
var remainingTournamentPlayers = State.ActiveTournamentPlayers;
|
|
if (remainingTournamentPlayers.Count <= 1)
|
|
{
|
|
// Koniec turnaja! Zostal iba 1 víťaz
|
|
State.IsGameOver = true;
|
|
State.IsMatchOver = true;
|
|
State.MatchWinner = remainingTournamentPlayers.FirstOrDefault() ?? lastPlayer;
|
|
State.TurnState = TurnState.GameOver;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.MatchWon,
|
|
State.MatchWinner,
|
|
Message: $"🥇 {State.MatchWinner?.Name} sa stal celkovým OLYMPIJSKÝM ŠAMPIÓNOM!"
|
|
));
|
|
}
|
|
else
|
|
{
|
|
// Koniec jedného kola, nasleduje ďalšie
|
|
State.IsRoundOver = true;
|
|
State.TurnState = TurnState.RoundOver;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.RoundOver,
|
|
lastPlayer,
|
|
ExtraData: State.RoundNumber,
|
|
Message: $"🏅 Kolo #{State.RoundNumber} sa skončilo! {lastPlayer?.Name} bude mať v ďalšom kole {lastPlayer?.OlympicCardsCount} kariet."
|
|
));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Bežná jednoduchá hra
|
|
State.IsGameOver = true;
|
|
State.TurnState = TurnState.GameOver;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.GameOver,
|
|
null,
|
|
Message: "Koniec hry! Všetky pozície sú určené."
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void StartNextRound()
|
|
{
|
|
if (!State.Rules.OlympicMode || State.IsMatchOver) return;
|
|
|
|
State.RoundNumber++;
|
|
State.IsRoundOver = false;
|
|
State.IsGameOver = false;
|
|
State.RoundLoser = null;
|
|
State.TurnState = TurnState.Playing;
|
|
State.TurnCount = 1;
|
|
State.PendingDrawCount = 0;
|
|
State.PendingSkip = false;
|
|
State.ActiveSuit = null;
|
|
State.PendingHornikPlayer = null;
|
|
|
|
foreach (var p in State.Players)
|
|
{
|
|
p.Reset();
|
|
}
|
|
|
|
// Vytvorenie a zamiešanie nového balíčka
|
|
State.DrawDeck = _deckManager.CreateShuffledDeck();
|
|
State.DiscardPile.Clear();
|
|
|
|
// Rozdanie kariet len aktívnym (nevyradeným) hráčom podľa ich OlympicCardsCount
|
|
foreach (var player in State.ActiveTournamentPlayers)
|
|
{
|
|
for (int i = 0; i < player.OlympicCardsCount; i++)
|
|
{
|
|
if (State.DrawDeck.Count > 0)
|
|
{
|
|
var card = State.DrawDeck[0];
|
|
State.DrawDeck.RemoveAt(0);
|
|
player.Hand.Add(card);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Otočenie prvej karty na odhadzovaciu kôpku
|
|
var startCard = State.DrawDeck[0];
|
|
State.DrawDeck.RemoveAt(0);
|
|
State.DiscardPile.Add(startCard);
|
|
|
|
// Nastavíme prvého hráča na prvého aktívneho
|
|
var firstActiveIndex = State.Players.FindIndex(p => !p.IsEliminated);
|
|
State.CurrentPlayerIndex = firstActiveIndex >= 0 ? firstActiveIndex : 0;
|
|
|
|
EmitEvent(new GameEvent(
|
|
GameEventType.GameStarted,
|
|
State.CurrentPlayer,
|
|
Card: startCard,
|
|
Message: $"🏅 Začalo sa Kolo #{State.RoundNumber} Olympijského Faraóna!"
|
|
));
|
|
}
|
|
|
|
private void AdvanceTurn()
|
|
{
|
|
if (State.IsGameOver || State.IsRoundOver) return;
|
|
|
|
// Odpočet lehoty na oživenie
|
|
if (State.LastFinishedPlayer != null && State.ReviveTurnsRemaining > 0)
|
|
{
|
|
State.ReviveTurnsRemaining--;
|
|
int activeCount = Math.Max(1, State.ActivePlayersCount);
|
|
State.ReviveRoundsRemaining = (int)Math.Ceiling((double)State.ReviveTurnsRemaining / activeCount);
|
|
|
|
if (State.ReviveTurnsRemaining <= 0)
|
|
{
|
|
State.LastFinishedPlayer = null;
|
|
State.ReviveRoundsRemaining = 0;
|
|
}
|
|
}
|
|
|
|
int attempts = 0;
|
|
do
|
|
{
|
|
State.CurrentPlayerIndex = (State.CurrentPlayerIndex + 1) % State.Players.Count;
|
|
attempts++;
|
|
}
|
|
while ((State.CurrentPlayer.HasFinished || State.CurrentPlayer.IsEliminated) && attempts <= State.Players.Count * 2);
|
|
|
|
State.TurnCount++;
|
|
|
|
// Ak hráme Pass & Play a nasledujúci hráč je človek a je zapnutá súkromná clona
|
|
if (State.Rules.PassAndPlayPrivacyScreen && State.CurrentPlayer.Type == PlayerType.Human && State.ActiveTournamentPlayers.Count(p => p.Type == PlayerType.Human) > 1)
|
|
{
|
|
State.TurnState = TurnState.PassScreen;
|
|
}
|
|
else
|
|
{
|
|
State.TurnState = TurnState.Playing;
|
|
}
|
|
}
|
|
|
|
private void EmitEvent(GameEvent e)
|
|
{
|
|
OnGameEvent?.Invoke(e);
|
|
}
|
|
}
|