diff --git a/Gamemodes/BedWars.cs b/Gamemodes/BedWars.cs index 2f2a9d548..cb456ed7c 100644 --- a/Gamemodes/BedWars.cs +++ b/Gamemodes/BedWars.cs @@ -290,7 +290,7 @@ public static class BedWars { WinnerData = (team.GetColor(), team.GetName() + Translator.GetString("Win")); CustomWinnerHolder.WinnerIds = Data.Where(x => x.Value.Team == team).Select(x => x.Key).ToHashSet(); - Logger.Info($"Winners: {team.GetName()} - {string.Join(", ", CustomWinnerHolder.WinnerIds.Select(id => Main.AllPlayerNames.GetValueOrDefault(id, string.Empty)))}", "BedWars"); + Logger.Info($"Winners: {team.GetName()} - {CustomWinnerHolder.WinnerIds.Join(", ", id => Main.AllPlayerNames.GetValueOrDefault(id, string.Empty))}", "BedWars"); SendRPC(); return true; } diff --git a/Gamemodes/CustomHnS.cs b/Gamemodes/CustomHnS.cs index fdd987217..486cdc4d1 100644 --- a/Gamemodes/CustomHnS.cs +++ b/Gamemodes/CustomHnS.cs @@ -346,34 +346,72 @@ internal static class CustomHnS return targetRole.Interface.Team == Team.Impostor && (targetRole.Role != CustomRoles.Agent || seerRole.Interface.Team == Team.Impostor); } + private static readonly StringBuilder TaskBarText = new(); + public static string GetTaskBarText() { - string text = Main.PlayerStates.IntersectBy(PlayerRoles.Keys, x => x.Key).Aggregate("", (current, state) => $"{current}{GetStateText(state)}\n"); - return $"{text}\r\n\r\n<#00ffa5>{Translator.GetString("HNS.TaskCount")} {GameData.Instance.CompletedTasks}/{GameData.Instance.TotalTasks}"; + bool seeRoles = PlayersSeeRoles.GetBool(); + bool agentEnabled = CustomRoles.Agent.IsEnable(); + string deadText = Translator.GetString("Dead"); - static string GetStateText(KeyValuePair state) + TaskBarText.Clear(); + TaskBarText.Append(""); + + foreach ((byte id, PlayerState state) in Main.PlayerStates) { - string name = Main.AllPlayerNames.GetValueOrDefault(state.Key, $"ID {state.Key}"); - name = Utils.ColorString(Main.PlayerColors.GetValueOrDefault(state.Key, Color.white), name); - bool isSeeker = PlayerRoles[state.Key].Interface.Team == Team.Impostor; - bool alive = !state.Value.IsDead; + if (!PlayerRoles.TryGetValue(id, out var playerRole)) continue; - TaskState taskState = state.Value.TaskState; - var stateText = string.Empty; + string name = Main.AllPlayerNames.TryGetValue(id, out string playerName) ? playerName : $"ID {id}"; + name = Utils.ColorString(Main.PlayerColors.GetValueOrDefault(id, Color.white), name); + TaskBarText.Append(name); - if (PlayersSeeRoles.GetBool()) - stateText = $" ({GetRole().ToColoredString()}){GetTaskCount()}"; - else if (isSeeker) stateText = $" ({CustomRoles.Seeker.ToColoredString()})"; + if (seeRoles) + { + CustomRoles role = state.MainRole == CustomRoles.Agent ? CustomRoles.Hider : state.MainRole; - if (!alive) stateText += $" {Translator.GetString("Dead")}"; + TaskBarText.Append(' '); + TaskBarText.Append('('); + TaskBarText.Append(role.ToColoredString()); + TaskBarText.Append(')'); - stateText = $"{name}{stateText}"; - return stateText; + TaskState taskState = state.TaskState; - CustomRoles GetRole() => state.Value.MainRole == CustomRoles.Agent ? CustomRoles.Hider : state.Value.MainRole; + if (state.MainRole != CustomRoles.GM && !agentEnabled && taskState.HasTasks) + { + TaskBarText.Append(' '); + TaskBarText.Append('('); + TaskBarText.Append(taskState.CompletedTasksCount); + TaskBarText.Append('/'); + TaskBarText.Append(taskState.AllTasksCount); + TaskBarText.Append(')'); + } + } + else if (playerRole.Interface.Team == Team.Impostor) + { + TaskBarText.Append(' '); + TaskBarText.Append('('); + TaskBarText.Append(CustomRoles.Seeker.ToColoredString()); + TaskBarText.Append(')'); + } - string GetTaskCount() => state.Value.MainRole == CustomRoles.GM || CustomRoles.Agent.IsEnable() || !taskState.HasTasks ? string.Empty : $" ({taskState.CompletedTasksCount}/{taskState.AllTasksCount})"; + if (state.IsDead) + { + TaskBarText.Append(" "); + TaskBarText.Append(deadText); + TaskBarText.Append(""); + } + + TaskBarText.Append('\n'); } + + TaskBarText.Append("\r\n\r\n<#00ffa5>"); + TaskBarText.Append(Translator.GetString("HNS.TaskCount")); + TaskBarText.Append(" "); + TaskBarText.Append(GameData.Instance.CompletedTasks); + TaskBarText.Append('/'); + TaskBarText.Append(GameData.Instance.TotalTasks); + + return TaskBarText.ToString(); } private static readonly StringBuilder Suffix = new(); @@ -401,7 +439,7 @@ internal static class CustomHnS if (PlayersSeeRoles.GetBool() && !CustomRoles.Agent.IsEnable() && IntroCutsceneDestroyPatch.IntroDestroyTS + 15 > Utils.TimeStamp) { Suffix.AppendLine(); - Suffix.AppendFormat(Translator.GetString("HNSSeekers"), string.Join(", ", PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).Select(x => x.Key.ColoredPlayerName()))); + Suffix.AppendFormat(Translator.GetString("HNSSeekers"), PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).Join(", ", x => x.Key.ColoredPlayerName())); } } } diff --git a/Gamemodes/Deathrace.cs b/Gamemodes/Deathrace.cs index 9d2cf096a..d847c19e1 100644 --- a/Gamemodes/Deathrace.cs +++ b/Gamemodes/Deathrace.cs @@ -250,7 +250,7 @@ public static class Deathrace var track = Track.ToList(); if (!Clockwise) track.Reverse(); - players.NotifyPlayers("<#ffffff>" + string.Format(Translator.GetString("Deathrace.Tutorial.Track"), string.Join(" » ", track.ConvertAll(x => Translator.GetString(x.ToString())))), 100f); + players.NotifyPlayers("<#ffffff>" + string.Format(Translator.GetString("Deathrace.Tutorial.Track"), track.Join(" » ", x => Translator.GetString(x.ToString()))), 100f); yield return new WaitForSecondsRealtime(Track.Count); NameNotifyManager.Reset(); @@ -394,7 +394,7 @@ public static class Deathrace public static string GetTaskBarText() { - return string.Join('\n', Data.Select(x => $"{x.Key.ColoredPlayerName()}: {string.Format(Translator.GetString("Deathrace.Lap"), x.Value.Lap + 1, LapsToWin)}")); + return Data.Join('\n', x => $"{x.Key.ColoredPlayerName()}: {string.Format(Translator.GetString("Deathrace.Lap"), x.Value.Lap + 1, LapsToWin)}"); } public static void OnCheckMurder(PlayerControl killer, PlayerControl target) diff --git a/Gamemodes/KingOfTheZones.cs b/Gamemodes/KingOfTheZones.cs index 0863bc862..e96132d22 100644 --- a/Gamemodes/KingOfTheZones.cs +++ b/Gamemodes/KingOfTheZones.cs @@ -579,10 +579,10 @@ public static class KingOfTheZones SystemTypes zone = !room ? SystemTypes.Hallway : room.RoomId; if (justStarted) Suffix.Append(GetString(Zones.Count == 1 ? "KOTZ.SuffixHelp.Zones.Single" : "KOTZ.SuffixHelp.Zones.Plural")); - Suffix.AppendLine(string.Join(" | ", Zones.Select(x => Utils.ColorString(ZoneDomination[x].GetColor(), (zone == x ? "" : string.Empty) + GetString($"{x}") + (zone == x ? "" : string.Empty) + (ZoneMoveSchedules.TryGetValue(x, out long moveTS) ? $" {(ZoneDowntimeExpire.TryGetValue(x, out long downtimeEndTS) ? Utils.ColorString(Color.gray, $"{downtimeEndTS - now}") : $"<#ffff44>{moveTS - now}")}" : string.Empty))))); + Suffix.AppendLine(Zones.Join(" | ", x => Utils.ColorString(ZoneDomination[x].GetColor(), (zone == x ? "" : string.Empty) + GetString($"{x}") + (zone == x ? "" : string.Empty) + (ZoneMoveSchedules.TryGetValue(x, out long moveTS) ? $" {(ZoneDowntimeExpire.TryGetValue(x, out long downtimeEndTS) ? Utils.ColorString(Color.gray, $"{downtimeEndTS - now}") : $"<#ffff44>{moveTS - now}")}" : string.Empty)))); if (justStarted) Suffix.Append(GetString("KOTZ.SuffixHelp.Points")); - Suffix.AppendLine(string.Join(" | ", Points.IntersectBy(PlayerTeams.Values, x => x.Key).Select(x => Utils.ColorString(x.Key.GetColor(), $"{x.Value}")))); + Suffix.AppendLine(Points.IntersectBy(PlayerTeams.Values, x => x.Key).Join(" | ", x => Utils.ColorString(x.Key.GetColor(), $"{x.Value}"))); int highestPoints = Points.Values.Max(); bool tie = Points.Values.Count(x => x == highestPoints) > 1; @@ -590,7 +590,7 @@ public static class KingOfTheZones if (tie && end) { - string tieTeams = string.Join(' ', Points.Where(x => x.Value == highestPoints).Select(x => Utils.ColorString(x.Key.GetColor(), "\u25a0"))); + string tieTeams = Points.Where(x => x.Value == highestPoints).Join(' ', x => Utils.ColorString(x.Key.GetColor(), "\u25a0")); Suffix.Append("").AppendFormat(GetString("KOTZ.Suffix.Tie"), tieTeams).AppendLine(""); } else @@ -966,7 +966,7 @@ public static class KingOfTheZones } } - Logger.Info($"Zone domination: {string.Join(", ", ZoneDomination.Select(x => $"{x.Key} = {x.Value}"))}", "KOTZ"); + Logger.Info($"Zone domination: {ZoneDomination.Join(", ", x => $"{x.Key} = {x.Value}")}", "KOTZ"); } catch (Exception e) { Utils.ThrowException(e); } diff --git a/Gamemodes/Mingle.cs b/Gamemodes/Mingle.cs index ced6c47f2..e4cef2545 100644 --- a/Gamemodes/Mingle.cs +++ b/Gamemodes/Mingle.cs @@ -130,7 +130,7 @@ public static class Mingle return true; case var p when p <= MaxWinningPlayers: CustomWinnerHolder.WinnerIds = aapc.Select(x => x.PlayerId).ToHashSet(); - Logger.Info($"Winners: {string.Join(", ", aapc.Select(x => x.GetRealName().RemoveHtmlTags()))}", "Mingle"); + Logger.Info($"Winners: {aapc.Join(", ", x => x.GetRealName().RemoveHtmlTags())}", "Mingle"); Main.DoBlockNameChange = true; return true; default: diff --git a/Gamemodes/NaturalDisasters.cs b/Gamemodes/NaturalDisasters.cs index 7820bf7d8..49ecd1a81 100644 --- a/Gamemodes/NaturalDisasters.cs +++ b/Gamemodes/NaturalDisasters.cs @@ -393,7 +393,7 @@ public static class NaturalDisasters if (DeathMessageQueue.Count > 0 && DeathMessageQueue.FindFirst(x => x.recordTimeStamp + 3 <= now, out var expired)) { - var names = string.Join(", ", DeathMessageQueue.Where(x => x.deathReason == expired.deathReason).Select(x => x.id.ColoredPlayerName())); + var names = DeathMessageQueue.Where(x => x.deathReason == expired.deathReason).Join(", ", x => x.id.ColoredPlayerName()); string msgOthers = string.Format(Translator.GetString($"ND_DRLaughMessageOthers-{IRandom.Instance.Next(4)}.{expired.deathReason}"), names); Main.EnumerateAlivePlayerControls().NotifyPlayers($"<#ff0000>[╳] {Utils.ColorString(DeathReasonColor(expired.deathReason), msgOthers)}"); DeathMessageQueue.RemoveAll(x => x.deathReason == expired.deathReason); diff --git a/Gamemodes/Quiz.cs b/Gamemodes/Quiz.cs index 1210d414f..a7f744bcd 100644 --- a/Gamemodes/Quiz.cs +++ b/Gamemodes/Quiz.cs @@ -149,7 +149,7 @@ public static class Quiz public static string GetStatistics(byte id) { if (!NumCorrectAnswers.TryGetValue(id, out var data)) return string.Empty; - string str = string.Join(" | ", data.Select(x => $"{x.Key.ToString()[0]}-{x.Value.Sum()}")); + string str = data.Join(" | ", x => $"{x.Key.ToString()[0]}-{x.Value.Sum()}"); return GetString("Quiz.EndResults.CorrectAnswerNum") + str; } @@ -235,7 +235,7 @@ public static class Quiz if (!AllowKills) return string.Empty; requiredCorrect = Settings[CurrentDifficulty].CorrectRequirement.GetInt(); - gotCorrect = NumCorrectAnswers[seer.PlayerId][CurrentDifficulty][Round]; + gotCorrect = NumCorrectAnswers[seer.PlayerId][CurrentDifficulty][Round - 1]; failed = gotCorrect < requiredCorrect; var ffaTimeLeft = FFAEndTS - Utils.TimeStamp; @@ -276,7 +276,7 @@ public static class Quiz var aapc = Main.AllAlivePlayerControlsToList; bool showTutorial = !SubmergedCompatibility.IsSubmerged() && aapc.ExceptBy(HasPlayedFriendCodes, x => x.FriendCode).Count() > aapc.Count / 2; - var usedRooms = string.Join('\n', UsedRooms[Main.CurrentMap].Select(x => $"{x.Key}: {GetString(x.Value.ToString())}")); + var usedRooms = UsedRooms[Main.CurrentMap].Join('\n', x => $"{x.Key}: {GetString(x.Value.ToString())}"); aapc.NotifyPlayers(string.Format(GetString("Quiz.Tutorial.Basics"), usedRooms), 11f); yield return new WaitForSecondsRealtime(showTutorial ? 9f : 5f); if (GameStates.IsMeeting || ExileController.Instance || !GameStates.InGame || GameStates.IsLobby) yield break; @@ -454,8 +454,8 @@ public static class Quiz if (DyingPlayers.Count == 0) NumAllCorrectAnswers++; bool everyoneWasWrong = DyingPlayers.Count == aapcCount; if (!everyoneWasWrong) NumCorrectAnswers.IntersectBy(aapc.Select(x => x.PlayerId), x => x.Key).DoIf(x => !DyingPlayers.Contains(x.Key), x => x.Value[CurrentDifficulty][Round]++); - Logger.Info($"{(everyoneWasWrong ? "Everyone" : "Players who")} got the question wrong: {string.Join(", ", DyingPlayers.Select(x => Main.AllPlayerNames.GetValueOrDefault(x, $"Someone (ID {x})")))}", "Quiz"); - Logger.Info($"Number of correct answers for everyone currently: {string.Join(", ", NumCorrectAnswers.Select(x => $"{Main.AllPlayerNames.GetValueOrDefault(x.Key, string.Empty)}: {x.Value[CurrentDifficulty][Round]}"))}", "Quiz"); + Logger.Info($"{(everyoneWasWrong ? "Everyone" : "Players who")} got the question wrong: {DyingPlayers.Join(", ", x => Main.AllPlayerNames.GetValueOrDefault(x, $"Someone (ID {x})"))}", "Quiz"); + Logger.Info($"Number of correct answers for everyone currently: {NumCorrectAnswers.Join(", ", x => $"{Main.AllPlayerNames.GetValueOrDefault(x.Key, string.Empty)}: {x.Value[CurrentDifficulty][Round]}")}", "Quiz"); if (everyoneWasWrong) QuestionsAsked--; Utils.NotifyRoles(); @@ -475,7 +475,7 @@ public static class Quiz var correctRequirement = settings.CorrectRequirement.GetInt(); List dyingPlayers = NumCorrectAnswers.Where(x => x.Value[CurrentDifficulty][Round] < correctRequirement).Select(x => x.Key).Where(x => Main.PlayerStates.TryGetValue(x, out var s) && !s.IsDead).ToList(); - Logger.Info($"Round {Round + 1} of {CurrentDifficulty} difficulty ended. Dying players: {dyingPlayers.Count} | {string.Join(", ", dyingPlayers.Select(x => Main.AllPlayerNames[x]))}", "Quiz"); + Logger.Info($"Round {Round + 1} of {CurrentDifficulty} difficulty ended. Dying players: {dyingPlayers.Count} | {dyingPlayers.Join(", ", x => Main.AllPlayerNames[x])}", "Quiz"); Round++; QuestionsAsked = 0; @@ -559,7 +559,7 @@ public static class Quiz { try { - var correctAnswers = string.Join('\n', NumCorrectAnswers.Select(x => $"{x.Key.ColoredPlayerName()}: {string.Join(' ', x.Value.Select(k => $"{k.Key.ToString()[0]}-{k.Value.Sum()}"))}")); + var correctAnswers = NumCorrectAnswers.Join('\n', x => $"{x.Key.ColoredPlayerName()}: {x.Value.Join(' ', k => $"{k.Key.ToString()[0]}-{k.Value.Sum()}")}"); return string.Format(GetString("Quiz.TaskBarText"), CurrentDifficulty, Round + 1, QuestionsAsked + 1, correctAnswers); } catch { return string.Empty; } diff --git a/Gamemodes/RoomRush.cs b/Gamemodes/RoomRush.cs index 55ebec004..8e020dcd7 100644 --- a/Gamemodes/RoomRush.cs +++ b/Gamemodes/RoomRush.cs @@ -899,7 +899,7 @@ public static class RoomRush if (WinByPointsInsteadOfDeaths.GetBool()) { - Logger.Info($"Points: {string.Join(", ", Points.Select(x => $"{Main.AllPlayerNames[x.Key]}: {x.Value}"))}", "RoomRush"); + Logger.Info($"Points: {Points.Join(", ", x => $"{Main.AllPlayerNames[x.Key]}: {x.Value}")}", "RoomRush"); if (Utils.DoRPC) { diff --git a/Gamemodes/Snowdown.cs b/Gamemodes/Snowdown.cs index 5f407bca4..9e591537b 100644 --- a/Gamemodes/Snowdown.cs +++ b/Gamemodes/Snowdown.cs @@ -198,7 +198,7 @@ public static class Snowdown { int max = Data.Values.Max(x => x.Points); CustomWinnerHolder.WinnerIds = Data.Where(x => x.Value.Points == max && x.Key.GetPlayer()).Select(x => x.Key).ToHashSet(); - Logger.Info($"Winners: {string.Join(", ", CustomWinnerHolder.WinnerIds.Select(x => Main.AllPlayerNames.GetValueOrDefault(x, "[Unknown player]")))}", "Snowdown"); + Logger.Info($"Winners: {CustomWinnerHolder.WinnerIds.Join(", ", x => Main.AllPlayerNames.GetValueOrDefault(x, "[Unknown player]"))}", "Snowdown"); Main.DoBlockNameChange = true; return true; } diff --git a/Gamemodes/Speedrun.cs b/Gamemodes/Speedrun.cs index ea1a5ff70..ba7254dbd 100644 --- a/Gamemodes/Speedrun.cs +++ b/Gamemodes/Speedrun.cs @@ -87,14 +87,15 @@ public static class Speedrun public static string GetTaskBarText() { - return string.Join('\n', Main.PlayerStates - .Join(Main.EnumerateAlivePlayerControls(), x => x.Key, x => x.PlayerId, (kvp, _) => ( - Name: kvp.Key.ColoredPlayerName(), - CompletedTasks: kvp.Value.TaskState.CompletedTasksCount, - AllTasks: kvp.Value.TaskState.AllTasksCount, - Time: AmongUsClient.Instance.AmHost ? $" ({Timers.GetValueOrDefault(kvp.Key)}s)" : string.Empty)) + return Main.PlayerStates + .Where(x => !x.Value.IsDead) + .Select(x => ( + Name: x.Key.ColoredPlayerName(), + CompletedTasks: x.Value.TaskState.CompletedTasksCount, + AllTasks: x.Value.TaskState.AllTasksCount, + Time: AmongUsClient.Instance.AmHost ? $" ({Timers.GetValueOrDefault(x.Key)}s)" : string.Empty)) .OrderByDescending(x => x.CompletedTasks) - .Select(x => x.CompletedTasks < x.AllTasks ? $"{x.Name}: {x.CompletedTasks}/{x.AllTasks}{x.Time}" : $"{x.Name}: {Translator.GetString("Speedrun_KillingPlayer")}{x.Time}")); + .Join('\n', x => x.CompletedTasks < x.AllTasks ? $"{x.Name}: {x.CompletedTasks}/{x.AllTasks}{x.Time}" : $"{x.Name}: {Translator.GetString("Speedrun_KillingPlayer")}{x.Time}"); } public static string GetSuffixText(PlayerControl pc) diff --git a/Gamemodes/StopAndGo.cs b/Gamemodes/StopAndGo.cs index ea3592fe5..91bea33ae 100644 --- a/Gamemodes/StopAndGo.cs +++ b/Gamemodes/StopAndGo.cs @@ -183,7 +183,7 @@ internal static class StopAndGo private static IntegerValueRule CounterValueRule => new(1, 100, 1); private static IntegerValueRule ExtraTimeValue => new(0, 50, 1); private static int DefaultMinValue => 5; - private static int DefaultMaxValue => 30; + private static int DefaultMaxValue => 20; public static string GetHudText() { diff --git a/Gamemodes/TheMindGame.cs b/Gamemodes/TheMindGame.cs index 03d3b91e0..358038b21 100644 --- a/Gamemodes/TheMindGame.cs +++ b/Gamemodes/TheMindGame.cs @@ -219,7 +219,7 @@ public static class TheMindGame sb.Append('\n'); sb.Append('\n'); sb.Append(""); - sb.Append(string.Join('\n', AllItem.Select(x => $"{Translator.GetString($"TMG.Item.{x}")} (ID {ItemIds[seer.PlayerId][x]}) ({string.Format(Translator.GetString("TMG.Suffix.ItemCost"), ItemCosts[x])}) - {Translator.GetString($"TMG.ItemDescription.{x}")}"))); + sb.Append(AllItem.Join('\n', x => $"{Translator.GetString($"TMG.Item.{x}")} (ID {ItemIds[seer.PlayerId][x]}) ({string.Format(Translator.GetString("TMG.Suffix.ItemCost"), ItemCosts[x])}) - {Translator.GetString($"TMG.ItemDescription.{x}")}")); sb.Append('\n'); sb.Append('\n'); sb.Append(Translator.GetString("TMG.Suffix.BuyItemHint")); @@ -236,7 +236,7 @@ public static class TheMindGame sb.Append('\n'); sb.Append(Translator.GetString("TMG.Suffix.YourItems")); sb.Append('\n'); - sb.Append(string.Join(", ", items.GroupBy(x => x).Select(x => $"{x.Count()}x {Translator.GetString($"TMG.Item.{x.Key}")} (ID {ItemIds[seer.PlayerId][x.Key]})"))); + sb.Append(items.GroupBy(x => x).Join(", ", x => $"{x.Count()}x {Translator.GetString($"TMG.Item.{x.Key}")} (ID {ItemIds[seer.PlayerId][x.Key]})")); sb.Append('\n'); sb.Append('\n'); sb.Append(Translator.GetString("TMG.Suffix.UseItemHint")); @@ -439,7 +439,7 @@ public static class TheMindGame List auctionWinners = Pick.Where(x => x.Value == highestBid).Select(x => x.Key).ToList(); auctionWinners.ForEach(x => SuperPoints[x] += AuctionValue); - yield return NotifyEveryone("TMG.Notify.AuctionEnd", 4, highestBid, string.Join(" & ", auctionWinners.ConvertAll(x => x.ColoredPlayerName())), AuctionValue); + yield return NotifyEveryone("TMG.Notify.AuctionEnd", 4, highestBid, auctionWinners.Join(" & ", x => x.ColoredPlayerName()), AuctionValue); if (Stop) yield break; } @@ -633,7 +633,7 @@ public static class TheMindGame Dictionary round4Points = ranking.ToDictionary(x => x, x => (ranking.Count - ranking.IndexOf(x)) * 10); round4Points.Do(x => Points[x.Key] += x.Value); - join = string.Join('\n', round4Points.Select(x => $"{x.Key.ColoredPlayerName()}: +{x.Value}")); + join = round4Points.Join('\n', x => $"{x.Key.ColoredPlayerName()}: +{x.Value}"); yield return NotifyEveryone("TMG.Notify.Round4PointGain", 5, join); if (Stop) yield break; diff --git a/Modules/CustomRoleSelector.cs b/Modules/CustomRoleSelector.cs index 5a03b3e77..242c2c7d1 100644 --- a/Modules/CustomRoleSelector.cs +++ b/Modules/CustomRoleSelector.cs @@ -205,12 +205,12 @@ internal static class CustomRoleSelector Logger.Info($"Number of Coven members: {covenLimits.MinSetting.GetInt()} - {covenLimits.MaxSetting.GetInt()} => {numCovens}", "FactionLimits"); Logger.Msg("=====================================================", "AllActiveRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Impostor].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "ImpRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NeutralKilling].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "NKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NonKillingNeutral].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "NNKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Crewmate].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "CrewRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Madmate].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "MadmateRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Coven].Select(x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}")), "CovenRoles"); + Logger.Info(roles[RoleAssignType.Impostor].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "ImpRoles"); + Logger.Info(roles[RoleAssignType.NeutralKilling].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "NKRoles"); + Logger.Info(roles[RoleAssignType.NonKillingNeutral].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "NNKRoles"); + Logger.Info(roles[RoleAssignType.Crewmate].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "CrewRoles"); + Logger.Info(roles[RoleAssignType.Madmate].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "MadmateRoles"); + Logger.Info(roles[RoleAssignType.Coven].Join(", ", x => $"{x.Role}: {x.SpawnChance}% - {x.MaxCount}"), "CovenRoles"); Logger.Msg("=====================================================", "AllActiveRoles"); Dictionary subCategoryLimits; @@ -232,7 +232,7 @@ internal static class CustomRoleSelector } catch (Exception e) { Utils.ThrowException(e); } - if (subCategoryLimits.Count > 0) Logger.Info($"Sub-Category Limits: {string.Join(", ", subCategoryLimits.Select(x => $"{x.Key}: {x.Value}"))}", "SubCategoryLimits"); + if (subCategoryLimits.Count > 0) Logger.Info($"Sub-Category Limits: {subCategoryLimits.Join(", ", x => $"{x.Key}: {x.Value}")}", "SubCategoryLimits"); int nkLimit = subCategoryLimits[RoleOptionType.Neutral_Killing]; int nnkLimit; @@ -254,12 +254,12 @@ internal static class CustomRoleSelector roles.Keys.Do(type => ApplySubCategoryLimits(type, subCategoryLimits)); Logger.Msg("===================================================", "PreSelectedRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Impostor].Select(x => x.Role.ToString())), "PreSelectedImpostorRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NeutralKilling].Select(x => x.Role.ToString())), "PreSelectedNKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NonKillingNeutral].Select(x => x.Role.ToString())), "PreSelectedNNKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Crewmate].Select(x => x.Role.ToString())), "PreSelectedCrewRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Madmate].Select(x => x.Role.ToString())), "PreSelectedMadmateRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Coven].Select(x => x.Role.ToString())), "PreSelectedCovenRoles"); + Logger.Info(roles[RoleAssignType.Impostor].Join(", ", x => x.Role.ToString()), "PreSelectedImpostorRoles"); + Logger.Info(roles[RoleAssignType.NeutralKilling].Join(", ", x => x.Role.ToString()), "PreSelectedNKRoles"); + Logger.Info(roles[RoleAssignType.NonKillingNeutral].Join(", ", x => x.Role.ToString()), "PreSelectedNNKRoles"); + Logger.Info(roles[RoleAssignType.Crewmate].Join(", ", x => x.Role.ToString()), "PreSelectedCrewRoles"); + Logger.Info(roles[RoleAssignType.Madmate].Join(", ", x => x.Role.ToString()), "PreSelectedMadmateRoles"); + Logger.Info(roles[RoleAssignType.Coven].Join(", ", x => x.Role.ToString()), "PreSelectedCovenRoles"); Logger.Msg("===================================================", "PreSelectedRoles"); try @@ -284,12 +284,12 @@ internal static class CustomRoleSelector catch (Exception e) { Utils.ThrowException(e); } Logger.Msg("======================================================", "SelectedRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Impostor].Select(x => x.Role.ToString())), "SelectedImpostorRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NeutralKilling].Select(x => x.Role.ToString())), "SelectedNKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.NonKillingNeutral].Select(x => x.Role.ToString())), "SelectedNNKRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Crewmate].Select(x => x.Role.ToString())), "SelectedCrewRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Madmate].Select(x => x.Role.ToString())), "SelectedMadmateRoles"); - Logger.Info(string.Join(", ", roles[RoleAssignType.Coven].Select(x => x.Role.ToString())), "SelectedCovenRoles"); + Logger.Info(roles[RoleAssignType.Impostor].Join(", ", x => x.Role.ToString()), "SelectedImpostorRoles"); + Logger.Info(roles[RoleAssignType.NeutralKilling].Join(", ", x => x.Role.ToString()), "SelectedNKRoles"); + Logger.Info(roles[RoleAssignType.NonKillingNeutral].Join(", ", x => x.Role.ToString()), "SelectedNNKRoles"); + Logger.Info(roles[RoleAssignType.Crewmate].Join(", ", x => x.Role.ToString()), "SelectedCrewRoles"); + Logger.Info(roles[RoleAssignType.Madmate].Join(", ", x => x.Role.ToString()), "SelectedMadmateRoles"); + Logger.Info(roles[RoleAssignType.Coven].Join(", ", x => x.Role.ToString()), "SelectedCovenRoles"); Logger.Msg("======================================================", "SelectedRoles"); List allPlayers = Main.EnumerateAlivePlayerControls().ToList(); @@ -391,7 +391,7 @@ internal static class CustomRoleSelector if (rd.Next(0, 100) < Bomber.NukerChance.GetInt() && finalRolesList.Remove(CustomRoles.Bomber)) finalRolesList.Add(CustomRoles.Nuker); RoleResult.AddRange(allPlayers.Shuffle().Zip(finalRolesList.Shuffle()).ToDictionary(x => x.First.PlayerId, x => x.Second), false); - Logger.Info(string.Join(", ", RoleResult.Values.Select(x => x.ToString())), "RoleResults"); + Logger.Info(RoleResult.Values.Join(", ", x => x.ToString()), "RoleResults"); if (RoleResult.Count < allPlayers.Count) Logger.Error("Role assignment error: There are players who have not been assigned a role", "CustomRoleSelector"); diff --git a/Modules/Extensions/CollectionExtensions.cs b/Modules/Extensions/CollectionExtensions.cs index 6e437bd01..f92a9a37e 100644 --- a/Modules/Extensions/CollectionExtensions.cs +++ b/Modules/Extensions/CollectionExtensions.cs @@ -346,6 +346,51 @@ public static class CollectionExtensions return list; } + + public string Join(string separator, Func selector) + { + separator ??= string.Empty; + selector ??= x => x.ToString(); + + using IEnumerator enumerator = collection.GetEnumerator(); + + if (!enumerator.MoveNext()) + return string.Empty; + + StringBuilder sb = new(); + + sb.Append(selector(enumerator.Current)); + + while (enumerator.MoveNext()) + { + sb.Append(separator); + sb.Append(selector(enumerator.Current)); + } + + return sb.ToString(); + } + + public string Join(char separator, Func selector) + { + selector ??= x => x.ToString(); + + using IEnumerator enumerator = collection.GetEnumerator(); + + if (!enumerator.MoveNext()) + return string.Empty; + + StringBuilder sb = new(); + + sb.Append(selector(enumerator.Current)); + + while (enumerator.MoveNext()) + { + sb.Append(separator); + sb.Append(selector(enumerator.Current)); + } + + return sb.ToString(); + } } /// The collection @@ -388,6 +433,49 @@ public static class CollectionExtensions if (collection.Count == 0) return default(T); return collection[IRandom.Instance.Next(collection.Count)]; } + + public string Join(string separator, Func selector) + { + separator ??= string.Empty; + selector ??= x => x.ToString(); + + int count = collection.Count; + + if (count == 0) + return string.Empty; + + StringBuilder sb = new(); + sb.Append(selector(collection[0])); + + for (int i = 1; i < count; i++) + { + sb.Append(separator); + sb.Append(selector(collection[i])); + } + + return sb.ToString(); + } + + public string Join(char separator, Func selector) + { + selector ??= x => x.ToString(); + + int count = collection.Count; + + if (count == 0) + return string.Empty; + + StringBuilder sb = new(); + sb.Append(selector(collection[0])); + + for (int i = 1; i < count; i++) + { + sb.Append(separator); + sb.Append(selector(collection[i])); + } + + return sb.ToString(); + } } /// diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 150d0507e..cbb0db9ec 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1151,7 +1151,7 @@ public static class Options if (values.Count == 0) continue; - string possibleValues = string.Join("
", values.Select(x => $"`{x}`")); + string possibleValues = values.Join("
", x => $"`{x}`"); string defaultValue = option switch { @@ -3373,7 +3373,7 @@ public static class Options OptionItem.SyncAllOptions(); if (CurrentGameMode == CustomGameMode.Standard) - Logger.SendInGame(string.Format(Translator.GetString("AutoFactionMinMaxSettings.Applied"), playerCount, usedPlayerCount, string.Join(", ", new[] { Team.Impostor, Team.Coven, Team.Neutral }.Select(x => $"{Utils.ColorString(x.GetColor(), Translator.GetString($"ShortTeamName.{x}").ToUpper())}: <#ffffff>{usedValues.TeamSettings[x].MinSetting.GetInt()}-{usedValues.TeamSettings[x].MaxSetting.GetInt()}")), usedValues.MinNNKs.GetInt(), usedValues.MaxNNKs.GetInt())); + Logger.SendInGame(string.Format(Translator.GetString("AutoFactionMinMaxSettings.Applied"), playerCount, usedPlayerCount, new[] { Team.Impostor, Team.Coven, Team.Neutral }.Join(", ", x => $"{Utils.ColorString(x.GetColor(), Translator.GetString($"ShortTeamName.{x}").ToUpper())}: <#ffffff>{usedValues.TeamSettings[x].MinSetting.GetInt()}-{usedValues.TeamSettings[x].MaxSetting.GetInt()}"), usedValues.MinNNKs.GetInt(), usedValues.MaxNNKs.GetInt())); LastUsedPlayerCount = usedPlayerCount; } diff --git a/Modules/PrivateTagManager.cs b/Modules/PrivateTagManager.cs index e402375d2..b779e84b4 100644 --- a/Modules/PrivateTagManager.cs +++ b/Modules/PrivateTagManager.cs @@ -25,7 +25,7 @@ public static class PrivateTagManager private static void SaveTagsToFile() { - try { File.WriteAllText(TagFile, string.Join("\n", Tags.Select(x => $"{x.Key}={x.Value}"))); } + try { File.WriteAllText(TagFile, Tags.Join("\n", x => $"{x.Key}={x.Value}")); } catch (Exception e) { Utils.ThrowException(e); } } diff --git a/Modules/TemplateManager.cs b/Modules/TemplateManager.cs index eec28ee6d..4b12720d1 100644 --- a/Modules/TemplateManager.cs +++ b/Modules/TemplateManager.cs @@ -53,8 +53,8 @@ public static class TemplateManager ["PlayerName"] = () => DataManager.Player.Customization.Name, ["HostName"] = () => Main.AllPlayerNames.GetValueOrDefault(PlayerControl.LocalPlayer.PlayerId, PlayerControl.LocalPlayer.GetRealName()), ["Players"] = () => string.Join(", ", Main.AllPlayerNames.Values), - ["AlivePlayers"] = () => string.Join(", ", Main.EnumerateAlivePlayerControls().Select(x => x.GetRealName())), - ["DeadPlayers"] = () => string.Join(", ", Main.EnumeratePlayerControls().Where(x => !x.IsAlive()).Select(x => x.GetRealName())), + ["AlivePlayers"] = () => Main.EnumerateAlivePlayerControls().Join(", ", x => x.GetRealName()), + ["DeadPlayers"] = () => Main.EnumeratePlayerControls().Where(x => !x.IsAlive()).Join(", ", x => x.GetRealName()), ["PlayerCount"] = () => (GameData.Instance ? GameData.Instance.PlayerCount : 0).ToString(), ["AlivePlayerCount"] = () => Main.EnumerateAlivePlayerControls().Count().ToString(), ["DeadPlayerCount"] = () => Main.EnumeratePlayerControls().Count(x => !x.IsAlive()).ToString(), @@ -507,14 +507,13 @@ public static class TemplateManager string msg = (roleBlocked, rankBlocked) switch { - (true, _) => string.Format(GetString("Message.TemplateRoleRequired"), string.Join('/', roleBlockSource.AllowedRoles - .Select(r => + (true, _) => string.Format(GetString("Message.TemplateRoleRequired"), roleBlockSource.AllowedRoles.Join('/', r => { string name = r.TrimStart('!'); return Enum.TryParse(name, ignoreCase: true, out CustomRoles role) ? GetString(role.ToString()) : name; - }))), + })), (_, true) => string.Format(GetString("Message.TemplateRankRequired"), string.Join('/', rankBlockSource.AllowedRanks)), _ => string.Format(GetString(playerId == 0xff ? "Message.TemplateNotFoundHost" : "Message.TemplateNotFoundClient"), str, string.Join(", ", tags)) }; diff --git a/Modules/Translator.cs b/Modules/Translator.cs index d4d34f1b3..80aae099a 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -328,7 +328,7 @@ public static class Translator private static void CreateTemplateFile() { - File.WriteAllText($"{Main.DataPath}/{LanguageFolderName}/template.dat", string.Join('\n', TranslateMaps.Keys.Select(x => $"{x}:"))); + File.WriteAllText($"{Main.DataPath}/{LanguageFolderName}/template.dat", TranslateMaps.Keys.Join('\n', x => $"{x}:")); } public static void ExportCustomTranslation() diff --git a/Modules/Utils.cs b/Modules/Utils.cs index b2eca7453..a43bd910b 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -2831,8 +2831,8 @@ public static class Utils if (Options.CurrentGameMode != CustomGameMode.Standard) return; - string seers = SeerList.Count == apc.Count ? "Everyone" : string.Join(", ", SeerList.Select(x => x.GetRealName())); - string targets = TargetList.Count == apc.Count ? "Everyone" : string.Join(", ", TargetList.Select(x => x.GetRealName())); + string seers = SeerList.Count == apc.Count ? "Everyone" : SeerList.Join(", ", x => x.GetRealName()); + string targets = TargetList.Count == apc.Count ? "Everyone" : TargetList.Join(", ", x => x.GetRealName()); if (seers.Length == 0) seers = "\u2205"; if (targets.Length == 0) targets = "\u2205"; diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 9f4a77c2a..6ca86a0ab 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -575,13 +575,13 @@ internal static class ChatCommands { if (args.Length < 2) { - Utils.SendMessage("" + string.Join('\n', Main.CachedAllPlayerControls().Select(x => + Utils.SendMessage("" + Main.CachedAllPlayerControls().Join('\n', x => { ClientData client = x.GetClient(); string name = Main.AllPlayerNames.GetValueOrDefault(x.PlayerId, string.Empty); string id = string.IsNullOrEmpty(name) ? $"ID {x.PlayerId}" : $" (ID {x.PlayerId})"; return $"{name}{id} - {x.FriendCode} | {client?.GetHashedPuid()} | {client?.PlatformData.Platform}"; - })) + "", player.PlayerId); + }) + "", player.PlayerId); } else if (byte.TryParse(args[1], out byte playerId)) { @@ -1019,7 +1019,7 @@ internal static class ChatCommands { if ((!player.IsHost() && !IsPlayerAdmin(player.FriendCode)) || args.Length < 3 || !GetRoleByName(args[1], out CustomRoles role1) || !GetRoleByName(args[2], out CustomRoles role2)) { - Utils.SendMessage(string.Join('\n', Main.XORRoles.ConvertAll(x => $"{x.Item1.ToColoredString()} ⊕ {x.Item2.ToColoredString()}")), player.PlayerId, GetString("XORListTitle")); + Utils.SendMessage(Main.XORRoles.Join('\n', x => $"{x.Item1.ToColoredString()} ⊕ {x.Item2.ToColoredString()}"), player.PlayerId, GetString("XORListTitle")); return; } @@ -1110,7 +1110,7 @@ internal static class ChatCommands { GMPollGameModes = Main.CustomGameModeValues[..^1].Where(x => Options.GMPollGameModesSettings[x].GetBool()).ToList(); if (GMPollGameModes.Contains(CustomGameMode.HideAndSeek)) GMPollGameModes.Add((CustomGameMode)100); - string gmNames = string.Join(' ', GMPollGameModes.Select(x => GetString((int)x == 100 ? "HNS.ShiftAndSeek" : x.ToString()).Replace(' ', '_'))); + string gmNames = GMPollGameModes.Join(' ', x => GetString((int)x == 100 ? "HNS.ShiftAndSeek" : x.ToString().Replace(' ', '_'))); var msg = $"/poll {GetString("GameModePoll.Question").TrimEnd('?')}? {gmNames}"; PollCommand(player, msg, msg.Split(' ')); } @@ -1118,7 +1118,7 @@ internal static class ChatCommands public static void MapPollCommand(PlayerControl player, string text, string[] args) { MPollMaps = Main.MapNamesValues.Where(x => Options.MPollMapsSettings[x].GetBool()).ToList(); - string mNames = string.Join(' ', MPollMaps.Select(x => GetString(x.ToString()).Replace(' ', '_'))); + string mNames = MPollMaps.Join(' ', x => GetString(x.ToString().Replace(' ', '_'))); var msg = $"/poll {GetString("MapPoll.Question").TrimEnd('?')}? {mNames}"; PollCommand(player, msg, msg.Split(' ')); } @@ -1126,10 +1126,7 @@ internal static class ChatCommands public static void PresetPollCommand(PlayerControl player, string text, string[] args) { var presetConfigs = new[] { Main.Preset1, Main.Preset2, Main.Preset3, Main.Preset4, Main.Preset5, Main.Preset6, Main.Preset7, Main.Preset8, Main.Preset9, Main.Preset10, Main.Preset11, Main.Preset12, Main.Preset13, Main.Preset14, Main.Preset15, Main.Preset16, Main.Preset17, Main.Preset18, Main.Preset19, Main.Preset20 }; - - string presetNames = string.Join(' ', presetConfigs.Select((cfg, i) => - (cfg.Value == (string)cfg.DefaultValue ? GetString($"Preset_{i + 1}") : cfg.Value) - .Replace(' ', '_'))); + string presetNames = string.Join(' ', presetConfigs.Select((cfg, i) => (cfg.Value == (string)cfg.DefaultValue ? GetString($"Preset_{i + 1}") : cfg.Value).Replace(' ', '_'))); var msg = $"/poll {GetString("PresetPoll.Question").TrimEnd('?')}? {presetNames}"; PollCommand(player, msg, msg.Split(' ')); @@ -1523,9 +1520,9 @@ internal static class ChatCommands if (notReadyPlayers.Length == 0) Utils.SendMessage("\n", player.PlayerId, GetString("EveryoneReadyTitle")); else - Utils.SendMessage(string.Join(", ", notReadyPlayers.Select(x => x.ColoredPlayerName())), player.PlayerId, string.Format(GetString("PlayersNotReadyTitle"), notReadyPlayers.Length)); + Utils.SendMessage(notReadyPlayers.Join(", ", x => x.ColoredPlayerName()), player.PlayerId, string.Format(GetString("PlayersNotReadyTitle"), notReadyPlayers.Length)); - if (Spectators.Count > 0) Utils.SendMessage(string.Join(", ", Spectators.Select(x => x.ColoredPlayerName())), player.PlayerId, string.Format(GetString("SpectatorsList"), Spectators.Count)); + if (Spectators.Count > 0) Utils.SendMessage(Spectators.Join(", ", x => x.ColoredPlayerName()), player.PlayerId, string.Format(GetString("SpectatorsList"), Spectators.Count)); } } @@ -1942,7 +1939,7 @@ internal static class ChatCommands string result = winners.Length == 1 ? string.Format(GetString("Poll.Winner"), winners[0].Key, PollAnswers[winners[0].Key], winners[0].Value) + PollVotes.Where(x => x.Value > 0 && x.Key != winners[0].Key).Aggregate("", (s, t) => s + $"{t.Key} - {t.Value} {PollAnswers[t.Key]}\n") - : string.Format(GetString("Poll.Tie"), string.Join(" & ", winners.Select(x => $"{x.Key}{PollAnswers[x.Key]}")), maxVotes); + : string.Format(GetString("Poll.Tie"), winners.Join(" & ", x => $"{x.Key}{PollAnswers[x.Key]}"), maxVotes); Utils.SendMessage(result, title: Utils.ColorString(new(0, 255, 165, 255), GetString("PollResultTitle"))); diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs index 1b7faf34b..8c13e5fdf 100644 --- a/Patches/GameOptionsMenuPatch.cs +++ b/Patches/GameOptionsMenuPatch.cs @@ -971,7 +971,7 @@ public static class StringOptionPatch _ => [] }; - return $" {string.Join('/', teams.Select(GetColoredShortTeamName))}"; + return $" {teams.Join('/', GetColoredShortTeamName)}"; string GetColoredShortTeamName(Team t) => Utils.ColorString(t.GetColor(), Translator.GetString($"ShortTeamName.{t}").ToUpper()); } diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs index 640544f0a..4d2a8e195 100644 --- a/Patches/GameStartManagerPatch.cs +++ b/Patches/GameStartManagerPatch.cs @@ -238,7 +238,7 @@ public static class GameStartManagerPatch Logger.SendInGame(GetString("Error.InvalidColorPreventStart"), Color.yellow); string msg = GetString("Error.InvalidColor"); - msg += "\n" + string.Join(",", invalidColor.Select(p => $"{p.GetRealName()}")); + msg += "\n" + invalidColor.Join(",", p => $"{p.GetRealName()}"); Utils.SendMessage(msg, importance: MessageImportance.Low); } @@ -576,7 +576,7 @@ public static class GameStartRandomMap { Logger.SendInGame(GetString("Error.InvalidColorPreventStart"), Color.yellow); string msg = GetString("Error.InvalidColor"); - msg += "\n" + string.Join(",", invalidColor.Select(p => $"{p.GetRealName()}")); + msg += "\n" + invalidColor.Join(",", p => $"{p.GetRealName()}"); Utils.SendMessage(msg, importance: MessageImportance.Low); return false; } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 66b61b29a..698fb4012 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -1390,7 +1390,7 @@ internal static class TaskPanelBehaviourPatch { FinalTextBuilder.Append("\r\n\r\n") .Append("") - .Append(string.Join('\n', Main.EnumeratePlayerControls().Select(pc => new { pc, alive = pc.IsAlive() }).OrderByDescending(x => x.alive).Select(x => $"{(!x.alive ? "<#777777>" : "")}{HotPotato.GetIndicator(x.pc.PlayerId)}{(x.alive ? x.pc.PlayerId.ColoredPlayerName() : Main.AllPlayerNames.GetValueOrDefault(x.pc.PlayerId, $"ID {x.pc.PlayerId}"))}{(!x.alive ? $" <#ff0000>{GetString("Dead")}" : "")}"))) + .Append(Main.CachedAllPlayerControls().Select(pc => new { pc, alive = pc.IsAlive() }).OrderByDescending(x => x.alive).Join('\n', x => $"{(!x.alive ? "<#777777>" : "")}{HotPotato.GetIndicator(x.pc.PlayerId)}{(x.alive ? x.pc.PlayerId.ColoredPlayerName() : Main.AllPlayerNames.GetValueOrDefault(x.pc.PlayerId, $"ID {x.pc.PlayerId}"))}{(!x.alive ? $" <#ff0000>{GetString("Dead")}" : "")}")) .Append(""); break; } diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs index 0a157643b..23908ccfc 100644 --- a/Patches/OutroPatch.cs +++ b/Patches/OutroPatch.cs @@ -81,7 +81,7 @@ internal static class EndGamePatch { if (state.RoleHistory.Count > 0) { - string join = string.Join(" > ", state.RoleHistory.ConvertAll(x => x.ToColoredString())); + string join = state.RoleHistory.Join(" > ", x => x.ToColoredString()); sb.AppendLine($"{id.ColoredPlayerName()}: {join} > {state.MainRole.ToColoredString()}"); } } diff --git a/Patches/TextBoxPatch.cs b/Patches/TextBoxPatch.cs index f94510d75..82b85b5fa 100644 --- a/Patches/TextBoxPatch.cs +++ b/Patches/TextBoxPatch.cs @@ -236,7 +236,7 @@ public static class TextBoxPatch if (additionalInfo.Length == 0 && argName.Replace('[', '{').Replace(']', '}') is "{id}" or "{id1}" or "{id2}") { Dictionary allIds = Main.EnumeratePlayerControls().ToDictionary(x => x.PlayerId, x => x.PlayerId.ColoredPlayerName()); - additionalInfo = $"{Translator.GetString("PlayerIdList").TrimEnd(' ')}\n{string.Join('\n', allIds.Select(x => $"{x.Key} \uffeb {x.Value}"))}"; + additionalInfo = $"{Translator.GetString("PlayerIdList").TrimEnd(' ')}\n{allIds.Join('\n', x => $"{x.Key} \uffeb {x.Value}")}"; // OptionShower.CurrentPage = 0; } @@ -278,7 +278,7 @@ public static class TextBoxPatch : argName switch { "{id}" or "{id1}" or "{id2}" => $" ({byte.Parse(arg).ColoredPlayerName()})", - "{ids}" => $" ({string.Join(", ", arg.Split(',').Select(x => byte.Parse(x).ColoredPlayerName()))})", + "{ids}" => $" ({arg.Split(',').Join(", ", x => byte.Parse(x).ColoredPlayerName())})", "{role}" or "{addon}" or "[role]" when ChatCommands.GetRoleByName(arg, out CustomRoles role) => $" ({role.ToColoredString()})", "{color}" when ColorUtility.TryParseHtmlString($"#{arg}", out Color color) => $" ({Utils.ColorString(color, "COLOR")})", _ => string.Empty diff --git a/Roles/Standard/Coven/Wyrd.cs b/Roles/Standard/Coven/Wyrd.cs index 15b076c2b..9e618a8ab 100644 --- a/Roles/Standard/Coven/Wyrd.cs +++ b/Roles/Standard/Coven/Wyrd.cs @@ -211,7 +211,7 @@ public class Wyrd : CovenBase if (!seerIsWyrd) { - var join = string.Join(", ", AllAction.Where(x => ActionSuicideSettings[x]).Select(x => Translator.GetString($"Wyrd.Suffix.SuicideWarningOnAction.{x}"))); + var join = AllAction.Where(x => ActionSuicideSettings[x]).Join(", ", x => Translator.GetString($"Wyrd.Suffix.SuicideWarningOnAction.{x}")); Suffix.AppendFormat(Translator.GetString("Wyrd.Suffix.SuicideWarnings"), join); } } diff --git a/Roles/Standard/Crewmate/Chaos/Tornado.cs b/Roles/Standard/Crewmate/Chaos/Tornado.cs index 06ad2bfc9..472ac5726 100644 --- a/Roles/Standard/Crewmate/Chaos/Tornado.cs +++ b/Roles/Standard/Crewmate/Chaos/Tornado.cs @@ -173,7 +173,7 @@ internal class Tornado : RoleBase { if (seer.PlayerId != target.PlayerId || !IsEnable || (seer.IsModdedClient() && !hud) || seer.PlayerId != TornadoPC.PlayerId || Tornados == null) return string.Empty; - return string.Join(hud ? "\n" : ", ", Tornados.Select(x => $"Tornado {GetFormattedRoomName(x.Key.RoomName)} {GetFormattedVectorText(x.Key.Location)} ({(int)(TornadoDuration.GetInt() - (TimeStamp - x.Value) + 1)}s)")); + return Tornados.Join(hud ? "\n" : ", ", x => $"Tornado {GetFormattedRoomName(x.Key.RoomName)} {GetFormattedVectorText(x.Key.Location)} ({(int)(TornadoDuration.GetInt() - (TimeStamp - x.Value) + 1)}s)"); } public override void ManipulateGameEndCheckCrew(PlayerState playerState, out bool keepGameGoing, out int countsAs) diff --git a/Roles/Standard/Crewmate/Investigate/Captain.cs b/Roles/Standard/Crewmate/Investigate/Captain.cs index a3b7c99b7..830addd2f 100644 --- a/Roles/Standard/Crewmate/Investigate/Captain.cs +++ b/Roles/Standard/Crewmate/Investigate/Captain.cs @@ -72,7 +72,7 @@ public class Captain : RoleBase LateTask.New(() => { - string msg = string.Format(Translator.GetString("Captain.TargetInfo"), TargetId.ColoredPlayerName(), string.Join(" ➡ ", TargetRooms.ConvertAll(x => Translator.GetString(x.ToString())))); + string msg = string.Format(Translator.GetString("Captain.TargetInfo"), TargetId.ColoredPlayerName(), TargetRooms.Join(" ➡ ", x => Translator.GetString(x.ToString()))); Utils.SendMessage(msg, CaptainId, CustomRoles.Captain.ToColoredString(), importance: MessageImportance.High); TargetRooms = []; }, 10f, "Captain Message"); diff --git a/Roles/Standard/Crewmate/Investigate/Catcher.cs b/Roles/Standard/Crewmate/Investigate/Catcher.cs index 85f7bd98c..0ccf2481b 100644 --- a/Roles/Standard/Crewmate/Investigate/Catcher.cs +++ b/Roles/Standard/Crewmate/Investigate/Catcher.cs @@ -149,7 +149,7 @@ public class Catcher : RoleBase { if (CaughtRoles.Count >= MinPlayersTrappedToShowInfo.GetInt()) { - string roles = string.Join(", ", CaughtRoles.Values.Select(x => x.ToColoredString())); + string roles = CaughtRoles.Values.Join(", ", x => x.ToColoredString()); Utils.SendMessage("\n", CatcherId, Translator.GetString("Catcher.CaughtRoles") + roles, importance: MessageImportance.High); } else diff --git a/Roles/Standard/Crewmate/Investigate/Druid.cs b/Roles/Standard/Crewmate/Investigate/Druid.cs index d1b95a1cf..4a929228e 100644 --- a/Roles/Standard/Crewmate/Investigate/Druid.cs +++ b/Roles/Standard/Crewmate/Investigate/Druid.cs @@ -189,7 +189,7 @@ public class Druid : RoleBase Suffix.Clear().Append("\n"); Suffix.AppendLine($"<#00ffa5>{Triggers.Count} trigger{(Triggers.Count == 1 ? string.Empty : 's')} active") - .Append(string.Join(", ", Triggers.Select(trigger => $"Trigger {GetFormattedRoomName(trigger.Value)} {GetFormattedVectorText(trigger.Key)}"))) + .Append(Triggers.Join(", ", trigger => $"Trigger {GetFormattedRoomName(trigger.Value)} {GetFormattedVectorText(trigger.Key)}")) .Append(""); return Suffix.ToString(); @@ -202,7 +202,7 @@ public class Druid : RoleBase HudText.Clear(); HudText.AppendLine($"<#00ffa5>{Triggers.Count} trigger{(Triggers.Count == 1 ? string.Empty : 's')} active"); - HudText.Append(string.Join('\n', Triggers.Select(trigger => $"Trigger {GetFormattedRoomName(trigger.Value)} {GetFormattedVectorText(trigger.Key)}"))); + HudText.Append(Triggers.Join('\n', trigger => $"Trigger {GetFormattedRoomName(trigger.Value)} {GetFormattedVectorText(trigger.Key)}")); return HudText.ToString(); } diff --git a/Roles/Standard/Crewmate/Investigate/Forensic.cs b/Roles/Standard/Crewmate/Investigate/Forensic.cs index c952a0f35..8d02540e6 100644 --- a/Roles/Standard/Crewmate/Investigate/Forensic.cs +++ b/Roles/Standard/Crewmate/Investigate/Forensic.cs @@ -63,7 +63,7 @@ internal class Forensic : RoleBase msg += ";" + string.Format(Translator.GetString("ForensicNoticeDeathReason"), Translator.GetString($"DeathReason.{Main.PlayerStates[tpc.PlayerId].deathReason}")); if (ForensicCanknowAddons.GetBool()) - msg += ";" + string.Format(Translator.GetString("ForensicNoticeAddons"), string.Join(", ", tpc.GetCustomSubRoles().Select(x => x.ToColoredString()))); + msg += ";" + string.Format(Translator.GetString("ForensicNoticeAddons"), tpc.GetCustomSubRoles().Join(", ", x => x.ToColoredString())); DateTime deathTimeStamp = Main.PlayerStates[tpc.PlayerId].RealKiller.TimeStamp; DateTime now = DateTime.Now; @@ -75,10 +75,8 @@ internal class Forensic : RoleBase if (ForensicCanknowColorType.GetBool() && realKiller != null && timeSpanSeconds >= ForensicCanknowColorTypeMinBodyAge.GetInt()) { var darker = new List { 0, 1, 2, 6, 8, 9, 12, 15 }; - bool isDarker = darker.Contains(realKiller.CurrentOutfit.ColorId); - Func selector = x => Utils.ColorString(Palette.PlayerColors[x], Palette.GetColorName(x)); - var colors = isDarker ? string.Join('/', darker.Select(selector)) : string.Join('/', Enumerable.Range(0, 18).Except(darker).Select(selector)); - var str = Translator.GetString(isDarker ? "WhispererInfo.ColorDark" : "WhispererInfo.ColorLight"); + var colors = (darker.Contains(realKiller.CurrentOutfit.ColorId) ? darker : Enumerable.Range(0, 18).Except(darker)).Join('/', x => Utils.ColorString(Palette.PlayerColors[x], Palette.GetColorName(x))); + var str = Translator.GetString(darker.Contains(realKiller.CurrentOutfit.ColorId) ? "WhispererInfo.ColorDark" : "WhispererInfo.ColorLight"); msg += ";" + string.Format(Translator.GetString("ForensicNoticeColorType"), str, colors); } diff --git a/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs b/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs index bce1dcdf5..4954958ce 100644 --- a/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs +++ b/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs @@ -89,7 +89,7 @@ public class FortuneTeller : RoleBase roleList.Do(x => x.RoleList.Insert(IRandom.Instance.Next(x.RoleList.Count), x.Player.GetCustomRole())); AllPlayerRoleList = roleList.ToDictionary(x => x.Player.PlayerId, x => x.RoleList); - Logger.Info(string.Join(" ---- ", AllPlayerRoleList.Select(x => $"ID {x.Key} ({x.Key.GetPlayer().GetNameWithRole()}): {string.Join(", ", x.Value)}")), "FortuneTeller Roles"); + Logger.Info(AllPlayerRoleList.Join(" ---- ", x => $"ID {x.Key} ({x.Key.GetPlayer().GetNameWithRole()}): {string.Join(", ", x.Value)}"), "FortuneTeller Roles"); }, 8f, log: false); } @@ -122,7 +122,7 @@ public class FortuneTeller : RoleBase msg = string.Format(GetString("FortuneTellerCheck.TaskDone"), target.GetRealName(), target.GetCustomRole().ToColoredString()); else { - string roles = string.Join(", ", AllPlayerRoleList[target.PlayerId].Select(x => x.ToColoredString())); + string roles = AllPlayerRoleList[target.PlayerId].Join(", ", x => x.ToColoredString()); msg = string.Format(GetString("FortuneTellerCheckResult"), target.GetRealName(), roles); } diff --git a/Roles/Standard/Crewmate/Investigate/Inquisitor.cs b/Roles/Standard/Crewmate/Investigate/Inquisitor.cs index c0b7b8f9d..1cc787772 100644 --- a/Roles/Standard/Crewmate/Investigate/Inquisitor.cs +++ b/Roles/Standard/Crewmate/Investigate/Inquisitor.cs @@ -55,9 +55,9 @@ public class Inquisitor : RoleBase if (knownRoles.Count <= 1) result = Translator.GetString("InquisitorNoInfo"); else if (KnowExactRolesAfterTasksFinished.GetBool() && voter.GetTaskState().IsTaskFinished) - result = string.Join('\n', knownRoles.ConvertAll(x => $"{x.Id.ColoredPlayerName()}: {x.Role.ToColoredString()}")); + result = knownRoles.Join('\n', x => $"{x.Id.ColoredPlayerName()}: {x.Role.ToColoredString()}"); else - result = string.Join(", ", knownRoles.ConvertAll(x => x.Id.ColoredPlayerName())); + result = knownRoles.Join(", ", x => x.Id.ColoredPlayerName()); Utils.SendMessage("\n", voter.PlayerId, string.Format(Translator.GetString("InquisitorVoteResult"), target.PlayerId.ColoredPlayerName(), result), importance: MessageImportance.High); diff --git a/Roles/Standard/Crewmate/Investigate/Whisperer.cs b/Roles/Standard/Crewmate/Investigate/Whisperer.cs index 6bdfd7827..c74f3a0d3 100644 --- a/Roles/Standard/Crewmate/Investigate/Whisperer.cs +++ b/Roles/Standard/Crewmate/Investigate/Whisperer.cs @@ -144,9 +144,9 @@ public class Whisperer : RoleBase { 0 => string.Format(Translator.GetString("WhispererInfo.Color"), GetColorInfo(GameData.Instance.GetPlayerById(ID).DefaultOutfit.ColorId, out string colors), colors), 1 => string.Format(Translator.GetString("WhispererInfo.Time"), (int)Math.Round((LastMeetingStart - TimeStamp).TotalSeconds)), - 2 => string.Format(Translator.GetString("WhispererInfo.Role"), state.MainRole.ToColoredString() + (state.SubRoles.Count == 0 ? string.Empty : string.Join(' ', state.SubRoles.ConvertAll(x => x.ToColoredString())))), - 3 => string.Format(Translator.GetString("WhispererInfo.KillerRole"), killerState.MainRole.ToColoredString() + (killerState.SubRoles.Count == 0 ? string.Empty : string.Join(' ', killerState.SubRoles.ConvertAll(x => x.ToColoredString())))), - 4 => string.Format(Translator.GetString(deathInfo.SameRoomPlayers.Length == 0 ? "WhispererInfo.AloneInRoomAtDeath" : "WhispererInfo.PlayersInSameRoomAtDeath"), string.Join(", ", deathInfo.SameRoomPlayers.Select(x => x.ColoredPlayerName()))), + 2 => string.Format(Translator.GetString("WhispererInfo.Role"), state.MainRole.ToColoredString() + (state.SubRoles.Count == 0 ? string.Empty : state.SubRoles.Join(' ', x => x.ToColoredString()))), + 3 => string.Format(Translator.GetString("WhispererInfo.KillerRole"), killerState.MainRole.ToColoredString() + (killerState.SubRoles.Count == 0 ? string.Empty : killerState.SubRoles.Join(' ', x => x.ToColoredString()))), + 4 => string.Format(Translator.GetString(deathInfo.SameRoomPlayers.Length == 0 ? "WhispererInfo.AloneInRoomAtDeath" : "WhispererInfo.PlayersInSameRoomAtDeath"), deathInfo.SameRoomPlayers.Join(", ", x => x.ColoredPlayerName())), 5 => string.Format(Translator.GetString(deathInfo.ActiveSabotage.HasValue ? "WhispererInfo.NoSabotageAtDeath" : "WhispererInfo.SabotageAtDeath"), Translator.GetString(deathInfo.ActiveSabotage.HasValue ? deathInfo.ActiveSabotage.ToString() : "None")), 6 => string.Format(Translator.GetString("WhispererInfo.DeathReason"), Translator.GetString($"DeathReason.{state.deathReason}")), _ => string.Empty @@ -190,8 +190,7 @@ public class Whisperer : RoleBase { var darker = new List { 0, 1, 2, 6, 8, 9, 12, 15 }; bool isDarker = darker.Contains(colorId); - Func selector = x => Utils.ColorString(Palette.PlayerColors[x], Palette.GetColorName(x)); - colors = isDarker ? string.Join('/', darker.Select(selector)) : string.Join('/', Enumerable.Range(0, 18).Except(darker).Select(selector)); + colors = (isDarker ? darker : Enumerable.Range(0, 18).Except(darker)).Join('/', x => Utils.ColorString(Palette.PlayerColors[x], Palette.GetColorName(x))); return isDarker ? Translator.GetString("WhispererInfo.ColorDark") : Translator.GetString("WhispererInfo.ColorLight"); } diff --git a/Roles/Standard/Crewmate/Power/Adventurer.cs b/Roles/Standard/Crewmate/Power/Adventurer.cs index 671e43fe4..5c3a97de8 100644 --- a/Roles/Standard/Crewmate/Power/Adventurer.cs +++ b/Roles/Standard/Crewmate/Power/Adventurer.cs @@ -460,9 +460,9 @@ internal class Adventurer : RoleBase ? string.Format( Translator.GetString("AdventurerIngredientsDisplay"), Translator.GetString($"AdventurerGun.{SelectedWeaponToCraft}"), - string.Join(' ', Ingredients[SelectedWeaponToCraft] - .Select(x => $"{Utils.ColorString(ResourceDisplayData[x.Resource].Color, $"{ResourceDisplayData[x.Resource].Icon}")}" + - $"{Utils.ColorString(x.Count > ResourceCounts[x.Resource] ? Color.red : Color.white, $"{x.Count}")}"))) + Ingredients[SelectedWeaponToCraft].Join(' ', x => + $"{Utils.ColorString(ResourceDisplayData[x.Resource].Color, $"{ResourceDisplayData[x.Resource].Icon}")}" + + $"{Utils.ColorString(x.Count > ResourceCounts[x.Resource] ? Color.red : Color.white, $"{x.Count}")}")) : Translator.GetString("AdventurerVentToEnterCrafting"); finalText += ""; diff --git a/Roles/Standard/Crewmate/Support/Aid.cs b/Roles/Standard/Crewmate/Support/Aid.cs index ee027aaad..b9b96f6dd 100644 --- a/Roles/Standard/Crewmate/Support/Aid.cs +++ b/Roles/Standard/Crewmate/Support/Aid.cs @@ -128,6 +128,6 @@ public class Aid : RoleBase return string.Format(Translator.GetString("AidCounterSelf"), timeLeft); } - return seer.PlayerId == AidId ? string.Join("\n", ShieldedPlayers.Select(x => string.Format(Translator.GetString("AidCounterTarget"), x.Key.ColoredPlayerName(), (int)Math.Ceiling(x.Value.Remaining.TotalSeconds)))) : string.Empty; + return seer.PlayerId == AidId ? ShieldedPlayers.Join("\n", x => string.Format(Translator.GetString("AidCounterTarget"), x.Key.ColoredPlayerName(), (int)Math.Ceiling(x.Value.Remaining.TotalSeconds))) : string.Empty; } } \ No newline at end of file diff --git a/Roles/Standard/Crewmate/Support/Chef.cs b/Roles/Standard/Crewmate/Support/Chef.cs index de4b95999..75d24907b 100644 --- a/Roles/Standard/Crewmate/Support/Chef.cs +++ b/Roles/Standard/Crewmate/Support/Chef.cs @@ -252,7 +252,7 @@ public class Chef : RoleBase if (meeting) return string.Empty; long now = Utils.TimeStamp; - if (ActiveEvents.TryGetValue(target.PlayerId, out List events) && (seer.PlayerId == target.PlayerId || seer.PlayerId == ChefId)) return $"{string.Join('\n', events.Select(e => string.Format(Translator.GetString("ChefBoostSuffix"), GetEventString(e), e.Duration - (now - e.StartTimeStamp))))}"; + if (ActiveEvents.TryGetValue(target.PlayerId, out List events) && (seer.PlayerId == target.PlayerId || seer.PlayerId == ChefId)) return $"{events.Join('\n', e => string.Format(Translator.GetString("ChefBoostSuffix"), GetEventString(e), e.Duration - (now - e.StartTimeStamp)))}"; if (RottenFood.TryGetValue(seer.PlayerId, out long ts) && seer.PlayerId == target.PlayerId) return string.Format(Translator.GetString("ChefRottenSuffix"), RottenTime.GetInt() - (now - ts)); diff --git a/Roles/Standard/Crewmate/Support/Doorjammer.cs b/Roles/Standard/Crewmate/Support/Doorjammer.cs index 0faf6c400..09d945633 100644 --- a/Roles/Standard/Crewmate/Support/Doorjammer.cs +++ b/Roles/Standard/Crewmate/Support/Doorjammer.cs @@ -87,7 +87,7 @@ public class Doorjammer : RoleBase public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false) { if (seer.PlayerId != DoorjammerId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty; - string join = string.Join(", ", JammedRooms.ConvertAll(x => Translator.GetString(x.ToString()))); + string join = JammedRooms.Join(", ", x => Translator.GetString(x.ToString())); return string.Format(Translator.GetString("Doorjammer.Suffix"), JammedRooms.Count, MaxRoomsJammedAtOnce.GetInt(), string.IsNullOrWhiteSpace(join) ? string.Empty : $"\n{join}"); } } \ No newline at end of file diff --git a/Roles/Standard/Crewmate/Support/Wizard.cs b/Roles/Standard/Crewmate/Support/Wizard.cs index f7c1fd117..34c914309 100644 --- a/Roles/Standard/Crewmate/Support/Wizard.cs +++ b/Roles/Standard/Crewmate/Support/Wizard.cs @@ -288,7 +288,7 @@ public class Wizard : RoleBase { if (seer.PlayerId != WizardId || meeting) return string.Empty; - if (PlayerBuffs.TryGetValue(target.PlayerId, out Dictionary buffs)) return string.Join('\n', buffs.Select(x => $"{Translator.GetString($"Wizard.Buff.{x.Key}")}: {Math.Round(x.Value, 1):N1}{GetBuffFormat(x.Key)}")); + if (PlayerBuffs.TryGetValue(target.PlayerId, out Dictionary buffs)) return buffs.Join('\n', x => $"{Translator.GetString($"Wizard.Buff.{x.Key}")}: {Math.Round(x.Value, 1):N1}{GetBuffFormat(x.Key)}"); if (seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud)) return string.Empty; diff --git a/Roles/Standard/Impostor/Killing/Abyssbringer.cs b/Roles/Standard/Impostor/Killing/Abyssbringer.cs index 8477340fc..9555cefe0 100644 --- a/Roles/Standard/Impostor/Killing/Abyssbringer.cs +++ b/Roles/Standard/Impostor/Killing/Abyssbringer.cs @@ -234,7 +234,7 @@ public class Abyssbringer : RoleBase { if (seer.PlayerId != target.PlayerId || seer.PlayerId != AbyssbringerId || meeting || (seer.IsModdedClient() && !hud) || BlackHoles.Count == 0) return string.Empty; - return string.Format(Translator.GetString("Abyssbringer.Suffix"), BlackHoles.Count, string.Join('\n', BlackHoles.Select(x => GetBlackHoleFormatText(x.RoomName, x.PlayersConsumed)))); + return string.Format(Translator.GetString("Abyssbringer.Suffix"), BlackHoles.Count, BlackHoles.Join('\n', x => GetBlackHoleFormatText(x.RoomName, x.PlayersConsumed))); string GetBlackHoleFormatText(string roomName, int playersConsumed) { diff --git a/Roles/Standard/Impostor/Killing/Kamikaze.cs b/Roles/Standard/Impostor/Killing/Kamikaze.cs index 193963520..cf4bbc910 100644 --- a/Roles/Standard/Impostor/Killing/Kamikaze.cs +++ b/Roles/Standard/Impostor/Killing/Kamikaze.cs @@ -114,7 +114,7 @@ internal class Kamikaze : RoleBase } } - Logger.Info($"Murder {kamikazePc.GetRealName()}'s targets: {string.Join(", ", kk.MarkedPlayers.Select(x => GetPlayerById(x).GetNameWithRole()))}", "Kamikaze"); + Logger.Info($"Murder {kamikazePc.GetRealName()}'s targets: {kk.MarkedPlayers.Join(", ", x => GetPlayerById(x).GetNameWithRole())}", "Kamikaze"); kk.MarkedPlayers.Clear(); } } diff --git a/Roles/Standard/Impostor/Killing/Wasp.cs b/Roles/Standard/Impostor/Killing/Wasp.cs index 3aa7e1212..464d45af7 100644 --- a/Roles/Standard/Impostor/Killing/Wasp.cs +++ b/Roles/Standard/Impostor/Killing/Wasp.cs @@ -120,7 +120,7 @@ public class Wasp : RoleBase { LateTask.New(() => { - string stung = string.Join(", ", MeetingKills.Select(x => x.ColoredPlayerName())); + string stung = MeetingKills.Join(", ", x => x.ColoredPlayerName()); string role = CustomRoles.Wasp.ToColoredString(); string text = string.Format(Translator.GetString("WaspStungPlayersMessage"), stung, role); Utils.SendMessage(text, title: Translator.GetString("MessageTitle.Attention"), importance: MessageImportance.High); diff --git a/Roles/Standard/Impostor/Killing/Witch.cs b/Roles/Standard/Impostor/Killing/Witch.cs index 69e858433..cdda8d3d7 100644 --- a/Roles/Standard/Impostor/Killing/Witch.cs +++ b/Roles/Standard/Impostor/Killing/Witch.cs @@ -220,7 +220,7 @@ public class Witch : RoleBase { LateTask.New(() => { - string cursed = string.Join(", ", spelledPlayers.Select(x => x.ColoredPlayerName())); + string cursed = spelledPlayers.Join(", ", x => x.ColoredPlayerName()); string role = IsHM ? CustomRoles.HexMaster.ToColoredString() : CustomRoles.Witch.ToColoredString(); string text = string.Format(GetString("WitchCursedPlayersMessage"), cursed, role); Utils.SendMessage(text, title: GetString("MessageTitle.Attention"), importance: MessageImportance.High); diff --git a/Roles/Standard/Impostor/Miscellaneous/Frightener.cs b/Roles/Standard/Impostor/Miscellaneous/Frightener.cs index 6f848350c..cd945b3f6 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Frightener.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Frightener.cs @@ -95,6 +95,6 @@ public class Frightener : RoleBase public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false) { if (seer.PlayerId != FrightenerId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting || AlarmedPlayers.Count == 0) return string.Empty; - return string.Format(Translator.GetString("Frightener.Suffix"), string.Join(", ", AlarmedPlayers.Select(x => x.ColoredPlayerName()))); + return string.Format(Translator.GetString("Frightener.Suffix"), AlarmedPlayers.Join(", ", x => x.ColoredPlayerName())); } } \ No newline at end of file diff --git a/Roles/Standard/Neutral/Evil/Gaslighter.cs b/Roles/Standard/Neutral/Evil/Gaslighter.cs index 0087778cb..411cb8ff3 100644 --- a/Roles/Standard/Neutral/Evil/Gaslighter.cs +++ b/Roles/Standard/Neutral/Evil/Gaslighter.cs @@ -187,7 +187,7 @@ public class Gaslighter : RoleBase { LateTask.New(() => { - string cursed = string.Join(", ", spelledPlayers.Select(x => x.ColoredPlayerName())); + string cursed = spelledPlayers.Join(", ", x => x.ColoredPlayerName()); string role = IRandom.Instance.Next(2) == 0 ? CustomRoles.HexMaster.ToColoredString() : CustomRoles.Witch.ToColoredString(); string text = string.Format(Translator.GetString("WitchCursedPlayersMessage"), cursed, role); Utils.SendMessage(text, title: Translator.GetString("MessageTitle.Attention"), importance: MessageImportance.High); diff --git a/Roles/Standard/Neutral/Killing/Bargainer.cs b/Roles/Standard/Neutral/Killing/Bargainer.cs index 4e8e458e4..7049d0bb0 100644 --- a/Roles/Standard/Neutral/Killing/Bargainer.cs +++ b/Roles/Standard/Neutral/Killing/Bargainer.cs @@ -486,14 +486,14 @@ internal class Bargainer : RoleBase if (seer.IsModdedClient()) result += ""; - result += string.Join(' ', bg.ActiveItems.Select(x => + result += bg.ActiveItems.Join(' ', x => { long timeLeft = x.Duration - (Utils.TimeStamp - x.ActivateTimeStamp) + 1; string icon = Icons[x.Item]; if (x.Item == Item.LensOfTruth && x.Target != byte.MaxValue) icon = Utils.ColorString(Main.PlayerColors[x.Target], icon); return seer.IsModdedClient() && timeLeft < 10 ? $"{icon} ({timeLeft}s)" : icon; - })); + }); if (seer.IsModdedClient()) result += ""; diff --git a/Roles/Standard/Neutral/Killing/Chemist.cs b/Roles/Standard/Neutral/Killing/Chemist.cs index f666d6c38..733611bb5 100644 --- a/Roles/Standard/Neutral/Killing/Chemist.cs +++ b/Roles/Standard/Neutral/Killing/Chemist.cs @@ -689,9 +689,9 @@ internal class Chemist : RoleBase (List<(int Count, Item Item)> ingredients, List<(int Count, Item Item)> results) = Processes[CurrentFactory][SelectedProcess]; Func<(int Count, Item Item), string> selector = x => $"{x.Count} {Utils.ColorString(GetItemColor(x.Item), $"{GetChemicalForm(x.Item)}")}"; - Suffix.Append(string.Join(", ", ingredients.Select(selector))); + Suffix.Append(ingredients.Join(", ", selector)); Suffix.Append(" → "); - Suffix.Append(string.Join(", ", results.Select(selector))); + Suffix.Append(results.Join(", ", selector)); } if ((AcidPlayersDieOptions)AcidPlayersDie.GetValue() == AcidPlayersDieOptions.AfterTime) diff --git a/Roles/Standard/Neutral/Killing/Evolver.cs b/Roles/Standard/Neutral/Killing/Evolver.cs index b27294259..cc3f62f63 100644 --- a/Roles/Standard/Neutral/Killing/Evolver.cs +++ b/Roles/Standard/Neutral/Killing/Evolver.cs @@ -264,7 +264,7 @@ public class Evolver : RoleBase { if (seer.PlayerId != target.PlayerId || seer.PlayerId != EvolverPC.PlayerId || (seer.IsModdedClient() && !hud) || meeting || ChooseTimer == 0 || Upgrades.Count == 0 || SelectedUpgradeIndex == -1) return string.Empty; - return string.Format(Translator.GetString("EvolverSuffix"), ChooseTimer, Translator.GetString($"EvolverUpgrade.{Upgrades[SelectedUpgradeIndex]}"), string.Join(", ", Upgrades.ConvertAll(x => Translator.GetString($"EvolverUpgrade.{x}")))); + return string.Format(Translator.GetString("EvolverSuffix"), ChooseTimer, Translator.GetString($"EvolverUpgrade.{Upgrades[SelectedUpgradeIndex]}"), Upgrades.Join(", ", x => Translator.GetString($"EvolverUpgrade.{x}"))); } public override void GetProgressText(byte playerId, bool comms, StringBuilder resultText) diff --git a/Roles/Standard/Neutral/Killing/Spider.cs b/Roles/Standard/Neutral/Killing/Spider.cs index 8ab453e24..c21367b1d 100644 --- a/Roles/Standard/Neutral/Killing/Spider.cs +++ b/Roles/Standard/Neutral/Killing/Spider.cs @@ -231,6 +231,6 @@ public class Spider : RoleBase public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false) { if (seer.PlayerId != SpiderId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty; - return string.Join('\n', Webs.Where(x => x.Value.Count > 0).Select(x => $"{LocateArrow.GetArrow(seer, x.Key)} {x.Value.Count} ({Math.Max(0, x.Value.Values.Min() - Utils.TimeStamp)}s)")); + return Webs.Where(x => x.Value.Count > 0).Join('\n', x => $"{LocateArrow.GetArrow(seer, x.Key)} {x.Value.Count} ({Math.Max(0, x.Value.Values.Min() - Utils.TimeStamp)}s)"); } }