speedrun game mode

This commit is contained in:
Gurge44 committed 2024-06-23 13:53:07 +02:00
1 parent 58f68777ab
commit 30c78537e8
22 files changed
+289 -32

No files matched your search

+3
View File
@@ -342,6 +342,9 @@ public enum CustomRoles
Agent,
Taskinator,
// Speedrun
Runner,
// GM
GM,
+133
View File
@@ -0,0 +1,133 @@
using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using HarmonyLib;
using UnityEngine;
namespace EHR
{
public class SpeedrunManager
{
private static OptionItem TaskFinishWins;
private static OptionItem TimeStacksUp;
private static OptionItem TimeLimit;
public static HashSet<byte> CanKill = [];
private static Dictionary<byte, int> Timers = [];
public static void SetupCustomOption()
{
const int id = 69_214_001;
Color color = Utils.GetRoleColor(CustomRoles.Speedrunner);
TaskFinishWins = new BooleanOptionItem(id, "Speedrun_TaskFinishWins", false, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.Speedrun)
.SetColor(color);
TimeStacksUp = new BooleanOptionItem(id + 1, "Speedrun_TimeStacksUp", false, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.Speedrun)
.SetColor(color);
TimeLimit = new IntegerOptionItem(id + 2, "Speedrun_TimeLimit", new(1, 90, 1), 20, TabGroup.GameSettings)
.SetGameMode(CustomGameMode.Speedrun)
.SetValueFormat(OptionFormat.Seconds)
.SetColor(color);
}
public static void Init()
{
CanKill = [];
Timers = Main.AllAlivePlayerControls.ToDictionary(x => x.PlayerId, _ => TimeLimit.GetInt());
}
public static void ResetTimer(PlayerControl pc)
{
if (TimeStacksUp.GetBool()) Timers[pc.PlayerId] += TimeLimit.GetInt();
else Timers[pc.PlayerId] = TimeLimit.GetInt();
}
public static void OnTaskFinish(PlayerControl pc)
{
if (TaskFinishWins.GetBool()) return;
CanKill.Add(pc.PlayerId);
pc.ChangeRoleBasis(RoleTypes.Impostor);
pc.Notify(Translator.GetString("Speedrun_CompletedTasks"));
}
public static string GetTaskBarText()
{
return string.Join('\n', Main.PlayerStates
.Join(Main.AllAlivePlayerControls, x => x.Key, x => x.PlayerId, (kvp, pc) => (
Name: Utils.ColorString(Main.PlayerColors.GetValueOrDefault(kvp.Key, Color.white), pc.GetRealName()),
CompletedTasks: kvp.Value.TaskState.CompletedTasksCount,
AllTasks: kvp.Value.TaskState.AllTasksCount))
.Select(x => $"{x.Name}: {x.CompletedTasks}/{x.AllTasks}"));
}
public static string GetSuffixText(PlayerControl pc)
{
int time = Timers[pc.PlayerId];
int alive = Main.AllAlivePlayerControls.Length;
int apc = Main.AllPlayerControls.Length;
int killers = CanKill.Count;
// ReSharper disable once ConvertIfStatementToReturnStatement
if (CanKill.Contains(pc.PlayerId)) return string.Format(Translator.GetString("Speedrun_CanKillSuffixInfo"), alive, apc, killers - 1, time);
return string.Format(Translator.GetString("Speedrun_DoTasksSuffixInfo"), pc.GetTaskState().RemainingTasksCount, alive, apc, killers, time);
}
public static bool CheckForGameEnd(out GameOverReason reason)
{
if (TaskFinishWins.GetBool())
{
var player = Main.AllAlivePlayerControls.FirstOrDefault(x => x.GetTaskState().IsTaskFinished);
if (player != null)
{
CustomWinnerHolder.WinnerIds = [player.PlayerId];
reason = GameOverReason.HumansByTask;
return true;
}
}
else
{
switch (Main.AllAlivePlayerControls.Length)
{
case 1:
CustomWinnerHolder.WinnerIds = [Main.AllAlivePlayerControls[0].PlayerId];
reason = GameOverReason.ImpostorByKill;
return true;
case 0:
CustomWinnerHolder.WinnerIds = [];
reason = GameOverReason.HumansDisconnect;
return true;
}
}
reason = GameOverReason.ImpostorByKill;
return false;
}
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
class FixedUpdatePatch
{
private static long LastUpdate;
public static void Postfix(PlayerControl __instance)
{
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.Speedrun || Main.HasJustStarted) return;
if (Timers[__instance.PlayerId] <= 0) __instance.Suicide();
long now = Utils.TimeStamp;
if (LastUpdate == now) return;
LastUpdate = now;
Timers.Keys.ToArray().Do(x => Timers[x]--);
Utils.NotifyRoles();
}
}
}
}
+3
View File
@@ -56,6 +56,9 @@ internal static class CustomRoleSelector
case CustomGameMode.HotPotato:
AssignRoleToEveryone(CustomRoles.Potato);
return;
case CustomGameMode.Speedrun:
AssignRoleToEveryone(CustomRoles.Runner);
return;
case CustomGameMode.HideAndSeek:
HnSManager.AssignRoles();
RoleResult = HnSManager.PlayerRoles.ToDictionary(x => Utils.GetPlayerById(x.Key), x => x.Value.Role);
+9
View File
@@ -44,6 +44,13 @@ internal static class CustomRolesHelper
public static bool IsExperimental(this CustomRoles role) => ExperimentalRoleList.Contains(role);
public static bool IsForOtherGameMode(this CustomRoles role) => HnSManager.AllHnSRoles.Contains(role) || role is
CustomRoles.KB_Normal or
CustomRoles.Killer or
CustomRoles.Tasker or
CustomRoles.Potato or
CustomRoles.Runner;
public static RoleBase GetRoleClass(this CustomRoles role)
{
var roleClass = role switch
@@ -334,6 +341,8 @@ internal static class CustomRolesHelper
CustomRoles.Tasker => RoleTypes.Crewmate,
// Hot Potato
CustomRoles.Potato => RoleTypes.Crewmate,
// Speedrun
CustomRoles.Runner => RoleTypes.Crewmate,
// Standard
CustomRoles.Executioner => Executioner.CRoleChangeRoles[Executioner.ChangeRolesAfterTargetKilled.GetValue()].GetDYRole(),
CustomRoles.Sheriff => UsePets && Sheriff.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
+6 -1
View File
@@ -487,7 +487,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 ? $" ({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 ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty);
}
public static string GetRoleColorCode(this PlayerControl player)
@@ -588,6 +588,7 @@ static class ExtendedPlayerControl
if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId)) return true;
if (Penguin.IsVictim(pc)) return false;
if (Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.MoveAndStop) return false;
if (Options.CurrentGameMode == CustomGameMode.Speedrun && !SpeedrunManager.CanKill.Contains(pc.PlayerId)) return false;
if (Pelican.IsEaten(pc.PlayerId)) return false;
if (pc.Data.Role.Role == RoleTypes.GuardianAngel) return false;
@@ -601,6 +602,8 @@ static class ExtendedPlayerControl
CustomRoles.Tasker => false,
// Hot Potato
CustomRoles.Potato => false,
// Speedrun
CustomRoles.Runner => SpeedrunManager.CanKill.Contains(pc.PlayerId),
// Hide And Seek
CustomRoles.Seeker => true,
CustomRoles.Hider => false,
@@ -638,6 +641,8 @@ static class ExtendedPlayerControl
CustomRoles.Tasker => false,
// Hot Potato
CustomRoles.Potato => false,
// Speedrun
CustomRoles.Runner => false,
_ => Main.PlayerStates.TryGetValue(pc.PlayerId, out var state) && state.Role.CanUseImpostorVentButton(pc)
};
@@ -159,6 +159,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender
}
break;
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
case CustomGameMode.MoveAndStop:
opt.SetVision(true);
+6
View File
@@ -317,6 +317,12 @@ public class TaskState
{
bool alive = player.IsAlive();
if (alive && Options.CurrentGameMode == CustomGameMode.Speedrun)
{
if (CompletedTasksCount + 1 >= AllTasksCount) SpeedrunManager.OnTaskFinish(player);
else SpeedrunManager.ResetTimer(player);
}
if (player.Is(CustomRoles.Unlucky) && alive)
{
var Ue = IRandom.Instance;
+3
View File
@@ -53,6 +53,9 @@ public static class NameColorManager
return true;
case CustomGameMode.HideAndSeek:
return HnSManager.KnowTargetRoleColor(seer, target, ref color);
case CustomGameMode.Speedrun when SpeedrunManager.CanKill.Contains(target.PlayerId):
color = Main.ImpostorColor;
return true;
}
// Global (low priority)
+12 -7
View File
@@ -22,6 +22,7 @@ public enum CustomGameMode
MoveAndStop = 0x04,
HotPotato = 0x05,
HideAndSeek = 0x06,
Speedrun = 0x07,
All = int.MaxValue
}
@@ -42,7 +43,8 @@ public static class Options
"FFA",
"MoveAndStop",
"HotPotato",
"HideAndSeek"
"HideAndSeek",
"Speedrun"
];
private static Dictionary<CustomRoles, int> roleCounts;
@@ -762,6 +764,7 @@ public static class Options
3 => CustomGameMode.MoveAndStop,
4 => CustomGameMode.HotPotato,
5 => CustomGameMode.HideAndSeek,
6 => CustomGameMode.Speedrun,
_ => CustomGameMode.Standard
};
@@ -787,7 +790,7 @@ public static class Options
var sb = new System.Text.StringBuilder();
var grouped = Enum.GetValues<CustomRoles>().GroupBy(x =>
{
if (x is CustomRoles.GM or CustomRoles.Philantropist or CustomRoles.Konan or CustomRoles.KB_Normal or CustomRoles.Killer or CustomRoles.Potato or CustomRoles.Tasker or CustomRoles.NotAssigned or CustomRoles.LovingCrewmate or CustomRoles.LovingImpostor or CustomRoles.Convict || HnSManager.AllHnSRoles.Contains(x) || x.IsVanilla() || x.ToString().Contains("EHR")) return 4;
if (x is CustomRoles.GM or CustomRoles.Philantropist or CustomRoles.Konan or CustomRoles.NotAssigned or CustomRoles.LovingCrewmate or CustomRoles.LovingImpostor or CustomRoles.Convict || x.IsForOtherGameMode() || x.IsVanilla() || x.ToString().Contains("EHR")) return 4;
if (x.IsAdditionRole()) return 3;
if (x.IsImpostor() || x.IsMadmate()) return 0;
if (x.IsNeutral()) return 1;
@@ -1247,15 +1250,17 @@ public static class Options
MainLoadingText = "Building Settings for Other Gamemodes";
//SoloKombat
// SoloKombat
SoloKombatManager.SetupCustomOption();
//FFA
// FFA
FFAManager.SetupCustomOption();
//Move And Stop
// Move And Stop
MoveAndStopManager.SetupCustomOption();
//Hot Potato
// Hot Potato
HotPotatoManager.SetupCustomOption();
//Hide And Seek
// Speedrun
SpeedrunManager.SetupCustomOption();
// Hide And Seek
HnSManager.SetupCustomOption();
+10 -9
View File
@@ -625,6 +625,7 @@ public static class Utils
case CustomGameMode.FFA: return false;
case CustomGameMode.MoveAndStop: return true;
case CustomGameMode.HotPotato: return false;
case CustomGameMode.Speedrun: return true;
case CustomGameMode.HideAndSeek: return HnSManager.HasTasks(p);
}
@@ -808,7 +809,7 @@ public static class Utils
public static bool IsRoleTextEnabled(PlayerControl __instance)
{
if (__instance.AmOwner || Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.SoloKombat or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato || (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 (__instance.AmOwner || 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;
switch (__instance.GetCustomRole())
{
@@ -1276,13 +1277,8 @@ public static class Utils
}
break;
case CustomGameMode.Speedrun:
case CustomGameMode.HotPotato:
foreach (byte id in cloneRoles)
{
sb.Append("\n\u3000 ").Append(EndGamePatch.SummaryText[id]);
}
break;
case CustomGameMode.HideAndSeek:
foreach (byte id in cloneRoles)
{
@@ -1793,6 +1789,7 @@ public static class Utils
CustomGameMode.MoveAndStop => $"<color=#00ffa5><size=1.7>{modeText}</size></color>\r\n" + name,
CustomGameMode.HotPotato => $"<color=#e8cd46><size=1.7>{modeText}</size></color>\r\n" + name,
CustomGameMode.HideAndSeek => $"<color=#345eeb><size=1.7>{modeText}</size></color>\r\n" + name,
CustomGameMode.Speedrun => ColorString(GetRoleColor(CustomRoles.Speedrunner), $"<size=1.7>{modeText}</size>\r\n") + name,
_ => name
};
}
@@ -2035,6 +2032,9 @@ public static class Utils
case CustomGameMode.HotPotato when seer.IsAlive() && !seer.IsModClient():
SelfSuffix.Append(HotPotatoManager.GetSuffixText(seer.PlayerId));
break;
case CustomGameMode.Speedrun:
SelfSuffix.Append(SpeedrunManager.GetSuffixText(seer));
break;
case CustomGameMode.HideAndSeek:
SelfSuffix.Append(HnSManager.GetSuffixText(seer, seer));
break;
@@ -2048,7 +2048,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)
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)
{
var team = CustomTeamManager.GetCustomTeam(seer.PlayerId);
if (team != null)
@@ -2254,7 +2254,7 @@ public static class Utils
CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(seer.PlayerId, CTAOption.KnowRoles) ||
Main.PlayerStates.Values.Any(x => x.Role.KnowRole(seer, target)) ||
Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { IsEnable: true, TargetRevealed: true } ms && ms.MarkedId == target.PlayerId) ||
Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato ||
Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun ||
(Options.CurrentGameMode == CustomGameMode.HideAndSeek && HnSManager.IsRoleTextEnabled(seer, target)) ||
(seer.IsRevealedPlayer(target) && !target.Is(CustomRoles.Trickster)) ||
seer.Is(CustomRoles.God) ||
@@ -2860,6 +2860,7 @@ public static class Utils
case CustomGameMode.FFA:
summary = $"{ColorString(Main.PlayerColors[id], name)} {GetKillCountText(id, ffa: true)}";
break;
case CustomGameMode.Speedrun:
case CustomGameMode.MoveAndStop:
summary = $"{ColorString(Main.PlayerColors[id], name)} -{TaskCount.Replace("(", string.Empty).Replace(")", string.Empty)} ({GetVitalText(id, true)})";
break;
+15
View File
@@ -357,6 +357,7 @@ class GameEndChecker
public static void SetPredicateToFFA() => Predicate = new FFAGameEndPredicate();
public static void SetPredicateToMoveAndStop() => Predicate = new MoveAndStopGameEndPredicate();
public static void SetPredicateToHotPotato() => Predicate = new HotPotatoGameEndPredicate();
public static void SetPredicateToSpeedrun() => Predicate = new SpeedrunGameEndPredicate();
public static void SetPredicateToHideAndSeek() => Predicate = new HideAndSeekGameEndPredicate();
class NormalGameEndPredicate : GameEndPredicate
@@ -686,6 +687,20 @@ class GameEndChecker
}
}
class SpeedrunGameEndPredicate : 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)
{
return SpeedrunManager.CheckForGameEnd(out reason);
}
}
public abstract class GameEndPredicate
{
/// <summary>Checks the game ending condition and stores the value in CustomWinnerHolder. </summary>
+1
View File
@@ -510,6 +510,7 @@ public static class SetRecommendationsPatch
__instance.KillCooldown = 0f;
__instance.NumEmergencyMeetings = 0;
break;
case CustomGameMode.Speedrun:
case CustomGameMode.MoveAndStop:
__instance.CrewLightMod = 1.25f;
__instance.ImpostorLightMod = 1.25f;
+7
View File
@@ -407,6 +407,7 @@ class SetHudActivePatch
{
case CustomGameMode.MoveAndStop:
case CustomGameMode.HotPotato:
case CustomGameMode.Speedrun:
__instance.ReportButton?.ToggleVisible(false);
__instance.KillButton?.ToggleVisible(false);
__instance.SabotageButton?.ToggleVisible(false);
@@ -698,6 +699,12 @@ class TaskPanelBehaviourPatch
AllText += $"\r\n\r\n{HnSManager.GetTaskBarText()}";
break;
case CustomGameMode.Speedrun:
AllText += $"\r\n\r\n{SpeedrunManager.GetTaskBarText()}";
break;
}
+19
View File
@@ -68,6 +68,16 @@ class SetUpRoleTextPatch
__instance.RoleBlurbText.text = GetString("PotatoInfo");
break;
}
case CustomGameMode.Speedrun:
{
var color = Utils.GetRoleColor(CustomRoles.Speedrunner);
__instance.YouAreText.transform.gameObject.SetActive(false);
__instance.RoleText.text = GetString("Runner");
__instance.RoleText.color = color;
__instance.RoleBlurbText.color = color;
__instance.RoleBlurbText.text = GetString("RunnerInfo");
break;
}
default:
{
CustomRoles role = PlayerControl.LocalPlayer.GetCustomRole();
@@ -508,6 +518,15 @@ class BeginCrewmatePatch
__instance.ImpostorText.text = GetString("PotatoInfo");
break;
}
case CustomGameMode.Speedrun:
{
__instance.TeamTitle.text = GetString("Runner");
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = Utils.GetRoleColor(CustomRoles.Speedrunner);
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Crewmate);
__instance.ImpostorText.gameObject.SetActive(true);
__instance.ImpostorText.text = GetString("RunnerInfo");
break;
}
case CustomGameMode.HideAndSeek:
{
__instance.TeamTitle.text = GetString("HideAndSeek");
+5 -1
View File
@@ -317,6 +317,7 @@ internal class ChangeRoleSettings
MoveAndStopManager.Init();
HotPotatoManager.Init();
HnSManager.Init();
SpeedrunManager.Init();
}
catch (Exception e)
{
@@ -757,6 +758,9 @@ internal class SelectRolesPatch
case CustomGameMode.HotPotato:
GameEndChecker.SetPredicateToHotPotato();
break;
case CustomGameMode.Speedrun:
GameEndChecker.SetPredicateToSpeedrun();
break;
case CustomGameMode.HideAndSeek:
GameEndChecker.SetPredicateToHideAndSeek();
break;
@@ -769,7 +773,7 @@ internal class SelectRolesPatch
}
// Add players with unclassified roles to the list of players who require ResetCam.
Main.ResetCamPlayerList.AddRange(Main.AllPlayerControls.Where(p => p.GetCustomRole() is CustomRoles.Arsonist or CustomRoles.Revolutionist or CustomRoles.Sidekick or CustomRoles.KB_Normal or CustomRoles.Killer or CustomRoles.Tasker or CustomRoles.Potato or CustomRoles.Seeker or CustomRoles.Hider or CustomRoles.Fox or CustomRoles.Troll or CustomRoles.Jumper or CustomRoles.Detector or CustomRoles.Jet or CustomRoles.Dasher or CustomRoles.Locator or CustomRoles.Venter or CustomRoles.Agent or CustomRoles.Taskinator or CustomRoles.Innocent || (p.Is(CustomRoles.Witness) && (!Options.UsePets.GetBool() || Options.WitnessUsePet.GetBool()))).Select(p => p.PlayerId));
Main.ResetCamPlayerList.AddRange(Main.AllPlayerControls.Where(p => p.GetCustomRole() is CustomRoles.Arsonist or CustomRoles.Revolutionist or CustomRoles.Sidekick or CustomRoles.Innocent || p.GetCustomRole().IsForOtherGameMode() || (p.Is(CustomRoles.Witness) && (!Options.UsePets.GetBool() || Options.WitnessUsePet.GetBool()))).Select(p => p.PlayerId));
Utils.CountAlivePlayers(true);
Utils.SyncAllSettings();
+16 -1
View File
@@ -63,7 +63,7 @@ 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;
var gmIsFMHH = gmIsFM || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun;
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))})");
@@ -250,6 +250,14 @@ class SetEverythingUpPatch
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
case CustomGameMode.Speedrun:
{
var winnerId = CustomWinnerHolder.WinnerIds.FirstOrDefault();
__instance.BackgroundBar.material.color = Utils.GetRoleColor(CustomRoles.Speedrunner);
WinnerText.text = Main.AllPlayerNames[winnerId] + " wins!";
WinnerText.color = Main.PlayerColors[winnerId];
goto EndOfText;
}
}
if (CustomWinnerHolder.WinnerTeam == CustomWinner.CustomTeam)
@@ -408,6 +416,13 @@ class SetEverythingUpPatch
sb.Append("\n\u3000 ").Append(EndGamePatch.SummaryText[id]);
break;
}
case CustomGameMode.Speedrun:
{
var list = cloneRoles.OrderByDescending(id => Main.PlayerStates[id].TaskState.CompletedTasksCount);
foreach (var id in list.Where(EndGamePatch.SummaryText.ContainsKey))
sb.Append("\n\u3000 ").Append(EndGamePatch.SummaryText[id]);
break;
}
default:
{
sb.Append("</b>\n");
+11
View File
@@ -219,6 +219,11 @@ class CheckMurderPatch
case CustomGameMode.MoveAndStop:
case CustomGameMode.HotPotato:
return false;
case CustomGameMode.Speedrun when !SpeedrunManager.CanKill.Contains(killer.PlayerId):
return false;
case CustomGameMode.Speedrun:
killer.Kill(target);
return false;
case CustomGameMode.HideAndSeek:
HnSManager.OnCheckMurder(killer, target);
return false;
@@ -589,6 +594,8 @@ class MurderPlayerPatch
}
Main.PlayerStates[killer.PlayerId].Role.OnMurder(killer, target);
if (Options.CurrentGameMode == CustomGameMode.Speedrun) SpeedrunManager.ResetTimer(killer);
if (killer.Is(CustomRoles.TicketsStealer) && killer.PlayerId != target.PlayerId)
killer.Notify(string.Format(GetString("TicketsStealerGetTicket"), ((Main.AllPlayerControls.Count(x => x.GetRealKiller()?.PlayerId == killer.PlayerId) + 1) * Options.TicketsPerKill.GetFloat()).ToString("0.0#####")));
@@ -1561,6 +1568,9 @@ class FixedUpdatePatch
case CustomGameMode.HotPotato when !seer.IsModClient() && self && seer.IsAlive():
Suffix.Append(HotPotatoManager.GetSuffixText(seer.PlayerId));
break;
case CustomGameMode.Speedrun when self:
Suffix.Append(SpeedrunManager.GetSuffixText(seer));
break;
case CustomGameMode.HideAndSeek:
Suffix.Append(HnSManager.GetSuffixText(seer, target));
break;
@@ -1792,6 +1802,7 @@ class CoEnterVentPatch
return true;
case CustomGameMode.MoveAndStop:
case CustomGameMode.HotPotato:
case CustomGameMode.Speedrun:
LateTask.New(() => { __instance.myPlayer?.MyPhysics?.RpcBootFromVent(id); }, 0.5f, log: false);
return true;
case CustomGameMode.HideAndSeek:
+13 -1
View File
@@ -3554,9 +3554,21 @@
"Potato": "Player",
"PotatoInfo": "AVOID HAVING THE HOT POTATO",
"PotatoInfoLong": "AVOID HAVING THE HOT POTATO",
"Speedrun": "SPEEDRUN",
"ModeSpeedrun": "Gamemode: Speedrun",
"ModeDescribe.Speedrun": "In the Speedrun gamemode, everything is about speed. Everyone has to complete all tasks as fast as possible, then kill everyone else as fast as possible!\\n\\nWhen someone finishes all their tasks, they become a killer and can kill everyone else. The last player alive wins!\\nBut to make this a bit harder, you have a time limit to complete a task or kill someone! The timer resets when you do so. If your time runs out, you die!\\n\\nThis gamemode is a hybrid of the Stop And Go and Free For All gamemodes.",
"Speedrun_TaskFinishWins": "First to Finish Tasks Wins Immediately (skips killing phase)",
"Speedrun_TimeStacksUp": "Time Remainder Adds to Next Time Limit (time stacks up)",
"Speedrun_TimeLimit": "Time Limit to Do a Task or Kill",
"Speedrun_CanKillSuffixInfo": "<#00ffa5>Time: {3}s</color>\\n<size=80%><#ffff00>Alive players: <#ffab1b>{0}</color>/{1}</color>\\n<#ff1919>Kill everyone to win</color>\\n<size=70%><#888888>Apart from you, <#ffffff>{2}</color> players can kill</color></size></size>",
"Speedrun_DoTasksSuffixInfo": "<#00ffa5>Time: {4}s</color>\\n<size=70%><#888888>Alive players: <#ffffff>{1}</color>/{2}</color>\\n<size=80%><#ffff00>Remaining tasks: {0}</color>\\n<#00ffa5>Finish your tasks</color>\\n<size=70%><#ffab1b><#ffffff>{3}</color> players can kill</color></size></size></size>",
"Speedrun_CompletedTasks": "<#00ff00>You're done with tasks!</color>",
"Runner": "Speedrunner",
"RunnerInfo": "COMPLETE TASKS AND KILL EVERYONE FIRST TO WIN",
"RunnerInfoLong": "COMPLETE TASKS AND KILL EVERYONE FIRST TO WIN",
"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\\n<b><u>Roles:</u></b>\\n\\n<#00ff00><b>Fox</b></color>:\\n<size=70%>Wins as long as they're alive at the end.</size>\\n\\n<#ff00ff><b>Troll</b></color>:\\n<size=70%>Wins if they die. Seekers and hiders lose.</size>",
"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",
"HideAndSeek_MaxGameTime": "Maximum Game Length",
"HNS.MinNeutrals": "<#00ffff>Minimum</color> Number of <#ffab1b>Neutrals</color>",
"HNS.MaxNeutrals": "<#0000ff>Maximum</color> Number of <#ffab1b>Neutrals</color>",
+1 -1
View File
@@ -62,7 +62,7 @@ public class Divinator : RoleBase
var players = Main.AllAlivePlayerControls;
int rolesNeeded = players.Length * (RolesPerCategory - 1);
AllPlayerRoleList = Enum.GetValues<CustomRoles>()
.Where(x => !x.IsVanilla() && !x.IsAdditionRole() && x is not CustomRoles.Killer and not CustomRoles.Tasker and not CustomRoles.KB_Normal and not CustomRoles.Potato and not CustomRoles.GM and not CustomRoles.Convict && !HnSManager.AllHnSRoles.Contains(x))
.Where(x => !x.IsVanilla() && !x.IsAdditionRole() && x is not CustomRoles.GM and not CustomRoles.Convict && !x.IsForOtherGameMode())
.OrderBy(x => x.IsEnable() ? IRandom.Instance.Next(10) : IRandom.Instance.Next(10, 100))
.Take(rolesNeeded)
.Chunk(RolesPerCategory - 1)
+7 -4
View File
@@ -66,12 +66,15 @@ public class Sheriff : RoleBase
UsePet = Options.CreatePetUseSetting(Id + 29, CustomRoles.Sheriff);
}
public static void SetUpNeutralOptions(int id)
private static void SetUpNeutralOptions(int id)
{
foreach (var neutral in Enum.GetValues<CustomRoles>().Where(x => x.IsNeutral() && x is not CustomRoles.KB_Normal and not CustomRoles.Konan and not CustomRoles.Pestilence and not CustomRoles.Killer and not CustomRoles.Tasker and not CustomRoles.Potato and not CustomRoles.Hider and not CustomRoles.Seeker and not CustomRoles.Fox and not CustomRoles.Troll and not CustomRoles.Jumper and not CustomRoles.Detector and not CustomRoles.Jet and not CustomRoles.Dasher and not CustomRoles.Locator and not CustomRoles.Venter and not CustomRoles.Agent and not CustomRoles.Taskinator and not CustomRoles.GM and not CustomRoles.Convict))
foreach (var neutral in Enum.GetValues<CustomRoles>())
{
SetUpKillTargetOption(neutral, id, true, CanKillNeutralsMode);
id++;
if (neutral.IsNeutral() && neutral is not CustomRoles.Konan and not CustomRoles.Pestilence and not CustomRoles.GM and not CustomRoles.Convict && !neutral.IsForOtherGameMode())
{
SetUpKillTargetOption(neutral, id, true, CanKillNeutralsMode);
id++;
}
}
}
+6 -7
View File
@@ -28,7 +28,7 @@ namespace EHR.Roles.Impostor
public class Mafioso : RoleBase
{
private const int Id = 642200;
private static List<byte> playerIdList = [];
private static List<byte> PlayerIdList = [];
private static OptionItem Delay;
private static OptionItem RewardForKilling;
@@ -47,7 +47,7 @@ namespace EHR.Roles.Impostor
private int Tier;
private int XP;
public override bool IsEnable => playerIdList.Count > 0;
public override bool IsEnable => PlayerIdList.Count > 0;
public static void SetupCustomOption()
{
@@ -67,7 +67,7 @@ namespace EHR.Roles.Impostor
public override void Init()
{
playerIdList = [];
PlayerIdList = [];
PreviouslyUsedVents = [];
Tier = 0;
XP = 0;
@@ -79,7 +79,7 @@ namespace EHR.Roles.Impostor
public override void Add(byte playerId)
{
playerIdList.Add(playerId);
PlayerIdList.Add(playerId);
lastUpdate = TimeStamp + 8;
MafiosoId = playerId;
PreviouslyUsedVents = [];
@@ -273,9 +273,8 @@ namespace EHR.Roles.Impostor
public override bool OnSabotage(PlayerControl pc)
{
if (Main.PlayerStates[pc.PlayerId].Role is not Mafioso { IsEnable: true } mo) return true;
mo.XP += RewardForSabotaging.GetInt();
mo.SendRPC();
XP += RewardForSabotaging.GetInt();
SendRPC();
return true;
}
+2
View File
@@ -598,6 +598,8 @@ public class Main : BasePlugin
{ CustomRoles.Tasker, "#00ffa5" },
// Hot Potato
{ CustomRoles.Potato, "#e8cd46" },
// Speedrun
{ CustomRoles.Runner, "#800080"},
// Hide And Seek
{ CustomRoles.Seeker, "#ff1919" },
{ CustomRoles.Hider, "#345eeb" },