using TMPro; using System; using System.Linq; using DG.Tweening; using UnityEngine; using System.Collections.Generic; public enum BotMove { FinishingPathMove = 0, SafeMove = 1, AttackMove = 2, NormalMove = 3, NoMoves = 4 } public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader { [SerializeField] private bool isDebugTest = false; public bool IsDebugTest => isDebugTest; [SerializeField] DiceRollHandler diceRollHandler; [SerializeField] private int diceValue = 0; [SerializeField] private int maxDiceSixRollCounter = 2; [SerializeField] private int totalStepsForCharacter = 57; [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; public PlayerType CurrentPlayerTypeTurn => currentPlayerTypeTurn; private int currentPlayerTurnIndex = 0; private List allPlayerTypes = new List(); private List botTypesInGame = new List(); private List playerDatas = new List(); private Dictionary playerGameDatasDict = new Dictionary(); private Dictionary> botRuntimeMovementData = new Dictionary>(); private TilesManager tilesManager; private UIManager uIManager; private GameManager gameManager; 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 int TotalPlayersInGame { get; private set; } public List PlayerDatas => playerDatas; public List PlayerTypesCollection => allPlayerTypes; public void Initialize() { InterfaceManager.Instance?.RegisterInterface(this); DOTween.useSafeMode = false; } public void InitializeData() { tilesManager = InterfaceManager.Instance.GetInterfaceInstance(); uIManager = InterfaceManager.Instance.GetInterfaceInstance(); gameManager = InterfaceManager.Instance.GetInterfaceInstance(); } public void InitPlayerTypesForPVP(List types, List names) { allPlayerTypes = new List(types); playerDatas.Clear(); TotalPlayersInGame = types.Count; for (int i=0; i(); botTypesInGame = new List(); allPlayerTypes = new List(); TotalPlayersInGame = botCount + 1; AssignBotTypes(selectedPlayerData.playerType, botCount); foreach (PlayerType playerType in Enum.GetValues(typeof(PlayerType))) { if (botTypesInGame.Contains(playerType)) { allPlayerTypes.Add(playerType); playerDatas.Add(new PlayerData { playerType = playerType, playerName = $"{playerType}" }); } else if (selectedPlayerData.playerType == playerType) { allPlayerTypes.Add(selectedPlayerData.playerType); playerDatas.Add(new PlayerData { playerType = selectedPlayerData.playerType, playerName = $"{selectedPlayerData.playerName}" }); } } tilesManager.InitTilesData(); playerBaseHandler.InitPlayerTypes(allPlayerTypes); InitCurrentGamePlayerInfo(); InitBotRuntimeData(); AssignPlayerAndBotStates(selectedPlayerData.playerType); SetCanRollDiceForUser(!botTypesInGame.Contains(allPlayerTypes[0])); if (botTypesInGame.Contains(allPlayerTypes[0])) Invoke(nameof(HandleDiceRoll), 1f); } private void InitBotRuntimeData() { botRuntimeMovementData = new Dictionary>(); 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); } } } public void InitCurrentGamePlayerInfo() { currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; Debug.Log($"currentPlayerTypeTurn: {currentPlayerTypeTurn}"); SetCurrentSelectedPointer(); // initialize the board based on the player types playerGameDatasDict = new Dictionary(); 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 > maxDiceSixRollCounter) // TODO :: Reset after test { 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 int savedPlayerId = -1; PlayerPawn pawn = null; Debug.Log($"SelectPawnFromBotBase: availPlayers.Count(): {availPlayers.Count()}, CanRollDiceAgain: {CanRollDiceAgain}"); if (playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInHome == 0) { UpdateActivePlayersAndSetDisplay(); } 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]: {key}, {botPawnsDictForCurrentPlayer[key]}"); // botPawnsDictForCurrentPlayer[key] = BotMove.NoMoves; } Debug.Log($"Before Iterating"); foreach (var playerPawn in availPlayers) { int possibleSteps = 0; Tile possibleTileData = null; if (playerPawn.GetPlayerState() != PlayerState.InFinishingPath) FindPossibleTileData(playerPawn, out possibleSteps, out possibleTileData); if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath || possibleSteps > playerGameDatasDict[currentPlayerTypeTurn].endIndex) // TODO :: have a better second check { 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 != null && possibleTileData.IsSafeZone) { Debug.Log($"AI playerPawn :: {playerPawn.name} :: {playerPawn.PlayerId} :: safeMove"); botPawnsDictForCurrentPlayer[playerPawn.PlayerId] = BotMove.SafeMove; } else if (possibleTileData != null && possibleTileData.HasPawnsAvailable && possibleTileData.CurrentHoldingPlayerType != playerPawn.PlayerType) { 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"); } } if (pawn != null) { Debug.Log($"AI playerPawn :: {pawn.name} :: SelectedPawn: {pawn.name}"); OnPawnSelected(pawn); } else { if (CheckForMaxDiceRollAttempt()) { return; } if (CanRollDiceAgain) HandleDiceRoll(); else SwitchPlayer(); } 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; } } } } private void FindPossibleTileData(PlayerPawn playerPawn, out int possibleSteps, out Tile possibleTileData) { int lastStepGenTile = totalStepsForCharacter - tilesManager.GetFinishingTileDataLength(playerPawn.PlayerType);//playerGameDatasDict[playerPawn.PlayerType].endIndex; int possibleTileIndex = playerPawn.CurrentTileIndex + diceRolledValue; int lastTileIndex = tilesManager.GetGeneralTilesLength() - 1; bool canGoingInsideFinishingPath = IsGoingInsideFinishingPath(playerPawn, out possibleSteps); int index = canGoingInsideFinishingPath ? possibleSteps - lastStepGenTile - 1 : possibleTileIndex > lastTileIndex ? possibleTileIndex - lastTileIndex - 1 : possibleTileIndex; // case for addressing the scenario when going through the last index of general tiles. Debug.Log($"possibleTileIndex: {possibleTileIndex}, lastStepGenTileIdx: {lastStepGenTile}"); Debug.Log($"index: {index}"); possibleTileData = canGoingInsideFinishingPath ? tilesManager.RetrieveFinishingTileBasedOnIndex(playerPawn.PlayerType, index) : tilesManager.RetrieveTileBasedOnIndex(index); } public bool IsGoingInsideFinishingPath(PlayerPawn playerPawn, out int possibleSteps) { possibleSteps = playerGameDatasDict[playerPawn.PlayerType].playerPawnsDict[playerPawn.PlayerId].StepsTaken + diceRolledValue; return possibleSteps > tilesManager.GetGeneralTilesLength() - 1; } 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 = new List(); 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 UpdateActivePlayersAndSetDisplay(); 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); } for (int idx = indexesToRemove.Count - 1; idx >= 0; idx--) availPlayers.RemoveAt(idx); // if (availPlayers.Count() < 1) Debug.Log($"CustomAvailablePlayers: {customAvailPlayers}"); canSwitchPlayer = customAvailPlayers < 1; CanRollDiceAgain = false; } Debug.Log($"CanRollDiceAgain: {CanRollDiceAgain}, canSwitchPlayer: {canSwitchPlayer}"); } private void UpdateActivePlayersAndSetDisplay() { availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn) .Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone || pawn.GetPlayerState() == PlayerState.Moving || pawn.GetPlayerState() == PlayerState.InFinishingPath).ToList(); SetDisplayCountForAllAvailPlayers(true); } 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) { Debug.Log($"#### UpdatePlayerState "); playerGameDatasDict[playerPawn.PlayerType].playerPawnsDict[playerPawn.PlayerId] = playerPawn; playerGameDatasDict[playerPawn.PlayerType].playerPawnsDict[playerPawn.PlayerId].SetPlayerState(playerState); playerPawn.SetPlayerState(playerState); } private void CheckDiceRollForBot() { if (CanRollDiceAgain) { HandleDiceRoll(); } } private void HandleDiceRoll() { if (isDebugTest) diceRollHandler.HandleDiceViewForBot((rollVal) => RollDiceForBot(rollVal), diceValue == 0 ? UnityEngine.Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1) : diceValue); else diceRollHandler.HandleDiceViewForBot((rollVal) => RollDiceForBot(rollVal)); } public void OnPawnSelected(PlayerPawn selectedPawn) { EnablePlayerSelectionStates(false); PlayerGameData playerGameData = playerGameDatasDict[currentPlayerTypeTurn]; Debug.Log($"playerPawn.GetPlayerState(): {selectedPawn.GetPlayerState()}"); if (selectedPawn.GetPlayerState() == PlayerState.InHome) { Tile targetTile = tilesManager.RetrieveTileBasedOnIndex(playerGameData.startIndex); selectedPawn.ShowPlayerCountCanvas(false); selectedPawn.MoveToTile( GetAndInitPositionInsideSafeZone(selectedPawn, targetTile), onComplete: () => { playerGameDatasDict[playerGameData.playerType].totalPawnsInHome--; UpdatePlayerState(selectedPawn, PlayerState.InSafeZone); ShowUpdatedPlayerCountOnTile(selectedPawn); if (CheckForMaxDiceRollAttempt()) { return; } if (selectedPawn.IsBotPlayer) CheckDiceRollForBot(); else SetCanRollDiceForUser(true); }, playerGameData.startIndex); return; } else if (selectedPawn.GetPlayerState() == PlayerState.InFinishingPath) { Tile currentSittingTile = tilesManager.RetrieveFinishingTileBasedOnIndex(selectedPawn.PlayerType, selectedPawn.CurrentTileIndex); currentSittingTile.ResetPlayerPawn(selectedPawn); if (currentSittingTile.HasPawnsAvailable) { var playerPawns = currentSittingTile.GetPlayerPawns(); foreach (var pawn in playerPawns) ShowUpdatedPlayerCountOnTile(pawn); } ApplyFinishingPathLogic(selectedPawn); } else if (selectedPawn.CurrentTileIndex == playerGameDatasDict[currentPlayerTypeTurn].endIndex) { tilesManager.RetrieveTileBasedOnIndex(selectedPawn.CurrentTileIndex).ResetPlayerPawn(selectedPawn); ApplyFinishingPathLogic(selectedPawn); } else if (selectedPawn.GetPlayerState() == PlayerState.InSafeZone || selectedPawn.GetPlayerState() == PlayerState.Moving) { // move based on the dice value Debug.Log($"Tile Index :: currentTileIndex: {selectedPawn.CurrentTileIndex}"); int nextTileIdx = GetNextGeneralTileIndex(selectedPawn); int targetIdx = selectedPawn.CurrentTileIndex + diceRolledValue; if (nextTileIdx == 0) targetIdx = (targetIdx - selectedPawn.CurrentTileIndex) - 1; Tile currentSittingTile = tilesManager.RetrieveTileBasedOnIndex(selectedPawn.CurrentTileIndex); if (currentSittingTile.IsSafeZone) { SafeTile safeTile = (SafeTile)currentSittingTile; safeTile.UpdateSafeZonePlayerData(currentPlayerTypeTurn, selectedPawn); if (safeTile.ContainsPlayerType(selectedPawn.PlayerType)) { var playerPawns = safeTile.GetPlayerPawns(selectedPawn.PlayerType); if (safeTile.PlayerTypesCount == 1) { PlayerType playerType = safeTile.GetFirstPlayerType(); foreach (var pawn in playerPawns) pawn.MoveToCustomTilePosition(safeTile.CenterPlacementPosition); } if (safeTile.ContainsPlayerType(selectedPawn.PlayerType)) { foreach (var pawn in playerPawns) ShowUpdatedPlayerCountOnTile(pawn); } } } else { currentSittingTile.ResetPlayerPawn(selectedPawn); if (currentSittingTile.HasPawnsAvailable) { var playerPawns = currentSittingTile.GetPlayerPawns(); foreach (var pawn in playerPawns) ShowUpdatedPlayerCountOnTile(pawn); } } MoveThroughTiles(selectedPawn, 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}"); playerPawn.ShowPlayerCountCanvas(false); 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 (playerPawn) UpdatePlayerState(playerPawn, tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex).IsSafeZone ? PlayerState.InSafeZone : PlayerState.Moving); if (!CanRollDiceAgain) { Debug.Log($"currentPlayerTurn: {currentPlayerTypeTurn}"); Debug.Log($"currentPlayerTurnIndex: {currentPlayerTurnIndex}"); Debug.Log($"before SwitchPlayer availPlayers: {availPlayers.Count}, playerPawn: {playerPawn}"); UpdateActivePlayersAndSetDisplay(); Debug.Log($"after SwitchPlayer availPlayers: {availPlayers.Count}, playerPawn: {playerPawn}"); SetDisplayCountForAllAvailPlayers(false); if (allPlayerTypes.Count == 1) { Debug.LogError($"GAME IS OVER"); return; } currentPlayerTurnIndex = allPlayerTypes.FindIndex(type => type == currentPlayerTypeTurn); if (currentPlayerTypeTurn == allPlayerTypes[allPlayerTypes.Count - 1]) { currentPlayerTurnIndex = 0; currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } else { currentPlayerTurnIndex++; currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } uIManager.UpdatePlayerTurnText(currentPlayerTypeTurn); diceSixRollCounter = 0; diceText.text = $"{0}"; UpdateActivePlayersAndSetDisplay(); } SetCanRollDiceForUser(!botTypesInGame.Contains(currentPlayerTypeTurn)); Debug.Log($"CurrentPlayerTurn: {currentPlayerTypeTurn}"); SetCurrentSelectedPointer(); pointerMeshRend.material = turnMat; // pointerMeshRend.materials[0] = turnMat; 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 SetCurrentSelectedPointer() { var tempPos = playerBaseHandler.GetPlayerBase(currentPlayerTypeTurn).transform.position; pointerDebug.position = new Vector3(tempPos.x, 3f, tempPos.z); } public void SetDisplayCountForAllAvailPlayers(bool state) { if (state) { availPlayers.ForEach(pawn => ShowUpdatedPlayerCountOnTile(pawn)); } else { availPlayers.ForEach(pawn => pawn.ShowPlayerCountCanvas(false)); } } 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.ShowPlayerCountCanvas(false); 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 (CanRollDiceAgain) ShowUpdatedPlayerCountOnTile(playerPawn); 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); // UpdatePlayerCountOnTile(playerPawn, true); return; } CanRollDiceAgain = true; if (!playerPawn.IsBotPlayer) SetCanRollDiceForUser(true); } nextTile.InitPlayerPawn(playerPawn, currentPlayerTypeTurn); ShowUpdatedPlayerCountOnTile(playerPawn); 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.RetrieveFinishingTileBasedOnIndex(currentPlayerTypeTurn, index).transform.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 { if (playerPawn.CurrentTileIndex == tilesManager.GetFinishingTileDataLength(currentPlayerTypeTurn) - 1) { playerPawn.ShowPlayerCountCanvas(false); UpdatePlayerState(playerPawn, PlayerState.HasFinished); playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished++; if (playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished == playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Count) { CanRollDiceAgain = false; var playerTypeToRemove = currentPlayerTypeTurn; SwitchPlayer(); if (allPlayerTypes.Contains(playerTypeToRemove)) { allPlayerTypes.Remove(playerTypeToRemove); playerDatas.FirstOrDefault(data => data.playerType == playerTypeToRemove).ranking = TotalPlayersInGame - allPlayerTypes.Count; } if (allPlayerTypes.Count == 1) { // Game is over var lastUnfinishingPlayerType = allPlayerTypes[0]; allPlayerTypes.RemoveAt(0); playerDatas.FirstOrDefault(data => data.playerType == lastUnfinishingPlayerType).ranking = TotalPlayersInGame - allPlayerTypes.Count; // Show Game Over panel gameManager.OnGameStateChanged(GameState.GameOver); return; } } else { CanRollDiceAgain = true; if (playerPawn.IsBotPlayer) CheckDiceRollForBot(); else SetCanRollDiceForUser(true); } } else { // activate here tilesManager.RetrieveFinishingTileBasedOnIndex(currentPlayerTypeTurn, playerPawn.CurrentTileIndex).InitPlayerPawn(playerPawn, currentPlayerTypeTurn); if (CheckForMaxDiceRollAttempt()) { return; } if (CanRollDiceAgain) ShowUpdatedPlayerCountOnTile(playerPawn); SwitchPlayer(); } } }, index); } private void SetCanRollDiceForUser(bool state) { CanRollDiceForUser = state; Debug.Log($"CAnRollDiceForUser: {CanRollDiceForUser}"); } private void ShowUpdatedPlayerCountOnTile(PlayerPawn playerPawn) { Tile tile = playerPawn.GetPlayerState() == PlayerState.InFinishingPath ? tilesManager.RetrieveFinishingTileBasedOnIndex(playerPawn.PlayerType, playerPawn.CurrentTileIndex) : tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex); playerPawn.ShowPlayerCountCanvas(true); int count = 0; if (tile.IsSafeZone) { count = (tile as SafeTile).GetPlayerPawnsCountInTile(playerPawn.PlayerType); } else { count = tile.TotalPawnsInTile; } Debug.Log($"ShowUpdatedPlayerCountOnTile: {count}"); playerPawn.PlayerCountCanvas.SetPlayerCount(count); } public void ResetData() { ResetGameRestartData(); playerDatas = null; botTypesInGame = null; allPlayerTypes = null; botRuntimeMovementData = null; playerGameDatasDict = null; playerDatas = null; availPlayers = null; } public void ResetGameRestartData() { currentPlayerTurnIndex = 0; } }