New game mode: Mingle

This commit is contained in:
Gurge44 committed 2025-10-10 14:37:26 +02:00
1 parent bb1561cb3b
commit 760c7d597f
26 files changed
+470 -22

No files matched your search

+3
View File
@@ -466,6 +466,9 @@ public enum CustomRoles
// Deathrace
Racer,
// Mingle
MinglePlayer,
// GM
GM,
+320
View File
@@ -0,0 +1,320 @@
using System;
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using UnityEngine;
namespace EHR;
public static class Mingle
{
public static readonly HashSet<string> HasPlayedFCs = [];
public static bool GameGoing;
public static DateTime GameStartDateTime;
public static Dictionary<SystemTypes, int> RequiredPlayerCount = [];
public static HashSet<SystemTypes> AllRooms = [];
public static long TimeEndTS;
public static long LastUpdateTS;
public static int Time;
public static int TimeLimit;
public static int TimeDecreaseOnNoDeath;
public static int ExtraTimeOnAirship;
public static int ExtraTimeOnFungle;
public static bool DisplayCurrentPlayerCountInEachRoom;
public static int MinTime;
public static int MaxRequiredPlayersPerRoom;
public static OptionItem TimeLimitOption;
public static OptionItem TimeDecreaseOnNoDeathOption;
public static OptionItem ExtraTimeOnAirshipOption;
public static OptionItem ExtraTimeOnFungleOption;
public static OptionItem DisplayCurrentPlayerCountInEachRoomOption;
public static OptionItem MinTimeOption;
public static OptionItem MaxRequiredPlayersPerRoomOption;
public static void SetupCustomOption()
{
var id = 69_224_001;
Color color = Utils.GetRoleColor(CustomRoles.MinglePlayer);
const CustomGameMode gameMode = CustomGameMode.Mingle;
const TabGroup tab = TabGroup.GameSettings;
TimeLimitOption = new IntegerOptionItem(id++, "Mingle.TimeLimitOption", new(1, 300, 1), 60, tab)
.SetHeader(true)
.SetColor(color)
.SetGameMode(gameMode);
TimeDecreaseOnNoDeathOption = new IntegerOptionItem(id++, "Mingle.TimeDecreaseOnNoDeathOption", new(0, 60, 1), 5, tab)
.SetColor(color)
.SetGameMode(gameMode);
ExtraTimeOnAirshipOption = new IntegerOptionItem(id++, "Mingle.ExtraTimeOnAirshipOption", new(0, 300, 1), 30, tab)
.SetColor(color)
.SetGameMode(gameMode);
ExtraTimeOnFungleOption = new IntegerOptionItem(id++, "Mingle.ExtraTimeOnFungleOption", new(0, 300, 1), 20, tab)
.SetColor(color)
.SetGameMode(gameMode);
DisplayCurrentPlayerCountInEachRoomOption = new BooleanOptionItem(id++, "Mingle.DisplayCurrentPlayerCountInEachRoomOption", true, tab)
.SetColor(color)
.SetGameMode(gameMode);
MinTimeOption = new IntegerOptionItem(id++, "Mingle.MinTimeOption", new(1, 300, 1), 15, tab)
.SetColor(color)
.SetGameMode(gameMode);
MaxRequiredPlayersPerRoomOption = new IntegerOptionItem(id++, "Mingle.MaxRequiredPlayersPerRoomOption", new(1, 30, 1), 10, tab)
.SetColor(color)
.SetGameMode(gameMode);
}
public static string GetSuffix(PlayerControl seer)
{
return seer.IsModdedClient() ? string.Empty : GetRoomsInfo(seer);
}
public static int GetSurvivalTime(byte id)
{
if (!Main.PlayerStates.TryGetValue(id, out PlayerState state) || ChatCommands.Spectators.Contains(id) || (id == 0 && Main.GM.Value) || state.deathReason == PlayerState.DeathReason.Disconnected) return -1;
if (!state.IsDead) return 0;
DateTime died = state.RealKiller.TimeStamp;
TimeSpan time = died - GameStartDateTime;
return (int)time.TotalSeconds;
}
public static bool CheckGameEnd(out GameOverReason reason)
{
reason = GameOverReason.ImpostorsByKill;
return false;
}
public static string GetTaskBarText()
{
return GetRoomsInfo(PlayerControl.LocalPlayer);
}
private static string GetRoomsInfo(PlayerControl pc)
{
StringBuilder sb = new("<#ffffff><size=90%>");
PlainShipRoom plainShipRoom = pc.GetPlainShipRoom();
foreach ((SystemTypes room, int required) in RequiredPlayerCount)
{
int count = GetNumPlayersInRoom(room);
if (plainShipRoom != null && plainShipRoom.RoomId == room)
sb.Append("<u>");
if (DisplayCurrentPlayerCountInEachRoom)
{
string color = count > required ? "FF4647" : count == required ? "91FF65" : "FFDE59";
sb.Append($"<#{color}>");
}
sb.Append(Translator.GetString(room.ToString()));
sb.Append(':');
sb.Append(' ');
if (DisplayCurrentPlayerCountInEachRoom)
{
sb.Append(count);
sb.Append(" / ");
}
sb.Append(required);
if (DisplayCurrentPlayerCountInEachRoom)
{
sb.Append(count > required ? "+ <#ff0000>╳</color>" : count == required ? "= <#00ff00>✓</color>" : "- <#ff0000>╳</color>");
sb.Append("</color>");
}
if (plainShipRoom != null && plainShipRoom.RoomId == room)
sb.Append("</u>");
sb.Append('\n');
}
sb.Append("</size>");
long timeLeft = TimeEndTS - Utils.TimeStamp;
if (timeLeft >= 0)
{
sb.Append('\n');
sb.Append(timeLeft);
}
if (plainShipRoom == null || !RequiredPlayerCount.ContainsKey(plainShipRoom.RoomId))
{
sb.Append('\n');
sb.Append("<#ffff00><size=70%>");
sb.Append('⚠');
sb.Append(' ');
sb.Append(Translator.GetString("Mingle.NotInRequiredRoom"));
sb.Append(' ');
sb.Append('⚠');
sb.Append("</size></color>");
}
return sb.ToString().TrimEnd();
}
public static System.Collections.IEnumerator GameStart()
{
GameGoing = false;
TimeLimit = TimeLimitOption.GetInt();
TimeDecreaseOnNoDeath = TimeDecreaseOnNoDeathOption.GetInt();
ExtraTimeOnAirship = ExtraTimeOnAirshipOption.GetInt();
ExtraTimeOnFungle = ExtraTimeOnFungleOption.GetInt();
DisplayCurrentPlayerCountInEachRoom = DisplayCurrentPlayerCountInEachRoomOption.GetBool();
MinTime = MinTimeOption.GetInt();
MaxRequiredPlayersPerRoom = MaxRequiredPlayersPerRoomOption.GetInt();
RequiredPlayerCount = [];
Time = TimeLimit + Main.CurrentMap switch
{
MapNames.Airship => ExtraTimeOnAirship,
MapNames.Fungle => ExtraTimeOnFungle,
_ => 0
};
TimeEndTS = 0;
LastUpdateTS = 0;
NameNotifyManager.Reset();
AllRooms = ShipStatus.Instance.AllRooms.Select(x => x.RoomId).ToHashSet();
AllRooms.Remove(SystemTypes.Hallway);
AllRooms.Remove(SystemTypes.Outside);
AllRooms.Remove(SystemTypes.Ventilation);
AllRooms.RemoveWhere(x => x.ToString().Contains("Decontamination"));
if (SubmergedCompatibility.IsSubmerged()) AllRooms.RemoveWhere(x => (byte)x > 135);
yield return new WaitForSeconds(Main.CurrentMap == MapNames.Airship ? 8f : 3f);
List<PlayerControl> players = Main.AllAlivePlayerControls.ToList();
if (Main.GM.Value) players.RemoveAll(x => x.IsHost());
if (ChatCommands.Spectators.Count > 0) players.RemoveAll(x => ChatCommands.Spectators.Contains(x.PlayerId));
bool showTutorial = players.ExceptBy(HasPlayedFCs, x => x.FriendCode).Count() > players.Count / 2;
if (showTutorial)
{
players.NotifyPlayers("<#ffffff>" + Translator.GetString("Mingle.Tutorial"), 100f);
yield return new WaitForSeconds(9f);
NameNotifyManager.Reset();
}
for (var i = 3; i > 0; i--)
{
NameNotifyManager.Reset();
players.NotifyPlayers(string.Format(Translator.GetString("RR_ReadyQM"), i));
yield return new WaitForSeconds(1f);
}
NameNotifyManager.Reset();
StartNewRound();
GameGoing = true;
GameStartDateTime = DateTime.Now;
}
private static void StartNewRound()
{
if (!GameGoing) return;
RequiredPlayerCount = [];
int playerCount = Main.AllAlivePlayerControls.Length;
while (playerCount > 0)
{
var room = AllRooms.Except(RequiredPlayerCount.Keys).RandomElement();
var count = IRandom.Instance.Next(1, MaxRequiredPlayersPerRoom + 1);
if (count > playerCount) count = playerCount;
RequiredPlayerCount[room] = count;
playerCount -= count;
}
TimeEndTS = Utils.TimeStamp + Time;
Main.AllPlayerSpeed.SetAllValues(Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod));
Utils.SyncAllSettings();
}
private static void KillPlayers()
{
var aapc = Main.AllAlivePlayerControls;
Dictionary<PlayerControl, SystemTypes> playerRooms = aapc.Select(x => (pc: x, room: x.GetPlainShipRoom())).ToDictionary(x => x.pc, x => x.room == null ? SystemTypes.Outside : x.room.RoomId);
Dictionary<SystemTypes, int> playerCount = [];
HashSet<PlayerControl> toKill = [];
foreach ((PlayerControl pc, SystemTypes room) in playerRooms)
{
if (room == SystemTypes.Outside || !RequiredPlayerCount.ContainsKey(room))
toKill.Add(pc);
else if (!playerCount.TryAdd(room, 1))
playerCount[room]++;
}
foreach ((SystemTypes room, int required) in RequiredPlayerCount)
{
int count = playerCount.GetValueOrDefault(room, 0);
if (count == 0 || required == count) continue;
playerRooms.DoIf(x => x.Value == room, x => toKill.Add(x.Key));
}
switch (toKill.Count)
{
case 0:
Time = Math.Clamp(Time - TimeDecreaseOnNoDeath, MinTime, TimeLimit);
break;
case var x when x == aapc.Length:
CustomWinnerHolder.ResetAndSetWinner(CustomWinner.None);
GameGoing = false;
break;
default:
toKill.Do(x => x.Suicide());
break;
}
}
private static int GetNumPlayersInRoom(SystemTypes room) => Main.AllAlivePlayerControls.Select(x => x.GetPlainShipRoom()).Count(x => x != null && x.RoomId == room);
public static void HandleDisconnect()
{
RequiredPlayerCount[AllRooms.First(x => RequiredPlayerCount.TryGetValue(x, out var required) && GetNumPlayersInRoom(x) < required)]--;
}
public static class FixedUpdatePatch
{
public static void Postfix()
{
long now = Utils.TimeStamp;
if (LastUpdateTS == now) return;
LastUpdateTS = now;
if (TimeEndTS == now)
{
Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed);
Utils.SyncAllSettings();
}
else if (TimeEndTS < now)
{
KillPlayers();
StartNewRound();
}
else if (RequiredPlayerCount.All(x => GetNumPlayersInRoom(x.Key) == x.Value))
{
Main.AllAlivePlayerControls.NotifyPlayers(Utils.ColorString(Color.green, "✓"));
Time = Math.Clamp(Time - TimeDecreaseOnNoDeath, MinTime, TimeLimit);
StartNewRound();
return;
}
Utils.NotifyRoles();
}
}
}
+1
View File
@@ -216,6 +216,7 @@ public static class NaturalDisasters
CustomGameMode.KingOfTheZones => (0, !KingOfTheZones.GameGoing),
CustomGameMode.RoomRush => (40, false),
CustomGameMode.Deathrace => (0, !Deathrace.GameGoing),
CustomGameMode.Mingle => (60, !Mingle.GameGoing),
_ => (0, false)
};
+1 -1
View File
@@ -171,7 +171,7 @@ public static class RoomRush
public static int GetSurvivalTime(byte id)
{
if (!Main.PlayerStates.TryGetValue(id, out PlayerState state) || ChatCommands.Spectators.Contains(id) || (id == 0 && Main.GM.Value)) return -1;
if (!Main.PlayerStates.TryGetValue(id, out PlayerState state) || ChatCommands.Spectators.Contains(id) || (id == 0 && Main.GM.Value) || state.deathReason == PlayerState.DeathReason.Disconnected) return -1;
if (!state.IsDead) return 0;
+4 -1
View File
@@ -759,6 +759,8 @@ public class Main : BasePlugin
{ CustomRoles.BedWarsPlayer, "#fc03f8" },
// Deathrace
{ CustomRoles.Racer, "#AFAFAF" },
// Mingle
{ CustomRoles.MinglePlayer, "#FE9900" },
// Hide And Seek
{ CustomRoles.Seeker, "#ff1919" },
{ CustomRoles.Hider, "#345eeb" },
@@ -840,7 +842,8 @@ public class Main : BasePlugin
[CustomGameMode.Quiz] = Utils.GetRoleColor(CustomRoles.QuizMaster),
[CustomGameMode.TheMindGame] = Color.yellow,
[CustomGameMode.BedWars] = Utils.GetRoleColor(CustomRoles.BedWarsPlayer),
[CustomGameMode.Deathrace] = Utils.GetRoleColor(CustomRoles.Racer)
[CustomGameMode.Deathrace] = Utils.GetRoleColor(CustomRoles.Racer),
[CustomGameMode.Mingle] = Utils.GetRoleColor(CustomRoles.MinglePlayer)
};
IL2CPPChainloader.Instance.Finished += () =>
+3 -2
View File
@@ -23,9 +23,10 @@ public static class AutoHaunt
CustomGameMode.HideAndSeek => validPCs.OrderByDescending(x => x.GetCustomRole() is CustomRoles.Venter or CustomRoles.Dasher).ThenByDescending(x => CustomHnS.PlayerRoles.TryGetValue(x.PlayerId, out (IHideAndSeekRole Interface, CustomRoles Role) info) && info.Interface.Team == Team.Impostor).ThenByDescending(x => CustomHnS.PlayerRoles.TryGetValue(x.PlayerId, out (IHideAndSeekRole Interface, CustomRoles Role) info) && info.Interface.Team == Team.Neutral).FirstOrDefault(),
CustomGameMode.Speedrun => Speedrun.CanKill.Count > 0 ? Speedrun.CanKill.ToValidPlayers().RandomElement() : validPCs.MaxBy(x => x.GetTaskState().CompletedTasksCount),
CustomGameMode.CaptureTheFlag => validPCs.OrderByDescending(x => CaptureTheFlag.IsCarrier(x.PlayerId)).ThenByDescending(x => CaptureTheFlag.GetFlagTime(x.PlayerId)).ThenByDescending(x => CaptureTheFlag.GetTagCount(x.PlayerId)).FirstOrDefault(),
CustomGameMode.RoomRush => RoomRush.PointsSystem ? validPCs.MaxBy(x => RoomRush.GetPoints(x.PlayerId)) : validPCs.FirstOrDefault(),
CustomGameMode.RoomRush => RoomRush.PointsSystem ? validPCs.MaxBy(x => RoomRush.GetPoints(x.PlayerId)) : validPCs.RandomElement(),
CustomGameMode.KingOfTheZones => validPCs.MaxBy(x => KingOfTheZones.GetZoneTime(x.PlayerId)),
_ => validPCs.FirstOrDefault()
CustomGameMode.Deathrace => validPCs.MaxBy(x => Deathrace.Data.TryGetValue(x.PlayerId, out var drData) ? drData.Lap : 0),
_ => validPCs.RandomElement()
};
}
+2 -1
View File
@@ -35,7 +35,8 @@ internal static class CustomRoleSelector
{ CustomGameMode.Quiz, CustomRoles.QuizPlayer },
{ CustomGameMode.TheMindGame, CustomRoles.TMGPlayer },
{ CustomGameMode.BedWars, CustomRoles.BedWarsPlayer },
{ CustomGameMode.Deathrace, CustomRoles.Racer }
{ CustomGameMode.Deathrace, CustomRoles.Racer },
{ CustomGameMode.Mingle, CustomRoles.MinglePlayer }
};
public static void SelectCustomRoles()
+4 -1
View File
@@ -72,7 +72,8 @@ internal static class CustomRolesHelper
CustomRoles.QuizPlayer or
CustomRoles.TMGPlayer or
CustomRoles.BedWarsPlayer or
CustomRoles.Racer;
CustomRoles.Racer or
CustomRoles.MinglePlayer;
}
public static RoleBase GetRoleClass(this CustomRoles role)
@@ -406,6 +407,8 @@ internal static class CustomRolesHelper
CustomRoles.QuizPlayer => CustomRoles.Crewmate,
// The Mind Game
CustomRoles.TMGPlayer => CustomRoles.Crewmate,
// Mingle
CustomRoles.MinglePlayer => CustomRoles.Crewmate,
_ => role.IsImpostor() ? CustomRoles.Impostor : CustomRoles.Crewmate
};
+3 -2
View File
@@ -1087,7 +1087,7 @@ internal static class ExtendedPlayerControl
{
try
{
bool addRoleName = GameStates.IsInGame && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace;
bool addRoleName = GameStates.IsInGame && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace and not CustomGameMode.Mingle;
return $"{player?.Data?.PlayerName}" + (addRoleName ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
}
catch (Exception e)
@@ -1360,7 +1360,7 @@ internal static class ExtendedPlayerControl
switch (Options.CurrentGameMode)
{
case CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.TheMindGame:
case CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.TheMindGame or CustomGameMode.Mingle:
case CustomGameMode.Speedrun when !Speedrun.CanKill.Contains(pc.PlayerId):
return false;
case CustomGameMode.HotPotato:
@@ -1430,6 +1430,7 @@ internal static class ExtendedPlayerControl
CustomGameMode.RoomRush => false,
CustomGameMode.Quiz => false,
CustomGameMode.TheMindGame => false,
CustomGameMode.Mingle => false,
CustomGameMode.Deathrace => Deathrace.CanUseVent(pc, pc.GetClosestVent().Id),
CustomGameMode.Standard when CopyCat.Instances.Any(x => x.CopyCatPC.PlayerId == pc.PlayerId) => true,
+4 -1
View File
@@ -204,7 +204,10 @@ public static class FixedUpdateCaller
goto default;
case CustomGameMode.Deathrace:
Deathrace.FixedUpdatePatch.Postfix();
break;
goto default;
case CustomGameMode.Mingle:
Mingle.FixedUpdatePatch.Postfix();
goto default;
default:
if (Options.IntegrateNaturalDisasters.GetBool()) goto case CustomGameMode.NaturalDisasters;
break;
@@ -174,6 +174,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
AURoleOptions.EngineerCooldown = 0.01f;
AURoleOptions.EngineerInVentMaxTime = 0f;
goto case CustomGameMode.RoomRush;
case CustomGameMode.Mingle:
case CustomGameMode.RoomRush:
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
+1 -1
View File
@@ -445,7 +445,7 @@ public class TaskState
GameData.Instance.RecomputeTaskCounts();
Logger.Info($"TotalTaskCounts = {GameData.Instance.CompletedTasks}/{GameData.Instance.TotalTasks}", "TaskState.Update");
if (Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz or CustomGameMode.TheMindGame)
if (Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.Mingle)
player.Notify(Translator.GetString("DoingTasksIsPointlessInThisGameMode"), 10f);
if (AllTasksCount == -1) Init(player);
+1
View File
@@ -46,6 +46,7 @@ public static class NameColorManager
if (FreeForAll.PlayerTeams.TryGetValue(target.PlayerId, out int team))
color = FreeForAll.TeamColors.GetValueOrDefault(team, "#00ffff");
return true;
case CustomGameMode.Mingle:
case CustomGameMode.RoomRush:
case CustomGameMode.NaturalDisasters:
case CustomGameMode.MoveAndStop:
+7 -1
View File
@@ -34,6 +34,7 @@ public enum CustomGameMode
TheMindGame = 0x0D,
BedWars = 0x0E,
Deathrace = 0x0F,
Mingle = 0x10,
All = int.MaxValue
}
@@ -86,7 +87,8 @@ public static class Options
"Quiz",
"TheMindGame",
"BedWars",
"Deathrace"
"Deathrace",
"Mingle"
];
private static Dictionary<CustomRoles, int> roleCounts;
@@ -904,6 +906,7 @@ public static class Options
12 => CustomGameMode.TheMindGame,
13 => CustomGameMode.BedWars,
14 => CustomGameMode.Deathrace,
15 => CustomGameMode.Mingle,
_ => CustomGameMode.Standard
};
@@ -1808,6 +1811,8 @@ public static class Options
BedWars.SetupCustomOption();
// Deathrace
Deathrace.SetupCustomOption();
// Mingle
Mingle.SetupCustomOption();
yield return null;
@@ -3149,6 +3154,7 @@ public static class Options
12 => CustomGameMode.TheMindGame,
13 => CustomGameMode.BedWars,
14 => CustomGameMode.Deathrace,
15 => CustomGameMode.Mingle,
_ => CustomGameMode.Standard
};
AutoGMRotationCompiled.AddRange(Enumerable.Repeat(gm, times));
+17 -5
View File
@@ -816,6 +816,7 @@ public static class Utils
case CustomGameMode.Quiz:
case CustomGameMode.BedWars:
case CustomGameMode.Deathrace:
case CustomGameMode.Mingle:
return false;
case CustomGameMode.HideAndSeek:
return CustomHnS.HasTasks(p);
@@ -1035,7 +1036,7 @@ public static class Utils
{
switch (Options.CurrentGameMode)
{
case CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace:
case CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle:
case CustomGameMode.Standard when IsRevivingRoleAlive() && Main.DiedThisRound.Contains(PlayerControl.LocalPlayer.PlayerId):
return PlayerControl.LocalPlayer.Is(CustomRoles.GM);
case CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun:
@@ -1540,6 +1541,7 @@ public static class Utils
}
break;
case CustomGameMode.Mingle:
case CustomGameMode.Deathrace:
case CustomGameMode.BedWars:
case CustomGameMode.RoomRush:
@@ -2140,6 +2142,7 @@ public static class Utils
CustomGameMode.Quiz => ColorString(GetRoleColor(CustomRoles.QuizMaster), $"{modeText}\r\n") + name,
CustomGameMode.BedWars => ColorString(GetRoleColor(CustomRoles.BedWarsPlayer), $"{modeText}\r\n") + name,
CustomGameMode.Deathrace => ColorString(GetRoleColor(CustomRoles.Racer), $"{modeText}\r\n") + name,
CustomGameMode.Mingle => ColorString(GetRoleColor(CustomRoles.MinglePlayer), $"{modeText}\r\n") + name,
_ => name
};
}
@@ -2602,6 +2605,9 @@ public static class Utils
case CustomGameMode.Deathrace:
additionalSuffixes.Add(Deathrace.GetSuffix(seer, seer, false));
break;
case CustomGameMode.Mingle:
additionalSuffixes.Add(Mingle.GetSuffix(seer));
break;
}
List<string> addSuff = additionalSuffixes.ConvertAll(x => x.Trim()).FindAll(x => !string.IsNullOrEmpty(x));
@@ -2618,7 +2624,7 @@ public static class Utils
if ((Options.CurrentGameMode == CustomGameMode.FFA && FreeForAll.FFATeamMode.GetBool()) || Options.CurrentGameMode == CustomGameMode.HotPotato)
seerRealName = seerRealName.ApplyNameColorData(seer, seer, forMeeting);
if (!forMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.KingOfTheZones and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace)
if (!forMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.KingOfTheZones and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace and not CustomGameMode.Mingle)
{
CustomTeamManager.CustomTeam team = CustomTeamManager.GetCustomTeam(seer.PlayerId);
@@ -2656,7 +2662,7 @@ public static class Utils
SelfSuffix.Append($"\n\n<#ffffff>{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}</color>\n");
}
bool noRoleText = GameStates.IsLobby || Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace;
bool noRoleText = GameStates.IsLobby || Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle;
// Combine the seer's job title and SelfTaskText with the seer's player name and SelfMark
string selfRoleName = noRoleText ? string.Empty : $"<size={fontSize}>{seer.GetDisplayRoleName()}{selfTaskText}</size>";
@@ -2690,7 +2696,7 @@ public static class Utils
if (!GameStates.IsLobby)
{
if (Options.CurrentGameMode is CustomGameMode.Quiz or CustomGameMode.BedWars)
if (Options.CurrentGameMode is CustomGameMode.Quiz or CustomGameMode.BedWars || (Options.CurrentGameMode == CustomGameMode.Mingle && !seer.IsModdedClient()))
selfName = string.Empty;
if (Options.CurrentGameMode != CustomGameMode.BedWars && NameNotifyManager.GetNameNotify(seer, out string name) && name.Length > 0)
@@ -2730,6 +2736,8 @@ public static class Utils
CustomGameMode.RoomRush => true,
CustomGameMode.KingOfTheZones => true,
CustomGameMode.Quiz => true,
CustomGameMode.Deathrace => true,
CustomGameMode.Mingle => true,
_ => false
};
@@ -2825,7 +2833,7 @@ public static class Utils
if (IsRevivingRoleAlive() && Main.DiedThisRound.Contains(seer.PlayerId))
targetRoleText = string.Empty;
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace)
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle)
targetRoleText = string.Empty;
if (!GameStates.IsLobby)
@@ -3842,6 +3850,10 @@ public static class Utils
case CustomGameMode.Deathrace:
summary = $"{ColorString(Main.PlayerColors[id], name)} - {Deathrace.GetStatistics(id)}";
break;
case CustomGameMode.Mingle:
int time3 = Mingle.GetSurvivalTime(id);
summary = $"{ColorString(Main.PlayerColors[id], name)} - <#e8cd46>{GetString("SurvivedTimePrefix")}: <#ffffff>{(time3 == 0 ? $"{GetString("SurvivedUntilTheEnd")}</color>" : $"{time3}</color>s")}</color> ({GetVitalText(id, true)})";
break;
}
return check && GetDisplayRoleName(id, true).RemoveHtmlTags().Contains("INVALID:NotAssigned")
+19
View File
@@ -553,6 +553,11 @@ internal static class GameEndChecker
{
Predicate = new DeathraceGameEndPredicate();
}
public static void SetPredicateToMingle()
{
Predicate = new MingleGameEndPredicate();
}
private class NormalGameEndPredicate : GameEndPredicate
{
@@ -1107,6 +1112,20 @@ internal static class GameEndChecker
}
}
private class MingleGameEndPredicate : GameEndPredicate
{
public override bool CheckForGameEnd(out GameOverReason reason)
{
reason = GameOverReason.ImpostorsByKill;
return WinnerIds.Count <= 0 && CheckGameEndByLivingPlayers(out reason);
}
private static bool CheckGameEndByLivingPlayers(out GameOverReason reason)
{
return Mingle.CheckGameEnd(out reason);
}
}
public abstract class GameEndPredicate
{
/// <summary>Checks the game ending condition and stores the value in CustomWinnerHolder. </summary>
+1 -1
View File
@@ -9,7 +9,7 @@ public static class DeconSystemUpdateSystemPatch
{
if (!AmongUsClient.Instance.AmHost || SubmergedCompatibility.IsSubmerged()) return;
bool fastDecon = Options.CurrentGameMode is CustomGameMode.BedWars or CustomGameMode.RoomRush or CustomGameMode.Deathrace;
bool fastDecon = Options.CurrentGameMode is CustomGameMode.BedWars or CustomGameMode.RoomRush or CustomGameMode.Deathrace or CustomGameMode.Mingle;
if (fastDecon || Options.ChangeDecontaminationTime.GetBool())
{
+10
View File
@@ -630,6 +630,9 @@ internal static class SetHudActivePatch
__instance.KillButton?.ToggleVisible(true);
__instance.SabotageButton?.ToggleVisible(false);
return;
case CustomGameMode.Mingle:
__instance.ReportButton?.ToggleVisible(false);
return;
}
PlayerControl player = PlayerControl.LocalPlayer;
@@ -1139,6 +1142,13 @@ internal static class TaskPanelBehaviourPatch
finalText += "</size>";
break;
}
case CustomGameMode.Mingle:
{
finalText += "\r\n\r\n<size=80%>";
finalText += Mingle.GetTaskBarText();
finalText += "</size>";
break;
}
}
panel.SetTaskText(finalText);
+22
View File
@@ -294,6 +294,16 @@ internal static class SetUpRoleTextPatch
__instance.RoleBlurbText.text = GetString("RacerInfo");
break;
}
case CustomGameMode.Mingle:
{
Color color = Utils.GetRoleColor(CustomRoles.MinglePlayer);
__instance.YouAreText.transform.gameObject.SetActive(false);
__instance.RoleText.text = GetString("MinglePlayer");
__instance.RoleText.color = color;
__instance.RoleBlurbText.color = color;
__instance.RoleBlurbText.text = GetString("MinglePlayerInfo");
break;
}
default:
{
CustomRoles role = lp.GetCustomRole();
@@ -963,6 +973,15 @@ internal static class BeginCrewmatePatch
__instance.ImpostorText.text = GetString("RacerInfo");
break;
}
case CustomGameMode.Mingle:
{
__instance.TeamTitle.text = GetString("MinglePlayer");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = Utils.GetRoleColor(CustomRoles.MinglePlayer);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Detective);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("MinglePlayerInfo");
break;
}
}
return;
@@ -1261,6 +1280,9 @@ internal static class IntroCutsceneDestroyPatch
case CustomGameMode.Deathrace:
Main.Instance.StartCoroutine(Deathrace.GameStart());
break;
case CustomGameMode.Mingle:
Main.Instance.StartCoroutine(Mingle.GameStart());
break;
}
Utils.CheckAndSetVentInteractions();
+3
View File
@@ -1094,6 +1094,9 @@ internal static class StartGameHostPatch
case CustomGameMode.Deathrace:
GameEndChecker.SetPredicateToDeathrace();
break;
case CustomGameMode.Mingle:
GameEndChecker.SetPredicateToMingle();
break;
}
// Add players with unclassified roles to the list of players who require ResetCam.
+13 -1
View File
@@ -66,7 +66,7 @@ internal static class EndGamePatch
byte killerId = value.GetRealKiller();
bool gmIsFm = Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop;
bool gmIsFmhh = gmIsFm || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace;
bool gmIsFmhh = gmIsFm || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle;
sb.Append($"\n{date:T} {Main.AllPlayerNames[key]} ({(gmIsFmhh ? string.Empty : Utils.GetDisplayRoleName(key, true))}{(gmIsFm ? string.Empty : Utils.GetSubRolesText(key, summary: true))}) [{Utils.GetVitalText(key)}]");
if (killerId != byte.MaxValue && killerId != key) sb.Append($"\n\t⇐ {Main.AllPlayerNames[killerId]} ({(gmIsFmhh ? string.Empty : Utils.GetDisplayRoleName(killerId, true))}{(gmIsFm ? string.Empty : Utils.GetSubRolesText(killerId, summary: true))})");
}
@@ -151,6 +151,9 @@ internal static class EndGamePatch
maps.Add(map);
}
break;
case CustomGameMode.Mingle:
Main.AllPlayerControls.Do(x => Mingle.HasPlayedFCs.Add(x.FriendCode));
break;
default:
if (Main.HasPlayedGM.TryGetValue(Options.CurrentGameMode, out HashSet<string> playedFCs))
@@ -318,6 +321,14 @@ internal static class SetEverythingUpPatch
winnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
case CustomGameMode.Mingle:
{
byte winnerId = CustomWinnerHolder.WinnerIds.FirstOrDefault();
__instance.BackgroundBar.material.color = Utils.GetRoleColor(CustomRoles.MinglePlayer);
winnerText.text = Main.AllPlayerNames[winnerId] + GetString("Win");
winnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
}
if (CustomWinnerHolder.WinnerTeam == CustomWinner.CustomTeam)
@@ -525,6 +536,7 @@ internal static class SetEverythingUpPatch
break;
}
case CustomGameMode.Mingle:
case CustomGameMode.Deathrace:
case CustomGameMode.BedWars:
case CustomGameMode.Quiz:
+5 -1
View File
@@ -279,6 +279,7 @@ internal static class CheckMurderPatch
if (HotPotato.CanPassViaKillButton && holderID == killer.PlayerId && (lastHolderID != target.PlayerId || Main.AllAlivePlayerControls.Length <= 2))
HotPotato.FixedUpdatePatch.PassHotPotato(target, false);
return false;
case CustomGameMode.Mingle:
case CustomGameMode.TheMindGame:
case CustomGameMode.MoveAndStop:
case CustomGameMode.RoomRush:
@@ -1659,7 +1660,7 @@ internal static class FixedUpdatePatch
bool self = lpId == __instance.PlayerId;
bool shouldUpdateRegardlessOfLowLoad = self && GameStates.InGame && PlayerControl.LocalPlayer.IsAlive() && ((PlayerControl.AllPlayerControls.Count > 30 && LastSelfNameUpdateTS != now && Options.CurrentGameMode is CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz) || DirtyName.Remove(lpId));
bool shouldUpdateRegardlessOfLowLoad = self && GameStates.InGame && PlayerControl.LocalPlayer.IsAlive() && ((PlayerControl.AllPlayerControls.Count > 30 && LastSelfNameUpdateTS != now && Options.CurrentGameMode is CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.Mingle) || DirtyName.Remove(lpId));
if (__instance == null || (lowLoad && !shouldUpdateRegardlessOfLowLoad)) return;
@@ -1948,6 +1949,9 @@ internal static class FixedUpdatePatch
case CustomGameMode.Deathrace:
additionalSuffixes.Add(Deathrace.GetSuffix(seer, target, false));
break;
case CustomGameMode.Mingle when self:
additionalSuffixes.Add(Mingle.GetSuffix(seer));
break;
}
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrEmpty(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloKombat or CustomGameMode.FFA)
+9 -1
View File
@@ -478,7 +478,15 @@ internal static class OnPlayerLeftPatch
{
if (GameStates.IsInGame && data != null && data.Character != null)
{
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek) CustomHnS.PlayerRoles.Remove(data.Character.PlayerId);
switch (Options.CurrentGameMode)
{
case CustomGameMode.HideAndSeek:
CustomHnS.PlayerRoles.Remove(data.Character.PlayerId);
break;
case CustomGameMode.Mingle:
Mingle.HandleDisconnect();
break;
}
if (data.Character.Is(CustomRoles.Lovers) && data.Character.IsAlive())
{
+1 -1
View File
@@ -253,7 +253,7 @@ internal static class CloseDoorsPatch
{
public static bool Prefix( /*ShipStatus __instance, */ [HarmonyArgument(0)] SystemTypes room)
{
bool allow = !Options.DisableSabotage.GetBool() && Options.CurrentGameMode is not CustomGameMode.SoloKombat and not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.KingOfTheZones and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace;
bool allow = !Options.DisableSabotage.GetBool() && Options.CurrentGameMode is not CustomGameMode.SoloKombat and not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato and not CustomGameMode.Speedrun and not CustomGameMode.CaptureTheFlag and not CustomGameMode.NaturalDisasters and not CustomGameMode.RoomRush and not CustomGameMode.KingOfTheZones and not CustomGameMode.Quiz and not CustomGameMode.TheMindGame and not CustomGameMode.BedWars and not CustomGameMode.Deathrace and not CustomGameMode.Mingle;
if (SecurityGuard.BlockSabo.Count > 0) allow = false;
if (Options.DisableCloseDoor.GetBool()) allow = false;
+1 -1
View File
@@ -177,7 +177,7 @@ internal static class RpcSetTasksPatch
}
// GM and Lazy Guy have no tasks
if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace)
if (pc.Is(CustomRoles.GM) || pc.Is(CustomRoles.Needy) || Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.HotPotato or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.Quiz or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle)
{
hasCommonTasks = false;
numShortTasks = 0;
+14
View File
@@ -5357,6 +5357,20 @@
"Racer": "DEATHRACE",
"RacerInfo": "COMPLETE ALL LAPS FIRST TO WIN",
"RacerInfoLong": "COMPLETE ALL LAPS FIRST TO WIN",
"Mingle": "MINGLE",
"ModeMingle": "Gamemode: Mingle",
"ModeDescribe.Mingle": "In the Mingle gamemode, the game assigns a certain number of players to certain rooms on the map. At the end of the time limit, exactly that number of players need to be in the rooms. If there are too many or too few players in a room, all players in that room die. If you are not in any of the assigned rooms, you die. Oh, and if no one dies in a round, the time limit permanently decreases. The last player alive wins!",
"Mingle.Tutorial": "The current game mode is <#CF2472>Mingle</color>.\\n<size=90%>The game assigns a certain number of players to certain rooms on the map.\\nAt the end of the time limit, exactly those numbers of players need to be in the rooms.\\nIf there are too many or too few players in a room, all players in that room die.\\nIf you are not in any of the assigned rooms, you die.\\nOh, and if no one dies in a round, the time limit permanently decreases.\\nThe last player alive wins!</size>",
"Mingle.TimeLimitOption": "Starting Time Limit",
"Mingle.TimeDecreaseOnNoDeathOption": "Time Decrease on No Death",
"Mingle.ExtraTimeOnAirshipOption": "Extra Time on Airship",
"Mingle.ExtraTimeOnFungleOption": "Extra Time on Fungle",
"Mingle.DisplayCurrentPlayerCountInEachRoomOption": "Display Current Player Count in Each Room",
"Mingle.MinTimeOption": "Minimum Time Limit",
"Mingle.MaxRequiredPlayersPerRoomOption": "Maximum Required Players Per Room",
"MinglePlayer": "MINGLE",
"MinglePlayerInfo": "SURVIVE BY BEING IN THE RIGHT ROOMS",
"MinglePlayerInfoLong": "SURVIVE BY BEING IN THE RIGHT ROOMS",
"Quiz": "QUIZ",
"ModeQuiz": "Gamemode: Quiz",
"ModeDescribe.Quiz": "In the Quiz game mode, you must answer questions correctly to survive. There are various difficulties with varying time limits. Each question has 5 answer choices: A, B, C, D, E. Each choice has a room name next to the answer. To pick an answer, you must enter the room corresponding to the answer. If you answer correctly, you survive. If you don't answer enough questions correctly, you eventually die or compete in a Free For All (FFA) match with the other players who got the questions wrong.",