private void HandleLocalPlayerOperation() { // update local data CurrentRoundStatus.SetCurrentPlaceIndex(OperationPlayerIndex); int placeIndex = CurrentRoundStatus.CurrentPlaceIndex; Assert.IsTrue(placeIndex == 0); SetRoundStatusData(); // update ui elements controller.TableTilesManager.SetMelds(placeIndex, HandData.OpenMelds); // if not kong, start timer if (Operation.Type != OutTurnOperationType.Kong) { controller.TurnTimeController.StartCountDown(CurrentRoundStatus.GameSetting.BaseTurnTime, BonusTurnTime, () => { Debug.Log("Time out, automatically discard rightmost tile"); CurrentRoundStatus.SetRichiing(false); var tile = HandData.HandTiles[HandData.HandTiles.Length - 1]; ClientBehaviour.Instance.OnDiscardTile(tile, false, 0); }); } }
private void HandleFourRichis() { // Get waiting tiles for each player var waitingDataArray = new WaitingData[players.Count]; for (int playerIndex = 0; playerIndex < players.Count; playerIndex++) { var hand = CurrentRoundStatus.HandTiles(playerIndex); var open = CurrentRoundStatus.Melds(playerIndex); waitingDataArray[playerIndex] = new WaitingData { HandTiles = hand, WaitingTiles = MahjongLogic.WinningTiles(hand, open).ToArray() }; } // Get messages for (int i = 0; i < players.Count; i++) { infos[i] = new EventMessages.RoundDrawInfo { RoundDrawType = RoundDrawType, WaitingData = waitingDataArray }; } next = waitingDataArray[CurrentRoundStatus.OyaPlayerIndex].WaitingTiles.Length > 0; extra = true; // Get point transfers for (int playerIndex = 0; playerIndex < players.Count; playerIndex++) { var waitingTiles = waitingDataArray[playerIndex].WaitingTiles; if (waitingTiles.Length > 0) { continue; } GetTransfersForFalseRichi(playerIndex, transfers); } }
public override void OnServerStateEnter() { PhotonNetwork.AddCallbackTarget(this); if (CurrentRoundStatus.CurrentPlayerIndex != CurrentPlayerIndex) { Debug.LogError("[Server] currentPlayerIndex does not match, this should not happen"); CurrentRoundStatus.CurrentPlayerIndex = CurrentPlayerIndex; } UpdateRoundStatus(); Debug.Log($"[Server] CurrentRoundStatus: {CurrentRoundStatus}"); responds = new bool[players.Count]; operations = new OutTurnOperation[players.Count]; var rivers = CurrentRoundStatus.Rivers; // Get messages and send them to players for (int i = 0; i < players.Count; i++) { var info = new EventMessages.DiscardOperationInfo { PlayerIndex = i, CurrentTurnPlayerIndex = CurrentPlayerIndex, IsRichiing = IsRichiing, DiscardingLastDraw = DiscardLastDraw, Tile = DiscardTile, BonusTurnTime = CurrentRoundStatus.GetBonusTurnTime(i), Zhenting = CurrentRoundStatus.IsZhenting(i), Operations = GetOperations(i), HandTiles = CurrentRoundStatus.HandTiles(i), Rivers = rivers }; var player = CurrentRoundStatus.GetPlayer(i); ClientBehaviour.Instance.photonView.RPC("RpcDiscardOperation", player, info); } firstSendTime = Time.time; serverTimeOut = gameSettings.BaseTurnTime + CurrentRoundStatus.MaxBonusTurnTime + ServerConstants.ServerTimeBuffer; }
private void NextState() { if (outTurnOperations.All(op => op.Type == OutTurnOperationType.Skip)) { // no one claimed a rob kong var turnDoraAfterDiscard = Kong.Side != MeldSide.Self; CurrentRoundStatus.BreakOneShotsAndFirstTurn(); ServerBehaviour.Instance.DrawTile(CurrentPlayerIndex, true, turnDoraAfterDiscard); return; } if (outTurnOperations.Any(op => op.Type == OutTurnOperationType.Rong)) { var discardingTile = GetTileFromKong(); ServerBehaviour.Instance.TurnEnd(CurrentPlayerIndex, discardingTile, false, outTurnOperations, true, false); return; } Debug.LogError( $"[Server] Logically cannot reach here, operations are {string.Join("|", outTurnOperations)}"); }
private OutTurnOperation[] GetOperations(int playerIndex) { if (playerIndex == CurrentPlayerIndex) { return new OutTurnOperation[] { new OutTurnOperation { Type = OutTurnOperationType.Skip } } } ; // other players' operations var operations = new List <OutTurnOperation> { new OutTurnOperation { Type = OutTurnOperationType.Skip } }; // test rong TestRong(playerIndex, DiscardTile, operations); if (!CurrentRoundStatus.RichiStatus(playerIndex)) { // get side var side = GetSide(playerIndex, CurrentPlayerIndex, CurrentRoundStatus.TotalPlayers); var handTiles = CurrentRoundStatus.HandTiles(playerIndex); // test kong TestKongs(handTiles, DiscardTile, side, operations); // test pong TestPongs(handTiles, DiscardTile, side, operations); // test chow TestChows(handTiles, DiscardTile, side, operations); } return(operations.ToArray()); }
public override void OnServerStateEnter() { MahjongSet.Reset(); // throwing dice var dice = Random.Range(CurrentRoundStatus.GameSettings.DiceMin, CurrentRoundStatus.GameSettings.DiceMax + 1); CurrentRoundStatus.NextRound(dice, NextRound, ExtraRound, KeepSticks); // draw initial tiles DrawInitial(); Debug.Log("[Server] Initial tiles distribution done"); CurrentRoundStatus.SortHandTiles(); CurrentRoundStatus.SetBonusTurnTime(gameSettings.BonusTurnTime); responds = new bool[players.Count]; var room = PhotonNetwork.CurrentRoom; for (int index = 0; index < players.Count; index++) { var tiles = CurrentRoundStatus.HandTiles(index); Debug.Log($"[Server] Hand tiles of player {index}: {string.Join("", tiles)}"); var info = new EventMessages.RoundStartInfo { PlayerIndex = index, Field = CurrentRoundStatus.Field, Dice = CurrentRoundStatus.Dice, Extra = CurrentRoundStatus.Extra, RichiSticks = CurrentRoundStatus.RichiSticks, OyaPlayerIndex = CurrentRoundStatus.OyaPlayerIndex, Points = CurrentRoundStatus.Points.ToArray(), InitialHandTiles = tiles, MahjongSetData = MahjongSet.Data }; var player = CurrentRoundStatus.GetPlayer(index); ClientBehaviour.Instance.photonView.RPC("RpcRoundStart", player, info); } firstTime = Time.time; }
private InTurnOperation[] GetOperations(int playerIndex) { var operations = new List <InTurnOperation> { new InTurnOperation { Type = InTurnOperationType.Discard } }; // test tsumo TestTsumo(playerIndex, justDraw, operations); var handTiles = CurrentRoundStatus.HandTiles(playerIndex); var openMelds = CurrentRoundStatus.Melds(playerIndex); // test round draw Test9Orphans(handTiles, operations); // test richi TestRichi(playerIndex, handTiles, openMelds, operations); // test kongs TestKongs(playerIndex, handTiles, operations); // test bei TestBei(playerIndex, handTiles, operations); return(operations.ToArray()); }
private void UpdateRoundStatus() { var lastDraw = (Tile)CurrentRoundStatus.LastDraw; CurrentRoundStatus.LastDraw = null; CurrentRoundStatus.AddTile(CurrentPlayerIndex, lastDraw); if (Kong.IsAdded) // add kong { CurrentRoundStatus.AddKong(CurrentPlayerIndex, Kong); CurrentRoundStatus.RemoveTile(CurrentPlayerIndex, Kong.Extra); } else // self kong { CurrentRoundStatus.AddMeld(CurrentPlayerIndex, Kong); CurrentRoundStatus.RemoveTile(CurrentPlayerIndex, Kong); } CurrentRoundStatus.SortHandTiles(); // turn dora if this is a self kong if (Kong.Side == MeldSide.Self) { MahjongSet.TurnDora(); } }
private void DrawInitial() { for (int round = 0; round < MahjongConstants.InitialDrawRound; round++) { // Draw 4 tiles for each player for (int index = 0; index < players.Count; index++) { for (int i = 0; i < MahjongConstants.TilesEveryRound; i++) { var tile = MahjongSet.DrawTile(); CurrentRoundStatus.AddTile(index, tile); } } } // Last round, 1 tile for each player for (int index = 0; index < players.Count; index++) { for (int i = 0; i < MahjongConstants.TilesLastRound; i++) { var tile = MahjongSet.DrawTile(); CurrentRoundStatus.AddTile(index, tile); } } }
private void HandleRoundDraw() { // Get waiting tiles for each player var waitingDataArray = new WaitingData[players.Count]; for (int playerIndex = 0; playerIndex < players.Count; playerIndex++) { var hand = CurrentRoundStatus.HandTiles(playerIndex); var open = CurrentRoundStatus.Melds(playerIndex); waitingDataArray[playerIndex] = new WaitingData { HandTiles = hand, WaitingTiles = MahjongLogic.WinningTiles(hand, open).ToArray() }; } // Get messages for (int i = 0; i < players.Count; i++) { infos[i] = new EventMessages.RoundDrawInfo { RoundDrawType = RoundDrawType, WaitingData = waitingDataArray }; } // Get point transfers // get player indices of those are ready and not var readyIndices = new List <int>(); var notReadyIndices = new List <int>(); for (int playerIndex = 0; playerIndex < players.Count; playerIndex++) { if (waitingDataArray[playerIndex].WaitingTiles.Length > 0) { readyIndices.Add(playerIndex); } else { notReadyIndices.Add(playerIndex); } } next = notReadyIndices.Contains(CurrentRoundStatus.OyaPlayerIndex); extra = true; // no one is ready or every one is ready if (readyIndices.Count == 0 || notReadyIndices.Count == 0) { return; } // get transfers according to total count of players switch (players.Count) { case 2: GetTransfersFor2(readyIndices, notReadyIndices, transfers); break; case 3: GetTransfersFor3(readyIndices, notReadyIndices, transfers); break; case 4: GetTransfersFor4(readyIndices, notReadyIndices, transfers); break; default: Debug.LogError("This should not happen"); break; } // test for false richi foreach (var playerIndex in notReadyIndices) { if (CurrentRoundStatus.RichiStatus(playerIndex)) { GetTransfersForFalseRichi(playerIndex, transfers); } } }
public override void OnClientStateExit() { CurrentRoundStatus.ClearPossibleWaitingTiles(); controller.InTurnPanelManager.Close(); }
public override void OnServerStateExit() { PhotonNetwork.RemoveCallbackTarget(this); CurrentRoundStatus.CheckOneShot(CurrentPlayerIndex); }
private OutTurnOperationType ChooseOperations() { Debug.Log($"[Server] Operation before choosing: {string.Join(",", Operations)}"); // test every circumstances by priority // test for rong if (Operations.Any(op => op.Type == OutTurnOperationType.Rong)) { // check if 3 rong if (CurrentRoundStatus.CheckThreeRongs(Operations)) { for (int i = 0; i < Operations.Length; i++) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.RoundDraw, RoundDrawType = RoundDrawType.ThreeRong }; } return(OutTurnOperationType.RoundDraw); } for (int i = 0; i < Operations.Length; i++) { if (Operations[i].Type != OutTurnOperationType.Rong) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.Skip } } ; } return(OutTurnOperationType.Rong); } // check if 4 winds if (CurrentRoundStatus.CheckFourWinds()) { Debug.Log($"[Server] Round draw -- Four winds"); for (int i = 0; i < Operations.Length; i++) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.RoundDraw, RoundDrawType = RoundDrawType.FourWinds }; } return(OutTurnOperationType.RoundDraw); } // check if 4 richis if (CurrentRoundStatus.CheckFourRichis()) { Debug.Log($"[Server] Round draw -- Four richis"); for (int i = 0; i < Operations.Length; i++) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.RoundDraw, RoundDrawType = RoundDrawType.FourRichis }; } return(OutTurnOperationType.RoundDraw); } // check if 4 kongs if (CurrentRoundStatus.CheckFourKongs()) { Debug.Log($"[Server] Round draw -- Four kongs"); for (int i = 0; i < Operations.Length; i++) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.RoundDraw, RoundDrawType = RoundDrawType.FourKongs }; } return(OutTurnOperationType.RoundDraw); } // check if run out of tiles -- leads to a normal round draw if (MahjongSet.TilesRemain == gameSettings.MountainReservedTiles) { // no more tiles to draw and no one choose a rong operation. Debug.Log("No more tiles to draw and nobody claims a rong, the round has drawn."); for (int i = 0; i < Operations.Length; i++) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.RoundDraw, RoundDrawType = RoundDrawType.RoundDraw } } ; return(OutTurnOperationType.RoundDraw); } // check if some one claimed kong if (Operations.Any(op => op.Type == OutTurnOperationType.Kong)) { for (int i = 0; i < Operations.Length; i++) { if (Operations[i].Type != OutTurnOperationType.Kong) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.Skip } } ; } return(OutTurnOperationType.Kong); } // check if some one claimed pong if (Operations.Any(op => op.Type == OutTurnOperationType.Pong)) { for (int i = 0; i < Operations.Length; i++) { if (Operations[i].Type != OutTurnOperationType.Pong) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.Skip } } ; } return(OutTurnOperationType.Pong); } // check if some one claimed chow if (Operations.Any(op => op.Type == OutTurnOperationType.Chow)) { for (int i = 0; i < Operations.Length; i++) { if (Operations[i].Type != OutTurnOperationType.Chow) { Operations[i] = new OutTurnOperation { Type = OutTurnOperationType.Skip } } ; } return(OutTurnOperationType.Chow); } // no particular operations -- skip return(OutTurnOperationType.Skip); }
public override void OnServerStateEnter() { PhotonNetwork.AddCallbackTarget(this); int multiplier = gameSettings.GetMultiplier(CurrentRoundStatus.IsDealer(TsumoPlayerIndex), players.Count); var netInfo = new NetworkPointInfo { Fu = TsumoPointInfo.Fu, YakuValues = TsumoPointInfo.YakuList.ToArray(), Dora = TsumoPointInfo.Dora, UraDora = TsumoPointInfo.UraDora, RedDora = TsumoPointInfo.RedDora, IsQTJ = TsumoPointInfo.IsQTJ }; var info = new EventMessages.TsumoInfo { TsumoPlayerIndex = TsumoPlayerIndex, TsumoPlayerName = CurrentRoundStatus.GetPlayerName(TsumoPlayerIndex), TsumoHandData = CurrentRoundStatus.HandData(TsumoPlayerIndex), WinningTile = WinningTile, DoraIndicators = MahjongSet.DoraIndicators, UraDoraIndicators = MahjongSet.UraDoraIndicators, IsRichi = CurrentRoundStatus.RichiStatus(TsumoPlayerIndex), TsumoPointInfo = netInfo, TotalPoints = TsumoPointInfo.BasePoint * multiplier }; // send rpc calls ClientBehaviour.Instance.photonView.RPC("RpcTsumo", RpcTarget.AllBufferedViaServer, info); // get point transfers // todo -- tsumo loss related, now there is tsumo loss by default transfers = new List <PointTransfer>(); for (int playerIndex = 0; playerIndex < players.Count; playerIndex++) { if (playerIndex == TsumoPlayerIndex) { continue; } int amount = TsumoPointInfo.BasePoint; if (CurrentRoundStatus.IsDealer(playerIndex)) { amount *= 2; } int extraPoints = CurrentRoundStatus.ExtraPoints; transfers.Add(new PointTransfer { From = playerIndex, To = TsumoPlayerIndex, Amount = amount + extraPoints }); } // richi-sticks-points transfers.Add(new PointTransfer { From = -1, To = TsumoPlayerIndex, Amount = CurrentRoundStatus.RichiSticksPoints }); responds = new bool[players.Count]; // determine server time out serverTimeOut = ServerMaxTimeOut + ServerConstants.ServerTimeBuffer; firstTime = Time.time; }
private void EnableAllTiles() { CurrentRoundStatus.SetForbiddenTiles(null); }
public override void OnServerStateEnter() { PhotonNetwork.AddCallbackTarget(this); responds = new bool[players.Count]; var playerNames = RongPlayerIndices.Select( playerIndex => CurrentRoundStatus.GetPlayerName(playerIndex) ).ToArray(); var handData = RongPlayerIndices.Select( playerIndex => CurrentRoundStatus.HandData(playerIndex) ).ToArray(); var richiStatus = RongPlayerIndices.Select( playerIndex => CurrentRoundStatus.RichiStatus(playerIndex) ).ToArray(); var multipliers = RongPlayerIndices.Select( playerIndex => gameSettings.GetMultiplier(CurrentRoundStatus.IsDealer(playerIndex), players.Count) ).ToArray(); var totalPoints = RongPointInfos.Select((info, i) => info.BasePoint * multipliers[i]).ToArray(); var netInfos = RongPointInfos.Select(info => new NetworkPointInfo { Fu = info.Fu, YakuValues = info.YakuList.ToArray(), Dora = info.Dora, UraDora = info.UraDora, RedDora = info.RedDora, BeiDora = info.BeiDora, IsQTJ = info.IsQTJ }).ToArray(); Debug.Log($"The following players are claiming rong: {string.Join(",", RongPlayerIndices)}, " + $"PlayerNames: {string.Join(",", playerNames)}"); var rongInfo = new EventMessages.RongInfo { RongPlayerIndices = RongPlayerIndices, RongPlayerNames = playerNames, HandData = handData, WinningTile = WinningTile, DoraIndicators = MahjongSet.DoraIndicators, UraDoraIndicators = MahjongSet.UraDoraIndicators, RongPlayerRichiStatus = richiStatus, RongPointInfos = netInfos, TotalPoints = totalPoints }; // send rpc calls ClientBehaviour.Instance.photonView.RPC("RpcRong", RpcTarget.AllBufferedViaServer, rongInfo); // get point transfers transfers = new List <PointTransfer>(); for (int i = 0; i < RongPlayerIndices.Length; i++) { var rongPlayerIndex = RongPlayerIndices[i]; var point = RongPointInfos[i]; var multiplier = multipliers[i]; int pointValue = point.BasePoint * multiplier; int extraPoints = i == 0 ? CurrentRoundStatus.ExtraPoints * (players.Count - 1) : 0; transfers.Add(new PointTransfer { From = CurrentPlayerIndex, To = rongPlayerIndex, Amount = pointValue + extraPoints }); } // richi-sticks-points transfers.Add(new PointTransfer { From = -1, To = RongPlayerIndices[0], Amount = CurrentRoundStatus.RichiSticksPoints }); next = !RongPlayerIndices.Contains(CurrentRoundStatus.OyaPlayerIndex); // determine server time out serverTimeOut = ServerMaxTimeOut * RongPointInfos.Length + ServerConstants.ServerTimeBuffer; firstTime = Time.time; }