cancel vanish, inform about version mismatch, add missing strings, add new role Stasis, fix some bugs & improvements

This commit is contained in:
Gurge44 committed 2024-12-13 22:36:32 +01:00
1 parent 5c08f79c0a
commit f8090f2e0e
27 files changed
+418 -187

No files matched your search

+2
View File
@@ -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,
+1
View File
@@ -91,6 +91,7 @@ public enum CustomRoles
Silencer,
Sniper,
ImperiusCurse, // Soul Catcher
Stasis,
Swapster,
Swiftclaw,
Swooper,
+1 -1
View File
@@ -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);
+5 -1
View File
@@ -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
}
}
+1 -6
View File
@@ -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()
-3
View File
@@ -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
View File
@@ -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"); }
}
}
+5
View File
@@ -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
View File
@@ -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);
+14 -8
View File
@@ -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));
}
}
+19 -15
View File
@@ -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;
+14 -3
View File
@@ -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
View File
@@ -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());
+9 -1
View File
@@ -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
View File
@@ -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)
+2 -15
View File
@@ -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
{
+3 -1
View File
@@ -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
+28 -6
View File
@@ -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
View File
@@ -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;
}
+135
View File
@@ -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
View File
@@ -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
}
}
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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);
}
+6 -1
View File
@@ -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);
}
}
+1 -1
View File
@@ -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()
+5 -4
View File
@@ -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 { }