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()); }
// 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)); } }
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); }
private string GetName(MafiaPlayer player) { var user = GetGuild().GetUser(player.GetId()); return(user.Nickname ?? user.Username); }
protected static bool IsNeutral(MafiaPlayer player) { return(NeutralRoles.Contains(player.GetRole())); }
protected static bool IsNotMafia(MafiaPlayer player) { return(!IsMafia(player)); }
protected static bool IsMafia(MafiaPlayer player) { return(MafiaRoles.Contains(player.GetRole())); }