コード例 #1
0
 private void DBAddBluff(CPlayer p, string cardUsed, bool v = false, CPlayer caller = null)
 {
     using (var db = new CoupContext())
     {
         var gp       = GetDBGamePlayer(p, db);
         var calledgp = GetDBGamePlayer(caller, db);
         var dbp      = GetDBPlayer(p, db);
         int?calledBy = GetDBPlayer(caller, db)?.Id;
         if (!v)
         {
             gp.BluffsMade++;
         }
         else
         {
             calledgp.BluffsCalled++;
         }
         var b = new Bluff
         {
             BluffCalled = v,
             BlufferId   = dbp.Id,
             CardBluffed = cardUsed,
             CalledById  = calledBy,
             GameId      = DBGameId
         };
         db.Bluffs.Add(b);
         db.SaveChanges();
     }
 }
コード例 #2
0
        public Game(int id, User u, bool group, bool random, Chat c = null)
        {
            GameId  = id;
            ChatId  = c?.Id ?? 0;
            IsGroup = group;
            if (IsGroup)
            {
                using (var db = new CoupContext())
                {
                    var grp = db.ChatGroups.FirstOrDefault(x => x.TelegramId == c.Id);
                    if (grp == null)
                    {
                        grp = new ChatGroup
                        {
                            TelegramId = c.Id,
                            Created    = DateTime.UtcNow,
                            Language   = "English",
                            Name       = c.Title,
                            Username   = c.Username
                        };
                        db.ChatGroups.Add(grp);
                    }

                    grp.Name     = c.Title;
                    grp.Username = c.Username;

                    db.SaveChanges();
                }
            }
            IsRandom = random;
            AddPlayer(u);
            new Task(JoinTimer).Start();
        }
コード例 #3
0
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>
            {
                //drop the error to log file and exit
                using (var sw = new StreamWriter(Path.Combine(Bot.RootDirectory, "Logs\\error.log"), true))
                {
                    var e = (eventArgs.ExceptionObject as Exception);
                    sw.WriteLine(DateTime.Now);
                    sw.WriteLine(e.Message);
                    sw.WriteLine(e.StackTrace + "\n");
                    if (eventArgs.IsTerminating)
                    {
                        Environment.Exit(5);
                    }
                }
            };

            //initialize EF before we start receiving
            using (var db = new CoupContext())
            {
                var count = db.ChatGroups.Count();
            }


            new Thread(Bot.Initialize).Start();
            new Thread(Cleaner).Start();
            new Thread(Monitor).Start();
            Thread.Sleep(-1);
        }
コード例 #4
0
        public static bool BetaCheck(this User u)
        {
            using (var db = new CoupContext())
            {
                var p = db.Players.FirstOrDefault(x => x.TelegramId == u.Id);
                if (p == null && db.Players.Count() < 700)
                {
                    p = new Player
                    {
                        Created    = DateTime.UtcNow,
                        Language   = "English",
                        Name       = (u.FirstName + " " + u.LastName).Trim(),
                        TelegramId = u.Id,
                        Username   = u.Username
                    };
                    db.Players.Add(p);
                    db.SaveChanges();
                    return(true);
                }
                else if (p != null)
                {
                    return(true);
                }

                return(false);
            }
        }
コード例 #5
0
 private Player GetDBPlayer(CPlayer player, CoupContext db)
 {
     if (player == null)
     {
         return(null);
     }
     if (player.DBPlayerId == 0)
     {
         var p = db.Players.FirstOrDefault(x => x.TelegramId == player.Id);
         player.DBPlayerId = p?.Id ?? 0;
         return(p);
     }
     try
     {
         return(db.Players.Find(player.DBPlayerId));
     }
     catch
     {
         return(null);
     }
 }
コード例 #6
0
        private GamePlayer GetDBGamePlayer(CPlayer player, CoupContext db)
        {
            if (player == null)
            {
                return(null);
            }
            if (player.DBGamePlayerId == 0)
            {
                var p = GetDBGamePlayer(GetDBPlayer(player, db));
                player.DBGamePlayerId = p?.Id ?? 0;
                return(p);
            }

            try
            {
                return(db.GamePlayers.Find(player.DBGamePlayerId));
            }
            catch
            {
                return(null);
            }
        }
コード例 #7
0
        private void DBAddValue(CPlayer p, Models.ValueType prop, int val = 1)
        {
            new Task(() =>
            {
                using (var db = new CoupContext())
                {
                    var gp = GetDBGamePlayer(p, db);
                    switch (prop)
                    {
                    case Models.ValueType.CoinsCollected:
                        gp.CoinsCollected += val;
                        break;

                    case Models.ValueType.CoinsStolen:
                        gp.CoinsStolen += val;
                        break;

                    case Models.ValueType.ActionsBlocked:
                        gp.ActionsBlocked += val;
                        break;

                    case Models.ValueType.BluffsCalled:
                        throw new Exception("Use DBAddBluff");

                    case Models.ValueType.PlayersCouped:
                        gp.PlayersCouped += val;
                        break;

                    case Models.ValueType.PlayersAssassinated:
                        gp.PlayersAssassinated += val;
                        break;
                    }
                    db.SaveChanges();
                }
            }).Start();
        }
コード例 #8
0
        public void TellCards(CPlayer p)
        {
            if (p.Cards.Count() == 0)
            {
                return;
            }
            var cards = p?.Cards.Aggregate("<b>Your cards</b>", (cur, b) => cur + $"\n{b.Name}");

            if (!p.HasCheckedCards)
            {
                using (var db = new CoupContext())
                {
                    var dbp = db.Players.FirstOrDefault(x => x.TelegramId == p.Id);
                    var gp  = dbp?.GamePlayers.FirstOrDefault(x => x.GameId == DBGameId);
                    if (gp != null)
                    {
                        gp.LookedAtCardsTurn = Math.Max(Round, 1);
                        db.SaveChanges();
                    }
                }
                p.HasCheckedCards = true;
            }
            Send(cards, p.Id, newMsg: true).ToList();
        }
コード例 #9
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;
                }
            }
        }
コード例 #10
0
        internal static void HandleCallback(CallbackQuery c)
        {
            try
            {
                //https://telegram.me/coup2bot?startgroup=gameid
                //https://telegram.me/coup2bot?start=gameid
                var cmd = c.Data;
                if (cmd.Contains("|"))
                {
                    cmd = cmd.Split('|')[0];
                }
                Game    g;
                int     id;
                CPlayer p;

                Models.Action a;
                if (Enum.TryParse(cmd, out a))
                {
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g != null)
                    {
                        if (g.Turn == c.From.Id)
                        {
                            g.ChoiceMade = a;
                            Bot.ReplyToCallback(c, $"Choice accepted: {cmd}");
                        }
                        else
                        {
                            Bot.ReplyToCallback(c, "It's not your turn!", false, true);
                        }
                    }
                    else
                    {
                        Bot.ReplyToCallback(c, $"That game isn't active anymore...");
                    }
                }

                switch (cmd)
                {
                case "players":
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g == null)
                    {
                        Bot.ReplyToCallback(c, "Game is no longer active!");
                        break;
                    }
                    //player wants status
                    var msg = g.Players.Where(x => x.Cards.Count > 0).Aggregate("Cards - Coins - Name", (cur, b) => cur + $"\n{b.Cards.Count} - {(b.Coins > 9 ? b.Coins.ToString() : "0" + b.Coins)} - {b.Name}");
                    Bot.ReplyToCallback(c, msg, false, true);
                    break;

                case "grave":
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g == null)
                    {
                        Bot.ReplyToCallback(c, "Game is no longer active!");
                        break;
                    }
                    //player wants graveyard
                    var grave = g.Graveyard.Aggregate("Graveyard", (cur, b) => cur + $"\n{b.Name}");
                    Bot.ReplyToCallback(c, grave, false, true);
                    break;

                case "cards":
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g == null)
                    {
                        Bot.ReplyToCallback(c, "Game is no longer active!");
                        break;
                    }
                    //player wants graveyard
                    var player = g.Players.FirstOrDefault(x => x.Id == c.From.Id);

                    var cards = player?.Cards.Aggregate("Your cards", (cur, b) => cur + $"\n{b.Name}");
                    if (!player.HasCheckedCards)
                    {
                        using (var db = new CoupContext())
                        {
                            var dbp = db.Players.FirstOrDefault(x => x.TelegramId == c.From.Id);
                            var gp  = dbp?.GamePlayers.FirstOrDefault(x => x.GameId == g.DBGameId);
                            if (gp != null)
                            {
                                gp.LookedAtCardsTurn = Math.Max(g.Round, 1);
                                db.SaveChanges();
                            }
                        }
                        player.HasCheckedCards = true;
                    }
                    Bot.ReplyToCallback(c, cards, false, true);
                    break;

                case "concede":
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g == null)
                    {
                        Bot.ReplyToCallback(c, "Game is no longer active!");
                        break;
                    }
                    if (g.Turn != c.From.Id)
                    {
                        Bot.ReplyToCallback(c, "Please concede on your turn only", false, true);
                        break;
                    }
                    g.Concede();
                    Bot.ReplyToCallback(c, "Accepted");
                    break;

                case "card":
                    //player is losing a card
                    var cardStr = c.Data.Split('|')[2];

                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g != null)
                    {
                        p = g.Players.FirstOrDefault(x => x.Id == c.From.Id);
                        if (p != null && p.Id == g.Turn)
                        {
                            g.CardToLose = cardStr;
                            Bot.ReplyToCallback(c, "Choice Accepted - " + cardStr);
                        }
                    }
                    break;

                case "bluff":
                    bool call = c.Data.Split('|')[1] == "call";
                    id = int.Parse(c.Data.Split('|')[2]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g != null)
                    {
                        //get the player
                        p = g.Players.FirstOrDefault(x => x.Id == c.From.Id);
                        if (p != null && p.Cards.Count() > 0)
                        {
                            if (p.Id == g.Turn)
                            {
                                Bot.ReplyToCallback(c, "You can't block yourself!", false, true);
                            }
                            else
                            {
                                switch (c.Data.Split('|')[1])
                                {
                                case "call":
                                    p.CallBluff = true;
                                    p.Block     = false;
                                    break;

                                case "allow":
                                    p.Block = p.CallBluff = false;
                                    break;

                                case "block":
                                    if (p.Block == false)
                                    {
                                        Bot.ReplyToCallback(c, "You are not allowed to block", false, true);
                                        break;
                                    }
                                    p.Block     = true;
                                    p.CallBluff = false;
                                    break;
                                }

                                Bot.ReplyToCallback(c, "Choice accepted", false, false);
                            }
                        }
                        else
                        {
                            Bot.ReplyToCallback(c, "You aren't in the game!", false, true);
                        }
                    }
                    break;

                case "choose":
                    //picking a target
                    var target = int.Parse(c.Data.Split('|')[2]);
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);


                    if (g != null)
                    {
                        //get the player
                        p = g.Players.FirstOrDefault(x => x.Id == c.From.Id);
                        if (p != null && p.Cards.Count() > 0)
                        {
                            if (g.Turn != c.From.Id)
                            {
                                Bot.ReplyToCallback(c, "It's not your choice!", false, true);
                            }
                            else
                            {
                                g.ChoiceTarget = target;
                                Bot.ReplyToCallback(c, "Choice accepted");
                            }
                        }
                        else
                        {
                            Bot.ReplyToCallback(c, "You aren't in the game!", false, true);
                        }
                    }
                    break;

                //TODO: change these to enums with int values
                case "spgf":
                    g = CreateGame(c.From);
                    var menu = new InlineKeyboardMarkup(new[]
                    {
                        new InlineKeyboardButton("Start", "start|" + g.GameId.ToString())
                    });
                    Bot.ReplyToCallback(c, $"Great! I've created a game for you.  Share this link to invite friends: https://telegram.me/{Bot.Me.Username}?start={g.GameId}", replyMarkup: menu);

                    break;

                case "spgs":
                    //check for a game waiting for more players
                    if (Program.Games.Any(x => x.Players.Any(pl => pl.Id == c.From.Id)))
                    {
                        Bot.ReplyToCallback(c, "You are already in a game!");
                    }

                    g = Program.Games.FirstOrDefault(x => x.State == GameState.Joining && x.Players.Count() < 6 & !x.IsGroup && x.IsRandom);
                    if (g != null)
                    {
                        var result = g.AddPlayer(c.From);
                        switch (result)
                        {
                        case 1:
                            Bot.ReplyToCallback(c, "You are already in the game!");
                            break;

                        case 0:
                            Bot.ReplyToCallback(c, "You have joined the game!");
                            break;
                        }
                        //TODO: give player list, total count
                        //Bot.ReplyToCallback(c, "You have joined a game!");
                    }
                    else
                    {
                        g = CreateGame(c.From, false, true);
                        Bot.ReplyToCallback(c, $"There were no games available, so I have created a new game for you.  Please wait for others to join!", replyMarkup: new InlineKeyboardMarkup(new[] { new InlineKeyboardButton("Start Game", $"start|{g.GameId}") }));
                    }
                    //Console.WriteLine($"{c.From.FirstName} has joined game: {g.GameId}");
                    break;

                case "sgg":
                    if (Program.Games.Any(x => x.Players.Any(pl => pl.Id == c.From.Id)))
                    {
                        Bot.ReplyToCallback(c, "You are already in a game!");
                    }
                    g = CreateGame(c.From, true);
                    Bot.ReplyToCallback(c, $"Great! I've created a game for you.  Click below to send the game to the group!", replyMarkup: new InlineKeyboardMarkup(new[] { new InlineKeyboardButton("Click here")
                                                                                                                                                                             {
                                                                                                                                                                                 Url = $"https://telegram.me/{Bot.Me.Username}?startgroup={g.GameId}"
                                                                                                                                                                             } }));
                    break;

                case "join":
                    if (!c.From.BetaCheck())
                    {
                        Bot.ReplyToCallback(c, "Sorry, but beta testing is full.  Please wait until the next beta extension.", false, true);
                        return;
                    }
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (Program.Games.Any(x => x.Players.Any(pl => pl.Id == c.From.Id)))
                    {
                        Bot.ReplyToCallback(c, "You are already in a game!", false, true);
                        break;
                    }
                    if (g != null)
                    {
                        var success = g.AddPlayer(c.From);
                        switch (success)
                        {
                        case 0:
                            Bot.ReplyToCallback(c, "You have joined a game!", false, true);
                            break;

                        case 1:
                            Bot.ReplyToCallback(c, "You are already in the game!", false, true);
                            break;
                        }
                    }
                    break;

                case "start":
                    id = int.Parse(c.Data.Split('|')[1]);
                    g  = Program.Games.FirstOrDefault(x => x.GameId == id);
                    if (g == null)
                    {
                        break;
                    }
                    if (!g.Players.Any(x => x.Id == c.From.Id))
                    {
                        Bot.ReplyToCallback(c, "You aren't even in the game!", false, true);
                        return;
                    }
                    if (g.Players.First().Id != c.From.Id)
                    {
                        Bot.ReplyToCallback(c, "Only game creator can start the game", false, true);
                        return;
                    }
                    g?.StartGame();
                    break;
                }
            }
            catch (AggregateException e)
            {
                Bot.ReplyToCallback(c, $"Error: {e.InnerExceptions[0].Message}");
            }
            catch (Exception e)
            {
                Bot.ReplyToCallback(c, $"Error: {e.Message}\n{e.StackTrace}");
            }
        }
コード例 #11
0
        internal static void HandleMessage(Message m)
        {
            try
            {
                if (m.Date < Program.StartTime.AddSeconds(-5))
                {
                    return;
                }
                //start@coup2bot gameid

                //get the command if any
                var cmd = m.Text.Split(' ')[0];
                if (!cmd.StartsWith("!") & !cmd.StartsWith("/"))
                {
                    return;
                }
                cmd = cmd.Replace("@" + Bot.Me.Username, "").Replace("!", "").Replace("/", "").ToLower();
                if (String.IsNullOrEmpty(cmd))
                {
                    return;
                }
                Game g;
                //TODO - Move all of these to Commands using reflection
                //basic commands
                switch (cmd)
                {
                case "addbeta":
                    if (m.From.Id != Bot.Para)
                    {
                        return;
                    }
                    //adds the player to the beta
                    var u = m.ReplyToMessage?.From;
                    if (u == null)
                    {
                        Bot.SendAsync("Reply to a user to add them to the beta", m.Chat.Id);
                        return;
                    }

                    using (var db = new CoupContext())
                    {
                        var p = db.Players.FirstOrDefault(x => x.TelegramId == u.Id);
                        if (p != null)
                        {
                            Bot.SendAsync("User is already in the beta!", m.Chat.Id);
                            return;
                        }
                        p = new Player {
                            Created = DateTime.UtcNow, Language = "English", Name = (u.FirstName + " " + u.LastName).Trim(), TelegramId = u.Id, Username = u.Username
                        };
                        db.Players.Add(p);
                        db.SaveChanges();
                        Bot.SendAsync($"{p.Name} has been added to Coup Beta", m.Chat.Id);
                    }
                    break;

                case "removeuseless":
                    if (m.From.Id != Bot.Para)
                    {
                        return;
                    }
                    using (var db = new CoupContext())
                    {
                        var delete      = db.Players.FirstOrDefault(x => x.TelegramId == 0);
                        var dropPlayers = db.Players.Where(x => x.GamePlayers.Count <= 1);
                        var count       = dropPlayers.Count();
                        var gps         = dropPlayers.SelectMany(x => x.GamePlayers).Select(x => x.Id).ToList();
                        var dropGp      = db.GamePlayers.Where(x => gps.Contains(x.Id));
                        foreach (var d in dropGp)
                        {
                            d.PlayerId = delete.Id;
                        }
                        foreach (var p in dropPlayers)
                        {
                            db.Players.Remove(p);
                        }
                        db.SaveChanges();
                        Bot.SendAsync($"Removed {count} players from beta", m.Chat.Id);
                    }
                    break;

                case "stats":
                    var stats = $"<b>Stats for {m.From.FirstName.FormatHTML()}</b>\n";
                    using (var db = new CoupContext())
                    {
                        var p = db.Players.FirstOrDefault(x => x.TelegramId == m.From.Id);
                        if (p == null)
                        {
                            return;
                        }
                        var gps = p.GamePlayers.ToList();
                        stats += $"Games played: {gps.Count()}\n" +
                                 $"Games won: {gps.Count(x => x.Won)}\n" +
                                 $"Checks cards on turn: {gps.Average(x => x.LookedAtCardsTurn)}\n" +
                                 $"Total coins collected: {gps.Sum(x => x.CoinsCollected)}\n" +
                                 $"Total coins stolen: {gps.Sum(x => x.CoinsStolen)}\n" +
                                 $"Successful blocks: {gps.Sum(x => x.ActionsBlocked)}\n" +
                                 $"Successful bluffs: {gps.Sum(x => x.BluffsMade)}\n" +
                                 $"Bluffs called: {gps.Sum(x => x.BluffsCalled)}\n" +
                                 $"Coups made: {gps.Sum(x => x.PlayersCouped)}\n" +
                                 $"Assassinations: {gps.Sum(x => x.PlayersAssassinated)}";
                        Bot.SendAsync(stats, m.Chat.Id);
                    }
                    break;

                case "help":
                    Bot.SendAsync("https://www.youtube.com/watch?v=xUNWl5fWfEY", m.Chat.Id);
                    break;

                case "ping":
                    Ping(m);
                    break;

                case "start":
                    if (!m.From.BetaCheck())
                    {
                        Bot.Api.SendTextMessageAsync(m.Chat.Id, "Sorry, but beta testing is full.  Please wait until the next beta extension.", replyToMessageId: m.MessageId);
                        return;
                    }
                    Bot.SendAsync("During the beta, we ask that players join the beta feedback group: https://telegram.me/joinchat/B7EXdEE_fl3Jmsi7TL02_A", m.Chat.Id);
                    //check for gameid
                    //Console.WriteLine(m.From.FirstName + ": " + m.From.Username + ": " + m.From.Id);
                    try
                    {
                        var id        = int.Parse(m.Text.Split(' ')[1]);
                        var startgame = Program.Games.FirstOrDefault(x => x.GameId == id);

                        if (startgame != null)
                        {
                            if (Program.Games.Any(x => x.Players.Any(p => p.Id == m.From.Id)))
                            {
                                Bot.SendAsync("You are already in a game!", m.From.Id);
                                return;
                            }
                            //check if group or PM
                            if (m.Chat.Type == Telegram.Bot.Types.Enums.ChatType.Private)
                            {
                                //private chat - was it sent by the actual person?
                                if (startgame.Players.Any(x => x.Id == m.From.Id))
                                {
                                    //already in game
                                    return;
                                }
                                startgame.AddPlayer(m.From);
                            }
                            else if (m.Chat.Type != Telegram.Bot.Types.Enums.ChatType.Channel)
                            {
                                startgame.ChatId = m.Chat.Id;
                                var menu = new InlineKeyboardMarkup(new[]
                                {
                                    new InlineKeyboardButton("Join", "join|" + id.ToString()),
                                    new InlineKeyboardButton("Start", "start|" + id.ToString())
                                });
                                var r = Bot.SendAsync(m.From.FirstName + " wants to play coup.  Up to 6 players total can join.  Click below to join the game!", m.Chat.Id, customMenu: menu
                                                      ).Result;
                                startgame.LastMessageId   = r.MessageId;
                                startgame.LastMessageSent = r.Text;
                                startgame.LastMenu        = menu;
                            }
                        }
                    }
                    catch
                    {
                        //no game / parameter
                        Bot.SendAsync("Well hi there!  Would you like to play a game?\r\nHow about a nice game of tic tac toe?\r\n....Global Thermonuclear War it is.  Just kidding!  Use /newgame to play a game of Coup with your friends, or complete strangers!", m.From.Id);
                    }
                    break;

                case "maint":
                    if (m.From.Id == Bot.Para)
                    {
                        Bot.Maintenance = true;
                        Bot.SendAsync("Maintenance mode enabled, no new games", m.Chat.Id);
                    }
                    break;

                case "shutdown":
                    if (m.From.Id == Bot.Para)
                    {
                        Bot.Maintenance = true;
                        var msg = "We've had to kill the game for a moment to patch a critical issue.  Please use /newgame in a moment to start a new game.\nSorry for the inconvenience.";
                        foreach (var game in Program.Games.ToList())
                        {
                            if (game.IsGroup)
                            {
                                Bot.SendAsync(msg, game.ChatId);
                            }
                            else
                            {
                                foreach (var p in game.Players.ToList())
                                {
                                    Bot.SendAsync(msg, p.Id);
                                    Thread.Sleep(500);
                                }
                            }
                            Thread.Sleep(500);
                        }
                        Bot.SendAsync("Bot killed", m.Chat.Id);
                        Thread.Sleep(1000);
                        Environment.Exit(0);
                    }
                    break;

                case "newgame":
                    if (Bot.Maintenance)
                    {
                        Bot.SendAsync("Cannot start game, bot is about to restart for patching", m.Chat.Id);
                        return;
                    }
                    if (!m.From.BetaCheck())
                    {
                        Bot.Api.SendTextMessageAsync(m.Chat.Id, "Sorry, but beta testing is full.  Please wait until the next beta extension.", replyToMessageId: m.MessageId);
                        return;
                    }
                    if (m.Chat.Id == -1001094680157)
                    {
                        Bot.SendAsync("This group is for feedback.  Please join https://telegram.me/joinchat/B7EXdEDhVB6A6RL6Mi3Hvw to play, or play in PM", m.Chat.Id);
                        return;
                    }
                    Bot.SendAsync("During the beta, we ask that players join the beta feedback group: https://telegram.me/joinchat/B7EXdEE_fl3Jmsi7TL02_A", m.Chat.Id);
                    //Console.WriteLine(m.From.FirstName + ": " + m.From.Username + ": " + m.From.Id);
                    //check to see if an existing game is already being played.
                    // if group, just look for a group game with the chat id
                    // if PM, look for a game with the user as one of the players (alive)
                    if (!UserCanStartGame(m.From.Id, m.Chat.Id))
                    {
                        return;
                    }
                    //all is good?  Ask if PM or Group game (if in PM, otherwise assume group)
                    if (m.Chat.Type == Telegram.Bot.Types.Enums.ChatType.Private)
                    {
                        Bot.Api.SendTextMessageAsync(m.Chat.Id, "You've chosen to start a new game.  Do you want to play in private with friends, private with random players, or in a group?", replyMarkup: new InlineKeyboardMarkup(new InlineKeyboardButton[][] {
                            new InlineKeyboardButton[] { new InlineKeyboardButton("Private game - Friends", "spgf") },
                            new InlineKeyboardButton[] { new InlineKeyboardButton("Private game - Strangers", "spgs") },
                            //new InlineKeyboardButton[] { new InlineKeyboardButton("Group game", "sgg") }
                        }));
                        Thread.Sleep(500);
                        Bot.SendAsync("Alternatively, you can start a game directly in a group", m.Chat.Id);
                    }
                    else
                    {
                        //group game
                        g = CreateGame(m.From, true, c: m.Chat);
                        var menu = new InlineKeyboardMarkup(new[]
                        {
                            new InlineKeyboardButton("Join", "join|" + g.GameId.ToString()),
                            new InlineKeyboardButton("Start", "start|" + g.GameId.ToString())
                        });
                        var r = Bot.SendAsync(m.From.FirstName + " wants to play coup.  Up to 6 players total can join.  Click below to join the game!", m.Chat.Id, customMenu: menu
                                              ).Result;
                        g.LastMessageId   = r.MessageId;
                        g.LastMessageSent = r.Text;
                        g.LastMenu        = menu;
                    }
                    break;

                case "leave":
                    //find the game
                    g = Program.Games.FirstOrDefault(x => x.Players.Any(p => p.Id == m.From.Id));
                    var rem = g?.RemovePlayer(m.From);
                    if (rem == 1)
                    {
                        Bot.Api.SendTextMessageAsync(m.From.Id, $"You have been removed from game {g.GameId}");
                    }
                    break;

                case "test":
                    break;
                }
            }
            catch (AggregateException e)
            {
                Bot.SendAsync($"Error: {e.InnerExceptions[0].Message}", m.Chat.Id);
            }
            catch (Exception e)
            {
                Bot.SendAsync($"Error: {e.Message}\n{e.StackTrace}", m.Chat.Id);
            }
        }