New game mode: Room Rush

This commit is contained in:
Gurge44 committed 2024-09-24 10:08:32 +02:00
1 parent b7c377c466
commit ddde40695d
26 files changed
+425 -66

No files matched your search

+3
View File
@@ -381,6 +381,9 @@ public enum CustomRoles
// Natural Disasters
NDPlayer,
// Room Rush
RRPlayer,
// GM
GM,
+9 -8
View File
@@ -43,41 +43,42 @@ namespace EHR
{
int id = 69_216_001;
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
const CustomGameMode gameMode = CustomGameMode.NaturalDisasters;
DisasterFrequency = new IntegerOptionItem(id++, "ND_DisasterFrequency", new(1, 20, 1), 2, TabGroup.GameSettings)
.SetHeader(true)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetColor(color)
.SetValueFormat(OptionFormat.Seconds);
DisasterWarningTime = new IntegerOptionItem(id++, "ND_DisasterWarningTime", new(1, 30, 1), 5, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetColor(color)
.SetValueFormat(OptionFormat.Seconds);
LimitMaximumDisastersAtOnce = new BooleanOptionItem(id++, "ND_LimitMaximumDisastersAtOnce", false, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetColor(color);
MaximumDisastersAtOnce = new IntegerOptionItem(id++, "ND_MaximumDisastersAtOnce", new(1, 120, 1), 20, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetParent(LimitMaximumDisastersAtOnce)
.SetColor(color);
WhenLimitIsReached = new StringOptionItem(id++, "ND_WhenLimitIsReached", LimitReachedOptions, 2, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetParent(LimitMaximumDisastersAtOnce)
.SetColor(color);
PreferRemovingThunderstorm = new BooleanOptionItem(id++, "ND_PreferRemovingThunderstorm", true, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetParent(WhenLimitIsReached)
.SetColor(color);
LoadAllDisasters();
AllDisasters.ConvertAll(x => x.Name).ForEach(x => DisasterSpawnChances[x] = new IntegerOptionItem(id++, "ND_Disaster.SpawnChance", new(0, 100, 5), 50, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.NaturalDisasters)
.SetGameMode(gameMode)
.SetColor(color)
.SetValueFormat(OptionFormat.Percent)
.AddReplacement(("{disaster}", Translator.GetString($"ND_{x}"))));
+214
View File
@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using AmongUs.GameOptions;
using HarmonyLib;
using UnityEngine;
namespace EHR
{
public static class RoomRush
{
private static OptionItem TimeWhenFirstPlayerEntersRoom;
private static OptionItem VentTimes;
public static HashSet<string> HasPlayedFriendCodes = [];
public static Dictionary<byte, int> VentLimit = [];
private static HashSet<SystemTypes> AllRooms = [];
private static SystemTypes RoomGoal;
private static int TimeLeft;
private static HashSet<byte> DonePlayers = [];
private static bool GameGoing;
private static RandomSpawn.SpawnMap Map;
public static void SetupCustomOption()
{
int id = 69_217_001;
Color color = Utils.GetRoleColor(CustomRoles.RRPlayer);
const CustomGameMode gameMode = CustomGameMode.RoomRush;
TimeWhenFirstPlayerEntersRoom = new IntegerOptionItem(id++, "RR_TimeWhenTwoPlayersEntersRoom", new(1, 30, 1), 5, TabGroup.GameSettings)
.SetHeader(true)
.SetColor(color)
.SetGameMode(gameMode)
.SetValueFormat(OptionFormat.Seconds);
VentTimes = new IntegerOptionItem(id, "RR_VentTimes", new(0, 90, 1), 1, TabGroup.GameSettings)
.SetColor(color)
.SetGameMode(gameMode)
.SetValueFormat(OptionFormat.Times);
}
public static int GetSurvivalTime(byte id)
{
if (!Main.PlayerStates.TryGetValue(id, out var state)) return 0;
DateTime start = DateTime.UtcNow;
DateTime died = state.RealKiller.TimeStamp;
TimeSpan time = start - died;
return (int)time.TotalSeconds;
}
public static void OnGameStart()
{
if (Options.CurrentGameMode != CustomGameMode.RoomRush) return;
Main.Instance.StartCoroutine(GameStartTasks());
}
private static System.Collections.IEnumerator GameStartTasks()
{
GameGoing = false;
VentLimit = Main.AllPlayerControls.ToDictionary(x => x.PlayerId, _ => VentTimes.GetInt());
AllRooms = ShipStatus.Instance.AllRooms.Select(x => x.RoomId).ToHashSet();
AllRooms.Remove(SystemTypes.Hallway);
AllRooms.RemoveWhere(x => x.ToString().Contains("Decontamination"));
DonePlayers = [];
Map = Main.CurrentMap switch
{
MapNames.Skeld => new RandomSpawn.SkeldSpawnMap(),
MapNames.Mira => new RandomSpawn.MiraHQSpawnMap(),
MapNames.Polus => new RandomSpawn.PolusSpawnMap(),
MapNames.Dleks => new RandomSpawn.DleksSpawnMap(),
MapNames.Airship => new RandomSpawn.AirshipSpawnMap(),
MapNames.Fungle => new RandomSpawn.FungleSpawnMap(),
_ => throw new ArgumentOutOfRangeException()
};
yield return new WaitForSeconds(8f);
PlayerControl[] aapc = Main.AllAlivePlayerControls;
bool showTutorial = aapc.ExceptBy(HasPlayedFriendCodes, x => x.FriendCode).Count() >= aapc.Length / 3;
if (showTutorial)
{
string[] notifies = [Translator.GetString("RR_Tutorial_1"), Translator.GetString("RR_Tutorial_2"), Translator.GetString("RR_Tutorial_3"), Translator.GetString("RR_Tutorial_4")];
foreach (string notify in notifies)
{
aapc.Do(x => x.Notify(notify, 6f));
yield return new WaitForSeconds(3f);
}
yield return new WaitForSeconds(4f);
}
aapc.Do(x => x.Notify(Translator.GetString("RR_ReadyQM"), 2f));
yield return new WaitForSeconds(2f);
for (int i = 3; i > 0; i--)
{
int time = i;
aapc.Do(x => x.Notify(time.ToString()));
yield return new WaitForSeconds(1f);
}
StartNewRound();
GameGoing = true;
}
private static void StartNewRound()
{
PlayerControl[] aapc = Main.AllAlivePlayerControls;
RoomGoal = AllRooms.RandomElement();
float distance = Vector2.Distance(Map.Positions.GetValueOrDefault(RoomGoal, RoomGoal.GetRoomClass().transform.position), aapc.RandomElement().transform.position);
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
TimeLeft = (int)Math.Ceiling(distance * 3f / speed);
}
private static PlainShipRoom GetRoomClass(this SystemTypes systemTypes) => ShipStatus.Instance.AllRooms.First(x => x.RoomId == systemTypes);
public static string GetSuffix(PlayerControl seer)
{
if (!GameGoing || Main.HasJustStarted) return string.Empty;
var sb = new StringBuilder();
sb.AppendLine(Translator.GetString(RoomGoal.ToString()));
sb.AppendLine(TimeLeft.ToString());
sb.AppendLine();
int vents = VentLimit.GetValueOrDefault(seer.PlayerId);
sb.Append(string.Format(Translator.GetString("RR_VentsRemaining"), vents));
return sb.ToString();
}
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
static class FixedUpdatePatch
{
private static long LastUpdate = Utils.TimeStamp;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
public static void Postfix(PlayerControl __instance)
{
if (!GameGoing || Main.HasJustStarted || Options.CurrentGameMode != CustomGameMode.RoomRush || !AmongUsClient.Instance.AmHost) return;
long now = Utils.TimeStamp;
if (__instance.IsAlive() && __instance.GetPlainShipRoom().RoomId == RoomGoal && DonePlayers.Add(__instance.PlayerId))
{
if (DonePlayers.Count == Main.AllAlivePlayerControls.Length)
{
__instance.Suicide();
__instance.Notify(Translator.GetString("RR_YouWereLast"));
}
else
{
__instance.Notify(Translator.GetString("RR_GoalReached"));
if (DonePlayers.Count == 2)
{
TimeLeft = TimeWhenFirstPlayerEntersRoom.GetInt();
LastUpdate = now;
}
}
}
if (LastUpdate == now) return;
LastUpdate = now;
TimeLeft--;
Utils.NotifyRoles();
if (TimeLeft <= 0)
{
Main.AllAlivePlayerControls.ExceptBy(DonePlayers, x => x.PlayerId).Do(x => x.Suicide());
StartNewRound();
}
}
}
}
public class RRPlayer : RoleBase
{
public override bool IsEnable => Options.CurrentGameMode == CustomGameMode.RoomRush;
public override void Init()
{
}
public override void Add(byte playerId)
{
}
public override void SetupCustomOption()
{
}
public override void OnEnterVent(PlayerControl pc, Vent vent)
{
RoomRush.VentLimit[pc.PlayerId]--;
}
public override bool CanUseVent(PlayerControl pc, int ventId) => pc.inVent || RoomRush.VentLimit[pc.PlayerId] > 0;
}
}
+3
View File
@@ -65,6 +65,9 @@ internal static class CustomRoleSelector
case CustomGameMode.NaturalDisasters:
AssignRoleToEveryone(CustomRoles.NDPlayer);
return;
case CustomGameMode.RoomRush:
AssignRoleToEveryone(CustomRoles.RRPlayer);
return;
case CustomGameMode.HideAndSeek:
HnSManager.AssignRoles();
RoleResult = HnSManager.PlayerRoles.ToDictionary(x => x.Key, x => x.Value.Role);
+4 -1
View File
@@ -47,7 +47,8 @@ internal static class CustomRolesHelper
CustomRoles.Potato or
CustomRoles.Runner or
CustomRoles.CTFPlayer or
CustomRoles.NDPlayer;
CustomRoles.NDPlayer or
CustomRoles.RRPlayer;
public static RoleBase GetRoleClass(this CustomRoles role)
{
@@ -374,6 +375,8 @@ internal static class CustomRolesHelper
CustomRoles.CTFPlayer => RoleTypes.Shapeshifter,
// Natural Disasters
CustomRoles.NDPlayer => RoleTypes.Crewmate,
// Room Rush
CustomRoles.RRPlayer => RoleTypes.Engineer,
// Standard
CustomRoles.Executioner => Executioner.CRoleChangeRoles[Executioner.ChangeRolesAfterTargetKilled.GetValue()].GetDYRole(),
CustomRoles.Sheriff => UsePets && Sheriff.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
+4 -2
View File
@@ -882,7 +882,7 @@ static class ExtendedPlayerControl
public static string GetNameWithRole(this PlayerControl player, bool forUser = false)
{
return $"{player?.Data?.PlayerName}" + (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 ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
return $"{player?.Data?.PlayerName}" + (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 ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
}
public static string GetRoleColorCode(this PlayerControl player)
@@ -997,7 +997,7 @@ static class ExtendedPlayerControl
switch (Options.CurrentGameMode)
{
case CustomGameMode.HotPotato or CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters:
case CustomGameMode.HotPotato or CustomGameMode.MoveAndStop or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush:
case CustomGameMode.Speedrun when !SpeedrunManager.CanKill.Contains(pc.PlayerId):
return false;
case CustomGameMode.CaptureTheFlag:
@@ -1065,6 +1065,8 @@ static class ExtendedPlayerControl
CustomRoles.CTFPlayer => false,
// Natural Disasters
CustomRoles.NDPlayer => false,
// Room Rush
CustomRoles.RRPlayer => false,
_ => Main.PlayerStates.TryGetValue(pc.PlayerId, out var state) && state.Role.CanUseImpostorVentButton(pc)
};
@@ -174,6 +174,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
SetMaxVision();
NaturalDisasters.ApplyGameOptions(opt, player.PlayerId);
break;
case CustomGameMode.RoomRush:
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
case CustomGameMode.MoveAndStop:
-37
View File
@@ -30,8 +30,6 @@ public static class GuessManager
public static TextMeshPro TextTemplate;
private static readonly int Mask = Shader.PropertyToID("_Mask");
private static List<GameObject> IDPanels = [];
public static string GetFormatString()
{
string text = GetString("PlayerIdList");
@@ -771,38 +769,6 @@ public static class GuessManager
}
}
public static void CreateIDLabels(MeetingHud __instance)
{
DestroyIDLabels();
if (__instance == null) return;
const int max = 2;
foreach (var pva in __instance.playerStates)
{
var levelDisplay = pva.transform.FindChild("PlayerLevel").gameObject;
var panel = Object.Instantiate(levelDisplay, pva.transform, true);
var panelTransform = panel.transform;
var background = panel.GetComponent<SpriteRenderer>();
background.color = Palette.Purple;
background.sortingOrder = max - 1;
panelTransform.SetAsFirstSibling();
panelTransform.localPosition = new(-1.21f, -0.05f, 0f);
var levelLabel = panelTransform.FindChild("LevelLabel").GetComponents<TextMeshPro>()[0];
levelLabel.DestroyTranslator();
levelLabel.text = "ID";
levelLabel.sortingOrder = max;
var levelNumber = panelTransform.FindChild("LevelNumber").GetComponent<TextMeshPro>();
levelNumber.text = pva.TargetPlayerId.ToString();
levelNumber.sortingOrder = max;
IDPanels.Add(panel);
}
}
public static void DestroyIDLabels()
{
IDPanels.ForEach(Object.Destroy);
IDPanels = [];
}
static void GuesserSelectRole(CustomRoleTypes Role, bool SetPage = true)
{
CurrentTeamType = Role;
@@ -1038,7 +1004,6 @@ public static class GuessManager
or CustomRoles.Paranoia
or CustomRoles.SuperStar
or CustomRoles.Konan
or CustomRoles.Oblivious
or CustomRoles.GuardianAngelEHR
) continue;
@@ -1224,8 +1189,6 @@ public static class GuessManager
if (alive && lp.Is(CustomRoles.Guesser))
CreateGuesserButton(__instance);
}
CreateIDLabels(__instance);
}
}
+1
View File
@@ -42,6 +42,7 @@ public static class NameColorManager
case CustomGameMode.FFA when FFAManager.FFATeamMode.GetBool():
color = FFAManager.TeamColors[FFAManager.PlayerTeams[target.PlayerId]];
return true;
case CustomGameMode.RoomRush:
case CustomGameMode.NaturalDisasters:
case CustomGameMode.MoveAndStop:
color = "#ffffff";
+4 -1
View File
@@ -28,6 +28,7 @@ public enum CustomGameMode
Speedrun = 0x07,
CaptureTheFlag = 0x08,
NaturalDisasters = 0x09,
RoomRush = 0x0A,
All = int.MaxValue
}
@@ -62,7 +63,8 @@ public static class Options
"HideAndSeek",
"Speedrun",
"CaptureTheFlag",
"NaturalDisasters"
"NaturalDisasters",
"RoomRush"
];
private static Dictionary<CustomRoles, int> roleCounts;
@@ -791,6 +793,7 @@ public static class Options
6 => CustomGameMode.Speedrun,
7 => CustomGameMode.CaptureTheFlag,
8 => CustomGameMode.NaturalDisasters,
9 => CustomGameMode.RoomRush,
_ => CustomGameMode.Standard
};
+13 -3
View File
@@ -676,6 +676,7 @@ public static class Utils
case CustomGameMode.Speedrun: return true;
case CustomGameMode.CaptureTheFlag: return false;
case CustomGameMode.NaturalDisasters: return false;
case CustomGameMode.RoomRush: return false;
case CustomGameMode.HideAndSeek: return HnSManager.HasTasks(p);
}
@@ -871,7 +872,7 @@ public static class Utils
public static bool IsRoleTextEnabled(PlayerControl __instance)
{
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters) return false;
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush) return false;
if (__instance.PlayerId == PlayerControl.LocalPlayer.PlayerId || Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun || (Options.CurrentGameMode == CustomGameMode.HideAndSeek && HnSManager.IsRoleTextEnabled(PlayerControl.LocalPlayer, __instance)) || Main.VisibleTasksCount && PlayerControl.LocalPlayer.Data.IsDead && Options.GhostCanSeeOtherRoles.GetBool() || PlayerControl.LocalPlayer.Is(CustomRoles.Mimic) && Main.VisibleTasksCount && __instance.Data.IsDead && Options.MimicCanSeeDeadRoles.GetBool()) return true;
if (Altruist.On && Main.DiedThisRound.Contains(PlayerControl.LocalPlayer.PlayerId)) return false;
@@ -1375,6 +1376,7 @@ public static class Utils
}
break;
case CustomGameMode.RoomRush:
case CustomGameMode.NaturalDisasters:
case CustomGameMode.CaptureTheFlag:
case CustomGameMode.Speedrun:
@@ -1701,6 +1703,7 @@ public static class Utils
CustomGameMode.HideAndSeek => $"<color=#345eeb><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.CaptureTheFlag => $"<color=#1313c2><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.NaturalDisasters => $"<color=#03fc4a><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.RoomRush => $"<color=#ffab1b><size=1.7>{modeText}</size></color>\r\n{name}",
CustomGameMode.Speedrun => ColorString(GetRoleColor(CustomRoles.Speedrunner), $"<size=1.7>{modeText}</size>\r\n") + name,
_ => name
};
@@ -1966,6 +1969,9 @@ public static class Utils
case CustomGameMode.NaturalDisasters:
SelfSuffix.Append(NaturalDisasters.SuffixText());
break;
case CustomGameMode.RoomRush:
SelfSuffix.Append(RoomRush.GetSuffix(seer));
break;
}
}
@@ -1976,7 +1982,7 @@ public static class Utils
if (Options.CurrentGameMode == CustomGameMode.FFA && FFAManager.FFATeamMode.GetBool())
SeerRealName = SeerRealName.ApplyNameColorData(seer, seer, isForMeeting);
if (!isForMeeting && 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)
if (!isForMeeting && 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)
{
var team = CustomTeamManager.GetCustomTeam(seer.PlayerId);
if (team != null)
@@ -2224,7 +2230,7 @@ public static class Utils
: string.Empty;
if (Altruist.On && Main.DiedThisRound.Contains(seer.PlayerId)) TargetRoleText = string.Empty;
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters) TargetRoleText = string.Empty;
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush) TargetRoleText = string.Empty;
if (!GameStates.IsLobby)
{
@@ -2914,6 +2920,10 @@ public static class Utils
int time2 = NaturalDisasters.SurvivalTime(id);
summary = $"{ColorString(Main.PlayerColors[id], name)} - <#e8cd46>{GetString("SurvivedTimePrefix")}: <#ffffff>{(time2 == 0 ? $"{GetString("SurvivedUntilTheEnd")}</color>" : $"{time2}</color>s")}</color> ({GetVitalText(id, true)})";
break;
case CustomGameMode.RoomRush:
int time3 = RoomRush.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;
case CustomGameMode.CaptureTheFlag:
summary = $"{ColorString(Main.PlayerColors[id], name)}: {CTFManager.GetStatistics(id)}";
if (CTFManager.IsDeathPossible) summary += $" ({GetVitalText(id, true)})";
+32
View File
@@ -390,6 +390,7 @@ static class GameEndChecker
public static void SetPredicateToHideAndSeek() => Predicate = new HideAndSeekGameEndPredicate();
public static void SetPredicateToCaptureTheFlag() => Predicate = new CaptureTheFlagGameEndPredicate();
public static void SetPredicateToNaturalDisasters() => Predicate = new NaturalDisastersGameEndPredicate();
public static void SetPredicateToRoomRush() => Predicate = new RoomRushGameEndPredicate();
class NormalGameEndPredicate : GameEndPredicate
{
@@ -779,6 +780,37 @@ static class GameEndChecker
}
}
}
class RoomRushGameEndPredicate : GameEndPredicate
{
public override bool CheckForEndGame(out GameOverReason reason)
{
reason = GameOverReason.ImpostorByKill;
return WinnerIds.Count <= 0 && CheckGameEndByLivingPlayers(out reason);
}
private static bool CheckGameEndByLivingPlayers(out GameOverReason reason)
{
reason = GameOverReason.ImpostorByKill;
var appc = Main.AllAlivePlayerControls;
switch (appc.Length)
{
case 1:
var winner = appc[0];
Logger.Info($"Winner: {winner.GetRealName().RemoveHtmlTags()}", "RoomRush");
WinnerIds = [winner.PlayerId];
Main.DoBlockNameChange = true;
return true;
case 0:
ResetAndSetWinner(CustomWinner.None);
Logger.Warn("No players alive. Force ending the game", "RoomRush");
return true;
default:
return false;
}
}
}
public abstract class GameEndPredicate
{
+2 -1
View File
@@ -183,6 +183,7 @@ public static class OptionsMenuBehaviourClosePatch
ClientOptionItem.CustomBackground?.gameObject.SetActive(false);
if (GameStates.InGame && GameStates.IsVoting && !DestroyableSingleton<HudManager>.Instance.Chat.IsOpenOrOpening)
GuessManager.CreateIDLabels(MeetingHud.Instance);
{
}
}
}
+6 -2
View File
@@ -416,7 +416,9 @@ public static class InGameRoleInfoMenu
Fill?.SetActive(true);
Menu?.SetActive(true);
if (GameStates.IsMeeting) GuessManager.DestroyIDLabels();
if (GameStates.IsMeeting)
{
}
}
}
@@ -427,7 +429,9 @@ public static class InGameRoleInfoMenu
Fill?.SetActive(false);
Menu?.SetActive(false);
if (GameStates.IsVoting) GuessManager.CreateIDLabels(MeetingHud.Instance);
if (GameStates.IsVoting)
{
}
}
}
}
+2 -1
View File
@@ -277,6 +277,7 @@ class OptionsMenuBehaviourOpenPatch
public static void Postfix()
{
if (GameStates.InGame && GameStates.IsMeeting)
GuessManager.DestroyIDLabels();
{
}
}
}
+1
View File
@@ -57,6 +57,7 @@ class SetRecommendationsPatch
{
case CustomGameMode.SoloKombat:
case CustomGameMode.FFA:
case CustomGameMode.RoomRush:
case CustomGameMode.NaturalDisasters:
case CustomGameMode.HotPotato:
case CustomGameMode.CaptureTheFlag:
+20 -4
View File
@@ -439,6 +439,7 @@ static class SetHudActivePatch
__instance.SabotageButton?.ToggleVisible(false);
__instance.AbilityButton?.ToggleVisible(false);
return;
case CustomGameMode.RoomRush:
case CustomGameMode.CaptureTheFlag:
case CustomGameMode.HideAndSeek:
__instance.ReportButton?.ToggleVisible(false);
@@ -537,7 +538,8 @@ static class MapTaskOverlayShowPatch
public static void Postfix()
{
if (GameStates.IsMeeting)
GuessManager.DestroyIDLabels();
{
}
}
}
@@ -547,7 +549,8 @@ static class MapTaskOverlayHidePatch
public static void Postfix()
{
if (GameStates.IsMeeting && !DestroyableSingleton<HudManager>.Instance.Chat.IsOpenOrOpening)
GuessManager.CreateIDLabels(MeetingHud.Instance);
{
}
}
}
@@ -761,6 +764,17 @@ static class TaskPanelBehaviourPatch
AllText += "</size>";
break;
case CustomGameMode.RoomRush:
AllText += Main.AllPlayerControls
.Select(x => (pc: x, alive: x.IsAlive(), time: RoomRush.GetSurvivalTime(x.PlayerId)))
.OrderByDescending(x => x.alive)
.ThenByDescending(x => x.time)
.Aggregate("<size=70%>", (s, x) => $"{s}\r\n{x.pc.PlayerId.ColoredPlayerName()} - {(x.alive ? $"<#00ff00>{GetString("Alive")}</color>" : $"{GetString("Dead")}: {string.Format(GetString("SurvivalTime"), x.time)}")}");
AllText += "</size>";
break;
}
__instance.taskText.text = AllText;
@@ -788,7 +802,8 @@ static class DialogueBoxShowPatch
public static void Postfix()
{
if (GameStates.IsMeeting)
GuessManager.DestroyIDLabels();
{
}
}
}
@@ -798,7 +813,8 @@ static class DialogueBoxHidePatch
public static void Postfix()
{
if (GameStates.IsMeeting && !DestroyableSingleton<HudManager>.Instance.Chat.IsOpenOrOpening)
GuessManager.CreateIDLabels(MeetingHud.Instance);
{
}
}
}
+20
View File
@@ -99,6 +99,17 @@ static class SetUpRoleTextPatch
__instance.RoleBlurbText.text = GetString("NDPlayerInfo");
break;
}
case CustomGameMode.RoomRush:
{
var color = ColorUtility.TryParseHtmlString("#ffab1b", out var c) ? c : new(255, 255, 255, 255);
CustomRoles role = lp.GetCustomRole();
__instance.YouAreText.color = color;
__instance.RoleText.text = GetString("RRPlayer");
__instance.RoleText.color = color;
__instance.RoleBlurbText.color = color;
__instance.RoleBlurbText.text = GetString("RRPlayerInfo");
break;
}
default:
{
CustomRoles role = lp.GetCustomRole();
@@ -599,6 +610,15 @@ static class BeginCrewmatePatch
__instance.ImpostorText.text = GetString("NDPlayerInfo");
break;
}
case CustomGameMode.RoomRush:
{
__instance.TeamTitle.text = GetString("RRPlayer");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = new Color32(255, 171, 27, byte.MaxValue);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Impostor);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("RRPlayerInfo");
break;
}
}
// if (Input.GetKey(KeyCode.RightShift))
+16 -1
View File
@@ -9,6 +9,7 @@ using EHR.Impostor;
using EHR.Modules;
using EHR.Neutral;
using HarmonyLib;
using TMPro;
using UnityEngine;
using static EHR.Translator;
@@ -820,6 +821,21 @@ static class MeetingHudStartPatch
var suffix = Main.PlayerStates[seer.PlayerId].Role.GetSuffix(seer, target, meeting: true);
if (roleTextMeeting.text.Length > 0 && suffix.Length > 0) roleTextMeeting.text += "\n" + suffix;
// Thanks BAU (By D1GQ) - are you happy now?
var playerLevel = pva.transform.Find("PlayerLevel");
var levelDisplay = Object.Instantiate(playerLevel, pva.transform);
levelDisplay.localPosition = new(-1.21f, -0.15f, playerLevel.transform.localPosition.z);
levelDisplay.transform.SetSiblingIndex(pva.transform.Find("PlayerLevel").GetSiblingIndex() + 1);
levelDisplay.gameObject.name = "PlayerId";
levelDisplay.GetComponent<SpriteRenderer>().color = Palette.Purple;
var idLabel = levelDisplay.transform.Find("LevelLabel");
var idNumber = levelDisplay.transform.Find("LevelNumber");
Object.Destroy(idLabel.GetComponent<TextTranslatorTMP>());
idLabel.GetComponent<TextMeshPro>().text = "ID";
idNumber.GetComponent<TextMeshPro>().text = pva.TargetPlayerId.ToString();
idLabel.name = "IdLabel";
idNumber.name = "IdNumber";
}
if (Options.SyncButtonMode.GetBool())
@@ -998,7 +1014,6 @@ static class MeetingHudUpdatePatch
if (DestroyableSingleton<HudManager>.Instance.Chat.IsOpenOrOpening)
{
GuessManager.DestroyIDLabels();
}
if (!GameStates.IsVoting && __instance.lastSecond < 1)
+6
View File
@@ -767,6 +767,9 @@ internal static class StartGameHostPatch
case CustomGameMode.NaturalDisasters:
NaturalDisasters.OnGameStart();
break;
case CustomGameMode.RoomRush:
RoomRushManager.OnGameStart();
break;
}
HudManager.Instance.SetHudActive(true);
@@ -814,6 +817,9 @@ internal static class StartGameHostPatch
case CustomGameMode.NaturalDisasters:
GameEndChecker.SetPredicateToNaturalDisasters();
break;
case CustomGameMode.RoomRush:
GameEndChecker.SetPredicateToRoomRush();
break;
}
// Add players with unclassified roles to the list of players who require ResetCam.
+25 -3
View File
@@ -64,7 +64,7 @@ static class EndGamePatch
if (date == DateTime.MinValue) continue;
var killerId = value.GetRealKiller();
var gmIsFM = Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop;
var gmIsFMHH = gmIsFM || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters;
var gmIsFMHH = gmIsFM || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush;
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))})");
@@ -117,8 +117,15 @@ static class EndGamePatch
GameOptionsSender.AllSenders.Clear();
GameOptionsSender.AllSenders.Add(new NormalGameOptionsSender());
if (Options.CurrentGameMode == CustomGameMode.MoveAndStop)
Main.AllPlayerControls.Do(x => MoveAndStopManager.HasPlayed.Add(x.FriendCode));
switch (Options.CurrentGameMode)
{
case CustomGameMode.MoveAndStop:
Main.AllPlayerControls.Do(x => MoveAndStopManager.HasPlayed.Add(x.FriendCode));
break;
case CustomGameMode.RoomRush:
Main.AllPlayerControls.Do(x => RoomRush.HasPlayedFriendCodes.Add(x.FriendCode));
break;
}
}
}
}
@@ -279,6 +286,14 @@ class SetEverythingUpPatch
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
case CustomGameMode.RoomRush:
{
var winnerId = CustomWinnerHolder.WinnerIds.FirstOrDefault();
__instance.BackgroundBar.material.color = new Color32(255, 171, 27, 255);
WinnerText.text = Main.AllPlayerNames[winnerId] + GetString("Win");
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
}
if (CustomWinnerHolder.WinnerTeam == CustomWinner.CustomTeam)
@@ -460,6 +475,13 @@ class SetEverythingUpPatch
sb.Append('\n').Append(EndGamePatch.SummaryText[id]);
break;
}
case CustomGameMode.RoomRush:
{
var list = cloneRoles.OrderByDescending(RoomRush.GetSurvivalTime);
foreach (var id in list.Where(EndGamePatch.SummaryText.ContainsKey))
sb.Append('\n').Append(EndGamePatch.SummaryText[id]);
break;
}
default:
{
foreach (byte id in cloneRoles)
+7 -1
View File
@@ -214,6 +214,7 @@ static class CheckMurderPatch
return false;
case CustomGameMode.MoveAndStop:
case CustomGameMode.HotPotato:
case CustomGameMode.RoomRush:
case CustomGameMode.NaturalDisasters:
return false;
case CustomGameMode.Speedrun when !SpeedrunManager.CanKill.Contains(killer.PlayerId):
@@ -1221,7 +1222,9 @@ static class FixedUpdatePatch
case true when DestroyableSingleton<HudManager>.Instance.Chat.IsClosedOrClosing:
ChatOpen = false;
if (GameStates.IsVoting)
GuessManager.CreateIDLabels(MeetingHud.Instance);
{
}
break;
}
}
@@ -1720,6 +1723,9 @@ static class FixedUpdatePatch
case CustomGameMode.CaptureTheFlag:
Suffix.Append(CTFManager.GetSuffixText(seer, target));
break;
case CustomGameMode.RoomRush when self:
Suffix.Append(RoomRush.GetSuffix(seer));
break;
}
if (Options.CurrentGameMode == CustomGameMode.SoloKombat)
+14
View File
@@ -53,6 +53,8 @@ class RandomSpawn
public abstract class SpawnMap
{
public abstract Dictionary<SystemTypes, Vector2> Positions { get; }
public virtual void RandomTeleport(PlayerControl player)
{
var spawn = GetLocation();
@@ -83,6 +85,8 @@ class RandomSpawn
[SystemTypes.MedBay] = new(-9.0f, -4.0f)
};
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault();
@@ -109,6 +113,8 @@ class RandomSpawn
[SystemTypes.Greenhouse] = new(17.8f, 23.0f)
};
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault();
@@ -136,6 +142,8 @@ class RandomSpawn
[SystemTypes.Specimens] = new(36.5f, -22.0f)
};
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault();
@@ -146,6 +154,8 @@ class RandomSpawn
{
public readonly Dictionary<SystemTypes, Vector2> positions = new SkeldSpawnMap().positions.ToDictionary(e => e.Key, e => new Vector2(-e.Value.x, e.Value.y));
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault();
@@ -177,6 +187,8 @@ class RandomSpawn
[SystemTypes.Showers] = new(21.2f, -0.8f)
};
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return Options.AirshipAdditionalSpawn.GetBool()
@@ -209,6 +221,8 @@ class RandomSpawn
[SystemTypes.Comms] = new(22.2f, 13.7f)
};
public override Dictionary<SystemTypes, Vector2> Positions => positions;
protected override KeyValuePair<SystemTypes, Vector2> GetLocation()
{
return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault();
+1 -1
View File
@@ -260,7 +260,7 @@ 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;
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;
if (SecurityGuard.BlockSabo.Count > 0) allow = false;
if (Options.DisableCloseDoor.GetBool()) allow = false;
+15
View File
@@ -4128,6 +4128,21 @@
"NDPlayer": "Natural Disasters",
"NDPlayerInfo": "SURVIVE ALL NATURAL DISASTERS TO WIN",
"NDPlayerInfoLong": "SURVIVE ALL NATURAL DISASTERS TO WIN",
"RoomRush": "ROOM RUSH",
"ModeRoomRush": "Gamemode: Room Rush",
"ModeDescribe.RoomRush": "In the Room Rush gamemode, everyone has to get to a specific room as fast as possible. The last player to get there dies. The last player alive wins!\\nOh yeah, and there's also a time limit. Everyone who doesn't get to the room in the specified time dies. Seems easy, right? Well.... When the first 2 players enter the correct room, the time limit gets set to a lower amount, like 5 seconds! Good luck!\\n\\nYou can see the room you have to get to below your name.\\nDepending on the settings, everyone may be able to vent limited times.\\nOh and I almost forgot, there may be some twists for individual players in each round....",
"RR_TimeWhenTwoPlayersEntersRoom": "When the first two players enter the correct room, the time limit is set to",
"RR_VentTimes": "Times each player can vent",
"RR_Tutorial_1": "<#ffab1b><size=80%>Tutorial</size></color>\\nHello! Welcome to Room Rush!\\n",
"RR_Tutorial_2": "The goal of this gamemode is to get to the room you see under your name as fast as possible.",
"RR_Tutorial_3": "When the first two players enter the correct room, the time limit is set to 5 seconds.",
"RR_Tutorial_4": "If you don't get to the room in time, you die.\\nGood luck!",
"RR_VentsRemaining": "<size=80%>Remaining vent uses: {0}</size>",
"RR_GoalReached": "<#00ff00>Goal Reached</color>",
"RR_YouWereLast": "<#ff1919>You were the last to get to the room</color>",
"RRPlayer": "Room Rush",
"RRPlayerInfo": "GET TO THE ROOM ASAP",
"RRPlayerInfoLong": "GET TO THE ROOM ASAP",
"HideAndSeek": "HIDE AND SEEK",
"ModeHideAndSeek": "Gamemode: Hide And Seek",
"ModeDescribe.HideAndSeek": "In the Hide And Seek gamemode, seekers have to kill all hiders, while hiders have to complete all tasks without being killed in order to win.\\nIf the time limit reaches 0, hiders win.\\n\\nRoles: Hider, Seeker, Fox, Troll, Jumper, Detector, Jet, Dasher, Locator, Venter, Agent, Taskinator",
+2
View File
@@ -639,6 +639,8 @@ public class Main : BasePlugin
{ CustomRoles.CTFPlayer, "#1313c2" },
// Natural Disaster
{ CustomRoles.NDPlayer, "#03fc4a" },
// Room Rush
{ CustomRoles.RRPlayer, "#ffab1b" },
// Hide And Seek
{ CustomRoles.Seeker, "#ff1919" },
{ CustomRoles.Hider, "#345eeb" },