예제 #1
0
        private void picMainBoard_Click(object sender, System.EventArgs e)
        {
            switch (m_Phase)
            {
            case GamePhase.PlacingShips:
                if (!Client.Board.CanPlaceShip(m_Placing))
                {
                    break;
                }

                //Client.Board.SetShip(m_PlacingType, m_Placing);
                picMainBoard.Enabled = false;
                lblGameStatus.Text   = "Hold on...";
                Client.SendPlaceShip(m_Placing);

                break;

            case GamePhase.OurTurn:
                if (!m_MousePosition.IsWithinBoard())
                {
                    break;
                }

                picMainBoard.Enabled = false;
                lblGameStatus.Text   = "Hold on...";
                Client.SendShootRequest(m_MousePosition);
                break;
            }
        }
예제 #2
0
        private static void OnPlayerShoot(Packet recv)
        {
            // trivial safety measure
            if (!gameStarted)
            {
                return;
            }

            // only the current player is allowed to place shots
            var player = GetPlayerForPeerID(recv.GetSender());

            if (player == null || player.IsPlayerOne != whoseTurn)
            {
                return;
            }

            // to prevent a player from firing multiple shots per turn
            if (shotLaunchedThisTurn)
            {
                return;
            }
            shotLaunchedThisTurn = true;

            var opponent = GetOtherPlayer(player); // whoseTurn ? player2 : player1;

            Debug.Assert(player != opponent);

            using (var instream = recv.GetStream()) {
                var        acceptable = true;
                var        pos        = new BoardPosition(instream.ReadByte(), instream.ReadByte());
                ShotResult result     = 0;

                // Reply to player who placed the shot
                using (var ms = new MemoryStream()) {
                    using (var outstream = new BinaryWriter(ms, Encoding.UTF8)) {
                        outstream.Write((byte)pos.x);
                        outstream.Write((byte)pos.y);

                        if (!pos.IsWithinBoard() || opponent.Board.Shots.ContainsKey(pos))
                        {
                            // this shot is invalid, it's either outside the board, or already been shot at before
                            shotLaunchedThisTurn = false; // permit retry
                            acceptable           = false;
                            outstream.Write(false);
                        }
                        else
                        {
                            // shot position is acceptable; actually place it and determine result
                            result = opponent.Board.DoIncomingShotAt(pos, out var hitWhat);
                            opponent.Board.SetShotResultAt(pos, result);

                            outstream.Write(true);
                            outstream.Write((byte)result);

                            // if shot hit a ship, also indicate whether the ship was sunk
                            if (result == ShotResult.Hit)
                            {
                                var ship = opponent.Board.Ships[hitWhat];
                                var sunk = ship.IsSunk();
                                outstream.Write(sunk);

                                // and only if actually sunk, do we tell the client what ship it was (minor security measure)
                                if (sunk)
                                {
                                    outstream.Write((byte)hitWhat);
                                    outstream.Write((byte)ship.Position.x);
                                    outstream.Write((byte)ship.Position.y);
                                    outstream.Write((byte)ship.Orientation);
                                }
                            }
                        }

                        using (var packet = new Packet((PacketCommand)GameCommand.ShootResult, ms.ToArray()))
                            peer.Send(packet, player.NetworkID, PacketOptions.RELIABLE);
                    }
                }

                // Inform other player of the shot
                if (!acceptable)
                {
                    return;
                }
                using (var ms = new MemoryStream()) {
                    using (var outstream = new BinaryWriter(ms, Encoding.UTF8)) {
                        outstream.Write((byte)pos.x);
                        outstream.Write((byte)pos.y);
                        outstream.Write((byte)result);

                        using (var packet = new Packet((PacketCommand)GameCommand.ShootIncoming, ms.ToArray()))
                            peer.Send(packet, opponent.NetworkID, PacketOptions.RELIABLE);
                    }
                }
            }

            // this is a very cheapskate way of pausing the game. I want both players to have some time to view the shot's
            // results, before the game switches to the next turn. And handling it clientside (in winforms) is too painful.
            Thread.Sleep(2000);

            // check if the opponent is now screwed
            if (opponent.Board.GetAllShipsSunk())
            {
                // game over
                using (var packet = new Packet((PacketCommand)GameCommand.GameWin, EmptyPayload))
                    peer.Send(packet, player.NetworkID, PacketOptions.RELIABLE);
                using (var packet = new Packet((PacketCommand)GameCommand.GameLose, EmptyPayload))
                    peer.Send(packet, opponent.NetworkID, PacketOptions.RELIABLE);

                gameStarted = false;
            }
            else
            {
                BeginNextTurn();
            }
        }