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; public PlayerType CurrentPlayerTypeTurn => currentPlayerTypeTurn; public PlayerBaseHandler PlayerBaseHandler => playerBaseHandler; private PlayerType 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>(); public TilesManager TilesManager { get; private set; } private UIManager uIManager; private GameManager gameManager; private GameModeHandler gameModeHandler; 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(); gameModeHandler = InterfaceManager.Instance.GetInterfaceInstance(); } public void InitPlayerTypesForPVP(List types, List names) { allPlayerTypes = new List(types); playerDatas = new List(); 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(true); } 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(gameModeHandler.CurrentGameModeType != GameModeType.Bot || !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(true); 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(bool state) { availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn) .Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone || pawn.GetPlayerState() == PlayerState.Moving || pawn.GetPlayerState() == PlayerState.InFinishingPath).ToList(); SetDisplayCountForAllAvailPlayers(state); } 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( TilesManager.GetAndInitPositionInsideSafeZone(selectedPawn, targetTile, currentPlayerTypeTurn), 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 = TilesManager.GetNextGeneralTileIndex(selectedPawn.CurrentTileIndex); 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 = TilesManager.GetNextFinishingTileIndex(playerPawn.CurrentTileIndex, playerPawn.PlayerType); 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); } // TODO :: move to tiles manager 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(false); Debug.Log($"after SwitchPlayer availPlayers: {availPlayers.Count}, playerPawn: {playerPawn}"); if (allPlayerTypes.Count == 0) { 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(true); } Debug.Log($"CurrentPlayerTurn: {currentPlayerTypeTurn}"); SetCanRollDiceForUser(gameModeHandler.CurrentGameModeType != GameModeType.Bot || !botTypesInGame.Contains(currentPlayerTypeTurn)); #if UNITY_EDITOR SetCurrentSelectedPointer(); pointerMeshRend.material = turnMat; // pointerMeshRend.materials[0] = turnMat; #endif // Debug.Log($"botTypesInGame.Contains(currentPlayerTypeTurn): {botTypesInGame.Contains(currentPlayerTypeTurn)}"); if (gameModeHandler.CurrentGameModeType == GameModeType.Bot && botTypesInGame.Contains(currentPlayerTypeTurn)) // TODO :: Double check calling of the function { Debug.Log($"Invoking RollDiceForBot"); Invoke(nameof(HandleDiceRoll), 1f); } } #if UNITY_EDITOR private void SetCurrentSelectedPointer() { var tempPos = playerBaseHandler.GetPlayerBase(currentPlayerTypeTurn).transform.position; pointerDebug.position = new Vector3(tempPos.x, 3f, tempPos.z); } #endif 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 = TilesManager.GetAndInitPositionInsideSafeZone(playerPawn, targetTile, currentPlayerTypeTurn); } } Debug.Log($"tile targetPosition: {targetPosition}"); playerPawn.ShowPlayerCountCanvas(false); playerPawn.MoveToTile( targetPosition, onComplete: () => { diceRolledValue--; Debug.Log($"DiceRolledValue: {diceRolledValue}"); if (diceRolledValue > 0) { int nextTileIndex = TilesManager.GetNextGeneralTileIndex(playerPawn.CurrentTileIndex); 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(); playerGameDatasDict[pawn.PlayerType].totalPawnsInHome++; playerBaseHandler.SendPlayerToHome(pawn); } 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 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 = TilesManager.GetNextFinishingTileIndex(playerPawn.CurrentTileIndex, playerPawn.PlayerType); 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) { Tile tile = TilesManager.RetrieveFinishingTileBasedOnIndex(playerPawn.PlayerType, playerPawn.CurrentTileIndex); tile.InitPlayerPawn(playerPawn, playerPawn.PlayerType); ShowUpdatedPlayerCountOnTile(playerPawn); 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 ResetTileDatasForPlayers() { foreach (PlayerData data in playerDatas) { var pawns = playerGameDatasDict[data.playerType].playerPawnsDict.Values; foreach (var pawn in pawns) { if (pawn.GetPlayerState() == PlayerState.InHome) continue; TilesManager.ResetTileData(pawn.PlayerType, pawn.CurrentTileIndex, pawn.GetPlayerState()); } } } public void ResetData() { ResetGameRestartData(); playerDatas = null; allPlayerTypes = null; playerGameDatasDict = null; playerDatas = null; availPlayers = null; botTypesInGame = null; botRuntimeMovementData = null; } public void ResetGameRestartData() { currentPlayerTurnIndex = 0; } }