Exemple #1
0
        public void StartGame()
        {
            if (State != GameState.Joining)
            {
                return;
            }
            LastMenu = null;
            Send("Game is starting!");
            if (Players.Count < 2)
            {
                Send("Not enough players to start the game..");
                State = GameState.Ended;
                return;
            }
            if (State != GameState.Joining)
            {
                return;
            }
            Program.GamesPlayed++;
            State = GameState.Initializing;
            Players.Shuffle();
            Players.Shuffle();
            //create db entry for game
            using (var db = new CoupContext())
            {
                var grp = db.ChatGroups.FirstOrDefault(x => x.TelegramId == ChatId);
                var g   = new Database.Game {
                    GroupId = grp?.Id, GameType = IsGroup ? "Group" : IsRandom ? "Stranger" : "Friend", TimeStarted = DateTime.Now
                };
                db.Games.Add(g);
                db.SaveChanges();
                DBGameId = g.Id;
            }

            //hand out cards
            foreach (var p in Players)
            {
                var card = Cards.First();
                Cards.Remove(card);
                p.Cards.Add(card);
            }
            //round robin :P
            foreach (var p in Players)
            {
                var card = Cards.First();
                Cards.Remove(card);
                p.Cards.Add(card);
                using (var db = new CoupContext())
                {
                    //create db entry
                    var dbp = db.Players.FirstOrDefault(x => x.TelegramId == p.Id);
                    if (dbp == null)
                    {
                        dbp = new Player {
                            TelegramId = p.Id, Created = DateTime.UtcNow, Language = "English", Name = p.Name, Username = p.TeleUser.Username
                        };
                        db.Players.Add(dbp);
                        db.SaveChanges();
                    }
                    dbp.Name     = p.Name;
                    dbp.Username = p.TeleUser.Username;

                    p.Language = dbp.Language;

                    var gp = new GamePlayer()
                    {
                        GameId        = DBGameId,
                        StartingCards = p.Cards.Aggregate("", (a, b) => a + "," + b.Name)
                    };
                    dbp.GamePlayers.Add(gp);
                    db.SaveChanges();
                }
                //tell player their cards
                SendMenu(p);
                //TellCards(p);
            }
            //DEBUG OUT
#if DEBUG
            //for (int i = 0; i < Players.Count(); i++)
            //{
            //    Console.WriteLine($"Player {i}: {Players[i].Cards[0].Name}, {Players[i].Cards[1].Name}");
            //}
            //Console.WriteLine($"Deck:\n{Cards.Aggregate("", (a, b) => a + "\n" + b.Name)}");
#endif
            State = GameState.Running;

            while (true)
            {
                try
                {
                    Round++;
                    //will use break to end the game
                    foreach (var p in Players)
                    {
                        Cards.Shuffle();
                        if (p.Cards.Count() == 0)
                        {
                            continue;
                        }
                        Turn = p.Id;
                        Send($"{p.GetName()}'s turn. {p.Name.ToBold()} has {p.Coins} coins.", newMsg: true).ToList();
                        p.CallBluff = false;
                        //it is the players turn.
                        //first off, do they have to Coup?
                        if (p.Coins >= 10)
                        {
                            //Coup time!
                            Send($"{p.GetName()} has 10 or more coins, and must Coup someone.");
                            ChoiceMade = Action.Coup;
                        }
                        else
                        {
                            //ok, no, so get actions that they can make
                            Send($"{p.Name.ToBold()} please choose an action.", p.Id, menu: CreateActionMenu(p), menuTo: p.Id, newMsg: true);
                            LastMenu = null;
                            if (IsGroup)
                            {
                                Send($"{p.Name.ToBold()} please choose an action.");
                            }
                        }
                        var choice = WaitForChoice(ChoiceType.Action);
                        Console.WriteLine($"{p.Name} has chosen to {ChoiceMade}");
                        CPlayer target;
                        CPlayer blocker;
                        CPlayer bluffer;
                        IEnumerable <CPlayer> choices;
                        switch (choice)
                        {
                        //DONE
                        case Action.Income:
                            LastMenu = null;
                            Send($"{p.Name.ToBold()} has chosen to take income (1 coin).");
                            DBAddValue(p, Models.ValueType.CoinsCollected);
                            p.Coins++;
                            break;

                        case Action.ForeignAid:
                            if (PlayerMadeBlockableAction(p, choice, cardUsed: "Ambassador"))
                            {
                                LastMenu = null;
                                Send($"{p.Name.ToBold()} was not blocked, and has gained two coins.");
                                DBAddValue(p, Models.ValueType.CoinsCollected, 2);
                                p.Coins += 2;
                            }
                            break;

                        case Action.Coup:
                            p.Coins -= 7;
                            Send($"{p.Name.ToBold()} has chosen to Coup.");
                            choices = Players.Where(x => x.Id != p.Id && x.Cards.Count() > 0);
                            if (choices.Count() == 1)
                            {
                                target = choices.First();
                            }
                            else
                            {
                                Send($"Please choose who to Coup.", p.Id, menu: CreateTargetMenu(p), menuTo: p.Id);
                                LastMenu = null;
                                WaitForChoice(ChoiceType.Target);
                                target = Players.FirstOrDefault(x => x.Id == ChoiceTarget);
                            }
                            DBAddValue(p, Models.ValueType.PlayersCouped);
                            if (target == null)
                            {
                                LastMenu = null;
                                Send($"{p.Name.ToBold()} did not choose in time, and has lost 7 coins");
                                Send("Times up!", p.Id, menuTo: p.Id);
                                break;
                            }

                            if (target.Cards.Count() == 1)
                            {
                                PlayerLoseCard(target, target.Cards.First());
                                //Graveyard.Add(target.Cards.First());
                                target.Cards.Clear();
                                LastMenu = null;
                                Send($"{target.Name.ToBold()}, you have been couped.  You are out of cards, and therefore out of the game!");
                            }
                            else
                            {
                                Send($"{p.Name.ToBold()} has chosen to Coup {target.Name.ToBold()}!  {target.Name.ToBold()} please choose a card to lose.");
                                PlayerLoseCard(target);
                            }
                            break;

                        case Action.Tax:
                            if (PlayerMadeBlockableAction(p, Action.Tax))
                            {
                                LastMenu = null;
                                Send($"{p.Name.ToBold()} was not blocked, and has gained three coins.");
                                DBAddValue(p, Models.ValueType.CoinsCollected, 3);
                                p.Coins += 3;
                            }
                            break;

                        case Action.Assassinate:
                            //OH BOY
                            p.Coins -= 3;
                            Send($"{p.Name.ToBold()} has paid 3 coins to assassinate.");
                            choices = Players.Where(x => x.Id != p.Id && x.Cards.Count() > 0);
                            if (choices.Count() == 1)
                            {
                                target = choices.First();
                            }
                            else
                            {
                                Send($"Please choose who to assassinate.", p.Id, menu: CreateTargetMenu(p), menuTo: p.Id);
                                LastMenu = null;
                                WaitForChoice(ChoiceType.Target);
                                target = Players.FirstOrDefault(x => x.Id == ChoiceTarget);
                            }

                            if (target == null)
                            {
                                LastMenu = null;
                                Send("Times up!", p.Id, menuTo: p.Id);
                                Send($"{p.Name.ToBold()} did not choose in time, and has lost 3 coins!");
                                break;
                            }
                            if (PlayerMadeBlockableAction(p, choice, target, "Assassin"))
                            {
                                DBAddValue(p, Models.ValueType.PlayersAssassinated);
                                //unblocked!
                                if (target.Cards.Count() == 1)
                                {
                                    Send($"{target.Name.ToBold()}, you have been assassinated.  You are out of cards, and therefore out of the game!");
                                    PlayerLoseCard(target, target.Cards.First());
                                    //Graveyard.Add(target.Cards.First());
                                    target.Cards.Clear();
                                }
                                else
                                {
                                    Send($"{p.Name.ToBold()} was not blocked!  {target.Name.ToBold()} please choose a card to lose.");
                                    PlayerLoseCard(target);
                                }
                            }
                            break;

                        case Action.Exchange:
                            if (PlayerMadeBlockableAction(p, choice))
                            {
                                LastMenu = null;
                                Cards.Shuffle();
                                var count    = p.Cards.Count();
                                var newCards = Cards.Take(count).ToList();
                                Cards.AddRange(p.Cards);
                                newCards.AddRange(p.Cards.ToList());
                                p.Cards.Clear();
                                var menu = new InlineKeyboardMarkup(new[]
                                {
                                    newCards.Select(x => new InlineKeyboardButton(x.Name, $"card|{GameId}|{x.Name}")).ToArray()
                                });
                                LastMenu = null;
                                Turn     = p.Id; //just to be sure
                                Send($"{p.Name.ToBold()} was not blocked. Please choose your new cards in PM @{Bot.Me.Username}.");
                                Send($"{p.Name}, choose your first card", p.Id, menu: menu, newMsg: true);
                                WaitForChoice(ChoiceType.Card);
                                if (String.IsNullOrEmpty(CardToLose))
                                {
                                    LastMenu = null;
                                    Send($"Time ran out, moving on");
                                    p.Cards.AddRange(newCards.Take(count));
                                    TellCards(p);
                                    break;
                                }
                                var card2 = "";

                                newCards.Remove(newCards.First(x => x.Name == CardToLose));
                                var card1 = CardToLose;
                                CardToLose = null;
                                if (count == 2)
                                {
                                    menu = new InlineKeyboardMarkup(new[]
                                    {
                                        newCards.Select(x => new InlineKeyboardButton(x.Name, $"card|{GameId}|{x.Name}")).ToArray()
                                    });
                                    Send($"{p.Name}, choose your second card", p.Id, menu: menu, menuTo: p.Id);
                                    WaitForChoice(ChoiceType.Card);
                                    if (String.IsNullOrEmpty(CardToLose))
                                    {
                                        LastMenu = null;
                                        Send($"Time ran out, moving on");
                                        p.Cards.Add(newCards.First());
                                        TellCards(p);
                                        break;
                                    }
                                    card2      = CardToLose;
                                    CardToLose = null;
                                    newCards.Remove(newCards.First(x => x.Name == card2));
                                }
                                var newCard = Cards.First(x => x.Name == card1);
                                Cards.Remove(newCard);
                                p.Cards.Add(newCard);
                                if (count == 2)
                                {
                                    newCard = Cards.First(x => x.Name == card2);
                                    Cards.Remove(newCard);
                                    p.Cards.Add(newCard);
                                }
                                Cards.Shuffle();
                                TellCards(p);
                            }
                            break;

                        case Action.Steal:
                            Send($"{p.Name.ToBold()} has chosen to steal.");
                            choices = Players.Where(x => x.Id != p.Id && x.Cards.Count() > 0);
                            if (choices.Count() == 1)
                            {
                                target = choices.First();
                            }
                            else
                            {
                                Send($"{p.Name.ToBold()} please choose who to steal from.", p.Id, menu: CreateTargetMenu(p), menuTo: p.Id);
                                LastMenu = null;
                                WaitForChoice(ChoiceType.Target);
                                target = Players.FirstOrDefault(x => x.Id == ChoiceTarget);
                            }
                            if (target == null)
                            {
                                LastMenu = null;
                                Send("Times up!", p.Id, menuTo: p.Id);
                                Send($"{p.Name.ToBold()} did not choose in time");
                                break;
                            }
                            if (PlayerMadeBlockableAction(p, choice, target, "Captain"))
                            {
                                LastMenu = null;
                                var coinsTaken = Math.Min(target.Coins, 2);
                                DBAddValue(p, Models.ValueType.CoinsStolen, coinsTaken);
                                p.Coins      += coinsTaken;
                                target.Coins -= coinsTaken;
                                Send($"{p.Name.ToBold()} was not blocked, and has taken {coinsTaken} coins from {target.Name.ToBold()}.");
                            }
                            break;

                        case Action.Concede:
                            Graveyard.AddRange(p.Cards);
                            p.Cards.Clear();
                            LastMenu = null;
                            Send($"{p.Name} has chosen to concede the game, and is out!");
                            break;

                        default:
                            LastMenu = null;
                            Send($"{p.Name.ToBold()} did not do anything, moving on...");
                            p.AfkCount++;
                            if (p.AfkCount >= 2)
                            {
                                //out!
                                Graveyard.AddRange(p.Cards);
                                p.Cards.Clear();
                                Send($"{p.Name} is AFK, and is out!");
                            }
                            break;
                        }

                        //reset all the things
                        ChoiceMade   = Action.None;
                        ChoiceTarget = 0;
                        CardToLose   = "";
                        foreach (var pl in Players)
                        {
                            pl.CallBluff = null;
                            pl.Block     = null;
                        }
                        if (Players.Count(x => x.Cards.Count() > 0) == 1)
                        {
                            //game is over
                            var winner = Players.FirstOrDefault(x => x.Cards.Count() > 0);
                            //set the winner in the database
                            using (var db = new CoupContext())
                            {
                                var gp = GetDBGamePlayer(winner, db);
                                gp.Won         = true;
                                gp.EndingCards = winner.Cards.Count() > 1 ? winner.Cards.Aggregate("", (a, b) => a + "," + b.Name) : winner.Cards.First().Name;

                                var g = db.Games.Find(DBGameId);
                                g.TimeEnded = DateTime.UtcNow;
                                db.SaveChanges();
                            }
                            LastMenu = null;
                            Send($"{winner.GetName()} has won the game!", newMsg: true);
                            State = GameState.Ended;
                            return;
                        }
                    }
                }
                catch (Exception e)
                {
                    Send($"Game error: {e.Message}\n{e.StackTrace}");
                    State = GameState.Ended;
                    return;
                }
            }
        }
Exemple #2
0
        private void GameTimer()
        {
            while (Phase != GamePhase.Ending && Phase != GamePhase.KillGame)
            {
                try
                {
#if DEBUG
                    AddPlayer(new User {
                        Id = 433942669, FirstName = "Mud9User", IsBot = false, LanguageCode = "zh-HK", Username = "******"
                    });
                    AddPlayer(new User {
                        Id = 415774316, FirstName = "Avalonese Dev", IsBot = false, LanguageCode = "zh-HK", Username = "******"
                    });
                    AddPlayer(new User {
                        Id = 267359519, FirstName = "Ian", IsBot = false, LanguageCode = "zh-HK", Username = "******"
                    });
#endif
                    for (var i = 0; i < JoinTime; i++)
                    {
                        if (Players.Count == 4)
                        {
                            break;
                        }
                        if (this.Phase == GamePhase.InGame)
                        {
                            break;
                        }
                        if (this.Phase == GamePhase.Ending)
                        {
                            return;
                        }
                        if (this.Phase == GamePhase.KillGame)
                        {
                            return;
                        }
                        //try to remove duplicated game
                        if (i == 10)
                        {
                            var count = Bot.Games.Count(x => x.ChatId == ChatId);
                            if (count > 1)
                            {
                                var toDel = Bot.Games.Where(x => x.Players.Count < this.Players.Count).OrderBy(x => x.Players.Count).Where(x => x.Id != this.Id && x.Phase != GamePhase.InGame);
                                if (toDel != null)
                                {
                                    Send(GetTranslation("DuplicatedGameRemoving"));
                                    foreach (var g in toDel)
                                    {
                                        g.Phase = GamePhase.KillGame;

                                        try
                                        {
                                            Bot.RemoveGame(g);
                                        }
                                        catch
                                        {
                                            // should be removed already
                                        }
                                    }
                                }
                            }
                        }
                        if (_secondsToAdd != 0)
                        {
                            i = Math.Max(i - _secondsToAdd, Constants.JoinTime - Constants.JoinTimeMax);
                            // Bot.Send(ChatId, GetTranslation("JoinTimeLeft", TimeSpan.FromSeconds(Constants.JoinTime - i).ToString(@"mm\:ss")));
                            _secondsToAdd = 0;
                        }
                        var specialTime = JoinTime - i;
                        if (new int[] { 10, 30, 60, 90 }.Contains(specialTime))
                        {
                            Bot.Send(ChatId, GetTranslation("JoinTimeSpecialSeconds", specialTime));
                        }
                        if (Players.Count == 4)
                        {
                            break;
                        }
                        Thread.Sleep(1000);
                    }

                    if (this.Phase == GamePhase.Ending)
                    {
                        return;
                    }
                    do
                    {
                        BTPlayer p = Players.FirstOrDefault(x => Players.Count(y => y.TelegramId == x.TelegramId) > 1);
                        if (p == null)
                        {
                            break;
                        }
                        Players.Remove(p);
                    }while (true);

                    if (this.Phase == GamePhase.Ending)
                    {
                        return;
                    }

                    if (this.Players.Count() == 4)
                    {
                        this.Phase = GamePhase.InGame;
                    }
                    if (this.Phase != GamePhase.InGame)
                    {
                        /*
                         * this.Phase = GamePhase.Ending;
                         * Bot.RemoveGame(this);
                         * Bot.Send(ChatId, "Game ended!");
                         */
                    }
                    else
                    {
                        #region Ready to start game
                        if (Players.Count < 4)
                        {
                            Send(GetTranslation("GameEnded"));
                            return;
                        }

                        Send(GetTranslation("GameStart"));

                        // create game + gameplayers in db
                        using (var db = new BigTwoDb())
                        {
                            DbGame = new Database.Game
                            {
                                GrpId        = DbGroup.Id,
                                GroupId      = ChatId,
                                GroupName    = GroupName,
                                TimeStarted  = DateTime.UtcNow,
                                ChipsPerCard = ChipsPerCard
                            };
                            db.Games.Add(DbGame);
                            db.SaveChanges();
                            GameId = DbGame.Id;
                            foreach (var p in Players)
                            {
                                GamePlayer DbGamePlayer = new GamePlayer
                                {
                                    PlayerId = db.Players.FirstOrDefault(x => x.TelegramId == p.TelegramId).Id,
                                    GameId   = GameId
                                };
                                db.GamePlayers.Add(DbGamePlayer);
                            }
                            db.SaveChanges();
                        }

                        PrepareGame();

                        // remove joined players from nextgame list
                        // RemoveFromNextGame(Players.Select(x => x.TelegramId).ToList());

                        #endregion

                        #region Start!
                        foreach (var player in Players)
                        {
                            SendDeck(player);
                        }
                        while (Phase != GamePhase.Ending)
                        {
                            // _playerList = Send(GeneratePlayerList()).MessageId;
                            PlayersChooseCard();
                            if (Phase == GamePhase.Ending)
                            {
                                break;
                            }
                            if (CurrentLargestDealt)
                            {
                                NextPlayerAfterCurrentLargest(CurrentLargestDealtBy);
                            }
                            else
                            {
                                NextPlayer();
                            }
                        }
                        EndGame();
                        #endregion
                    }
                    this.Phase = GamePhase.Ending;
                    Bot.Send(ChatId, GetTranslation("GameEnded"));
                }
                catch (Exception ex)
                {
                    if (Phase == GamePhase.KillGame)
                    {
                        // normal
                    }
                    else
                    {
                        Log(ex);
                        Phase = GamePhase.KillGame;
                    }
                }
            }

            Bot.RemoveGame(this);
        }