using System; using System.Collections.Generic; using System.Linq; using DG.Tweening; using TMPro; using UnityEngine; public enum PlayerType { Player1 = 0, Player2 = 1, Player3 = 2, Player4 = 3 } [System.Serializable] public class PlayerGameData { public PlayerType playerType; public int startIndex; public int endIndex; public Transform playersParent; public Dictionary playerPawnsDict; public int totalPawnsInHome = 0; public int totalPawnsFinished = 0; } [System.Serializable] public enum MatchType { PVP, Bot } public enum BotMove { FinishingPathMove = 0, SafeMove = 1, AttackMove = 2, NormalMove = 3, NoMoves = 4 } public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader { [SerializeField] DiceRollHandler diceRollHandler; [SerializeField] private int diceValue = 0; [SerializeField] private TextMeshProUGUI diceText; [SerializeField] private Transform pointerDebug; [SerializeField] private MeshRenderer pointerMeshRend; [SerializeField] private Material turnMat; [SerializeField] private Material selectMat; [SerializeField] private PlayerGameData[] playerGameDatas; [SerializeField] private PlayerBaseHandler playerBaseHandler; private PlayerType currentPlayerTypeTurn; private int currentPlayerTurnIndex = 0; private List allPlayerTypes = new List(); private List botTypesInGame = new List(); private List playerRankings = new List(); // private Dictionary playerPawnsDict = new Dictionary>(); private Dictionary playerGameDatasDict = new Dictionary(); // botRuntimeMovementData: where can the bot move if a particular dice value is thrown, and based on the value set the bot move for each using a predictive approach and select based on the the priority private Dictionary> botRuntimeMovementData = new Dictionary>(); private TilesManager tilesManager; private int diceRolledValue; private bool CanRollDiceAgain = false; // used for when you get a 6 or when you reach the finish point private int diceSixRollCounter = 0; private List availPlayers = new List(); private bool canSwitchPlayer = false; public bool CanRollDiceForUser { get; private set; } public List PlayerTypesCollection => allPlayerTypes; public void Initialize() { InterfaceManager.Instance?.RegisterInterface(this); DOTween.useSafeMode = false; } public void InitializeData() { tilesManager = InterfaceManager.Instance.GetInterfaceInstance(); InitPlayerTypesForBotMatch(PlayerType.Player1, 3); } // TODO :: Call when the UI selection is made and game starts public void InitPlayerTypesForPVP(List types) { // TODO :: 2P, 3P, 4P allPlayerTypes = new List(types); playerBaseHandler.InitPlayerTypes(allPlayerTypes); InitCurrentGamePlayerInfo(); SetCanRollDiceForUser(true); } public void InitPlayerTypesForBotMatch(PlayerType selectedPlayerType, int botCount) { botTypesInGame.Clear(); allPlayerTypes.Clear(); AssignBotTypes(selectedPlayerType, botCount); allPlayerTypes.Add(selectedPlayerType); allPlayerTypes.AddRange(botTypesInGame); playerBaseHandler.InitPlayerTypes(allPlayerTypes); InitCurrentGamePlayerInfo(); InitBotRuntimeData(); AssignPlayerAndBotStates(selectedPlayerType); SetCanRollDiceForUser(!botTypesInGame.Contains(selectedPlayerType)); } private void InitBotRuntimeData() { botRuntimeMovementData.Clear(); foreach (var botType in botTypesInGame) { PlayerGameData playerGameData = playerGameDatasDict[botType]; if (!botRuntimeMovementData.ContainsKey(botType)) { botRuntimeMovementData.Add(botType, new Dictionary()); } foreach (var pawn in playerGameData.playerPawnsDict) { botRuntimeMovementData[botType].Add(pawn.Value.PlayerId, BotMove.NoMoves); } } } private void AssignPlayerAndBotStates(PlayerType selectedPlayerType) { PlayerBase playerBase = playerBaseHandler.GetPlayerBase(selectedPlayerType); playerBase.AssignBotState(PawnType.User); foreach (PlayerType playerType in botTypesInGame) { playerBase = playerBaseHandler.GetPlayerBase(playerType); playerBase.AssignBotState(PawnType.Bot); } } private void AssignBotTypes(PlayerType selectedPlayerType, int botCount) { int addedBots = 0; if (botCount == 1) { var playerType = (PlayerType)((int)selectedPlayerType + 2 < Enum.GetValues(typeof(PlayerType)).Length ? (int)selectedPlayerType + 2 : (int)selectedPlayerType - 2); botTypesInGame.Add(playerType); } else if (botCount == 2) { foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType))) { if (enumType == selectedPlayerType) continue; botTypesInGame.Add(enumType); addedBots++; if (addedBots == botCount) break; } } else { foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType))) { if (enumType == selectedPlayerType) continue; botTypesInGame.Add(enumType); } } } // TODO :: Call based on 2P/3P/4P public void InitCurrentGamePlayerInfo() { currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; // initialize the board based on the player types foreach (PlayerGameData playerGameData in playerGameDatas) { if (!allPlayerTypes.Contains(playerGameData.playerType)) continue; Debug.Log($"playerGameData.playerType: {playerGameData.playerType}"); playerGameDatasDict.Add(playerGameData.playerType, playerGameData); playerGameDatasDict[playerGameData.playerType].playerPawnsDict = new Dictionary(); foreach (Transform playerPawnChild in playerGameData.playersParent) { if (!playerPawnChild.gameObject.activeInHierarchy) continue; var pawn = playerPawnChild.GetComponent(); playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Add(pawn.PlayerId, pawn); } playerGameDatasDict[playerGameData.playerType].totalPawnsInHome = playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Count; } } public void EnablePlayerSelectionStates(bool state) { foreach (var playerPawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) { if (playerPawn.Value.GetPlayerState() == PlayerState.InFinishingPath) continue; playerPawn.Value.SetPlayerSelectionState(state); } } public void OnDiceInteracted() { diceRollHandler.HandleDiceViewForUser(); } public void RollDiceForPlayer(int rolledVal) { OnDiceRolled(rolledVal); OnNoMovesLeft(); } // Summary :: Function will be called and effective when a dice is rolled and no selection of pawns is made. private void OnNoMovesLeft() { if (canSwitchPlayer && !CanRollDiceAgain) { Debug.Log($"Switching player"); SwitchPlayer(); } } private bool CheckForMaxDiceRollAttempt() { if (diceSixRollCounter == 3) { CanRollDiceAgain = false; SwitchPlayer(); return true; } return false; } private void RollDiceForBot(int rolledVal) { Debug.Log($"CallTest: RollDiceForBot"); // OnDiceRolled(diceValue == 0 ? UnityEngine.Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1) : diceValue); OnDiceRolled(rolledVal); SelectPawnFromBotBase(); OnNoMovesLeft(); } // TODO :: Call right after the dice is rolled with the animation // What happens when you get a 6 private void SelectPawnFromBotBase() { if (canSwitchPlayer || availPlayers.Count() < 1 && !CanRollDiceAgain || !botTypesInGame.Contains(currentPlayerTypeTurn)) { Debug.Log($"returning from SelectPawnFromBotBase"); return; // Have a better check here } Debug.Log($"CallTest: SelectPawnFromBotBase: {currentPlayerTypeTurn}"); var botPawnsDictForCurrentPlayer = botRuntimeMovementData[currentPlayerTypeTurn]; // set the data inside this dict // check the data from the playerGameDataDict // change playerPawnsDict to list // only select the pawns that are active // if no pawns have left the home select the first pawn inside the base should be selected int savedPlayerId = -1; PlayerPawn pawn = null; Debug.Log($"SelectPawnFromBotBase: availPlayers.Count(): {availPlayers.Count()}, CanRollDiceAgain: {CanRollDiceAgain}"); if (playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInHome == 0) { InitActivePlayers(); } if (availPlayers.Count() < 1 && CanRollDiceAgain) // got a 6 roll value { pawn = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.FirstOrDefault(pawn => pawn.GetPlayerState() == PlayerState.InHome); Debug.Log($"SelectedPawn: {pawn.name}"); OnPawnSelected(pawn); return; } // TODO :: Double check foreach (var key in botPawnsDictForCurrentPlayer.Keys) { Debug.Log($"b :: botPawnsDictForCurrentPlayer[key]: {botPawnsDictForCurrentPlayer[key]}"); // botPawnsDictForCurrentPlayer[key] = BotMove.NoMoves; Debug.Log($"a :: botPawnsDictForCurrentPlayer[key]: {botPawnsDictForCurrentPlayer[key]}"); } Debug.Log($"Before Iterating"); foreach (var playerPawn in availPlayers) { Debug.Log($"Iterating"); var possibleLandingIndex = playerPawn.CurrentTileIndex + diceRolledValue; int lastIndex = tilesManager.GetGeneralTilesLength() - 1; int index = possibleLandingIndex > lastIndex ? possibleLandingIndex - lastIndex - 1 : possibleLandingIndex; Tile possibleTileData = tilesManager.RetrieveTileBasedOnIndex(index); Debug.Log($"AI playerPawn :: {playerPawn.name} :: state: {playerPawn.GetPlayerState()}, possibleLandingIndex: {possibleLandingIndex > playerGameDatasDict[currentPlayerTypeTurn].endIndex}"); Debug.Log($"AI playerPawn :: {playerPawn.name} :: possibleTileData.IsSafeZone: {possibleTileData.IsSafeZone}"); Debug.Log($"AI playerPawn :: {playerPawn.name} :: possibleTileData.PlayerPawn: {possibleTileData.HasPawnsAvailable}"); if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath || possibleLandingIndex > playerGameDatasDict[currentPlayerTypeTurn].endIndex) { Debug.Log($"AI playerPawn :: {playerPawn.name} :: {playerPawn.PlayerId} :: inFinishingPath :: canSelectPlayer: {playerPawn.CanSelectPlayer}"); if (playerPawn.CanSelectPlayer) { botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.FinishingPathMove; savedPlayerId = playerPawn.PlayerId; break; } else { botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.NoMoves; } } else if (possibleTileData.IsSafeZone) { Debug.Log($"AI playerPawn :: {playerPawn.name} :: {playerPawn.PlayerId} :: safeMove"); botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.SafeMove; } else if (possibleTileData.HasPawnsAvailable) { Debug.Log($"AI playerPawn :: {playerPawn.name} :: {playerPawn.PlayerId} :: attackMove"); botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.AttackMove; } else { Debug.Log($"AI playerPawn :: {playerPawn.name} :: {playerPawn.PlayerId} :: normalMove"); botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.NormalMove; } } List playerIds = new List(); if (savedPlayerId != -1) Debug.Log($"SavedPlayerId: {savedPlayerId}, CanSelectPlayer: {playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[savedPlayerId].CanSelectPlayer}"); if (savedPlayerId != -1 && playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[savedPlayerId].CanSelectPlayer) { pawn = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[savedPlayerId]; // chances are when one of the character reaches towards the finishing point } else { if (botPawnsDictForCurrentPlayer.ContainsValue(BotMove.SafeMove) && botPawnsDictForCurrentPlayer.ContainsValue(BotMove.AttackMove)) { InitPlayerIdsBasedOnState((val) => val == BotMove.AttackMove || val == BotMove.SafeMove); savedPlayerId = playerIds[UnityEngine.Random.Range(0, playerIds.Count)]; pawn = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[savedPlayerId]; Debug.Log($"AI playerPawn :: {pawn.name} :: Getting savedplayer id"); } else if (botPawnsDictForCurrentPlayer.ContainsValue(BotMove.SafeMove)) { InitPawnBasedOnState(BotMove.SafeMove); Debug.Log($"AI playerPawn :: {pawn.name} :: Getting savedplayer id"); } else if (botPawnsDictForCurrentPlayer.ContainsValue(BotMove.AttackMove)) { InitPawnBasedOnState(BotMove.AttackMove); Debug.Log($"AI playerPawn :: {pawn.name} :: Getting savedplayer id"); } else if (botPawnsDictForCurrentPlayer.ContainsValue(BotMove.NormalMove)) { InitPawnBasedOnState(BotMove.NormalMove); Debug.Log($"AI playerPawn :: {pawn.name} :: Getting savedplayer id"); } } Debug.Log($"AI playerPawn :: {pawn.name} :: SelectedPawn: {pawn.name}"); OnPawnSelected(pawn); void InitPawnBasedOnState(BotMove botMove) { InitPlayerIdsBasedOnState((val) => val == botMove); ReturnPlayerWithMaxSteps(ref savedPlayerId); pawn = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[savedPlayerId]; } void InitPlayerIdsBasedOnState(Predicate state) { foreach (var botPair in botPawnsDictForCurrentPlayer) if (state.Invoke(botPair.Value)) playerIds.Add(botPair.Key); } void ReturnPlayerWithMaxSteps(ref int savedPlayerId) { int maxStepsTaken = -999; foreach (var id in playerIds) { if (playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[id].StepsTaken > maxStepsTaken) { maxStepsTaken = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict[id].StepsTaken; savedPlayerId = id; } } } } public void OnDiceRolled(int rolledVal) { SetCanRollDiceForUser(false); // add core dice logic here Debug.Log($"Tile Index :: LUDO :: rolledVal: {rolledVal} :: {currentPlayerTypeTurn}"); diceRolledValue = rolledVal; diceText.text = $"{diceRolledValue}"; availPlayers.Clear(); if (rolledVal == Ludo_3D_Constants.Max_Dice_Rolls) { canSwitchPlayer = false; // provide option to select a pawn from the list // also play a simple animation before selecting CanRollDiceAgain = true; diceSixRollCounter++; pointerMeshRend.material = selectMat; foreach (var playerPawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) if (playerPawn.Value.GetPlayerState() == PlayerState.InFinishingPath) playerPawn.Value.SetPlayerSelectionState(false); Debug.Log($"### AreAllPawnsInFinishingPath"); if (AreAllPawnsInFinishingPath()) { SetCanRollDiceForUser(!botTypesInGame.Contains(currentPlayerTypeTurn)); return; } Debug.Log($"### EnablePlayerSelectionStates"); EnablePlayerSelectionStates(true); // pointerMeshRend.materials[0] = selectMat; } else // if there are any other pawns that are in safe or moving state { // for player's logic InitActivePlayers(); int customAvailPlayers = availPlayers.Count(); Debug.Log($"before CustomAvailablePlayers: {customAvailPlayers}"); List indexesToRemove = new List(); for (int i = 0; i < availPlayers.Count; i++) { Debug.Log($"## playerPawn.GetPlayerState(): {availPlayers[i].GetPlayerState()}"); if (availPlayers[i].GetPlayerState() == PlayerState.InFinishingPath) { Debug.Log($"diceRolledValue: {diceRolledValue}, FinishingDataLen: {tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn)}, playerPawn.CurrentTileIndex: {availPlayers[i].CurrentTileIndex}"); if (diceRolledValue <= tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - (availPlayers[i].CurrentTileIndex + 1)) { availPlayers[i].SetPlayerSelectionState(true); } else { indexesToRemove.Add(i); availPlayers[i].SetPlayerSelectionState(false); customAvailPlayers--; } continue; } availPlayers[i].SetPlayerSelectionState(true); } foreach (int i in indexesToRemove) availPlayers.RemoveAt(i); // if (availPlayers.Count() < 1) Debug.Log($"CustomAvailablePlayers: {customAvailPlayers}"); canSwitchPlayer = customAvailPlayers < 1; CanRollDiceAgain = false; } Debug.Log($"CanRollDiceAgain: {CanRollDiceAgain}, canSwitchPlayer: {canSwitchPlayer}"); } private void InitActivePlayers() { availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn) .Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone || pawn.GetPlayerState() == PlayerState.Moving || pawn.GetPlayerState() == PlayerState.InFinishingPath).ToList(); } private bool AreAllPawnsInFinishingPath() { bool areAllPawnsInFinishingPath = false; foreach (var pawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) { if (pawn.Value.GetPlayerState() == PlayerState.HasFinished) continue; if (pawn.Value.GetPlayerState() == PlayerState.InFinishingPath) { areAllPawnsInFinishingPath = true; continue; } areAllPawnsInFinishingPath = false; break; } return areAllPawnsInFinishingPath; } private void UpdatePlayerState(PlayerPawn playerPawn, PlayerState playerState) { playerGameDatasDict[playerPawn.PlayerType].playerPawnsDict[playerPawn.PlayerId] = playerPawn; playerGameDatasDict[playerPawn.PlayerType].playerPawnsDict[playerPawn.PlayerId].SetPlayerState(playerState); playerPawn.SetPlayerState(playerState); } private void CheckDiceRollForBot(PlayerPawn playerPawn) { if (CanRollDiceAgain) { HandleDiceRoll(); } } private void HandleDiceRoll() { diceRollHandler.HandleDiceViewForBot((rollVal) => RollDiceForBot(rollVal)); } public void OnPawnSelected(PlayerPawn playerPawn) { EnablePlayerSelectionStates(false); PlayerGameData playerGameData = playerGameDatasDict[currentPlayerTypeTurn]; Debug.Log($"playerPawn.GetPlayerState(): {playerPawn.GetPlayerState()}"); if (playerPawn.GetPlayerState() == PlayerState.InHome) { Tile targetTile = tilesManager.RetrieveTileBasedOnIndex(playerGameData.startIndex); playerPawn.MoveToTile( GetAndInitPositionInsideSafeZone(playerPawn, targetTile), onComplete: () => { playerGameDatasDict[playerGameData.playerType].totalPawnsInHome--; UpdatePlayerState(playerPawn, PlayerState.InSafeZone); if (CheckForMaxDiceRollAttempt()) { return; } if (playerPawn.IsBotPlayer) CheckDiceRollForBot(playerPawn); else SetCanRollDiceForUser(true); }, playerGameData.startIndex); return; } else if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath) { ApplyFinishingPathLogic(playerPawn); } else if (playerPawn.CurrentTileIndex == playerGameDatasDict[currentPlayerTypeTurn].endIndex) { tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex).ResetPlayerPawn(playerPawn); ApplyFinishingPathLogic(playerPawn); } else if (playerPawn.GetPlayerState() == PlayerState.InSafeZone || playerPawn.GetPlayerState() == PlayerState.Moving) { // move based on the dice value Debug.Log($"Tile Index :: currentTileIndex: {playerPawn.CurrentTileIndex}"); int nextTileIdx = GetNextGeneralTileIndex(playerPawn); int targetIdx = playerPawn.CurrentTileIndex + diceRolledValue; if (nextTileIdx == 0) targetIdx = (targetIdx - playerPawn.CurrentTileIndex) - 1; Tile currentSittingTile = tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex); if (currentSittingTile.IsSafeZone) { SafeTile safeTile = (SafeTile)currentSittingTile; safeTile.UpdateSafeZonePlayerData(currentPlayerTypeTurn, playerPawn); if (safeTile.PlayerTypesCount == 1) { PlayerType playerType = safeTile.GetFirstPlayerType(); var playerPawns = safeTile.GetPlayerPawns(playerType); foreach (var pawn in playerPawns) pawn.MoveToCustomTilePosition(safeTile.CenterPlacementPosition); } } else { currentSittingTile.ResetPlayerPawn(playerPawn); } MoveThroughTiles(playerPawn, nextTileIdx, targetIndex: targetIdx); } } private void ApplyFinishingPathLogic(PlayerPawn playerPawn) { int finishingPathIndex = GetNextFinishingTileIndex(playerPawn); int targetIdx = finishingPathIndex + diceRolledValue > tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1 ? tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1 : finishingPathIndex + diceRolledValue; Debug.Log($"TargetIdx: {targetIdx}, finishingPathIndex: {finishingPathIndex}"); MoveThroughFinishingPath(playerPawn, finishingPathIndex, targetIdx); } public int GetNextGeneralTileIndex(PlayerPawn playerPawn) { return playerPawn.CurrentTileIndex == tilesManager.GetGeneralTilesLength() - 1 ? 0 : playerPawn.CurrentTileIndex + 1; } private int GetNextFinishingTileIndex(PlayerPawn playerPawn) { return playerPawn.CurrentTileIndex > tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1 ? 0 : playerPawn.CurrentTileIndex + 1; } private void SwitchPlayer(PlayerPawn playerPawn = null) { Debug.Log($"CallTest: SwitchPlayer"); if (!CanRollDiceAgain) { Debug.Log($"currentPlayerTurn: {currentPlayerTypeTurn}"); Debug.Log($"currentPlayerTurnIndex: {currentPlayerTurnIndex}"); if (allPlayerTypes.Count == 1) { Debug.LogError($"GAME IS OVER"); return; } if (currentPlayerTypeTurn == allPlayerTypes[allPlayerTypes.Count - 1]) { currentPlayerTurnIndex = 0; currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } else { currentPlayerTurnIndex++; currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } diceSixRollCounter = 0; diceText.text = $"{0}"; } SetCanRollDiceForUser(!botTypesInGame.Contains(currentPlayerTypeTurn)); Debug.Log($"CurrentPlayerTurn: {currentPlayerTypeTurn}"); var tempPos = playerBaseHandler.GetPlayerBase(currentPlayerTypeTurn).transform.position; pointerDebug.position = new Vector3(tempPos.x, 3f, tempPos.z); pointerMeshRend.material = turnMat; // pointerMeshRend.materials[0] = turnMat; if (playerPawn) UpdatePlayerState(playerPawn, tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex).IsSafeZone ? PlayerState.InSafeZone : PlayerState.Moving); Debug.Log($"botTypesInGame.Contains(currentPlayerTypeTurn): {botTypesInGame.Contains(currentPlayerTypeTurn)}"); if (botTypesInGame.Contains(currentPlayerTypeTurn)) // TODO :: Double check calling of the function { Debug.Log($"Invoking RollDiceForBot"); Invoke(nameof(HandleDiceRoll), 1f); } } private void MoveThroughTiles(PlayerPawn playerPawn, int index, int targetIndex) { Tile nextTile = tilesManager.RetrieveTileBasedOnIndex(index); Vector3 targetPosition = nextTile.CenterPlacementPosition; Debug.Log($"Tile Index :: nextIndex: {index}, targetIndex: {targetIndex}, nextTileName: {nextTile.name}"); if (index == targetIndex) // if the target index is the safe zone only then apply the logic for rearranging pawns { Tile targetTile = tilesManager.RetrieveTileBasedOnIndex(targetIndex); if (targetTile.IsSafeZone) { targetPosition = GetAndInitPositionInsideSafeZone(playerPawn, targetTile); } } Debug.Log($"tile targetPosition: {targetPosition}"); playerPawn.MoveToTile( targetPosition, onComplete: () => { diceRolledValue--; Debug.Log($"DiceRolledValue: {diceRolledValue}"); if (diceRolledValue > 0) { int nextTileIndex = GetNextGeneralTileIndex(playerPawn); Debug.Log($"currentTileIndex: {playerPawn.CurrentTileIndex}, nextTileIndex: {nextTileIndex}, targetIndex: {targetIndex}"); if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath || index == playerGameDatasDict[currentPlayerTypeTurn].endIndex) { // MoveThroughTiles(playerPawn, index, targetIndex); Debug.Log($"TargetIdx: {targetIndex - index}"); MoveThroughFinishingPath(playerPawn, 0, targetIndex - index); } else if (nextTileIndex <= targetIndex) { if (nextTileIndex == 0) targetIndex = (targetIndex - playerPawn.CurrentTileIndex) - 1; MoveThroughTiles(playerPawn, nextTileIndex, targetIndex); } } else { // TODO :: Improve this logic, use a collection Debug.Log($"nextTile.IsSafeZone: {nextTile.IsSafeZone}"); if (!nextTile.IsSafeZone) { Debug.Log($"nextTile.HasPawnsAvailable: {nextTile.HasPawnsAvailable}"); if (nextTile.HasPawnsAvailable && playerPawn.PlayerType != nextTile.CurrentHoldingPlayerType) { Debug.Log($"nextTile.PlayerPawn: {nextTile.CurrentHoldingPlayerType}, {nextTile.transform.name}"); Debug.Log($"nextTile.TotalPawnsInTile: {nextTile.TotalPawnsInTile}"); // play animation for moving back to base. // TODO :: Send existing pawn back to base. // means there's already a pawn there, move him back to the base. int counter = nextTile.TotalPawnsInTile; for (int i = counter; i > 0; i--) { var pawn = nextTile.GetPlayerPawn(); Debug.Log($"pawn: {pawn}"); Debug.Log($"playerBase: {playerBaseHandler}"); var playerBasePos = playerBaseHandler.GetPlayerBase(pawn.PlayerType) .GetBasePlacementDataPosition(pawn.PlayerId - 1); Debug.Log($"playerBasePos: {playerBasePos}"); playerGameDatasDict[pawn.PlayerType].totalPawnsInHome++; pawn.MoveBackToHome(playerBasePos); } if (CheckForMaxDiceRollAttempt()) { nextTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); return; } CanRollDiceAgain = true; if (playerPawn.IsBotPlayer) CheckDiceRollForBot(playerPawn); else SetCanRollDiceForUser(true); } nextTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); if (CheckForMaxDiceRollAttempt()) { return; } } else { if (CheckForMaxDiceRollAttempt()) { return; } } SwitchPlayer(playerPawn); } }, index); } private Vector3 GetAndInitPositionInsideSafeZone(PlayerPawn playerPawn, Tile targetTile) { Vector3 targetPosition; SafeTile targetSafeTile = (SafeTile)targetTile; Debug.Log($"targetSafeTile.PlayerTypesCount: {targetSafeTile.PlayerTypesCount}"); if (targetSafeTile.PlayerTypesCount == 1) { Debug.Log($"targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn): {targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn)}"); if (!targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn)) // means it is a new player type, the second one { PlayerType initialPlayerType = targetSafeTile.GetFirstPlayerType(); // rearrange already existing player from center position to it's saved transform var playerPawns = targetSafeTile.GetPlayerPawns(initialPlayerType); foreach (var pawn in playerPawns) { var placementPoint = targetSafeTile.GetPlacementPoint(initialPlayerType); pawn.MoveToCustomTilePosition(placementPoint.position); } targetSafeTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); targetPosition = targetSafeTile.GetPlacementPoint(currentPlayerTypeTurn).position; } else { targetSafeTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); targetPosition = targetTile.CenterPlacementPosition; } } else { // TODO :: Check the data if it's consistent Debug.Log($"targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn): {targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn)}"); if (!targetSafeTile.ContainsPlayerType(currentPlayerTypeTurn)) { Debug.Log($"targetSafeTile.PlayerTypesCount: {targetSafeTile.PlayerTypesCount}"); if (targetSafeTile.PlayerTypesCount < 1) // he is the only player that is being added to the safe zone { targetSafeTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); targetPosition = targetTile.CenterPlacementPosition; } else { targetSafeTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); targetPosition = targetSafeTile.GetPlacementPoint(currentPlayerTypeTurn).position; } } else { targetSafeTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); targetPosition = targetSafeTile.GetPlacementPoint(currentPlayerTypeTurn).position; } } return targetPosition; } private void MoveThroughFinishingPath(PlayerPawn playerPawn, int index, int targetIndex) { UpdatePlayerState(playerPawn, PlayerState.InFinishingPath); playerPawn.MoveToTile( tilesManager.RetrievePositionForFinishingTile(currentPlayerTypeTurn, index).position, onComplete: () => { diceRolledValue--; Debug.Log($"DiceRolledValue: {diceRolledValue}"); if (diceRolledValue > 0) { int tileIndex = GetNextFinishingTileIndex(playerPawn); Debug.Log($"tileIndex: {tileIndex}, targetIndex: {targetIndex}"); if (tileIndex <= targetIndex) { // MoveThroughTiles(playerPawn, index, targetIndex); MoveThroughFinishingPath(playerPawn, tileIndex, targetIndex); } } else { Debug.Log($"CurrentTileIndex: {playerPawn.CurrentTileIndex} == lastIndex: {tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1}"); if (playerPawn.CurrentTileIndex == tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1) { UpdatePlayerState(playerPawn, PlayerState.HasFinished); playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished++; Debug.Log($"totalPawnsFinished: {playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished}, playerPawnsDict.Count: {playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Count}"); if (playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished == playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Count) { CanRollDiceAgain = false; if (allPlayerTypes.Contains(currentPlayerTypeTurn)) { playerRankings.Add(currentPlayerTypeTurn); allPlayerTypes.Remove(currentPlayerTypeTurn); } if (allPlayerTypes.Count == 1) { // Game is over playerRankings.Add(allPlayerTypes[0]); allPlayerTypes.Remove(0); // Show Game Over panel return; } SwitchPlayer(); Debug.Log($"PlayerTypes: {allPlayerTypes.Count}"); } else { CanRollDiceAgain = true; if (playerPawn.IsBotPlayer) CheckDiceRollForBot(playerPawn); else SetCanRollDiceForUser(true); } } else { if (CheckForMaxDiceRollAttempt()) { return; } SwitchPlayer(); } } }, index); } private void SetCanRollDiceForUser(bool state) { CanRollDiceForUser = state; Debug.Log($"CAnRollDiceForUser: {CanRollDiceForUser}"); } }