Advertisement
SemlerPDX

PlayHandsPhase.cs

Jun 17th, 2025
257
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.34 KB | Gaming | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5.  
  6. using GameFramework.AI;
  7. using GameFramework.CardZones;
  8. using GameFramework.Data;
  9. using GameFramework.Utilities;
  10.  
  11. using UnityEngine;
  12.  
  13. namespace GameFramework.GamePhases
  14. {
  15.     public class PlayHandsPhase : GamePhaseBase
  16.     {
  17.         private static readonly WaitForSeconds _pauseOpponentThink = new(0.9f);
  18.         private static readonly WaitForSeconds _pauseShowGo = new(1.2f);
  19.         private static readonly WaitForSeconds _pauseShowLastCard = new(1.5f);
  20.  
  21.         protected override IEnumerator RunPhaseLogic()
  22.         {
  23.             // Starts or Continues the Play Hands Phase --
  24.             // This phase has two additional phases with two sub-phase event triggered functions
  25.             // following the base phase, for selecting cards or clicking go button
  26.             // This phase naturally transitions to/from CountHands phase when all cards have been played while peg score < 131
  27.             // This phase may also transition to/from the MovingPegs phase (and its additional phase MovePeg)
  28.             // When in a PlayerOut phase, only one player has cards and board had been reset - no go points, just play out
  29.  
  30.             TrySetActiveState(Context.TableScoreTotalPanel, true);
  31.  
  32.             // ---- PLAYER GO BUTTON ----
  33.             if (Context.PlayPanelGoButton.activeSelf)
  34.             {
  35.                 TrySetActiveState(Context.PlayPanelGoButton, false);
  36.             }
  37.             else
  38.             {
  39.                 if (CurrentPhase == GamePhase.PlayHands)
  40.                 {
  41.                     SetPhase(GamePhase.PlayCard);
  42.                 }
  43.             }
  44.  
  45.             // ---- PLAYER OUT PHASE ----
  46.             if (CurrentPhase == GamePhase.PlayerOut)
  47.             {
  48.                 yield return HandleOpponentPlayOut();
  49.                 yield break;
  50.             }
  51.  
  52.             // ---- PLAYER CARD SELECTED ----
  53.             if (SelectedCard != null)
  54.             {
  55.                 yield return HandlePlayerMove(SelectedCard);
  56.                 yield return HandlePlayerPlayOut();
  57.                 yield break;
  58.             }
  59.  
  60.             // ---- WHOSE TURN? ----
  61.             var isNewRound = IsNewRound();
  62.             var isPlayerCribOwner = IsPlayerCribOwner();
  63.             var playerHand = Context.PlayerHandManager.GetCards();
  64.             var opponentHand = Context.OpponentHandManager.GetCards();
  65.  
  66.             // Player or opponent leads?
  67.             var isOpponentsMove = (LastPlayer == GamePlayer.Player1) || !HasPlayableCard(playerHand);
  68.             var isPlayersMove = (isNewRound && !isPlayerCribOwner) || (!isNewRound && !isOpponentsMove);
  69.  
  70.             // ---- NEW ROUND SCENARIO: Need to ensure table score is zeroed ----
  71.             if (isNewRound)
  72.             {
  73.                 UpdateRunningScore(0);
  74.             }
  75.  
  76.             // ---- GO SCENARIO: No one can play, but table <= 31 ----
  77.             var tableScore = GetCurrentTableScore();
  78.             if (!IsCountPhaseReady() && !HasPlayableCard(playerHand) && !HasPlayableCard(opponentHand))
  79.             {
  80.                 if (tableScore != 31 && LastPlayer == GamePlayer.Player1)
  81.                 {
  82.                     SetPhase(GamePhase.PlayHands);
  83.  
  84.                     yield return ShowGoMessage();
  85.                 }
  86.  
  87.                 if (tableScore == 31)
  88.                 {
  89.                     if (LastPlayer != GamePlayer.Opponent)
  90.                     {
  91.                         SetPhase(GamePhase.PlayHands);
  92.                     }
  93.                 }
  94.  
  95.                 yield return MovePlayedCardsToPlayedZone();
  96.  
  97.                 ResetTableScore();
  98.  
  99.                 if (!CheckAndEnterPlayOut())
  100.                 {
  101.                     if (LastPlayer == GamePlayer.Opponent)
  102.                     {
  103.                         SetPhase(GamePhase.PlayCard);
  104.                     }
  105.                 }
  106.  
  107.                 yield break;
  108.             }
  109.  
  110.             // ---- LAST CARD/COUNT PHASE ----
  111.             if (IsCountPhaseReady())
  112.             {
  113.                 if (tableScore < 31)
  114.                 {
  115.                     yield return ShowLastCardMessage();
  116.                 }
  117.  
  118.                 yield break;
  119.             }
  120.  
  121.             // ---- PLAYER MOVE CHECK ----
  122.             if (isPlayersMove)
  123.             {
  124.                 // Wait for player input (card select or Go button)
  125.                 // Defensive: if player can't play, show Go button
  126.                 if (!HasPlayableCard(playerHand) && HasPlayableCard(opponentHand))
  127.                 {
  128.                     TrySetActiveState(Context.PlayPanelGoButton, true);
  129.                 }
  130.  
  131.                 if (!CheckAndEnterPlayOut())
  132.                 {
  133.                     SetPhase(GamePhase.PlayCard);
  134.                 }
  135.  
  136.                 yield break;
  137.             }
  138.  
  139.             // ---- OPPONENT MOVE CHECK ----
  140.             if (HasPlayableCard(opponentHand))
  141.             {
  142.                 yield return HandleOpponentMove();
  143.  
  144.                 tableScore = GetCurrentTableScore();
  145.                 if (tableScore == 31)
  146.                 {
  147.                     // TODO: Opponent scores 2 points, implement scoring event later
  148.  
  149.                     yield return MovePlayedCardsToPlayedZone();
  150.  
  151.                     ResetTableScore();
  152.  
  153.                     yield break;
  154.                 }
  155.  
  156.                 // If EITHER player has cards in PlayHands/PlayCard phase, it is still not over and go button should be conditionally shown to player
  157.                 var isRoundStillGoing = CurrentPhase != GamePhase.PlayerOut && CurrentPhase != GamePhase.CountHands;
  158.                 var canStillPlay = playerHand.Count > 0 || Context.OpponentHandManager.GetCards().Count > 0;
  159.                 if (isRoundStillGoing && canStillPlay)
  160.                 {
  161.                     TrySetActiveState(Context.PlayPanelGoButton, !HasPlayableCard(playerHand));
  162.                 }
  163.  
  164.                 if (!canStillPlay)
  165.                 {
  166.                     if (IsCountPhaseReady() && tableScore < 31)
  167.                     {
  168.                         yield return ShowLastCardMessage();
  169.                     }
  170.                 }
  171.  
  172.                 yield break;
  173.             }
  174.             else
  175.             {
  176.                 if (tableScore != 31 && LastPlayer == GamePlayer.Player1)
  177.                 {
  178.                     // TODO:  Player scores a go point
  179.  
  180.                     yield return ShowGoMessage();
  181.                 }
  182.             }
  183.         }
  184.  
  185.         // ------------------- HELPERS & HANDLERS -------------------
  186.  
  187.         private IEnumerator HandlePlayerMove(CardData card)
  188.         {
  189.             var playerHand = Context.PlayerHandManager.GetCards();
  190.             if (!playerHand.Contains(card) || !CheckCanPlay(card))
  191.             {
  192.                 yield break;
  193.             }
  194.  
  195.             // Move card
  196.             ZonesCardTransfer.TransferCard(
  197.                 Context.PlayerHandManager,
  198.                 Context.CardPlayPanelManager,
  199.                 card,
  200.                 Context.CardSprites,
  201.                 Context.CardSprites[card.SpriteName]);
  202.  
  203.             SetLastPlayer(GamePlayer.Player1);
  204.             Context.PlayerLowestCardManager.AddCard(card, Context.CardSprites);
  205.             UpdateRunningScore(card.Value);
  206.  
  207.             // Check for playout state (if PlayerOut phase, clear table if needed)
  208.             if (CurrentPhase == GamePhase.OpponentOut && IsCountPhaseReady())
  209.             {
  210.                 if (GetCurrentTableScore() == 31)
  211.                 {
  212.                     // TODO: 2 points to this player here, fire event when scoring system implemented
  213.                 }
  214.             }
  215.  
  216.             // Normal flow: let opponent move else wait for next player action on playout
  217.             if (CurrentPhase != GamePhase.OpponentOut)
  218.             {
  219.                 SetPhase(GamePhase.PlayHands);
  220.             }
  221.         }
  222.  
  223.         private IEnumerator HandleOpponentMove()
  224.         {
  225.             yield return _pauseOpponentThink;
  226.  
  227.             var opponentHand = Context.OpponentHandManager.GetCards();
  228.             var playZone = Context.CardPlayPanelManager.GetCards();
  229.             var card = OpponentCardSelection.GetPlayCard(opponentHand, playZone, GetCurrentTableScore());
  230.  
  231.             if (card == null)
  232.             {
  233.                 if (CurrentPhase != GamePhase.PlayerOut)
  234.                 {
  235.                     SetPhase(GamePhase.PlayHands);
  236.                 }
  237.  
  238.                 yield break;
  239.             }
  240.  
  241.             ZonesCardTransfer.TransferCard(
  242.                 Context.OpponentHandManager,
  243.                 Context.CardPlayPanelManager,
  244.                 card,
  245.                 Context.CardSprites,
  246.                 Context.CardSprites[card.SpriteName]);
  247.  
  248.             SetLastPlayer(GamePlayer.Opponent);
  249.             Context.OpponentLowestCardManager.AddCard(card, Context.CardSprites);
  250.             UpdateRunningScore(card.Value);
  251.  
  252.             if (CurrentPhase == GamePhase.PlayerOut && IsCountPhaseReady())
  253.             {
  254.                 if (GetCurrentTableScore() == 31)
  255.                 {
  256.                     // TODO: 2 points to this player here, fire event when scoring system implemented
  257.                 }
  258.                 else
  259.                 {
  260.                     yield return ShowLastCardMessage();
  261.                 }
  262.             }
  263.         }
  264.  
  265.         private IEnumerator HandlePlayerPlayOut()
  266.         {
  267.             // ---- PHASE OUT LOGIC ----
  268.             if (CurrentPhase != GamePhase.OpponentOut)
  269.             {
  270.                 yield break;
  271.             }
  272.  
  273.             var playerHand = Context.PlayerHandManager.GetCards();
  274.             if (playerHand.Count == 0)
  275.             {
  276.                 yield return MovePlayedCardsToPlayedZone();
  277.  
  278.                 SetPhase(GamePhase.CountHands);
  279.  
  280.                 yield break;
  281.             }
  282.         }
  283.  
  284.         private IEnumerator HandleOpponentPlayOut()
  285.         {
  286.             var opponentHand = Context.OpponentHandManager.GetCards();
  287.             if (opponentHand.Count == 0)
  288.             {
  289.                 yield return MovePlayedCardsToPlayedZone();
  290.  
  291.                 SetPhase(GamePhase.CountHands);
  292.  
  293.                 yield break;
  294.             }
  295.  
  296.             yield return HandleOpponentMove();
  297.         }
  298.  
  299.         private IEnumerator ShowGoMessage()
  300.         {
  301.             TrySetActiveState(Context.PlayPanelGoMessage, true);
  302.  
  303.             // TODO: Player1 earns 1 point for go, once scoring is implemented
  304.  
  305.             yield return _pauseShowGo;
  306.  
  307.             TrySetActiveState(Context.PlayPanelGoMessage, false);
  308.         }
  309.  
  310.         private IEnumerator ShowLastCardMessage()
  311.         {
  312.             var isActiveSelf = Context.PlayerLastCardMessage.activeSelf || Context.OpponentLastCardMessage.activeSelf;
  313.             if (isActiveSelf)
  314.             {
  315.                 yield break; // Should not happen, but defensive check
  316.             }
  317.  
  318.             var lastPlayerIsPlayer = (LastPlayer == GamePlayer.Player1);
  319.             TrySetActiveState(Context.PlayerLastCardMessage, lastPlayerIsPlayer);
  320.             TrySetActiveState(Context.OpponentLastCardMessage, !lastPlayerIsPlayer);
  321.  
  322.             yield return _pauseShowLastCard;
  323.  
  324.             TrySetActiveState(Context.PlayerLastCardMessage, false);
  325.             TrySetActiveState(Context.OpponentLastCardMessage, false);
  326.         }
  327.  
  328.         private IEnumerator MovePlayedCardsToPlayedZone()
  329.         {
  330.             var playZone = Context.CardPlayPanelManager;
  331.             var playedZone = Context.CardsPlayedPanelManager;
  332.             var currentCards = playZone.GetCards().ToList();
  333.  
  334.             foreach (var card in currentCards)
  335.             {
  336.                 ZonesCardTransfer.TransferCard(playZone, playedZone, card, Context.CardSprites);
  337.                 yield return new WaitForSeconds(0.15f);
  338.             }
  339.  
  340.             playZone.ClearZone();
  341.  
  342.             yield return new WaitForSeconds(0.4f);
  343.         }
  344.  
  345.         private void ResetTableScore()
  346.         {
  347.             UpdateRunningScore(0);
  348.             TrySetActiveState(Context.PlayPanelGoButton, false);
  349.             TrySetActiveState(Context.PlayPanelGoMessage, false);
  350.         }
  351.  
  352.         // --------------- Utility Logic ---------------
  353.  
  354.         private bool HasPlayableCard(IReadOnlyList<CardData> hand)
  355.         {
  356.             foreach (var card in hand)
  357.             {
  358.                 if (CheckCanPlay(card))
  359.                 {
  360.                     return true;
  361.                 }
  362.             }
  363.  
  364.             return false;
  365.         }
  366.  
  367.         private bool IsNewRound()
  368.         {
  369.             var isPlayerHandFull = Context.PlayerHandManager.GetCards().Count == 4;
  370.             var isOpponentHandFull = Context.OpponentHandManager.GetCards().Count == 4;
  371.             return isPlayerHandFull && isOpponentHandFull;
  372.         }
  373.  
  374.         private bool IsPlayerCribOwner()
  375.         {
  376.             return Context.PlayerCribPanelManager.GetCards().Count > 0;
  377.         }
  378.  
  379.         private bool CheckAndEnterPlayOut()
  380.         {
  381.             var playerHand = Context.PlayerHandManager.GetCards();
  382.             var opponentHand = Context.OpponentHandManager.GetCards();
  383.             var playerOut = playerHand.Count == 0;
  384.             var opponentOut = opponentHand.Count == 0;
  385.  
  386.             if (playerOut && !opponentOut)
  387.             {
  388.                 SetPhase(GamePhase.PlayerOut);
  389.                 return true;
  390.             }
  391.  
  392.             if (opponentOut && !playerOut)
  393.             {
  394.                 SetPhase(GamePhase.OpponentOut);
  395.                 return true;
  396.             }
  397.  
  398.             return false;
  399.         }
  400.  
  401.         private int GetCurrentTableScore()
  402.         {
  403.             var text = Context.TableScoreValueTextMesh.text ?? "0";
  404.             return int.TryParse(text, out int score) ? score : 0;
  405.         }
  406.  
  407.         private void UpdateRunningScore(int value)
  408.         {
  409.             var current = GetCurrentTableScore();
  410.             current = value == 0 ? 0 : current + GetNormalizedValue(value);
  411.             Context.TableScoreValueTextMesh.text = current.ToString();
  412.  
  413.             // TODO: Check for 15-2 and 31 for 2 here when scoring events implemented (??)
  414.         }
  415.  
  416.         private bool IsCountPhaseReady()
  417.         {
  418.             var playerCardsCount = Context.PlayerHandManager.GetCards().Count;
  419.             var opponentCardsCount = Context.OpponentHandManager.GetCards().Count;
  420.             if (playerCardsCount == 0 && opponentCardsCount == 0)
  421.             {
  422.                 TrySetActiveState(Context.PlayPanelGoButton, false); // TEST: Commented out ResetTablescore, using this now
  423.                 TrySetActiveState(Context.PlayPanelGoMessage, false); // TEST: Commented out ResetTablescore, using this now
  424.                 SetPhase(GamePhase.CountHands);
  425.                 return true;
  426.             }
  427.  
  428.             return false;
  429.         }
  430.  
  431.         // NOTE: now repeated this method in AI class OpponentCardSelection - consider util later
  432.         private int GetNormalizedValue(int value) => value > 10 ? 10 : value;
  433.  
  434.         private bool CheckCanPlay(CardData card)
  435.         {
  436.             var cardValue = GetNormalizedValue(card.Value);
  437.             var currentScore = GetCurrentCardsCount();
  438.             return currentScore + cardValue <= 31;
  439.         }
  440.  
  441.         private int GetCurrentCardsCount()
  442.         {
  443.             var playZone = Context.CardPlayPanelManager;
  444.             var currentCards = playZone.GetCards();
  445.             return currentCards.Sum(card => GetNormalizedValue(card.Value));
  446.         }
  447.     }
  448. }
  449.  
Tags: Unity
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement