mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
cancel vanish, inform about version mismatch, add missing strings, add new role Stasis, fix some bugs & improvements
This commit is contained in:
1 parent
5c08f79c0a
commit
f8090f2e0e
27 files changed
+418
-187
No files matched your search
@@ -91,6 +91,7 @@ public enum CustomRoles
|
||||
Silencer,
|
||||
Sniper,
|
||||
ImperiusCurse, // Soul Catcher
|
||||
Stasis,
|
||||
Swapster,
|
||||
Swiftclaw,
|
||||
Swooper,
|
||||
@@ -261,6 +262,7 @@ public enum CustomRoles
|
||||
|
||||
Agitater,
|
||||
Amnesiac,
|
||||
Amogus,
|
||||
Arsonist,
|
||||
Backstabber,
|
||||
Bandit,
|
||||
|
||||
@@ -91,6 +91,7 @@ public enum CustomRoles
|
||||
Silencer,
|
||||
Sniper,
|
||||
ImperiusCurse, // Soul Catcher
|
||||
Stasis,
|
||||
Swapster,
|
||||
Swiftclaw,
|
||||
Swooper,
|
||||
|
||||
@@ -148,7 +148,7 @@ public static class RoomRush
|
||||
.SetColor(color)
|
||||
.SetGameMode(gameMode);
|
||||
|
||||
DisplayArrowToRoom = new BooleanOptionItem(id, "RR_DisplayArrowToRoom", false, TabGroup.GameSettings)
|
||||
DisplayArrowToRoom = new BooleanOptionItem(id++, "RR_DisplayArrowToRoom", false, TabGroup.GameSettings)
|
||||
.SetColor(color)
|
||||
.SetGameMode(gameMode);
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Inhibitor => CustomRoles.Impostor,
|
||||
CustomRoles.Occultist => CustomRoles.Impostor,
|
||||
CustomRoles.Kidnapper => CustomRoles.Shapeshifter,
|
||||
CustomRoles.Stasis => UsePets ? CustomRoles.Impostor : CustomRoles.Shapeshifter,
|
||||
CustomRoles.Wasp => CustomRoles.Impostor,
|
||||
CustomRoles.Assumer => CustomRoles.Impostor,
|
||||
CustomRoles.Augmenter => CustomRoles.Shapeshifter,
|
||||
@@ -629,6 +630,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Augmenter or
|
||||
CustomRoles.Inhibitor or
|
||||
CustomRoles.Kidnapper or
|
||||
CustomRoles.Stasis or
|
||||
CustomRoles.Occultist or
|
||||
CustomRoles.Wasp or
|
||||
CustomRoles.Hypnotist or
|
||||
@@ -918,6 +920,7 @@ internal static class CustomRolesHelper
|
||||
{
|
||||
return role is
|
||||
CustomRoles.Wizard or
|
||||
CustomRoles.Stasis or
|
||||
CustomRoles.Occultist or
|
||||
CustomRoles.Warlock or
|
||||
CustomRoles.Swiftclaw or
|
||||
@@ -1485,6 +1488,7 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.RiftMaker => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.Scavenger => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.ImperiusCurse => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.Stasis => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.Swiftclaw => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.Swooper => RoleOptionType.Impostor_Concealing,
|
||||
CustomRoles.Stealth => RoleOptionType.Impostor_Concealing,
|
||||
@@ -1748,4 +1752,4 @@ public enum CountTypes
|
||||
Arsonist,
|
||||
Cherokious,
|
||||
Sheriff
|
||||
}
|
||||
}
|
||||
@@ -39,9 +39,7 @@ public class ErrorText : MonoBehaviour
|
||||
public void LateUpdate()
|
||||
{
|
||||
if (!Text.enabled) return;
|
||||
|
||||
if (!Camera) Camera = !HudManager.InstanceExists ? _camera : _camera1;
|
||||
|
||||
if (Camera) transform.position = AspectPosition.ComputeWorldPosition(Camera, AspectPosition.EdgeAlignments.Top, TextOffset);
|
||||
}
|
||||
|
||||
@@ -107,10 +105,7 @@ public class ErrorText : MonoBehaviour
|
||||
Text.text = text;
|
||||
}
|
||||
catch (NullReferenceException) { }
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.ToString(), "ErrorText.UpdateText");
|
||||
}
|
||||
catch (Exception e) { Logger.Error(e.ToString(), "ErrorText.UpdateText"); }
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
@@ -1804,14 +1804,11 @@ internal static class ExtendedPlayerControl
|
||||
|
||||
List<CustomRoles> subRoles = target.GetCustomSubRoles();
|
||||
if (subRoles.Contains(CustomRoles.Bloodlust) || target.IsConverted()) return Team.Neutral;
|
||||
|
||||
if (subRoles.Contains(CustomRoles.Madmate)) return Team.Impostor;
|
||||
|
||||
CustomRoles role = target.GetCustomRole();
|
||||
if (role.IsImpostorTeamV2()) return Team.Impostor;
|
||||
|
||||
if (role.IsNeutralTeamV2()) return Team.Neutral;
|
||||
|
||||
return role.IsCrewmateTeamV2() ? Team.Crewmate : Team.None;
|
||||
}
|
||||
|
||||
|
||||
@@ -400,15 +400,18 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
AURoleOptions.ShapeshifterDuration = 1f;
|
||||
}
|
||||
|
||||
if (Options.UsePhantomBasis.GetBool() && role.SimpleAbilityTrigger()) AURoleOptions.PhantomDuration = 1f;
|
||||
if (Options.UsePhantomBasis.GetBool() && role.SimpleAbilityTrigger())
|
||||
AURoleOptions.PhantomDuration = 1f;
|
||||
|
||||
if ((Options.UseUnshiftTrigger.GetBool() || role.AlwaysUsesUnshift()) && role.SimpleAbilityTrigger()) AURoleOptions.ShapeshifterDuration = 0f;
|
||||
if ((Options.UseUnshiftTrigger.GetBool() || role.AlwaysUsesUnshift()) && role.SimpleAbilityTrigger())
|
||||
AURoleOptions.ShapeshifterDuration = 0f;
|
||||
|
||||
// ===================================================================================================================
|
||||
|
||||
AURoleOptions.EngineerCooldown = Mathf.Max(0.01f, AURoleOptions.EngineerCooldown);
|
||||
|
||||
if (Main.AllPlayerKillCooldown.TryGetValue(player.PlayerId, out float killCooldown)) AURoleOptions.KillCooldown = Mathf.Max(0.01f, killCooldown);
|
||||
if (Main.AllPlayerKillCooldown.TryGetValue(player.PlayerId, out float killCooldown))
|
||||
AURoleOptions.KillCooldown = Mathf.Max(0.01f, killCooldown);
|
||||
|
||||
if (Main.AllPlayerSpeed.TryGetValue(player.PlayerId, out float speed))
|
||||
{
|
||||
@@ -428,7 +431,8 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
Options.AdditionalEmergencyCooldownTime.GetInt());
|
||||
}
|
||||
|
||||
if (Options.SyncButtonMode.GetBool() && Options.SyncedButtonCount.GetValue() <= Options.UsedButtonCount) opt.SetInt(Int32OptionNames.EmergencyCooldown, 3600);
|
||||
if (Options.SyncButtonMode.GetBool() && Options.SyncedButtonCount.GetValue() <= Options.UsedButtonCount)
|
||||
opt.SetInt(Int32OptionNames.EmergencyCooldown, 3600);
|
||||
|
||||
MeetingTimeManager.ApplyGameOptions(opt);
|
||||
|
||||
@@ -456,8 +460,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Fatal($"Error for {player.GetRealName()} ({player.GetCustomRole()}): {e}", "PlayerGameOptionsSender.BuildGameOptions");
|
||||
Logger.SendInGame($"Error syncing settings for {player.GetRealName()} - Please report this bug to the developer AND SEND LOGS");
|
||||
Logger.Error($"Error for {player.GetRealName()} ({player.GetCustomRole()}): {e}", "PlayerGameOptionsSender.BuildGameOptions");
|
||||
return BasedGameOptions;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-10
@@ -41,7 +41,7 @@ public static class ModUpdater
|
||||
if (!IsChecked)
|
||||
{
|
||||
bool done = CheckReleaseFromGithub(Main.BetaBuildUrl.Value != "").GetAwaiter().GetResult();
|
||||
Logger.Warn("done: " + done, "CheckRelease");
|
||||
Logger.Msg("done: " + done, "CheckRelease");
|
||||
Logger.Info("hasupdate: " + HasUpdate, "CheckRelease");
|
||||
Logger.Info("forceupdate: " + ForceUpdate, "CheckRelease");
|
||||
Logger.Info("downloadUrl: " + DownloadUrl, "CheckRelease");
|
||||
@@ -61,17 +61,14 @@ public static class ModUpdater
|
||||
using StreamReader reader = new(stream);
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
finally { stream.Close(); }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<bool> CheckReleaseFromGithub(bool beta = false)
|
||||
{
|
||||
Logger.Warn("Checking GitHub Release", "CheckRelease");
|
||||
Logger.Msg("Checking GitHub Release", "CheckRelease");
|
||||
const string url = URLGithub + "/releases/latest";
|
||||
|
||||
try
|
||||
@@ -191,10 +188,7 @@ public static class ModUpdater
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to clear update residue\n{e}", "DeleteOldFiles");
|
||||
}
|
||||
catch (Exception e) { Logger.Error($"Failed to clear update residue\n{e}", "DeleteOldFiles"); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,11 @@ public static class Statistics
|
||||
if (correctGuesses >= 2) Achievements.Type.BeginnerGuesser.CompleteAfterGameEnd();
|
||||
if (correctGuesses >= 4) Achievements.Type.GuessMaster.CompleteAfterGameEnd();
|
||||
if (correctGuesses >= 6) Achievements.Type.BestGuesserAward.CompleteAfterGameEnd();
|
||||
|
||||
|
||||
Main.NumWinsPerGM.TryAdd(Options.CurrentGameMode, []);
|
||||
Main.NumWinsPerGM[Options.CurrentGameMode].AddRange(CustomWinnerHolder.WinnerIds.ToValidPlayers().ToDictionary(x => x.FriendCode, _ => 0), overrideExistingKeys: false);
|
||||
Main.NumWinsPerGM[Options.CurrentGameMode].AdjustAllValues(x => ++x);
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
|
||||
+32
-17
@@ -1360,11 +1360,11 @@ public static class Utils
|
||||
}
|
||||
}
|
||||
|
||||
public static void ShowLastRoles(byte PlayerId = byte.MaxValue)
|
||||
public static void ShowLastRoles(byte playerId = byte.MaxValue)
|
||||
{
|
||||
if (AmongUsClient.Instance.IsGameStarted)
|
||||
{
|
||||
SendMessage(GetString("CantUse.lastroles"), PlayerId);
|
||||
SendMessage(GetString("CantUse.lastroles"), playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1460,25 +1460,25 @@ public static class Utils
|
||||
|
||||
sb.Append("</size>");
|
||||
|
||||
SendMessage("\n", PlayerId, sb.ToString());
|
||||
SendMessage("\n", playerId, sb.ToString());
|
||||
}
|
||||
|
||||
public static void ShowKillLog(byte PlayerId = byte.MaxValue)
|
||||
public static void ShowKillLog(byte playerId = byte.MaxValue)
|
||||
{
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
SendMessage(GetString("CantUse.killlog"), PlayerId);
|
||||
SendMessage(GetString("CantUse.killlog"), playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EndGamePatch.KillLog != string.Empty) SendMessage(EndGamePatch.KillLog, PlayerId);
|
||||
if (EndGamePatch.KillLog != string.Empty) SendMessage(EndGamePatch.KillLog, playerId);
|
||||
}
|
||||
|
||||
public static void ShowLastResult(byte PlayerId = byte.MaxValue)
|
||||
public static void ShowLastResult(byte playerId = byte.MaxValue)
|
||||
{
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
SendMessage(GetString("CantUse.lastresult"), PlayerId);
|
||||
SendMessage(GetString("CantUse.lastresult"), playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1486,24 +1486,38 @@ public static class Utils
|
||||
|
||||
StringBuilder sb = new();
|
||||
if (SetEverythingUpPatch.LastWinsText != string.Empty) sb.Append($"<size=90%>{GetString("LastResult")} {SetEverythingUpPatch.LastWinsText}</size>");
|
||||
|
||||
if (SetEverythingUpPatch.LastWinsReason != string.Empty) sb.Append($"\n<size=90%>{GetString("LastEndReason")} {SetEverythingUpPatch.LastWinsReason}</size>");
|
||||
|
||||
if (sb.Length > 0) SendMessage("\n", PlayerId, sb.ToString());
|
||||
if (sb.Length > 0) SendMessage("\n", playerId, sb.ToString());
|
||||
}
|
||||
|
||||
public static void ShowLastAddOns(byte PlayerId = byte.MaxValue)
|
||||
public static void ShowLastAddOns(byte playerId = byte.MaxValue)
|
||||
{
|
||||
if (GameStates.IsInGame)
|
||||
{
|
||||
SendMessage(GetString("CantUse.lastresult"), PlayerId);
|
||||
SendMessage(GetString("CantUse.lastresult"), playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CustomGameMode.Standard.IsActiveOrIntegrated()) return;
|
||||
|
||||
string result = Main.LastAddOns.Values.Join(delimiter: "\n");
|
||||
SendMessage("\n", PlayerId, result);
|
||||
SendMessage("\n", playerId, result);
|
||||
}
|
||||
|
||||
public static string GetWinCountsString()
|
||||
{
|
||||
if (!Main.NumWinsPerGM.TryGetValue(Options.CurrentGameMode, out var dictionary) || dictionary.Count == 0) return string.Empty;
|
||||
|
||||
StringBuilder sb = new();
|
||||
sb.AppendLine($"<#ffffff><u>{GetString("WinsCountTitle")}:</u></color>");
|
||||
|
||||
foreach ((string friendcode, int wins) in dictionary)
|
||||
{
|
||||
if (!Main.AllAlivePlayerControls.FindFirst(x => x.FriendCode == friendcode, out var player)) continue;
|
||||
sb.AppendLine($"{player.PlayerId.ColoredPlayerName()}: {wins}");
|
||||
}
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
public static string GetSubRolesText(byte id, bool disableColor = false, bool intro = false, bool summary = false)
|
||||
@@ -2644,16 +2658,17 @@ public static class Utils
|
||||
CustomRoles.Twister => Twister.ShapeshiftCooldown.GetInt(),
|
||||
CustomRoles.Abyssbringer => Abyssbringer.BlackHolePlaceCooldown.GetInt(),
|
||||
CustomRoles.Warlock => Warlock.IsCursed ? -1 : Warlock.ShapeshiftCooldown.GetInt(),
|
||||
CustomRoles.Stasis => Stasis.AbilityCooldown.GetInt() + (includeDuration ? Stasis.AbilityDuration.GetInt() : 0),
|
||||
CustomRoles.Swiftclaw => Swiftclaw.DashCD.GetInt() + (includeDuration ? Swiftclaw.DashDuration.GetInt() : 0),
|
||||
CustomRoles.Hypnotist => Hypnotist.AbilityCooldown.GetInt() + (includeDuration ? Hypnotist.AbilityDuration.GetInt() : 0),
|
||||
CustomRoles.Parasite => (int)Parasite.SSCD + (includeDuration ? (int)Parasite.SSDur : 0),
|
||||
CustomRoles.Tiger => Tiger.EnrageCooldown.GetInt() + (includeDuration ? Tiger.EnrageDuration.GetInt() : 0),
|
||||
CustomRoles.Nonplus => Nonplus.BlindCooldown.GetInt() + (includeDuration ? Nonplus.BlindDuration.GetInt() : 0),
|
||||
CustomRoles.Amogus => Amogus.AbilityCooldown.GetInt() + (includeDuration ? Amogus.AbilityDuration.GetInt() : 0),
|
||||
CustomRoles.Cherokious => Cherokious.KillCooldown.GetInt(),
|
||||
CustomRoles.Shifter => Shifter.KillCooldown.GetInt(),
|
||||
CustomRoles.NoteKiller => NoteKiller.AbilityCooldown.GetInt(),
|
||||
CustomRoles.Weatherman => Weatherman.AbilityCooldown.GetInt(),
|
||||
CustomRoles.Amogus => Amogus.AbilityCooldown.GetInt(),
|
||||
_ => -1
|
||||
};
|
||||
|
||||
@@ -2882,8 +2897,8 @@ public static class Utils
|
||||
|
||||
TargetDies(target.GetRealKiller(), target);
|
||||
}
|
||||
|
||||
if (!onMeeting)
|
||||
|
||||
if (!onMeeting)
|
||||
Amogus.OnAnyoneDead(target);
|
||||
|
||||
Adventurer.OnAnyoneDead(target);
|
||||
|
||||
@@ -103,7 +103,7 @@ internal static class ChatCommands
|
||||
|
||||
public static Dictionary<byte, List<CustomRoles>> DraftRoles = [];
|
||||
public static Dictionary<byte, CustomRoles> DraftResult = [];
|
||||
|
||||
|
||||
public static readonly HashSet<byte> Spectators = [];
|
||||
public static readonly HashSet<byte> LastSpectators = [];
|
||||
|
||||
@@ -341,12 +341,18 @@ internal static class ChatCommands
|
||||
|
||||
private static void SpectateCommand(ChatController __instance, PlayerControl player, string text, string[] args)
|
||||
{
|
||||
if (Options.DisableSpectateCommand.GetBool())
|
||||
{
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("SpectateDisabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
RequestCommandProcessingFromHost(nameof(SpectateCommand), text);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (LastSpectators.Contains(player.PlayerId))
|
||||
{
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("SpectateCommand.WasSpectatingLastRound"));
|
||||
@@ -358,14 +364,14 @@ internal static class ChatCommands
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("SpectateCommand.AlreadySpectating"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("SpectateCommand.Success"));
|
||||
}
|
||||
|
||||
|
||||
private static void WhisperCommand(ChatController __instance, PlayerControl player, string text, string[] args)
|
||||
{
|
||||
if (!player.IsAlive()) return;
|
||||
|
||||
|
||||
if (Options.DisableWhisperCommand.GetBool())
|
||||
{
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("WhisperDisabled"));
|
||||
@@ -380,10 +386,10 @@ internal static class ChatCommands
|
||||
|
||||
if (args.Length < 3 || !byte.TryParse(args[1], out byte targetId)) return;
|
||||
if (!player.IsLocalPlayer()) ChatManager.SendPreviousMessagesToAll();
|
||||
|
||||
|
||||
string msg = args[2..].Join(delimiter: " ");
|
||||
string title = string.Format(GetString("WhisperTitle"), player.PlayerId.ColoredPlayerName(), player.PlayerId);
|
||||
|
||||
|
||||
Utils.SendMessage(msg, targetId, title);
|
||||
ChatUpdatePatch.LastMessages.Add((msg, targetId, title, Utils.TimeStamp));
|
||||
}
|
||||
@@ -478,7 +484,7 @@ internal static class ChatCommands
|
||||
Utils.SendMessage("\n", player.PlayerId, GetString("EveryoneReadyTitle"));
|
||||
else
|
||||
Utils.SendMessage(string.Join(", ", notReadyPlayers.Select(x => x.ColoredPlayerName())), player.PlayerId, string.Format(GetString("PlayersNotReadyTitle"), notReadyPlayers.Length));
|
||||
|
||||
|
||||
if (Spectators.Count > 0) Utils.SendMessage(string.Join(", ", Spectators.Select(x => x.ColoredPlayerName())), player.PlayerId, string.Format(GetString("SpectatorsList"), Spectators.Count));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,44 +76,44 @@ internal static class GameEndChecker
|
||||
{
|
||||
case CustomWinner.Crewmate:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => (pc.Is(CustomRoleTypes.Crewmate) || (pc.Is(CustomRoles.Haunter) && Haunter.CanWinWithCrew(pc))) && !pc.IsMadmate() && !pc.IsConverted() && !pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => (pc.Is(CustomRoleTypes.Crewmate) || (pc.Is(CustomRoles.Haunter) && Haunter.CanWinWithCrew(pc))) && !pc.IsMadmate() && !pc.IsConverted() && !pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Impostor:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => ((pc.Is(CustomRoleTypes.Impostor) && (!pc.Is(CustomRoles.DeadlyQuota) || Main.PlayerStates.Count(x => x.Value.GetRealKiller() == pc.PlayerId) >= Options.DQNumOfKillsNeeded.GetInt())) || pc.IsMadmate()) && !pc.IsConverted() && !pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => ((pc.Is(CustomRoleTypes.Impostor) && (!pc.Is(CustomRoles.DeadlyQuota) || Main.PlayerStates.Count(x => x.Value.GetRealKiller() == pc.PlayerId) >= Options.DQNumOfKillsNeeded.GetInt())) || pc.IsMadmate()) && !pc.IsConverted() && !pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Succubus:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => pc.Is(CustomRoles.Succubus) || pc.Is(CustomRoles.Charmed))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => pc.Is(CustomRoles.Succubus) || pc.Is(CustomRoles.Charmed))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Necromancer:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => pc.Is(CustomRoles.Necromancer) || pc.Is(CustomRoles.Deathknight) || pc.Is(CustomRoles.Undead))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => pc.Is(CustomRoles.Necromancer) || pc.Is(CustomRoles.Deathknight) || pc.Is(CustomRoles.Undead))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Virus:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => pc.Is(CustomRoles.Virus) || pc.Is(CustomRoles.Contagious))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => pc.Is(CustomRoles.Virus) || pc.Is(CustomRoles.Contagious))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Jackal:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => pc.Is(CustomRoles.Jackal) || pc.Is(CustomRoles.Sidekick) || pc.Is(CustomRoles.Recruit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => pc.Is(CustomRoles.Jackal) || pc.Is(CustomRoles.Sidekick) || pc.Is(CustomRoles.Recruit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
break;
|
||||
case CustomWinner.Spiritcaller:
|
||||
WinnerIds.UnionWith(Main.AllPlayerControls
|
||||
.Where(pc => pc.Is(CustomRoles.Spiritcaller) || pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
.Where(pc => pc.Is(CustomRoles.Spiritcaller) || pc.Is(CustomRoles.EvilSpirit))
|
||||
.Select(pc => pc.PlayerId));
|
||||
|
||||
WinnerRoles.Add(CustomRoles.Spiritcaller);
|
||||
break;
|
||||
@@ -229,6 +229,10 @@ internal static class GameEndChecker
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.NoteKiller);
|
||||
break;
|
||||
case CustomRoles.NecroGuesser when (Main.PlayerStates[pc.PlayerId].Role as NecroGuesser).GuessedPlayers >= NecroGuesser.NumGuessesToWin.GetInt():
|
||||
WinnerIds.Add(pc.PlayerId);
|
||||
AdditionalWinnerTeams.Add(AdditionalWinners.NecroGuesser);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +248,7 @@ internal static class GameEndChecker
|
||||
case > 1 when WinnerIds.Any(x => GetPlayerById(x).Is(CustomRoles.Egoist)):
|
||||
WinnerIds.RemoveWhere(x => GetPlayerById(x).Is(CustomRoles.Egoist));
|
||||
break;
|
||||
// If there's only 1 impostor alive, and all alive impostors are Egoists, the Egoist wins alone
|
||||
// If there's only 1 impostor alive, and all living impostors are Egoists, the Egoist wins alone
|
||||
case 1 when imps.All(x => x.Is(CustomRoles.Egoist)):
|
||||
PlayerControl pc = imps[0];
|
||||
reason = GameOverReason.ImpostorByKill;
|
||||
|
||||
@@ -288,10 +288,11 @@ public static class GameStartManagerPatch
|
||||
{
|
||||
if (AmongUsClient.Instance == null || AmongUsClient.Instance.IsGameStarted || GameStates.IsInGame || __instance == null || __instance.startState == GameStartManager.StartingStates.Starting) return;
|
||||
|
||||
var canStartGame = true;
|
||||
var mismatchedClientName = string.Empty;
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
var canStartGame = true;
|
||||
|
||||
foreach (ClientData client in AmongUsClient.Instance.allClients)
|
||||
{
|
||||
if (client.Character == null) continue;
|
||||
@@ -299,7 +300,11 @@ public static class GameStartManagerPatch
|
||||
var dummyComponent = client.Character.GetComponent<DummyBehaviour>();
|
||||
if (dummyComponent != null && dummyComponent.enabled) continue;
|
||||
|
||||
if (!MatchVersions(client.Character.PlayerId, true)) canStartGame = false;
|
||||
if (!MatchVersions(client.Character.PlayerId, true))
|
||||
{
|
||||
canStartGame = false;
|
||||
mismatchedClientName = client.Character.PlayerId.ColoredPlayerName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!canStartGame) __instance.StartButton.gameObject.SetActive(false);
|
||||
@@ -335,6 +340,12 @@ public static class GameStartManagerPatch
|
||||
if (Options.NoGameEnd.GetBool())
|
||||
suffix = suffix.Insert(0, Utils.ColorString(Color.yellow, $"{GetString("NoGameEnd").ToUpper()}") + Utils.ColorString(Color.gray, " | "));
|
||||
|
||||
if (!canStartGame)
|
||||
{
|
||||
suffix = suffix.Insert(0, Utils.ColorString(Color.red, string.Format(GetString("VersionMismatch"), mismatchedClientName)) + "\n");
|
||||
suffix += "\n";
|
||||
}
|
||||
|
||||
TextMeshPro tmp = GameStartManagerStartPatch.GameCountdown;
|
||||
|
||||
if (tmp.text == string.Empty)
|
||||
|
||||
+25
-29
@@ -29,7 +29,7 @@ internal static class CheckForEndVotingPatch
|
||||
|
||||
if (Medic.PlayerIdList.Count > 0) Medic.OnCheckMark();
|
||||
|
||||
//Meeting Skip with vote counting on keystroke (m + delete)
|
||||
// Meeting Skip with vote counting
|
||||
bool shouldSkip = Input.GetKeyDown(KeyCode.F6);
|
||||
|
||||
LogHandler voteLog = Logger.Handler("Vote");
|
||||
@@ -124,7 +124,7 @@ internal static class CheckForEndVotingPatch
|
||||
!(Options.WhenSkipVoteIgnoreFirstMeeting.GetBool() && MeetingStates.FirstMeeting) &&
|
||||
!(Options.WhenSkipVoteIgnoreNoDeadBody.GetBool() && !MeetingStates.IsExistDeadBody) &&
|
||||
!(Options.WhenSkipVoteIgnoreEmergency.GetBool() && MeetingStates.IsEmergencyMeeting)
|
||||
)
|
||||
)
|
||||
{
|
||||
switch (Options.GetWhenSkipVote())
|
||||
{
|
||||
@@ -160,25 +160,33 @@ internal static class CheckForEndVotingPatch
|
||||
}
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Divinator) && Divinator.HideVote.GetBool()) continue;
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Eraser) && Eraser.HideVote.GetBool()) continue;
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.NiceEraser) && NiceEraser.HideVote.GetBool()) continue;
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Scout) && Scout.HideVote.GetBool()) continue;
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Oracle) && Oracle.HideVote.GetBool()) continue;
|
||||
|
||||
if (ps.TargetPlayerId == ps.VotedFor && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) continue;
|
||||
|
||||
AddVote();
|
||||
bool canVote = !(CheckRole(ps.TargetPlayerId, CustomRoles.Glitch) && !Glitch.CanVote.GetBool());
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Shifter) && !Shifter.CanVote.GetBool()) canVote = false;
|
||||
if (ps.VotedFor.GetPlayer() != null && CheckRole(ps.VotedFor, CustomRoles.Zombie)) canVote = false;
|
||||
|
||||
if (Main.PlayerStates[ps.TargetPlayerId].Role is Adventurer { IsEnable: true } av && av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy)) AddVote();
|
||||
switch (Main.PlayerStates[ps.TargetPlayerId].Role)
|
||||
{
|
||||
case Adventurer { IsEnable: true } av when av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy):
|
||||
AddVote();
|
||||
break;
|
||||
case Amogus { IsEnable: true, ExtraVotes: > 0 } amogus:
|
||||
Loop.Times(amogus.ExtraVotes, _ => AddVote());
|
||||
break;
|
||||
case Dad { IsEnable: true } dad when dad.UsingAbilities.Contains(Dad.Ability.GoForMilk):
|
||||
canVote = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (canVote) AddVote();
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Mayor) && !Mayor.MayorHideVote.GetBool()) Loop.Times(Mayor.MayorAdditionalVote.GetInt(), _ => AddVote());
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Vindicator) && !Options.VindicatorHideVote.GetBool()) Loop.Times(Options.VindicatorAdditionalVote.GetInt(), _ => AddVote());
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.Knighted)) AddVote();
|
||||
|
||||
if (CheckRole(ps.TargetPlayerId, CustomRoles.DualPersonality) && Options.DualVotes.GetBool())
|
||||
@@ -363,9 +371,7 @@ internal static class CheckForEndVotingPatch
|
||||
}
|
||||
|
||||
if (Options.ConfirmEgoistOnEject.GetBool() && player.Is(CustomRoles.Egoist)) coloredRole = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Egoist), GetRoleString("Temp.Blank") + coloredRole.RemoveHtmlTags());
|
||||
|
||||
if (Options.ConfirmLoversOnEject.GetBool() && Main.LoversPlayers.Exists(x => x.PlayerId == player.PlayerId)) coloredRole = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lovers), GetRoleString("Temp.Blank") + coloredRole.RemoveHtmlTags());
|
||||
|
||||
if (Options.RascalAppearAsMadmate.GetBool() && player.Is(CustomRoles.Rascal)) coloredRole = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Madmate), GetRoleString("Mad-") + coloredRole.RemoveHtmlTags());
|
||||
|
||||
var name = string.Empty;
|
||||
@@ -574,16 +580,10 @@ internal static class CheckForEndVotingPatch
|
||||
if (Main.PlayerStates.TryGetValue(id, out PlayerState state) && state.SubRoles.Contains(CustomRoles.Avanger))
|
||||
RevengeOnExile(playerId /*, deathReason*/);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.ThrowException(e);
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.ThrowException(e);
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
}
|
||||
|
||||
private static void RevengeOnExile(byte playerId /*, PlayerState.DeathReason deathReason*/)
|
||||
@@ -659,6 +659,9 @@ internal static class ExtendedMeetingHud
|
||||
case Dad { IsEnable: true } dad when dad.UsingAbilities.Contains(Dad.Ability.GoForMilk):
|
||||
VoteNum = 0;
|
||||
break;
|
||||
case Amogus { IsEnable: true, ExtraVotes: > 0 } amogus:
|
||||
VoteNum += amogus.ExtraVotes;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ps.TargetPlayerId == ps.VotedFor && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) VoteNum = 0;
|
||||
@@ -783,13 +786,9 @@ internal static class MeetingHudStartPatch
|
||||
}
|
||||
|
||||
if (Mortician.MsgToSend.TryGetValue(pc.PlayerId, out string value2)) AddMsg(value2, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mortician), GetString("MorticianCheckTitle")));
|
||||
|
||||
if (Mediumshiper.ContactPlayer.ContainsValue(pc.PlayerId)) AddMsg(string.Format(GetString("MediumshipNotifySelf"), Main.AllPlayerNames[Mediumshiper.ContactPlayer.FirstOrDefault(x => x.Value == pc.PlayerId).Key], pc.GetAbilityUseLimit()), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshipTitle")));
|
||||
|
||||
if (Mediumshiper.ContactPlayer.ContainsKey(pc.PlayerId) && (!Mediumshiper.OnlyReceiveMsgFromCrew.GetBool() || pc.IsCrewmate())) AddMsg(string.Format(GetString("MediumshipNotifyTarget"), Main.AllPlayerNames[Mediumshiper.ContactPlayer[pc.PlayerId]]), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshipTitle")));
|
||||
|
||||
if (Virus.VirusNotify.TryGetValue(pc.PlayerId, out string value3)) AddMsg(value3, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Virus), GetString("VirusNoticeTitle")));
|
||||
|
||||
if (Enigma.MsgToSend.TryGetValue(pc.PlayerId, out string value4)) AddMsg(value4, pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Enigma), Enigma.MsgToSendTitle[pc.PlayerId]));
|
||||
|
||||
if (QuizMaster.On && QuizMaster.MessagesToSend.TryGetValue(pc.PlayerId, out string value5))
|
||||
@@ -1228,10 +1227,7 @@ internal static class MeetingHudCastVotePatch
|
||||
PlayerVoteArea pva_src = info.SourcePVA;
|
||||
PlayerControl pc_src = info.SourcePC;
|
||||
|
||||
try
|
||||
{
|
||||
pva_src.UnsetVote();
|
||||
}
|
||||
try { pva_src.UnsetVote(); }
|
||||
catch { }
|
||||
|
||||
__instance.RpcClearVote(pc_src.GetClientId());
|
||||
|
||||
@@ -111,7 +111,7 @@ internal static class EndGamePatch
|
||||
Main.RealOptionsData.Restore(GameOptionsManager.Instance.CurrentGameOptions);
|
||||
GameOptionsSender.AllSenders.Clear();
|
||||
GameOptionsSender.AllSenders.Add(new NormalGameOptionsSender());
|
||||
|
||||
|
||||
ChatCommands.Spectators.Clear();
|
||||
|
||||
switch (Options.CurrentGameMode)
|
||||
@@ -496,6 +496,14 @@ internal static class SetEverythingUpPatch
|
||||
|
||||
sb.Append("</font>");
|
||||
|
||||
var winCounts = Utils.GetWinCountsString();
|
||||
|
||||
if (winCounts != string.Empty)
|
||||
{
|
||||
sb.Append("\n\n");
|
||||
sb.Append(winCounts);
|
||||
}
|
||||
|
||||
var RoleSummary = RoleSummaryObject.GetComponent<TextMeshPro>();
|
||||
RoleSummary.alignment = TextAlignmentOptions.TopLeft;
|
||||
RoleSummary.color = Color.white;
|
||||
|
||||
+52
-26
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Crewmate;
|
||||
using EHR.Impostor;
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
@@ -52,12 +54,37 @@ public static class PhantomRolePatch
|
||||
// Called when Phantom press vanish button when visible
|
||||
[HarmonyPatch(nameof(PlayerControl.CheckVanish))]
|
||||
[HarmonyPrefix]
|
||||
private static void CheckVanish_Prefix(PlayerControl __instance)
|
||||
private static bool CheckVanish_Prefix(PlayerControl __instance)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (!AmongUsClient.Instance.AmHost) return true;
|
||||
|
||||
PlayerControl phantom = __instance;
|
||||
Logger.Info($"Player: {phantom.GetRealName()}", "CheckVanish");
|
||||
Logger.Info($"Player: {phantom.GetNameWithRole()}", "CheckVanish");
|
||||
|
||||
if (!Rhapsode.CheckAbilityUse(phantom) || Stasis.IsTimeFrozen || !Main.PlayerStates[__instance.PlayerId].Role.OnVanish(__instance))
|
||||
{
|
||||
if (phantom.AmOwner)
|
||||
{
|
||||
DestroyableSingleton<HudManager>.Instance.AbilityButton.SetFromSettings(phantom.Data.Role.Ability);
|
||||
phantom.Data.Role.SetCooldown();
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomRpcSender sender = CustomRpcSender.Create($"Cancel vanish for {phantom.GetRealName()}");
|
||||
sender.StartMessage(phantom.GetClientId());
|
||||
|
||||
sender.StartRpc(phantom.NetId, (byte)RpcCalls.SetRole)
|
||||
.Write((ushort)RoleTypes.Phantom)
|
||||
.Write(true)
|
||||
.EndRpc();
|
||||
|
||||
sender.EndMessage();
|
||||
sender.SendMessage();
|
||||
|
||||
phantom.RpcResetAbilityCooldown();
|
||||
|
||||
LateTask.New(() => phantom.SetKillCooldown(Math.Max(Main.KillTimers[phantom.PlayerId], 0.001f)), 0.2f);
|
||||
}
|
||||
|
||||
foreach (PlayerControl target in Main.AllPlayerControls)
|
||||
{
|
||||
@@ -67,22 +94,24 @@ public static class PhantomRolePatch
|
||||
phantom.RpcCheckVanishDesync(target);
|
||||
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (GameStates.IsMeeting || phantom == null) return;
|
||||
{
|
||||
if (GameStates.IsMeeting || phantom == null) return;
|
||||
|
||||
string petId = phantom.Data.DefaultOutfit.PetId;
|
||||
string petId = phantom.Data.DefaultOutfit.PetId;
|
||||
|
||||
if (petId != "")
|
||||
{
|
||||
PetsList[phantom.PlayerId] = petId;
|
||||
phantom.RpcSetPetDesync("", target);
|
||||
}
|
||||
if (petId != "")
|
||||
{
|
||||
PetsList[phantom.PlayerId] = petId;
|
||||
phantom.RpcSetPetDesync("", target);
|
||||
}
|
||||
|
||||
phantom.RpcExileDesync(target);
|
||||
}, 1.2f, $"Set Phantom invisible {target.PlayerId}");
|
||||
phantom.RpcExileDesync(target);
|
||||
}, 1.2f, $"Set Phantom invisible {target.PlayerId}");
|
||||
}
|
||||
|
||||
InvisibilityList.Add(phantom);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(PlayerControl.CheckAppear))]
|
||||
@@ -105,19 +134,19 @@ public static class PhantomRolePatch
|
||||
phantom.RpcSetRoleDesync(RoleTypes.Phantom, clientId);
|
||||
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (target != null) phantom.RpcCheckAppearDesync(shouldAnimate, target);
|
||||
}, 0.5f, $"Check Appear when vanish is over {target.PlayerId}");
|
||||
{
|
||||
if (target != null) phantom.RpcCheckAppearDesync(shouldAnimate, target);
|
||||
}, 0.5f, $"Check Appear when vanish is over {target.PlayerId}");
|
||||
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (GameStates.IsMeeting || phantom == null) return;
|
||||
{
|
||||
if (GameStates.IsMeeting || phantom == null) return;
|
||||
|
||||
InvisibilityList.Remove(phantom);
|
||||
phantom.RpcSetRoleDesync(RoleTypes.Scientist, clientId);
|
||||
InvisibilityList.Remove(phantom);
|
||||
phantom.RpcSetRoleDesync(RoleTypes.Scientist, clientId);
|
||||
|
||||
if (PetsList.TryGetValue(phantom.PlayerId, out string petId)) phantom.RpcSetPetDesync(petId, target);
|
||||
}, 1.8f, $"Set Scientist when vanish is over {target.PlayerId}");
|
||||
if (PetsList.TryGetValue(phantom.PlayerId, out string petId)) phantom.RpcSetPetDesync(petId, target);
|
||||
}, 1.8f, $"Set Scientist when vanish is over {target.PlayerId}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,10 +176,7 @@ public static class PhantomRolePatch
|
||||
Main.Instance.StartCoroutine(CoRevertInvisible(phantom, seer, force));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Utils.ThrowException(e);
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
}
|
||||
|
||||
private static bool InValid(PlayerControl phantom, PlayerControl seer)
|
||||
|
||||
@@ -777,7 +777,7 @@ internal static class ShapeshiftPatch
|
||||
|
||||
if (AmongUsClient.Instance.AmHost && shapeshifting)
|
||||
{
|
||||
if (!Rhapsode.CheckAbilityUse(shapeshifter)) return false;
|
||||
if (!Rhapsode.CheckAbilityUse(shapeshifter) || Stasis.IsTimeFrozen) return false;
|
||||
|
||||
if (shapeshifter.Is(CustomRoles.Trainee) && MeetingStates.FirstMeeting)
|
||||
{
|
||||
@@ -1988,7 +1988,7 @@ internal static class CoEnterVentPatch
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Rhapsode.CheckAbilityUse(__instance.myPlayer))
|
||||
if (!Rhapsode.CheckAbilityUse(__instance.myPlayer) || Stasis.IsTimeFrozen)
|
||||
{
|
||||
LateTask.New(() => __instance.RpcBootFromVent(id), 0.5f, log: false);
|
||||
return true;
|
||||
@@ -2290,19 +2290,6 @@ internal static class CmdCheckAppearPatch
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckVanish))]
|
||||
internal static class CheckVanishPatch
|
||||
{
|
||||
public static bool Prefix(PlayerControl __instance)
|
||||
{
|
||||
Logger.Info($" {__instance.GetNameWithRole()}", "CheckVanish");
|
||||
bool allow = Main.PlayerStates[__instance.PlayerId].Role.OnVanish(__instance);
|
||||
if (!allow) LateTask.New(__instance.RpcResetAbilityCooldown, 0.2f, log: false);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.AssertWithTimeout))]
|
||||
internal static class AssertWithTimeoutPatch
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EHR.Crewmate;
|
||||
using EHR.Impostor;
|
||||
using EHR.Modules;
|
||||
using EHR.Neutral;
|
||||
using HarmonyLib;
|
||||
@@ -365,8 +366,9 @@ public static class SabotageSystemTypeRepairDamagePatch
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.Is(Team.Impostor) && !player.IsAlive() && Options.DeadImpCantSabotage.GetBool()) return false;
|
||||
if (Rhapsode.CheckAbilityUse(player) || Stasis.IsTimeFrozen) return false;
|
||||
|
||||
if (player.Is(Team.Impostor) && !player.IsAlive() && Options.DeadImpCantSabotage.GetBool()) return false;
|
||||
if (!player.Is(Team.Impostor) && !player.IsAlive()) return false;
|
||||
|
||||
bool allow = player.GetCustomRole() switch
|
||||
|
||||
@@ -2422,6 +2422,7 @@
|
||||
"WhisperTitle": "{0} <#ffffff>(ID <#00ffa5>{1}</color>) whispers to you:</color>",
|
||||
"DisableWhisperCommand": "Disable /whisper command",
|
||||
"DisableSpectateCommand": "Disable /spectate command",
|
||||
"SpectateDisabled": "<#ff0000>X</color> The /spectate command is disabled in this lobby.",
|
||||
"WhisperDisabled": "<#ff0000>X</color> The /whisper command is disabled in this lobby.",
|
||||
"ThankYouForUsingEHR": "Thank you for using EHR!",
|
||||
"GMRoles": "<color=#ff5b70>【 ★ Roles ★ 】</color>",
|
||||
@@ -2676,9 +2677,10 @@
|
||||
"Outside": "Outside",
|
||||
"UnsupportedVersion": "Unsupported Among Us version.\\nPlease update Among Us.",
|
||||
"Error.MeetingException": "Error: {0}\\r\\nPlease use SHIFT+M+ENTER to end the meeting",
|
||||
"Error.InvalidRoleAssignment": "Error: Invalid role found for a player during role assignment({0})",
|
||||
"Error.InvalidColor": "Error: Only default colors are available",
|
||||
"Error.InvalidColorPreventStart": "Other players are not allowed to use other colors, otherwise it will result in a serious error",
|
||||
"Error.InvalidRoleAssignment": "Error: Invalid role found for a player during role assignment ({0})",
|
||||
"Error.InvalidColor": "Error: Only default colors are available - this means someone had fortegreen color in the lobby, which causes disconnects, so it's best to kick them",
|
||||
"Error.InvalidColorPreventStart": "Other players are not allowed to use other colors (e.g. fortegreen), otherwise it will result in a serious error",
|
||||
"VersionMismatch": "{0} has a different version of the mod installed",
|
||||
"ErrorLevel1": "Bugs may occur.",
|
||||
"ErrorLevel2": "This can cause serious issues with the game.",
|
||||
"ErrorLevel3": "This version shouldn't have been released.",
|
||||
@@ -2808,6 +2810,7 @@
|
||||
"AntiAdminerVI": "<size=1.7><color=#ffff00>⚠ Vitals Monitor ⚠</color></size>",
|
||||
"AntiAdminerDL": "<size=1.7><color=#ffff00>⚠ DoorLog ⚠</color></size>",
|
||||
"AntiAdminerCA": "<size=1.7><color=#ffff00>⚠ Security Cameras ⚠</color></size>",
|
||||
"WinsCountTitle": "Number of wins in this game mode",
|
||||
"Roles": "Roles",
|
||||
"Settings": "Settings",
|
||||
"Addons": "Add-Ons",
|
||||
@@ -2956,9 +2959,9 @@
|
||||
"Disabled": "Disabled",
|
||||
"FailToTrack": "Failed To Track",
|
||||
"CanGuessTarget": "Can Guess their Target",
|
||||
"UsePhantomBasis": "Use Phantom Basis for some roles (DEPRECATED, use Unshift Trigger ^^)",
|
||||
"UsePhantomBasis": "Use Vanish Button (Phantom basis) as Ability Trigger",
|
||||
"UsePhantomBasisForNKs": "Even for <#ffab1b>Neutral</color> <#ff1919>Killing</color> (Desynced) roles <#ffff00>(EXPERIMENTAL)</color>",
|
||||
"UseUnshiftTrigger": "Use Unshift Button as Ability Trigger",
|
||||
"UseUnshiftTrigger": "Use Unshift Button (Shapeshifter basis) as Ability Trigger",
|
||||
"UseUnshiftTriggerForNKs": "Even for <#ffab1b>Neutral</color> <#ff1919>Killing</color> (Desynced) roles <#ffff00>(EXPERIMENTAL)</color>",
|
||||
"Mad-": "Mad ",
|
||||
"Charmed-": "Charmed ",
|
||||
@@ -3837,6 +3840,25 @@
|
||||
"HHNumOfTargets": "Number of Targets",
|
||||
"HHMaxKCD": "Maximum Kill Cooldown",
|
||||
"HHMinKCD": "Minimum Kill Cooldown",
|
||||
"Stasis": "Stasis",
|
||||
"StasisInfo": "Freeze Time",
|
||||
"StasisInfoLong": "(Impostors):\\nAs the Stasis, you can shapeshift/pet/vanish to 'freeze time'. That means, all players will be frozen and blind, and no one will be able to do anything. Depending on the settings, the blinding and freezing may exclude other impostor-teamed players.",
|
||||
"Stasis.AffectsOtherImpostors": "Time Freezing Affects Other <#ff1919>Impostors</color>",
|
||||
"Stasis.TimeFrozenNotify": "Time Frozen",
|
||||
"Amogus": "Amogus",
|
||||
"AmogusInfo": "You're the sussy baka",
|
||||
"AmogusInfoLong": "(Neutrals):\\nAs the Amogus, you can thank Rabek for the role idea. Lol.\\nAnyway, Amogus is a neutral killer that can use shift/vanish/pet button to switch between regular and amogus form. You can vent and you have impostor vision. You can only kill in amogus form. You can stay in amogus form for a limited amount of time. After killing someone, your amogus form upgrades. These are the levels:\\n<b>Amogus -> Sugoma -> Sumogus -> Suspicious Sus -> Ultimate Sus</b>\\nWhen you're in amogus form, you're anonymous and look different depending on your level. Levels also give extra abilities that work only in amogus form.<size=70%>\\n\\nAmogus: Starting level, regular white amogus without extra special abilities.\\nSugoma: Upside down amogus. Is faster, but your controls are inverted.\\nSumogus: Wide amogus with two visors. No one can interact with you and you have sugoma ability, but your controls aren't inverted anymore.\\nSuspicious Sus: Amogus that is robot. You have all abilities of Sumogus and in addition you can see an arrow to every player.\\nUltimate Sus: Red amogus. Has all abilities of lower levels. Your kill cooldown is reduced by 50%. If you kill someone, you get additional vote(s).</size>",
|
||||
"Amogus.StartingLevel": "Starting Level",
|
||||
"Amogus.SugomaSpeed": "Speed at Sugoma level",
|
||||
"Amogus.SuspiciousSusArrowsToBodies": "At Suspicious Sus level, when someone dies, the arrow points at the dead body instead of disappearing",
|
||||
"Amogus.UltimateSusVotesPerKill": "Number of Extra Votes gained for every kill, when the level is Ultimate Sus",
|
||||
"Amogus.Suffix": "<#00ffa5>Current level:</color> <b>{0}</b>",
|
||||
"Amogus.Levels.Amogus": "Amogus",
|
||||
"Amogus.Levels.Sugoma": "Sugoma",
|
||||
"Amogus.Levels.Sumogus": "Sumogus",
|
||||
"Amogus.Levels.SuspiciousSus": "Suspicious Sus",
|
||||
"Amogus.Levels.UltimateSus": "Ultimate Sus",
|
||||
"ExtraVotesPT": "<#00a5ff>(<#00ffff>+<#00ffa5>{0}</color> votes</color>)</color>",
|
||||
"Rabbit": "Rabbit",
|
||||
"RabbitInfo": "Get Clues Toward Impostor Locations",
|
||||
"RabbitInfoLong": "(Crewmates):\\nAs the Rabbit, each time you complete a task, you see an arrow pointing towards a random impostor for 5 seconds.\\nNote: This ability may only activate after you've completed a set number of tasks.",
|
||||
@@ -4111,7 +4133,7 @@
|
||||
"DeliverCooldown": "Deliver Cooldown",
|
||||
"NecroGuesser": "Necro-Guesser",
|
||||
"NecroGuesserInfo": "Guess Dead Players' Roles",
|
||||
"NecroGuesserInfoLong": "(Neutrals):\\nAs the Necro-Guesser, your job is to guess the roles of dead players. Use <b>/bt {id} {role}</b> to guess. {id} is the player's ID, biew them by using /id, {role} is the player's role. You need to guess a certain amount of dead players' roles to win with the winning team at the end.",
|
||||
"NecroGuesserInfoLong": "(Neutrals):\\nAs the Necro-Guesser, your job is to guess the roles of dead players. Use <b>/bt {id} {role}</b> to guess. {id} is the player's ID, view them by using /id, {role} is the player's role. You need to guess a certain amount of dead players' roles to win with the winning team at the end.",
|
||||
"NecroGuesser.NumGuessesToWin": "Number of Guesses Required to Win",
|
||||
"NecroGuesser.GuessCorrect": "Your guess was <#00ff00>correct</color>!",
|
||||
"NecroGuesser.GuessIncorrect": "Your guess was <#ff0000>incorrect</color>!",
|
||||
|
||||
+13
-10
@@ -315,26 +315,29 @@ public class ParityCop : RoleBase
|
||||
|
||||
switch (firstRoleClass)
|
||||
{
|
||||
case Lawyer when Lawyer.Target[first.PlayerId] == second.PlayerId: return true;
|
||||
case Totocalcio tc when tc.BetPlayer == second.PlayerId: return true;
|
||||
case Romantic when Romantic.HasPickedPartner && Romantic.PartnerId == second.PlayerId: return true;
|
||||
case Necromancer when secondRoleClass is Deathknight: return true;
|
||||
case Lawyer when Lawyer.Target[first.PlayerId] == second.PlayerId:
|
||||
case Totocalcio tc when tc.BetPlayer == second.PlayerId:
|
||||
case Romantic when Romantic.HasPickedPartner && Romantic.PartnerId == second.PlayerId:
|
||||
case Necromancer when secondRoleClass is Deathknight:
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (secondRoleClass)
|
||||
{
|
||||
case Lawyer when Lawyer.Target[second.PlayerId] == first.PlayerId: return true;
|
||||
case Totocalcio tc when tc.BetPlayer == first.PlayerId: return true;
|
||||
case Romantic when Romantic.HasPickedPartner && Romantic.PartnerId == first.PlayerId: return true;
|
||||
case Necromancer when firstRoleClass is Deathknight: return true;
|
||||
case Lawyer when Lawyer.Target[second.PlayerId] == first.PlayerId:
|
||||
case Totocalcio tc when tc.BetPlayer == first.PlayerId:
|
||||
case Romantic when Romantic.HasPickedPartner && Romantic.PartnerId == first.PlayerId:
|
||||
case Necromancer when firstRoleClass is Deathknight:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CustomTeamManager.AreInSameCustomTeam(first.PlayerId, second.PlayerId)) return true;
|
||||
|
||||
if (firstSubRoles.Contains(CustomRoles.Bloodlust) || secondSubRoles.Contains(CustomRoles.Bloodlust)) return false;
|
||||
|
||||
if (firstRole.IsNeutral() && secondRole.IsNeutral()) return false;
|
||||
|
||||
if (firstSubRoles.Contains(CustomRoles.Rascal) && secondTeam != Team.Impostor) return false;
|
||||
if (secondSubRoles.Contains(CustomRoles.Rascal) && firstTeam != Team.Impostor) return false;
|
||||
|
||||
return firstTeam == secondTeam || firstRole == secondRole;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR.Impostor;
|
||||
|
||||
public class Stasis : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
private static List<Stasis> Instances = [];
|
||||
|
||||
public static OptionItem AbilityCooldown;
|
||||
public static OptionItem AbilityDuration;
|
||||
private static OptionItem AffectsOtherImpostors;
|
||||
private static OptionItem CanVent;
|
||||
private static OptionItem KillCooldown;
|
||||
|
||||
private bool UsingAbility;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public static bool IsTimeFrozen => Instances.Any(x => x.UsingAbility);
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(649025, true)
|
||||
.AutoSetupOption(ref AbilityCooldown, 30, new IntegerValueRule(1, 60, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref AbilityDuration, 10, new IntegerValueRule(1, 60, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref AffectsOtherImpostors, true)
|
||||
.AutoSetupOption(ref CanVent, false)
|
||||
.AutoSetupOption(ref KillCooldown, 30f, new FloatValueRule(0f, 180f, 1f), OptionFormat.Seconds);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
On = false;
|
||||
Instances = [];
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
Instances.Add(this);
|
||||
UsingAbility = false;
|
||||
}
|
||||
|
||||
public override bool CanUseImpostorVentButton(PlayerControl pc)
|
||||
{
|
||||
return CanVent.GetBool();
|
||||
}
|
||||
|
||||
public override void SetKillCooldown(byte id)
|
||||
{
|
||||
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
|
||||
}
|
||||
|
||||
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
|
||||
{
|
||||
if (Options.UsePets.GetBool()) return;
|
||||
|
||||
AURoleOptions.ShapeshifterCooldown = AbilityCooldown.GetInt();
|
||||
AURoleOptions.ShapeshifterDuration = 1f;
|
||||
}
|
||||
|
||||
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
||||
{
|
||||
if (!shapeshifting && !Options.UseUnshiftTrigger.GetBool()) return true;
|
||||
|
||||
OnPet(shapeshifter);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnVanish(PlayerControl pc)
|
||||
{
|
||||
OnPet(pc);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnPet(PlayerControl pc)
|
||||
{
|
||||
UsingAbility = true;
|
||||
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(false);
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed);
|
||||
Main.PlayerStates.Values.DoIf(x => !x.IsDead, x => x.IsBlackOut = true);
|
||||
|
||||
int time = AbilityDuration.GetInt();
|
||||
|
||||
foreach (PlayerControl player in Main.AllPlayerControls)
|
||||
{
|
||||
if (!player.IsAlive() || player.PlayerId == pc.PlayerId || (player.Is(Team.Impostor) && !AffectsOtherImpostors.GetBool()))
|
||||
{
|
||||
ReportDeadBodyPatch.CanReport[player.PlayerId] = true;
|
||||
Main.AllPlayerSpeed[player.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
Main.PlayerStates[player.PlayerId].IsBlackOut = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Main.KillTimers[player.PlayerId] < time) player.SetKillCooldown(time);
|
||||
player.RpcResetAbilityCooldown();
|
||||
|
||||
if (!player.HasAbilityCD() && player.GetCustomRole().PetActivatedAbility())
|
||||
player.AddAbilityCD(time);
|
||||
}
|
||||
}
|
||||
|
||||
Utils.SyncAllSettings();
|
||||
Main.Instance.StartCoroutine(Countdown());
|
||||
return;
|
||||
|
||||
IEnumerator Countdown()
|
||||
{
|
||||
var imps = AffectsOtherImpostors.GetBool() ? [pc] : Main.AllAlivePlayerControls.Where(x => x.Is(Team.Impostor)).ToArray();
|
||||
|
||||
for (int i = 0; i < time; i++)
|
||||
{
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
imps.Do(x => x.Notify($"<#00ffa5>{Translator.GetString("Stasis.TimeFrozenNotify")}</color> <#888888>-</color> {time - i}", overrideAll: true));
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
|
||||
UsingAbility = false;
|
||||
imps.Do(x => x.Notify(Translator.GetString("Stasis.TimeFreezeEndNotify"), overrideAll: true));
|
||||
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod));
|
||||
Main.PlayerStates.Values.Do(x => x.IsBlackOut = false);
|
||||
Utils.SyncAllSettings();
|
||||
|
||||
pc.RpcResetAbilityCooldown();
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-19
@@ -10,34 +10,25 @@ namespace EHR.Neutral;
|
||||
public class Amogus : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
public static List<Amogus> Instances = [];
|
||||
private static List<Amogus> Instances = [];
|
||||
|
||||
private static OptionItem StartingLevel;
|
||||
private static OptionItem SugomaSpeed;
|
||||
private static OptionItem SuspiciousSusArrowsToBodies;
|
||||
private static OptionItem UltimateSusVotesPerKill;
|
||||
public static OptionItem AbilityCooldown;
|
||||
private static OptionItem AbilityDuration;
|
||||
public static OptionItem AbilityDuration;
|
||||
private static OptionItem KillCooldown;
|
||||
private static OptionItem CanVent;
|
||||
private static OptionItem ImpostorVision;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
enum Levels
|
||||
{
|
||||
Amogus,
|
||||
Sugoma,
|
||||
Sumogus,
|
||||
SuspiciousSus,
|
||||
UltimateSus
|
||||
}
|
||||
private long AmogusFormEndTS;
|
||||
|
||||
private byte AmogusID;
|
||||
private long AmogusFormEndTS;
|
||||
private Levels CurrentLevel;
|
||||
public int ExtraVotes;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(649075)
|
||||
@@ -107,9 +98,7 @@ public class Amogus : RoleBase
|
||||
public override void OnPet(PlayerControl pc)
|
||||
{
|
||||
if (CurrentLevel >= Levels.SuspiciousSus)
|
||||
{
|
||||
Main.AllAlivePlayerControls.Do(x => TargetArrow.Add(AmogusID, x.PlayerId));
|
||||
}
|
||||
|
||||
AmogusFormEndTS = Utils.TimeStamp + AbilityDuration.GetInt();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, AmogusID, 1, AmogusFormEndTS);
|
||||
@@ -135,6 +124,7 @@ public class Amogus : RoleBase
|
||||
if (!GameStates.IsInTask || ExileController.Instance || !pc.IsAlive()) return;
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
|
||||
if (AmogusFormEndTS != 0 && AmogusFormEndTS <= now)
|
||||
{
|
||||
FormExpired();
|
||||
@@ -146,7 +136,7 @@ public class Amogus : RoleBase
|
||||
{
|
||||
TargetArrow.RemoveAllTarget(AmogusID);
|
||||
LocateArrow.RemoveAllTarget(AmogusID);
|
||||
|
||||
|
||||
AmogusFormEndTS = 0;
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, AmogusID, 1, AmogusFormEndTS);
|
||||
}
|
||||
@@ -157,9 +147,8 @@ public class Amogus : RoleBase
|
||||
{
|
||||
CurrentLevel++;
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, AmogusID, 2, (int)CurrentLevel);
|
||||
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: killer);
|
||||
}
|
||||
|
||||
|
||||
switch (CurrentLevel)
|
||||
{
|
||||
case Levels.SuspiciousSus:
|
||||
@@ -167,6 +156,7 @@ public class Amogus : RoleBase
|
||||
break;
|
||||
case Levels.UltimateSus:
|
||||
ExtraVotes += UltimateSusVotesPerKill.GetInt();
|
||||
Utils.SendRPC(CustomRPC.SyncRoleData, AmogusID, 3, ExtraVotes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -200,6 +190,9 @@ public class Amogus : RoleBase
|
||||
case 2:
|
||||
CurrentLevel = (Levels)reader.ReadPackedInt32();
|
||||
break;
|
||||
case 3:
|
||||
ExtraVotes = reader.ReadPackedInt32();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +202,23 @@ public class Amogus : RoleBase
|
||||
|
||||
var sb = new StringBuilder();
|
||||
if (AmogusFormEndTS != 0) sb.Append($"\u25a9 ({Utils.TimeStamp - AmogusFormEndTS}s)\n");
|
||||
if (!hud) sb.Append("<size=70%>");
|
||||
sb.Append(string.Format(Translator.GetString("Amogus.Suffix"), Translator.GetString($"Amogus.Levels.{CurrentLevel}")));
|
||||
if (!hud) sb.Append("</size>");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override string GetProgressText(byte playerId, bool comms)
|
||||
{
|
||||
return $"{base.GetProgressText(playerId, comms)} {string.Format(Translator.GetString("ExtraVotesPT"), ExtraVotes)}";
|
||||
}
|
||||
|
||||
enum Levels
|
||||
{
|
||||
Amogus,
|
||||
Sugoma,
|
||||
Sumogus,
|
||||
SuspiciousSus,
|
||||
UltimateSus
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ public class NecroGuesser : RoleBase
|
||||
{
|
||||
public static bool On;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
private static OptionItem NumGuessesToWin;
|
||||
public static OptionItem NumGuessesToWin;
|
||||
|
||||
public int GuessedPlayers;
|
||||
|
||||
public override bool IsEnable => On;
|
||||
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(647125)
|
||||
|
||||
@@ -49,7 +49,7 @@ public class NoteKiller : RoleBase
|
||||
.AutoSetupOption(ref NumLettersRevealed, 2, new IntegerValueRule(1, Names.Max(x => x.Length), 1))
|
||||
.AutoSetupOption(ref ClueShowDuration, 5, new IntegerValueRule(0, 30, 1), OptionFormat.Seconds)
|
||||
.AutoSetupOption(ref WinCondition, 0, WinConditions)
|
||||
.AutoSetupOption(ref NumPlayersToKill, 2, new IntegerValueRule(0, 14, 1))
|
||||
.AutoSetupOption(ref NumPlayersToKill, 2, new IntegerValueRule(0, 14, 1), overrideParent: WinCondition)
|
||||
.AutoSetupOption(ref CanVent, true)
|
||||
.AutoSetupOption(ref ImpostorVision, true);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class Tank : RoleBase
|
||||
public override void SetupCustomOption()
|
||||
{
|
||||
StartSetup(646950)
|
||||
.AutoSetupOption(ref Speed, 0.7f, new FloatValueRule(0.1f, 3f, 0.1f), OptionFormat.Multiplier)
|
||||
.AutoSetupOption(ref Speed, 0.9f, new FloatValueRule(0.1f, 3f, 0.1f), OptionFormat.Multiplier)
|
||||
.AutoSetupOption(ref CanBeGuessed, false)
|
||||
.AutoSetupOption(ref CanBeKilled, true)
|
||||
.AutoSetupOption(ref VentCooldown, 15f, new FloatValueRule(0f, 60f, 0.5f), OptionFormat.Seconds);
|
||||
@@ -77,4 +77,9 @@ public class Tank : RoleBase
|
||||
string randomVentName = ShipStatus.Instance?.AllVents?.FirstOrDefault(x => x.Id == AllVents.Except(EnteredVents).FirstOrDefault())?.name ?? string.Empty;
|
||||
return randomVentName == string.Empty ? string.Empty : string.Format(Translator.GetString("Tank.Suffix"), randomVentName);
|
||||
}
|
||||
|
||||
public override bool CanUseVent(PlayerControl pc, int ventId)
|
||||
{
|
||||
return !IsThisRole(pc) || (!EnteredVents.Contains(ventId) && pc.GetClosestVent()?.Id == ventId);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class Vulture : RoleBase
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Vulture]);
|
||||
|
||||
ChangeRole = new StringOptionItem(Id + 17, "VultureChangeRole", ChangeRoles.Select(x => x.ToColoredString()).ToArray(), 0, TabGroup.NeutralRoles, noTranslation: true)
|
||||
.SetParent(CustomRoleSpawnChances[CustomRoles.Vulture]);
|
||||
.SetParent(ChangeRoleWhenCantWin);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
|
||||
@@ -108,6 +108,7 @@ public class Main : BasePlugin
|
||||
public static string FirstDied = string.Empty;
|
||||
public static string ShieldPlayer = string.Empty;
|
||||
|
||||
public static Dictionary<CustomGameMode, Dictionary<string, int>> NumWinsPerGM = [];
|
||||
public static HashSet<byte> DiedThisRound = [];
|
||||
public static List<PlayerControl> LoversPlayers = [];
|
||||
public static bool IsLoversDead = true;
|
||||
@@ -740,9 +741,9 @@ public class Main : BasePlugin
|
||||
try
|
||||
{
|
||||
AllRoleClasses.AddRange(Assembly.GetAssembly(typeof(RoleBase))!
|
||||
.GetTypes()
|
||||
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(RoleBase)))
|
||||
.Select(t => (RoleBase)Activator.CreateInstance(t, null)));
|
||||
.GetTypes()
|
||||
.Where(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(typeof(RoleBase)))
|
||||
.Select(t => (RoleBase)Activator.CreateInstance(t, null)));
|
||||
|
||||
AllRoleClasses.Sort();
|
||||
}
|
||||
@@ -957,4 +958,4 @@ public enum TieMode
|
||||
Random
|
||||
}
|
||||
|
||||
public class Coroutines : MonoBehaviour { }
|
||||
public class Coroutines : MonoBehaviour { }
|
||||
Reference in new issue
Block a user