From da4b44957b89a589a148505dfd6e2b72e1357ba0 Mon Sep 17 00:00:00 2001 From: Ashby Issac Date: Wed, 11 Feb 2026 19:53:16 +0530 Subject: [PATCH] Applied probability logic for pawns. --- .../Gameplay/Snake and Ladder/DiceView.cs | 79 +++++++++++++------ Assets/Scripts/Abstraction/Game.meta | 8 ++ Assets/Scripts/Abstraction/Game/IRollBase.cs | 11 +++ .../Abstraction/Game/IRollBase.cs.meta | 11 +++ Assets/Scripts/Gameplay/GameplayManager.cs | 62 +++++++++++---- Assets/Scripts/Gameplay/Player/PlayerBase.cs | 23 +++++- .../Gameplay/Player/PlayerBaseHandler.cs | 3 +- Assets/Scripts/Input/DiceRollHandler.cs | 12 ++- 8 files changed, 164 insertions(+), 45 deletions(-) create mode 100644 Assets/Scripts/Abstraction/Game.meta create mode 100644 Assets/Scripts/Abstraction/Game/IRollBase.cs create mode 100644 Assets/Scripts/Abstraction/Game/IRollBase.cs.meta diff --git a/Assets/External-Assets/packages/Project/Scripts/Gameplay/Snake and Ladder/DiceView.cs b/Assets/External-Assets/packages/Project/Scripts/Gameplay/Snake and Ladder/DiceView.cs index 5c62e5b..f254ac2 100644 --- a/Assets/External-Assets/packages/Project/Scripts/Gameplay/Snake and Ladder/DiceView.cs +++ b/Assets/External-Assets/packages/Project/Scripts/Gameplay/Snake and Ladder/DiceView.cs @@ -1,6 +1,8 @@ using System; using System.Collections; +using System.Collections.Generic; using UnityEngine; +using Random = UnityEngine.Random; public class DiceView : MonoBehaviour, IBase { @@ -16,10 +18,14 @@ public class DiceView : MonoBehaviour, IBase [SerializeField] private float sideForce = 0.18f; [SerializeField] private float liftForce = 0.1f; + private List probabilityValues = new List() { 3, 4, 5 }; private Quaternion startRotation; private Action onRollingComplete = null; + + private IRollBase rollBase = null; + private bool hasNoActionOnRoll = false; - void Awake() + private void Awake() { rb = GetComponent(); rb.useGravity = false; @@ -39,31 +45,31 @@ public class DiceView : MonoBehaviour, IBase } } - IEnumerator RollRoutine() + private IEnumerator RollRoutine() { rolling = true; // MICRO DELAY → breaks physics sync between dice - yield return new WaitForSeconds(UnityEngine.Random.Range(0.01f, 0.06f)); + yield return new WaitForSeconds(Random.Range(0.01f, 0.06f)); rb.useGravity = true; // PER-DICE FORCE MULTIPLIER - float spinMultiplier = UnityEngine.Random.Range(0.8f, 1.25f); + float spinMultiplier = Random.Range(0.8f, 1.25f); // RANDOM TORQUE rb.AddTorque( - UnityEngine.Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, - UnityEngine.Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, - UnityEngine.Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, + Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, + Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, + Random.Range(-baseSpinForce, baseSpinForce) * spinMultiplier, ForceMode.Impulse ); // RANDOM SIDE FORCE Vector3 sideDir = new Vector3( - UnityEngine.Random.Range(-1f, 1f), + Random.Range(-1f, 1f), 0f, - UnityEngine.Random.Range(-1f, 1f) + Random.Range(-1f, 1f) ).normalized; rb.AddForce(sideDir * sideForce, ForceMode.Impulse); @@ -73,28 +79,44 @@ public class DiceView : MonoBehaviour, IBase yield return new WaitForSeconds(sideValueTime); - int value = GetDiceValue(); - - //TODO: Use the dice value as needed - Debug.Log($"Dice rolled: {value}"); - - ResetDice(); - onRollingComplete?.Invoke(value); - } - - int GetDiceValue() - { - foreach (DiceSide side in diceSides) + int rolledVal = 0; + if (hasNoActionOnRoll) { - if (side.OnGround()) - return side.sideValue; + if (rollBase.SixRollCount == 0) + { + rollBase.UpdateMaxRollCount(probabilityValues[Random.Range(0, probabilityValues.Count)]); + } + + rollBase.UpdateSixRollCount(); + rolledVal = rollBase.SixRollCount == rollBase.MaxRollCount ? + Ludo_3D_Constants.Max_Dice_Rolls : GetDiceValue(); + } + else + { + rolledVal = GetDiceValue(); } - return 1; + if (rolledVal == Ludo_3D_Constants.Max_Dice_Rolls) + ResetRollData(); + + ResetDice(); + Debug.Log($"Dice rolled: {rolledVal}"); + onRollingComplete?.Invoke(rolledVal); + } + + private int GetDiceValue() + { + return Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1); + } + + public void ResetRollData() + { + if (rollBase != null) rollBase.ResetRollData(); } public void ResetDice() { + rollBase = null; rb.useGravity = false; rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; @@ -108,4 +130,13 @@ public class DiceView : MonoBehaviour, IBase transform.localRotation = startRotation; onRollingComplete = null; } + + public void InitOnNoActionsAfterRoll(IRollBase rollBase, bool state) + { + hasNoActionOnRoll = state; + if (!state) + return; + + this.rollBase = rollBase; + } } diff --git a/Assets/Scripts/Abstraction/Game.meta b/Assets/Scripts/Abstraction/Game.meta new file mode 100644 index 0000000..194c636 --- /dev/null +++ b/Assets/Scripts/Abstraction/Game.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05273ddf992ca4671b13f0b4b9dde85d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Abstraction/Game/IRollBase.cs b/Assets/Scripts/Abstraction/Game/IRollBase.cs new file mode 100644 index 0000000..5343e22 --- /dev/null +++ b/Assets/Scripts/Abstraction/Game/IRollBase.cs @@ -0,0 +1,11 @@ + +public interface IRollBase +{ + public int SixRollCount { get; } + + public int MaxRollCount { get; } + + void UpdateSixRollCount(); + void UpdateMaxRollCount(int val); + void ResetRollData(); +} diff --git a/Assets/Scripts/Abstraction/Game/IRollBase.cs.meta b/Assets/Scripts/Abstraction/Game/IRollBase.cs.meta new file mode 100644 index 0000000..4c36559 --- /dev/null +++ b/Assets/Scripts/Abstraction/Game/IRollBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4683cbbafe11541cf8a71cdd12df62ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/GameplayManager.cs b/Assets/Scripts/Gameplay/GameplayManager.cs index a5d53ac..12dfd21 100644 --- a/Assets/Scripts/Gameplay/GameplayManager.cs +++ b/Assets/Scripts/Gameplay/GameplayManager.cs @@ -169,7 +169,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader private void HandleDiceRollWithDelay() { - Invoke(nameof(HandleDiceRoll), botDiceRollDelay); + Invoke(nameof(RollDiceForBot), botDiceRollDelay); } private void InitBotRuntimeData() @@ -267,7 +267,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader currentPlayerTurnTimer.Init(currentPlayerTurnMaxTime, onComplete: () => { Debug.Log($"currentPlayerTurnTimer: HandleDiceViewForUser"); - diceRollHandler.HandleDiceViewForUser(); + RollDiceForUser(); }, inProgress: (remTime) => { uIManager.UpdatePlayerTurnText(currentPlayerTypeTurn, currentPlayerTurnMaxTime - (int)remTime); @@ -349,7 +349,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader public void OnDiceInteracted() { ResetCurrentPlayerTurnTimer(); - diceRollHandler.HandleDiceViewForUser(); + RollDiceForUser(); } public void RollDiceForPlayer(int rolledVal) @@ -515,7 +515,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader } if (CanRollDiceAgain) - HandleDiceRoll(); + RollDiceForBot(); else SwitchPlayer(); } @@ -570,6 +570,8 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader return possibleSteps > TilesManager.GetGeneralTilesLength() - 1; } + private bool HasNoPlayersTravelling() => Mathf.Abs(availPlayersToMove.Count - playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInFinishingPath) < 1; + public void OnDiceRolled(int rolledVal) { SetCanRollDiceForUser(false); @@ -578,9 +580,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader Debug.Log($"Tile Index :: LUDO :: rolledVal: {rolledVal} :: {currentPlayerTypeTurn}"); diceRolledValue = rolledVal; diceText.text = $"{diceRolledValue}"; - availPlayersToMove = new List(); - - InitActivePlayers(); + if (!CanRollDiceAgain) { SetDisplayCountForAllAvailPlayers(true); @@ -596,9 +596,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader if (botTypesInGame != null && !botTypesInGame.Contains(currentPlayerTypeTurn)) { - var hasNoPlayersTraveling = Mathf.Abs(availPlayersToMove.Count - playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInFinishingPath) < 1; - Debug.Log($"availPlayersToMove.Count: {availPlayersToMove.Count}, hasNoPlayersTraveling: {hasNoPlayersTraveling}, totalPawnsInFinishingPath: {playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInFinishingPath}"); - if (availPlayersToMove.Count < 1 || hasNoPlayersTraveling) + if (availPlayersToMove.Count < 1 || HasNoPlayersTravelling()) { if (playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInHome > 0) { @@ -707,6 +705,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader private void InitActivePlayers() { + availPlayersToMove = new List(); availPlayersToMove = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn) .Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone || pawn.GetPlayerState() == PlayerState.Moving || @@ -745,16 +744,48 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader { if (CanRollDiceAgain) { - HandleDiceRoll(); + RollDiceForBot(); } } - private void HandleDiceRoll() + private void RollDiceForUser() + { + InitActivePlayers(); + bool canUsePawnsFromHome = CanUsePawnsFromHome(); + diceRollHandler.HandleDiceViewForUser( + hasNoActionOnRoll: canUsePawnsFromHome, + playerBase: canUsePawnsFromHome ? PlayerBaseHandler.GetPlayerBase(currentPlayerTypeTurn) : null); + } + + private void RollDiceForBot() + { + InitActivePlayers(); + HandleDiceRollForBot(); + } + + /*** + * Summary: + * Scenario where the user/bot has no other move when some of the pawns/characters out of home + * are in finishing path and doesn't have a move from dice rolled value + */ + private bool CanUsePawnsFromHome() + { + return playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInHome > 0 && HasNoPlayersTravelling(); + } + + private void HandleDiceRollForBot() { if (isDebugAITest) - 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)); + diceRollHandler.HandleDiceViewForBot((rollVal) => RollDiceForBot(rollVal), + diceValue == 0 ? UnityEngine.Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1) : diceValue); + else + { + bool canUsePawnsFromHome = CanUsePawnsFromHome(); + diceRollHandler.HandleDiceViewForBot( + (rollVal) => RollDiceForBot(rollVal), + hasNoActionOnRoll: canUsePawnsFromHome, + playerBase: canUsePawnsFromHome ? PlayerBaseHandler.GetPlayerBase(currentPlayerTypeTurn) : null); + } } public void OnPawnSelected(PlayerPawn selectedPawn) @@ -1106,6 +1137,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader // ShowUpdatedPlayerCountOnTile(playerPawn); UpdatePlayerState(playerPawn, PlayerState.HasFinished); + playerGameDatasDict[currentPlayerTypeTurn].totalPawnsFinished++; playerGameDatasDict[currentPlayerTypeTurn].totalPawnsInFinishingPath--; diff --git a/Assets/Scripts/Gameplay/Player/PlayerBase.cs b/Assets/Scripts/Gameplay/Player/PlayerBase.cs index 49ed2fe..765d0b8 100644 --- a/Assets/Scripts/Gameplay/Player/PlayerBase.cs +++ b/Assets/Scripts/Gameplay/Player/PlayerBase.cs @@ -7,12 +7,17 @@ public class BasePlacementData public Transform placementTransform; } -public class PlayerBase : MonoBehaviour +public class PlayerBase : MonoBehaviour, IRollBase { [SerializeField] private PlayerType playerType; [SerializeField] private BasePlacementData[] basePlacementDatas; [SerializeField] private PlayerPawn[] playerPawns; [SerializeField] private GameObject playerBaseEffect; + + private int sixRollCount, maxRollCount; + + public int SixRollCount => sixRollCount; + public int MaxRollCount => maxRollCount; public bool IsBotBase { @@ -21,6 +26,22 @@ public class PlayerBase : MonoBehaviour public PlayerType GetPlayerType() => playerType; + public void UpdateSixRollCount() + { + sixRollCount++; + } + + public void ResetRollData() + { + sixRollCount = 0; + maxRollCount = 0; + } + + public void UpdateMaxRollCount(int val) + { + maxRollCount = val; + } + public void InitPlayerData() { for (int idx = 0; idx < basePlacementDatas.Length; idx++) diff --git a/Assets/Scripts/Gameplay/Player/PlayerBaseHandler.cs b/Assets/Scripts/Gameplay/Player/PlayerBaseHandler.cs index 4c431d4..709f3db 100644 --- a/Assets/Scripts/Gameplay/Player/PlayerBaseHandler.cs +++ b/Assets/Scripts/Gameplay/Player/PlayerBaseHandler.cs @@ -1,6 +1,5 @@ -using System; -using System.Collections.Generic; using UnityEngine; +using System.Collections.Generic; [System.Serializable] public class PlayerBaseData diff --git a/Assets/Scripts/Input/DiceRollHandler.cs b/Assets/Scripts/Input/DiceRollHandler.cs index 5ae04e2..c43904a 100644 --- a/Assets/Scripts/Input/DiceRollHandler.cs +++ b/Assets/Scripts/Input/DiceRollHandler.cs @@ -29,7 +29,7 @@ public class DiceRollHandler : MonoBehaviour inputManager.SetDiceRollValue(rolledVal); } - public void HandleDiceViewForUser() + public void HandleDiceViewForUser(bool hasNoActionOnRoll = false, PlayerBase playerBase = null) { if (!inputManager.GameplayManager.CanRollDiceForUser) return; @@ -39,11 +39,17 @@ public class DiceRollHandler : MonoBehaviour if (inputManager.GameplayManager.IsDebugPlayerTest) OnUserDiceRollComplete(GetDiceTestVal()); else - diceView.Roll(onComplete: (rolledVal) => OnUserDiceRollComplete(rolledVal), false); + { + diceView.InitOnNoActionsAfterRoll(playerBase, hasNoActionOnRoll); + diceView.Roll( + (rolledVal) => OnUserDiceRollComplete(rolledVal), + false); + } } - public void HandleDiceViewForBot(Action onComplete) + public void HandleDiceViewForBot(Action onComplete, bool hasNoActionOnRoll = false, PlayerBase playerBase = null) { + diceView.InitOnNoActionsAfterRoll(playerBase, hasNoActionOnRoll); diceView.Roll(onComplete: onComplete, true); }