Пример #1
0
        protected async Task Kill(MafiaPlayer player, DeathReason reason)
        {
            Players.Remove(player);
            Killed.Add(player);
            await GetGuild().GetUser(player.GetId()).AddRoleAsync(GetDeadRole());

            await ChannelVisibility(GetGeneral(), Killed, x => false, true);
            await ChannelVisibility(GetDead(), Killed, x => true);
            await VoiceMute(Killed, false);

            if (IsMafia(player))
            {
                await ChannelVisibility(GetMafia(), new List <MafiaPlayer> {
                    player
                }, false, true);
            }

            var dm = await player.GetDm();

            await dm.SendMessageAsync("", false, new EmbedBuilder()
                                      .WithColor(Color.Red)
                                      .WithTitle("You are dead.")
                                      .WithDescription(DeathDescription(reason))
                                      .Build());
        }
Пример #2
0
        // This is an enormous function that has most game logic.
        private async Task RunGame()
        {
            try {
                while (CheckGameWin() == WinReason.NoWinYet)
                {
                    // Night Time
                    await ChannelVisibility(GetGeneral(), Players, false, true);
                    await VoiceMute(Players, false);

                    MafiaPlayer mafiaToKill       = null;
                    var         hunterToKill      = new List <MafiaPlayer>();
                    var         doctorToSave      = new List <MafiaPlayer>();
                    var         silencerToSilence = new List <MafiaPlayer>();

                    // Role Setup
                    _voteOptions = Players.Where(IsNotMafia).ToList();
                    await SendMafia("Who do want to kill? Vote with `-vote <number>`:\n"
                                    + Utils.Code(BuildVoteOptions(_voteOptions)));

                    foreach (var player in Players)
                    {
                        switch (player.GetRole())
                        {
                        case MafiaPlayer.Role.Doctor: {
                            var doctorInfo = player.GetInfo <DoctorRoleInfo>();
                            var healedLast = doctorInfo.HealedLast();
                            _selectOptions[player.GetId()] = healedLast.HasValue
                                    ? Players.Where(x => x.GetId() != healedLast.Value).ToList()
                                    : new List <MafiaPlayer>(Players);

                            var dm = await player.GetDm();

                            await dm.SendMessageAsync(
                                "Who do you want to save? Select someone with `-select <number>`:\n"
                                + Utils.Code(BuildVoteOptions(_selectOptions[player.GetId()])));

                            break;
                        }

                        case MafiaPlayer.Role.Detective: {
                            _selectOptions[player.GetId()] = Players.Where(
                                x => x.GetId() != player.GetId()).ToList();

                            var dm = await player.GetDm();

                            await dm.SendMessageAsync(
                                "Who do you want to investigate? Select someone with `-select <number>`:\n"
                                + Utils.Code(BuildVoteOptions(_selectOptions[player.GetId()])));

                            break;
                        }

                        case MafiaPlayer.Role.Silencer: {
                            _selectOptions[player.GetId()] = Players.Where(
                                x => x.GetId() != player.GetId()).ToList();

                            var dm = await player.GetDm();

                            await dm.SendMessageAsync(
                                "Who do you want to silence? Select someone with `-select <number>`:\n"
                                + Utils.Code(BuildVoteOptions(_selectOptions[player.GetId()])));

                            break;
                        }

                        case MafiaPlayer.Role.Hunter: {
                            var dm = await player.GetDm();

                            var info = player.GetInfo <HunterRoleInfo>();
                            if (info.IsStalking())
                            {
                                var killId = info.Kill();
                                if (killId.HasValue)
                                {
                                    var stalkee = Players.FirstOrDefault(x => x.GetId() == killId.Value);
                                    if (stalkee != null)
                                    {
                                        hunterToKill.Add(stalkee);
                                        await dm.SendMessageAsync(
                                            $"You are going to kill {GetName(stalkee)}.");

                                        break;
                                    }
                                }
                            }

                            _selectOptions[player.GetId()] = Players.Where(
                                x => x.GetId() != player.GetId()).ToList();

                            await dm.SendMessageAsync(
                                "Who do you want to stalk? You will kill them the next night. " +
                                "Select someone with `-select <number>`:\n"
                                + Utils.Code(BuildVoteOptions(_selectOptions[player.GetId()])));

                            break;
                        }
                        }
                    }

                    // Wait Through Night Time
                    var stopwatch = new Stopwatch();
                    stopwatch.Start();
                    var validVotes = new List <MafiaVote>();
                    while (stopwatch.ElapsedMilliseconds < NightTime &&
                           (_selectOptions.Count > 0 || validVotes.Count < Players.Count(IsMafia)))
                    {
                        // -vote
                        while (_voteQueue.Count > 0)
                        {
                            var vote = _voteQueue.Dequeue();

                            // Verify Vote
                            if (vote.Channel != GetMafia().Id)
                            {
                                Console.WriteLine("Ignored non-#mafia vote.");
                                continue;
                            }

                            if (vote.Vote <= 0 || vote.Vote > _voteOptions.Count)
                            {
                                await SendMafia($"Please select a valid option (1 - {_voteOptions.Count}).");

                                continue;
                            }

                            if (validVotes.Exists(x => x.Voter == vote.Voter))
                            {
                                validVotes.RemoveAll(x => x.Voter == vote.Voter);
                            }

                            validVotes.Add(vote);
                            await SendMafia($"<@{vote.Voter}>! Your vote for #{vote.Vote} has been registered.");
                        }

                        // -select
                        while (_selectQueue.Count > 0)
                        {
                            var vote = _selectQueue.Dequeue();

                            // Verify Selection
                            var player = Players.First(x => x.GetId() == vote.Voter);
                            var dm     = await player.GetDm();

                            if (!_selectOptions.ContainsKey(vote.Voter))
                            {
                                await dm.SendMessageAsync("Wait until its your turn!");

                                continue;
                            }

                            var options = _selectOptions[vote.Voter];

                            if (vote.Vote <= 0 || vote.Vote > options.Count)
                            {
                                await dm.SendMessageAsync($"Please select a valid option (1 - {options.Count}).");

                                continue;
                            }

                            var target = options[vote.Vote - 1];

                            // After Selection
                            switch (player.GetRole())
                            {
                            case MafiaPlayer.Role.Doctor:
                                doctorToSave.Add(target);
                                await dm.SendMessageAsync($"You decided to visit {GetName(target)}.");

                                break;

                            case MafiaPlayer.Role.Detective: {
                                var isGood = IsGood(target);
                                await dm.SendMessageAsync("The person you investigated... "
                                                          + (isGood ? "seems normal." : "is suspicious."));

                                break;
                            }

                            case MafiaPlayer.Role.Silencer:
                                silencerToSilence.Add(target);
                                await dm.SendMessageAsync($"You decided to silence {GetName(target)}");

                                break;

                            case MafiaPlayer.Role.Hunter: {
                                var info = player.GetInfo <HunterRoleInfo>();
                                if (!info.IsStalking())
                                {
                                    info.Stalk(target.GetId());
                                    await dm.SendMessageAsync($"You stalked {GetName(target)}. " +
                                                              $"He/She appears to be a {target.GetRole().ToString()}.");
                                }
                                break;
                            }

                            default:
                                await dm.SendMessageAsync("You don't have anything to select from.");

                                continue;
                            }

                            _selectOptions.Remove(player.GetId());
                        }
                    }

                    var top = HighestScore(validVotes);
                    if (top.HasValue)
                    {
                        mafiaToKill = _voteOptions[top.Value - 1];
                    }
                    _voteOptions = null;
                    _selectOptions.Clear();

                    if (mafiaToKill != null && !doctorToSave.Contains(mafiaToKill))
                    {
                        await Kill(mafiaToKill, DeathReason.MafiaAttack);
                    }

                    foreach (var hunted in hunterToKill)
                    {
                        if (hunted == mafiaToKill)
                        {
                            continue;
                        }
                        if (doctorToSave.Contains(hunted))
                        {
                            continue;
                        }

                        await Kill(hunted, DeathReason.HunterAttacked);
                    }

                    foreach (var silenced in silencerToSilence)
                    {
                        var dm = await silenced.GetDm();

                        await dm.SendMessageAsync("You have been silenced! You aren't able to say anything!");
                    }

                    // Day Time
                    await ChannelVisibility(GetGeneral(), Players, x => !silencerToSilence.Contains(x), true);
                    await VoiceMute(Players, x => !silencerToSilence.Contains(x));

                    var embedTitle  = "Uneventful night.";
                    var embedColor  = Color.Blue;
                    var newsBuilder = new StringBuilder();
                    if (mafiaToKill == null)
                    {
                        newsBuilder.Append("The mafia was asleep and didn't do anything.\n");
                    }
                    else
                    {
                        embedTitle = $"**{GetName(mafiaToKill)}** was killed!";
                        embedColor = Color.Red;
                        newsBuilder.Append(RandomDeathMessage(GetName(mafiaToKill)) + "\n");
                        if (doctorToSave.Contains(mafiaToKill))
                        {
                            embedTitle = $"**{GetName(mafiaToKill)}** was attacked and saved!";
                            embedColor = Color.Green;
                            newsBuilder.Append($"{GetName(mafiaToKill)} was saved by a doctor!\n");
                        }
                    }

                    foreach (var hunterTarget in hunterToKill)
                    {
                        if (hunterTarget == mafiaToKill)
                        {
                            continue;
                        }
                        newsBuilder.Append($"\nAnd {GetName(hunterTarget)} was attacked by the hunter!\n");

                        if (doctorToSave.Contains(hunterTarget))
                        {
                            newsBuilder.Append("But doctor saved him!\n");
                        }
                    }

                    await SendGeneral(new EmbedBuilder()
                                      .WithColor(embedColor)
                                      .WithTitle(embedTitle)
                                      .WithDescription(newsBuilder.ToString())
                                      .Build());

                    if (CheckGameWin() != WinReason.NoWinYet)
                    {
                        break;
                    }

                    Thread.Sleep(DiscussionTime);

                    var citizenToKill = await DoCitizenVote(silencerToSilence);

                    // Last Stand
                    if (citizenToKill != null)
                    {
                        await SendGeneral($"<@{citizenToKill.GetId()}> **You're on your last stand. " +
                                          "You have 20 seconds to defend yourself.**");
                        await ChannelVisibility(GetGeneral(), Players,
                                                x => x.GetId() == citizenToKill.GetId(), true);
                        await VoiceMute(Players, x => x.GetId() == citizenToKill.GetId());

                        Thread.Sleep(DefendTime);

                        // Make the game think there is a vote with two options, sketchy solution for now.
                        await ChannelVisibility(GetGeneral(), Players, x => !silencerToSilence.Contains(x));
                        await VoiceMute(Players, true);

                        _voteOptions = new List <MafiaPlayer>();
                        var options = Utils.Code(
                            "1. Innocent\n" +
                            "2. Guilty");
                        var tally = await SendGeneral("Guilty or innocent? Vote with `-vote <number>`." + options);

                        var innocent = new List <ulong>();
                        var guilty   = new List <ulong>();

                        stopwatch.Restart();
                        while (stopwatch.ElapsedMilliseconds < LastStandVoteTime)
                        {
                            while (_voteQueue.Count > 0)
                            {
                                var vote = _voteQueue.Dequeue();

                                if (silencerToSilence.Exists(x => x.GetId() == vote.Voter))
                                {
                                    Console.WriteLine("Ignored silenced vote.");
                                    continue;
                                }

                                if (vote.Vote <= 0 || vote.Vote > 2)
                                {
                                    await SendGeneral("Please select a valid option (1 - 2).");

                                    continue;
                                }

                                if (vote.Voter == citizenToKill.GetId())
                                {
                                    await SendGeneral("You can't vote for yourself, defendant.");

                                    continue;
                                }

                                if (innocent.Contains(vote.Voter))
                                {
                                    innocent.Remove(vote.Voter);
                                }
                                if (guilty.Contains(vote.Voter))
                                {
                                    guilty.Remove(vote.Voter);
                                }

                                if (vote.Vote == 1)
                                {
                                    innocent.Add(vote.Voter);
                                }
                                if (vote.Vote == 2)
                                {
                                    guilty.Add(vote.Voter);
                                }

                                await tally.ModifyAsync(
                                    x => x.Content = "Guilty or innocent? Vote with `-vote <number>`. " +
                                    $"{innocent.Count} Innocent, {guilty.Count} Guilty" + options);
                            }
                        }
                        _voteOptions = null;

                        if (innocent.Count < guilty.Count)
                        {
                            await SendGeneral($"<@{citizenToKill.GetId()}> is found guilty. He/She is now dead. " +
                                              "Everyone goes to bed.");
                            await Kill(citizenToKill, DeathReason.VotedOut);
                        }
                        else
                        {
                            await SendGeneral("Citizens are not convinced! " +
                                              $"<@{citizenToKill.GetId()}> is acquitted. " +
                                              "Time for bed!");
                        }
                    }
                    else
                    {
                        await SendGeneral("No one was put on trial. Time to go to bed.");
                    }
                }

                await SendGeneral("Game is over. " + WinReasonExplanation(CheckGameWin()));
                await Reset();
            } catch (Exception e) {
                await SendGeneral(Utils.Code("RunGame() Exception -> " + e.Message + "\n\n" + e.StackTrace));
            }
        }
Пример #3
0
        private async Task <MafiaPlayer> DoCitizenVote(List <MafiaPlayer> cannotVote)
        {
            _voteOptions = new List <MafiaPlayer>(Players);
            await SendGeneral("Anyone suspicious? Vote for someone to kill with `-vote <number>`:\n"
                              + Utils.Code(BuildVoteOptions(_voteOptions)));

            var validVotes = new List <MafiaVote>();
            var stopwatch  = new Stopwatch();

            stopwatch.Start();
            while (stopwatch.ElapsedMilliseconds < CitizenVoteTime &&
                   !(validVotes.Count > 0 &&
                     VoteScores(validVotes).Max(x => x.Value) >= Math.Ceiling(Players.Count / 2.0)))
            {
                while (_voteQueue.Count > 0)
                {
                    var vote = _voteQueue.Dequeue();

                    if (vote.Channel != GetGeneral().Id)
                    {
                        Console.WriteLine("Ignored non-#general vote during mafia vote.");
                        continue;
                    }

                    if (cannotVote.Exists(x => x.GetId() == vote.Voter))
                    {
                        Console.WriteLine("Ignored silenced vote.");
                        continue;
                    }

                    if (vote.Vote <= 0 || vote.Vote > _voteOptions.Count)
                    {
                        await SendGeneral($"Please select a valid option (1 - {_voteOptions.Count}).");

                        continue;
                    }

                    if (_voteOptions[vote.Vote - 1].GetId() == vote.Voter)
                    {
                        await SendGeneral("You can't vote for yourself.");

                        continue;
                    }

                    validVotes.Add(vote);
                    await SendGeneral($"<@{vote.Voter}>! Your vote for #{vote.Vote} has been registered.");
                }
            }

            MafiaPlayer selected = null;
            var         top      = HighestScore(validVotes);

            if (top.HasValue)
            {
                selected = _voteOptions[top.Value - 1];
            }

            _voteOptions = null;

            return(selected);
        }
Пример #4
0
        private string GetName(MafiaPlayer player)
        {
            var user = GetGuild().GetUser(player.GetId());

            return(user.Nickname ?? user.Username);
        }
Пример #5
0
 protected static bool IsNeutral(MafiaPlayer player)
 {
     return(NeutralRoles.Contains(player.GetRole()));
 }
Пример #6
0
 protected static bool IsNotMafia(MafiaPlayer player)
 {
     return(!IsMafia(player));
 }
Пример #7
0
 protected static bool IsMafia(MafiaPlayer player)
 {
     return(MafiaRoles.Contains(player.GetRole()));
 }