diff --git a/Strings.xlsx b/Strings.xlsx index 23bcd61..a1f8477 100644 Binary files a/Strings.xlsx and b/Strings.xlsx differ diff --git a/TheOtherRoles/Buttons.cs b/TheOtherRoles/Buttons.cs index 9a42890..133a0df 100644 --- a/TheOtherRoles/Buttons.cs +++ b/TheOtherRoles/Buttons.cs @@ -1682,7 +1682,7 @@ public static void createButtonsPostfix(HudManager __instance) { Helpers.checkMurderAttemptAndKill(Veteran.veteran, Eraser.eraser); return; } - eraserButton.MaxTimer += 10; + eraserButton.MaxTimer += Eraser.cooldownIncrease; eraserButton.Timer = eraserButton.MaxTimer; _ = new StaticAchievementToken("eraser.common1"); @@ -1750,40 +1750,7 @@ public static void createButtonsPostfix(HudManager __instance) { SoundEffectsManager.play("moriartyBrainwash"); // 洗脳終了までのカウントダウン - TMPro.TMP_Text text; - RoomTracker roomTracker = HudManager.Instance?.roomTracker; - GameObject gameObject = UnityEngine.Object.Instantiate(roomTracker.gameObject); - UnityEngine.Object.DestroyImmediate(gameObject.GetComponent()); - gameObject.transform.SetParent(HudManager.Instance.transform); - gameObject.transform.localPosition = new Vector3(0, -1.3f, gameObject.transform.localPosition.z); - gameObject.transform.localScale = Vector3.one * 3f; - text = gameObject.GetComponent(); - PlayerControl tmpP = Moriarty.target; - bool done = false; - HudManager.Instance.StartCoroutine(Effects.Lerp(Moriarty.brainwashTime, new Action((p) => - { - if (done) - { - return; - } - if (Moriarty.target == null || MeetingHud.Instance != null || p == 1f) - { - if (text != null && text.gameObject) UnityEngine.Object.Destroy(text.gameObject); - if (Moriarty.target == tmpP) Moriarty.target = null; - done = true; - return; - } - else - { - string message = (Moriarty.brainwashTime - (p * Moriarty.brainwashTime)).ToString("0"); - bool even = ((int)(p * Moriarty.brainwashTime / 0.25f)) % 2 == 0; // Bool flips every 0.25 seconds - // string prefix = even ? "" : ""; - string prefix = ""; - text.text = prefix + message + ""; - if (text != null) text.color = even ? Color.yellow : Color.red; - - } - }))); + Moriarty.generateBrainwashText(); } Moriarty.tmpTarget = null; moriartyBrainwashButton.Timer = moriartyBrainwashButton.MaxTimer; @@ -1823,6 +1790,7 @@ public static void createButtonsPostfix(HudManager __instance) { { moriartyKillCounterText.text = $"{Moriarty.counter}/{Moriarty.numberToWin}"; } + moriartyKillButton.buttonText = Moriarty.killTarget ? Moriarty.killTarget.Data.PlayerName : ModTranslation.getString("moriartyTargetNone"); return Moriarty.killTarget != null && CachedPlayer.LocalPlayer.PlayerControl.CanMove; }, // OnMeetingEnds @@ -1836,7 +1804,8 @@ public static void createButtonsPostfix(HudManager __instance) { CustomButton.ButtonPositions.upperRowRight, __instance, KeyCode.Q, - actionName: FastDestroyableSingleton.Instance.GetString(StringNames.KillLabel).camelString() + actionName: FastDestroyableSingleton.Instance.GetString(StringNames.KillLabel).camelString(), + buttonText: ModTranslation.getString("moriartyTargetNone") ); moriartyKillCounterText = GameObject.Instantiate(moriartyKillButton.actionButton.cooldownTimerText, moriartyKillButton.actionButton.cooldownTimerText.transform.parent); moriartyKillCounterText.text = ""; @@ -3049,7 +3018,8 @@ public static void createButtonsPostfix(HudManager __instance) { KeyCode.H, false, FastDestroyableSingleton.Instance.GetString(StringNames.Admin), - actionName: FastDestroyableSingleton.Instance.GetString(StringNames.Admin).camelString() + actionName: FastDestroyableSingleton.Instance.GetString(StringNames.Admin).camelString(), + abilityTexture: CustomButton.ButtonLabelType.AdminButton ); // Ninja Stealth @@ -3701,7 +3671,7 @@ Func fortuneTellerCouldUse(byte index) int adjustedIndex = index < CachedPlayer.LocalPlayer.PlayerId ? index : index - 1; // 占い師以外の場合、リソースがない場合はボタンを表示しない if (!TORMapOptions.playerIcons.ContainsKey(index) || - !CachedPlayer.LocalPlayer.PlayerControl == FortuneTeller.fortuneTeller || + CachedPlayer.LocalPlayer.PlayerControl != FortuneTeller.fortuneTeller || CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead || CachedPlayer.LocalPlayer.PlayerControl.PlayerId == index || !FortuneTeller.isCompletedNumTasks(FortuneTeller.fortuneTeller) || diff --git a/TheOtherRoles/CustomGameModes/FreePlayGM.cs b/TheOtherRoles/CustomGameModes/FreePlayGM.cs index a8d9af9..4fcf0ec 100644 --- a/TheOtherRoles/CustomGameModes/FreePlayGM.cs +++ b/TheOtherRoles/CustomGameModes/FreePlayGM.cs @@ -86,6 +86,8 @@ void SetWidget(int tab) } else if (formerRole.roleId is RoleId.Fox or RoleId.JekyllAndHyde or RoleId.TaskMaster) { var options = GameOptionsManager.Instance.currentNormalGameOptions; PlayerControl.LocalPlayer.generateAndAssignTasks(options.NumCommonTasks, options.NumShortTasks, options.NumLongTasks); + } else if (r.roleId == RoleId.FortuneTeller) { + FortuneTeller.meetingFlag = false; } RPCProcedure.resetAchievement(); roleScreen.CloseScreen(); diff --git a/TheOtherRoles/CustomOptionHolder.cs b/TheOtherRoles/CustomOptionHolder.cs index f69c487..6a678d1 100644 --- a/TheOtherRoles/CustomOptionHolder.cs +++ b/TheOtherRoles/CustomOptionHolder.cs @@ -1,5 +1,6 @@ using Epic.OnlineServices.RTCAudio; using System.Collections.Generic; +using System.Linq; using UnityEngine; using static TheOtherRoles.TheOtherRoles; using Types = TheOtherRoles.CustomOption.CustomOptionType; @@ -44,7 +45,9 @@ public class CustomOptionHolder { public static CustomOption eraserSpawnRate; public static CustomOption eraserCooldown; + public static CustomOption eraserCooldownIncrease; public static CustomOption eraserCanEraseAnyone; + public static CustomOption guesserSpawnRate; public static CustomOption guesserIsImpGuesserRate; public static CustomOption guesserNumberOfShots; @@ -518,7 +521,9 @@ public class CustomOptionHolder { public static CustomOption modifierChameleonMinVisibility; public static CustomOption madmateSpawnRate; - public static CustomOption madmateQuantity; + public static CustomOption madmateQuantity; + public static CustomOption madmateFixedRole; + public static CustomOption madmateFixedRoleGuesserGamemode; public static CustomOption madmateCanDieToSheriff; public static CustomOption madmateCanEnterVents; public static CustomOption madmateCanSabotage; @@ -660,6 +665,7 @@ public static void Load() { eraserSpawnRate = CustomOption.Create(230, Types.Impostor, cs(Eraser.color, "eraser"), rates, null, true); eraserCooldown = CustomOption.Create(231, Types.Impostor, "eraserCooldown", 30f, 10f, 120f, 5f, eraserSpawnRate, false, "unitSeconds"); + eraserCooldownIncrease = CustomOption.Create(233, Types.Impostor, "eraserCooldownIncrease", 10f, 0f, 120f, 2.5f, eraserSpawnRate, format: "unitSeconds"); eraserCanEraseAnyone = CustomOption.Create(232, Types.Impostor, "eraserCanEraseAnyone", false, eraserSpawnRate); tricksterSpawnRate = CustomOption.Create(250, Types.Impostor, cs(Trickster.color, "trickster"), rates, null, true); @@ -1136,6 +1142,8 @@ public static void Load() { madmateSpawnRate = CustomOption.Create(4041, Types.Modifier, cs(Color.yellow, "madmate"), rates, null, true); madmateQuantity = CustomOption.Create(7005, Types.Modifier, cs(Color.yellow, "madmateQuantity"), ratesModifier, madmateSpawnRate); + madmateFixedRole = CustomOption.Create(7006, Types.Modifier, "madmateFixedRole", Madmate.validRoles, madmateSpawnRate); + madmateFixedRoleGuesserGamemode = CustomOption.Create(7007, Types.Modifier, "madmateFixedRole", Madmate.validRoles.Where(x => x != RoleId.NiceGuesser).ToList(), madmateSpawnRate); madmateAbility = CustomOption.Create(4047, Types.Modifier, "madmateAbility", true, madmateSpawnRate); madmateCommonTasks = CustomOption.Create(4049, Types.Modifier, "madmateCommonTasks", 1f, 0f, 3f, 1f, madmateAbility, false, "unitScrews"); madmateShortTasks = CustomOption.Create(4048, Types.Modifier, "madmateShortTasks", 3f, 0f, 4f, 1f, madmateAbility, false, "unitScrews"); @@ -1214,10 +1222,10 @@ public static void Load() { fungleElectrical = CustomOption.Create(6074, Types.General, "fungleElectrical", false); randomGameStartPosition = CustomOption.Create(6071, Types.General, "randomGameStartPosition", false); activateProps = CustomOption.Create(6083, Types.General, "activateProps", false, null, true, heading: "headingPropSetting"); - numAccelTraps = CustomOption.Create(6084, Types.General, "numAccelTraps", 1f, 1f, 5f, 1f, activateProps, false, "unitScrews"); + numAccelTraps = CustomOption.Create(6084, Types.General, "numAccelTraps", 1f, 0f, 5f, 1f, activateProps, false, "unitScrews"); accelerationDuration = CustomOption.Create(6085, Types.General, "accelerationDuration", 5f, 1f, 20f, 1f, activateProps, false, "unitSeconds"); speedAcceleration = CustomOption.Create(6086, Types.General, "speedAcceleration", 1.25f, 0.5f, 2f, 0.25f, activateProps, false, "unitTimes"); - numDecelTraps = CustomOption.Create(6087, Types.General, "numDecelTraps", 1f, 1f, 3f, 1f, activateProps, false, "unitScrews"); + numDecelTraps = CustomOption.Create(6087, Types.General, "numDecelTraps", 1f, 0f, 3f, 1f, activateProps, false, "unitScrews"); decelerationDuration = CustomOption.Create(6091, Types.General, "decelerationDuration", 5f, 1f, 20f, 1f, activateProps, false, "unitSeconds"); speedDeceleration = CustomOption.Create(6089, Types.General, "speedDeceleration", -0.5f, -0.8f, -0.1f, 0.1f, activateProps, false, "unitTimes"); decelUpdateInterval = CustomOption.Create(6090, Types.General, "decelUpdateInterval", 10f, 5f, 60f, 2.5f, activateProps, false, "unitSeconds"); diff --git a/TheOtherRoles/Helpers.cs b/TheOtherRoles/Helpers.cs index 8eb9836..6bf008b 100644 --- a/TheOtherRoles/Helpers.cs +++ b/TheOtherRoles/Helpers.cs @@ -198,7 +198,7 @@ public static string GradientColorText(string startColorHex, string endColorHex, public static Color HexToColor(string hex) { Color color = new(); - ColorUtility.TryParseHtmlString("#" + hex, out color); + _ = ColorUtility.TryParseHtmlString("#" + hex, out color); return color; } @@ -330,7 +330,7 @@ public static bool isLighterColor(int colorId) { public static bool isCustomServer() { if (FastDestroyableSingleton.Instance == null) return false; StringNames n = FastDestroyableSingleton.Instance.CurrentRegion.TranslateName; - return n != StringNames.ServerNA && n != StringNames.ServerEU && n != StringNames.ServerAS; + return n is not StringNames.ServerNA and not StringNames.ServerEU and not StringNames.ServerAS; } static public int[] Sequential(int length) @@ -372,17 +372,17 @@ public static int GetDisplayType(int players) } public static bool hasFakeTasks(this PlayerControl player) { - return (player == Jester.jester || player == Jackal.jackal || player == Sidekick.sidekick || player == Arsonist.arsonist || player == Opportunist.opportunist || player == Vulture.vulture || Jackal.formerJackals.Any(x => x == player) || player == Moriarty.moriarty || player == Moriarty.formerMoriarty + return player == Jester.jester || player == Jackal.jackal || player == Sidekick.sidekick || player == Arsonist.arsonist || player == Opportunist.opportunist || player == Vulture.vulture || Jackal.formerJackals.Any(x => x == player) || player == Moriarty.moriarty || player == Moriarty.formerMoriarty || (Madmate.madmate.Any(x => x.PlayerId == player.PlayerId) && !Madmate.hasTasks) || - (player == CreatedMadmate.createdMadmate && !CreatedMadmate.hasTasks) || player == Akujo.akujo || player == Kataomoi.kataomoi || player == PlagueDoctor.plagueDoctor || player == JekyllAndHyde.formerJekyllAndHyde || player == Cupid.cupid || (player == SchrodingersCat.schrodingersCat && !SchrodingersCat.hideRole)); + (player == CreatedMadmate.createdMadmate && !CreatedMadmate.hasTasks) || player == Akujo.akujo || player == Kataomoi.kataomoi || player == PlagueDoctor.plagueDoctor || player == JekyllAndHyde.formerJekyllAndHyde || player == Cupid.cupid || (player == SchrodingersCat.schrodingersCat && !SchrodingersCat.hideRole); } public static bool canBeErased(this PlayerControl player) { - return (player != Jackal.jackal && player != Sidekick.sidekick && !Jackal.formerJackals.Any(x => x == player)); + return player != Jackal.jackal && player != Sidekick.sidekick && !Jackal.formerJackals.Any(x => x == player); } public static bool shouldShowGhostInfo() { - return CachedPlayer.LocalPlayer.PlayerControl != null && CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && !(CachedPlayer.LocalPlayer.PlayerControl == Busker.busker && Busker.pseudocideFlag) && TORMapOptions.ghostsSeeInformation || AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Ended; + return (CachedPlayer.LocalPlayer.PlayerControl != null && CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && !(CachedPlayer.LocalPlayer.PlayerControl == Busker.busker && Busker.pseudocideFlag) && TORMapOptions.ghostsSeeInformation) || AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Ended; } public static void clearAllTasks(this PlayerControl player) { @@ -447,8 +447,8 @@ public static string camelString(this string input) if (string.IsNullOrEmpty(input)) return input; - string firstLetter = input.Substring(0, 1).ToUpper(); - string remainingLetters = input.Substring(1).ToLower(); + string firstLetter = input[..1].ToUpper(); + string remainingLetters = input[1..].ToLower(); return firstLetter + remainingLetters; } @@ -600,7 +600,7 @@ private static IEnumerator AnimateCoroutine(HideAndSeekDeathPopup __instance) while (true) { AnimatorStateInfo animatorStateInfo = andSeekDeathPopup.animator.GetCurrentAnimatorStateInfo(0); - if ((animatorStateInfo).IsName("Show")) + if (animatorStateInfo.IsName("Show")) { if (doNeedReduceSpeed && DateTime.UtcNow.Subtract(startTime).TotalSeconds >= 0.5) { @@ -836,9 +836,8 @@ public static float sabotageTimer() public static bool canUseSabotage() { var sabSystem = ShipStatus.Instance.Systems[SystemTypes.Sabotage].CastFast(); - ISystemType systemType; IActivatable doors = null; - if (ShipStatus.Instance.Systems.TryGetValue(SystemTypes.Doors, out systemType)) + if (ShipStatus.Instance.Systems.TryGetValue(SystemTypes.Doors, out ISystemType systemType)) { doors = systemType.CastFast(); } @@ -950,7 +949,7 @@ public static bool hidePlayerName(PlayerControl source, PlayerControl target) { else if (!TORMapOptions.hidePlayerNames) return false; // All names are visible else if (source == null || target == null) return true; else if (source == target) return false; // Player sees his own name - else if (source.Data.Role.IsImpostor && (target.Data.Role.IsImpostor || target == Spy.spy || target == Sidekick.sidekick && Sidekick.wasTeamRed || target == Jackal.jackal && Jackal.wasTeamRed)) return false; // Members of team Impostors see the names of Impostors/Spies + else if (source.Data.Role.IsImpostor && (target.Data.Role.IsImpostor || target == Spy.spy || (target == Sidekick.sidekick && Sidekick.wasTeamRed) || (target == Jackal.jackal && Jackal.wasTeamRed))) return false; // Members of team Impostors see the names of Impostors/Spies else if ((source == Lovers.lover1 || source == Lovers.lover2) && (target == Lovers.lover1 || target == Lovers.lover2)) return false; // Members of team Lovers see the names of each other else if ((source == Jackal.jackal || source == Sidekick.sidekick) && (target == Jackal.jackal || target == Sidekick.sidekick || target == Jackal.fakeSidekick)) return false; // Members of team Jackal see the names of each other else if (Deputy.knowsSheriff && (source == Sheriff.sheriff || source == Deputy.deputy) && (target == Sheriff.sheriff || target == Deputy.deputy)) return false; // Sheriff & Deputy see the names of each other @@ -1197,7 +1196,7 @@ public static PlainShipRoom getPlainShipRoom(PlayerControl p) { PlainShipRoom[] array = null; Il2CppReferenceArray buffer = new Collider2D[10]; - ContactFilter2D filter = default(ContactFilter2D); + ContactFilter2D filter = default; filter.layerMask = Constants.PlayersOnlyMask; filter.useLayerMask = true; filter.useTriggers = false; @@ -1537,7 +1536,7 @@ public static async Task checkBeta() { public static bool hasImpVision(NetworkedPlayerInfo player) { return player.Role.IsImpostor - || ((Jackal.jackal != null && Jackal.jackal.PlayerId == player.PlayerId || Jackal.formerJackals.Any(x => x.PlayerId == player.PlayerId)) && Jackal.hasImpostorVision) + || (((Jackal.jackal != null && Jackal.jackal.PlayerId == player.PlayerId) || Jackal.formerJackals.Any(x => x.PlayerId == player.PlayerId)) && Jackal.hasImpostorVision) || (Sidekick.sidekick != null && Sidekick.sidekick.PlayerId == player.PlayerId && Sidekick.hasImpostorVision) || (Spy.spy != null && Spy.spy.PlayerId == player.PlayerId && Spy.hasImpostorVision) || (Jester.jester != null && Jester.jester.PlayerId == player.PlayerId && Jester.hasImpostorVision) diff --git a/TheOtherRoles/MapOptions.cs b/TheOtherRoles/MapOptions.cs index ba5b581..f9a213a 100644 --- a/TheOtherRoles/MapOptions.cs +++ b/TheOtherRoles/MapOptions.cs @@ -58,5 +58,11 @@ public static void reloadPluginOptions() { ShowChatNotifications = TheOtherRolesPlugin.ShowChatNotifications.Value; //Patches.ShouldAlwaysHorseAround.isHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value; } + + public static void resetPoolables() { + foreach (PoolablePlayer p in playerIcons.Values) { + if (p != null && p.gameObject != null) p.gameObject.SetActive(false); + } + } } } diff --git a/TheOtherRoles/Modules/CustomOptions.cs b/TheOtherRoles/Modules/CustomOptions.cs index 589e623..e19fc58 100644 --- a/TheOtherRoles/Modules/CustomOptions.cs +++ b/TheOtherRoles/Modules/CustomOptions.cs @@ -85,6 +85,11 @@ public static CustomOption Create(int id, CustomOptionType type, string name, bo return new CustomOption(id, type, name, new string[]{ "optionOff", "optionOn" }, defaultValue ? "optionOn" : "optionOff", parent, isHeader, format, heading); } + public static CustomOption Create(int id, CustomOptionType type, string name, List roleId, CustomOption parent = null, bool isHeader = false) { + return new CustomOption(id, type, name, roleId.Select(x => x == RoleId.Jester ? "optionOff" : RoleInfo.allRoleInfos.FirstOrDefault(y => y.roleId == x + && y.color != Palette.ImpostorRed && !y.isNeutral).nameKey).ToArray(), 0, parent, isHeader, ""); + } + // Static behaviour public static void switchPreset(int newPreset) { @@ -501,7 +506,10 @@ public static void drawTab(LobbyViewSettingsPane __instance, CustomOptionType op } if (TORMapOptions.gameMode == CustomGamemodes.Guesser) // Exclude guesser options in neutral mode - relevantOptions = relevantOptions.Where(x => !(new List { 310, 311, 312, 313, 314, 315, 316, 317, 318 }).Contains(x.id)).ToList(); + relevantOptions = relevantOptions.Where(x => !(new List { 310, 311, 312, 313, 314, 315, 316, 317, 318, 7006 }).Contains(x.id)).ToList(); + else + relevantOptions = relevantOptions.Where(x => x.id != 7007).ToList(); + if (TORMapOptions.gameMode != CustomGamemodes.FreePlay) relevantOptions = relevantOptions.Where(x => x.id != 10424).ToList(); @@ -975,7 +983,10 @@ public static void createGameOptionsMenu(GameSettingMenu __instance, CustomOptio torSettingsGOM.Children.Clear(); var relevantOptions = options.Where(x => x.type == optionType).ToList(); if (TORMapOptions.gameMode == CustomGamemodes.Guesser) // Exclude guesser options in neutral mode - relevantOptions = relevantOptions.Where(x => !(new List { 310, 311, 312, 313, 314, 315, 316, 317, 318 }).Contains(x.id)).ToList(); + relevantOptions = relevantOptions.Where(x => !(new List { 310, 311, 312, 313, 314, 315, 316, 317, 318, 7006 }).Contains(x.id)).ToList(); + else + relevantOptions = relevantOptions.Where(x => x.id != 7007).ToList(); + if (TORMapOptions.gameMode != CustomGamemodes.FreePlay) relevantOptions = relevantOptions.Where(x => x.id != 10424).ToList(); createSettings(torSettingsGOM, relevantOptions); @@ -1119,10 +1130,10 @@ private static string buildOptionsOfType(CustomOption.CustomOptionType type, boo if (TORMapOptions.gameMode == CustomGamemodes.Guesser) { if (type == CustomOption.CustomOptionType.General) options = CustomOption.options.Where(o => o.type == type || o.type == CustomOption.CustomOptionType.Guesser); - List remove = new() { 308, 310, 311, 312, 313, 314, 315, 316, 317, 318 }; + List remove = new() { 308, 310, 311, 312, 313, 314, 315, 316, 317, 318, 7006 }; options = options.Where(x => !remove.Contains(x.id)); } else if (TORMapOptions.gameMode == CustomGamemodes.Classic) - options = options.Where(x => !(x.type == CustomOption.CustomOptionType.Guesser || x == CustomOptionHolder.crewmateRolesFill)); + options = options.Where(x => !(x.type == CustomOption.CustomOptionType.Guesser || x == CustomOptionHolder.crewmateRolesFill || x.id == 7007)); else if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) options = options.Where(x => (x.type == CustomOption.CustomOptionType.HideNSeekMain || x.type == CustomOption.CustomOptionType.HideNSeekRoles)); if (TORMapOptions.gameMode != CustomGamemodes.FreePlay) diff --git a/TheOtherRoles/Patches/ExileControllerPatch.cs b/TheOtherRoles/Patches/ExileControllerPatch.cs index 2ba9f9e..7fff7aa 100644 --- a/TheOtherRoles/Patches/ExileControllerPatch.cs +++ b/TheOtherRoles/Patches/ExileControllerPatch.cs @@ -387,6 +387,7 @@ static void WrapUpPostfix(NetworkedPlayerInfo exiled) TORMapOptions.playerIcons[p.PlayerId].gameObject.SetActive(false); } else { TORMapOptions.playerIcons[p.PlayerId].transform.localPosition = newBottomLeft + Vector3.right * visibleCounter * 0.35f; + TORMapOptions.playerIcons[p.PlayerId].gameObject.SetActive(true); visibleCounter++; } } diff --git a/TheOtherRoles/Patches/IntroPatch.cs b/TheOtherRoles/Patches/IntroPatch.cs index 6e59382..061e074 100644 --- a/TheOtherRoles/Patches/IntroPatch.cs +++ b/TheOtherRoles/Patches/IntroPatch.cs @@ -50,10 +50,6 @@ public static void Prefix(IntroCutscene __instance) { player.transform.localScale = Vector3.one * 0.2f; player.setSemiTransparent(true); player.gameObject.SetActive(true); - } else if (CachedPlayer.LocalPlayer.PlayerControl == Kataomoi.kataomoi && p == Kataomoi.target) { - player.transform.localPosition = bottomLeft + new Vector3(-0.25f, 0f, 0); - player.transform.localScale = Vector3.one * 0.4f; - player.gameObject.SetActive(true); } else if (HideNSeek.isHideNSeekGM) { if (HideNSeek.isHunted() && p.Data.Role.IsImpostor) { player.transform.localPosition = bottomLeft + new Vector3(-0.25f, 0.4f, 0) + Vector3.right * playerCounter++ * 0.6f; @@ -76,14 +72,14 @@ public static void Prefix(IntroCutscene __instance) { } // Force Bounty Hunter to load a new Bounty when the Intro is over - if (BountyHunter.bounty != null && CachedPlayer.LocalPlayer.PlayerControl == BountyHunter.bountyHunter) { - BountyHunter.bountyUpdateTimer = 0f; + if (BountyHunter.bounty != null) { + if (CachedPlayer.LocalPlayer.PlayerControl == BountyHunter.bountyHunter) BountyHunter.bountyUpdateTimer = 0f; if (FastDestroyableSingleton.Instance != null) { BountyHunter.cooldownText = UnityEngine.Object.Instantiate(FastDestroyableSingleton.Instance.KillButton.cooldownTimerText, FastDestroyableSingleton.Instance.transform); BountyHunter.cooldownText.alignment = TMPro.TextAlignmentOptions.Center; BountyHunter.cooldownText.transform.localPosition = bottomLeft + new Vector3(0f, -0.35f, -62f); BountyHunter.cooldownText.transform.localScale = Vector3.one * 0.4f; - BountyHunter.cooldownText.gameObject.SetActive(true); + BountyHunter.cooldownText.gameObject.SetActive(CachedPlayer.LocalPlayer.PlayerControl == BountyHunter.bountyHunter); } } @@ -321,15 +317,15 @@ public static void Prefix(IntroCutscene __instance) { GameStatistics.MinimapPrefab = ShipStatus.Instance.MapPrefab; GameStatistics.MapScale = ShipStatus.Instance.MapScale; - if (Kataomoi.kataomoi != null && CachedPlayer.LocalPlayer.PlayerControl == Kataomoi.kataomoi) + if (Kataomoi.kataomoi != null) { if (FastDestroyableSingleton.Instance != null) { Kataomoi.stareText = UnityEngine.Object.Instantiate(FastDestroyableSingleton.Instance.KillButton.cooldownTimerText, FastDestroyableSingleton.Instance.transform); Kataomoi.stareText.alignment = TMPro.TextAlignmentOptions.Center; - Kataomoi.stareText.transform.localPosition = bottomLeft + new Vector3(-0.25f, -0.35f, -62f); + Kataomoi.stareText.transform.localPosition = bottomLeft + new Vector3(0f, -0.35f, -62f); Kataomoi.stareText.transform.localScale = Vector3.one * 0.5f; - Kataomoi.stareText.gameObject.SetActive(true); + Kataomoi.stareText.gameObject.SetActive(CachedPlayer.LocalPlayer.PlayerControl == Kataomoi.kataomoi); Kataomoi.gaugeRenderer[0] = UnityEngine.Object.Instantiate(FastDestroyableSingleton.Instance.KillButton.graphic, FastDestroyableSingleton.Instance.transform); var killButton = Kataomoi.gaugeRenderer[0].GetComponent(); @@ -366,6 +362,8 @@ public static void Prefix(IntroCutscene __instance) { Kataomoi.gaugeRenderer[2].transform.localScale = Vector3.one; Kataomoi.gaugeTimer = 1.0f; + + for (int i = 0; i < 3; i++) if (Kataomoi.gaugeRenderer[i] != null) Kataomoi.gaugeRenderer[i].gameObject.SetActive(false); } } diff --git a/TheOtherRoles/Patches/MapBehaviourPatch.cs b/TheOtherRoles/Patches/MapBehaviourPatch.cs index 4dd4fe3..ec7cc91 100644 --- a/TheOtherRoles/Patches/MapBehaviourPatch.cs +++ b/TheOtherRoles/Patches/MapBehaviourPatch.cs @@ -142,7 +142,7 @@ static void Postfix(MapBehaviour __instance) { { targetHerePoint = GameObject.Instantiate(__instance.HerePoint, __instance.HerePoint.transform.parent); } - targetHerePoint.gameObject.SetActive(!EvilTracker.target.Data.IsDead); + targetHerePoint.gameObject.SetActive(!EvilTracker.target.Data.IsDead && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead); NetworkedPlayerInfo playerById = GameData.Instance.GetPlayerById(EvilTracker.target.PlayerId); PlayerMaterial.SetColors((playerById != null) ? playerById.DefaultOutfit.ColorId : 0, targetHerePoint); Vector3 pos = new(EvilTracker.target.transform.position.x, EvilTracker.target.transform.position.y, EvilTracker.target.transform.position.z); @@ -154,7 +154,7 @@ static void Postfix(MapBehaviour __instance) { else UnityEngine.Object.Destroy(targetHerePoint); // Use the red icons to indicate the Impostors' positions - if (impostorHerePoint == null) impostorHerePoint = new(); + impostorHerePoint ??= new(); foreach (PlayerControl p in CachedPlayer.AllPlayers) { if ((p.Data.Role.IsImpostor && p != CachedPlayer.LocalPlayer.PlayerControl) || (Spy.spy != null && p == Spy.spy) || (p == Sidekick.sidekick && Sidekick.wasTeamRed) @@ -164,7 +164,7 @@ static void Postfix(MapBehaviour __instance) { { impostorHerePoint[p.PlayerId] = GameObject.Instantiate(__instance.HerePoint, __instance.HerePoint.transform.parent); } - impostorHerePoint[p.PlayerId].gameObject.SetActive(!p.Data.IsDead && MeetingHud.Instance == null); + impostorHerePoint[p.PlayerId].gameObject.SetActive(!p.Data.IsDead && MeetingHud.Instance == null && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead); NetworkedPlayerInfo playerById = GameData.Instance.GetPlayerById(p.PlayerId); PlayerMaterial.SetColors(0, impostorHerePoint[p.PlayerId]); Vector3 pos = new(p.transform.position.x, p.transform.position.y, p.transform.position.z); diff --git a/TheOtherRoles/Patches/PlayerControlPatch.cs b/TheOtherRoles/Patches/PlayerControlPatch.cs index 755c53e..b7f9092 100644 --- a/TheOtherRoles/Patches/PlayerControlPatch.cs +++ b/TheOtherRoles/Patches/PlayerControlPatch.cs @@ -510,17 +510,14 @@ public static void kataomoiSetTarget() static void kataomoiUpdate() { - if (Kataomoi.kataomoi != CachedPlayer.LocalPlayer.PlayerControl) return; - + if (Kataomoi.kataomoi != CachedPlayer.LocalPlayer.PlayerControl || Kataomoi.target == null) return; + TORMapOptions.resetPoolables(); if (Kataomoi.kataomoi.Data.IsDead) { if (Kataomoi.arrow != null) UnityEngine.Object.Destroy(Kataomoi.arrow.arrow); Kataomoi.arrow = null; if (Kataomoi.stareText != null && Kataomoi.stareText.gameObject != null) UnityEngine.Object.Destroy(Kataomoi.stareText.gameObject); Kataomoi.stareText = null; - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } for (int i = 0; i < Kataomoi.gaugeRenderer.Length; ++i) { if (Kataomoi.gaugeRenderer[i] != null) { @@ -534,14 +531,26 @@ static void kataomoiUpdate() // Update Stare Count Text if (Kataomoi.stareText != null) { + Kataomoi.stareText.gameObject.SetActive(true); if (Kataomoi.stareCount > 0) Kataomoi.stareText.text = $"{Kataomoi.stareCount}"; else Kataomoi.stareText.text = ""; } + if (Kataomoi.target != null && TORMapOptions.playerIcons.ContainsKey(Kataomoi.target?.PlayerId ?? byte.MaxValue)) { + TORMapOptions.playerIcons[Kataomoi.target.PlayerId].gameObject.SetActive(true); + } + for (int i = 0; i < Kataomoi.gaugeRenderer.Length; ++i) + { + if (Kataomoi.gaugeRenderer[i] != null) + { + Kataomoi.gaugeRenderer[i].gameObject?.SetActive(!MeetingHud.Instance); + } + } + // Update Arrow - if (Kataomoi.arrow == null) Kataomoi.arrow = new Arrow(Kataomoi.color); + Kataomoi.arrow ??= new Arrow(Kataomoi.color); Kataomoi.arrow.arrow.SetActive(Kataomoi.isSearch); if (Kataomoi.isSearch && Kataomoi.target != null) { @@ -858,15 +867,15 @@ static void trackerUpdate() { } } - if (Tracker.trackingMode == 1 || Tracker.trackingMode == 2) Arrow.UpdateProximity(position); - if (Tracker.trackingMode == 0 || Tracker.trackingMode == 2) + if (Tracker.trackingMode is 1 or 2) Arrow.UpdateProximity(position); + if (Tracker.trackingMode is 0 or 2) { Tracker.arrow.Update(position); Tracker.arrow.arrow.SetActive(trackedOnMap); } Tracker.timeUntilUpdate = Tracker.updateIntervall; } else { - if (Tracker.trackingMode == 0 || Tracker.trackingMode == 2) + if (Tracker.trackingMode is 0 or 2) Tracker.arrow.Update(); } @@ -1145,6 +1154,11 @@ static void snitchUpdate() { if (snitchIsDead) Snitch.text.text = ModTranslation.getString("snitchDead"); } } + else if (Snitch.isRevealed) + { + if (Snitch.text != null && Snitch.text.isActiveAndEnabled) + Snitch.text.gameObject.SetActive(false); + } if (snitchIsDead) { if (MeetingHud.Instance == null) Snitch.needsUpdate = false; @@ -1168,9 +1182,7 @@ static void bountyHunterUpdate() { if (BountyHunter.cooldownText != null && BountyHunter.cooldownText.gameObject != null) UnityEngine.Object.Destroy(BountyHunter.cooldownText.gameObject); BountyHunter.cooldownText = null; BountyHunter.bounty = null; - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } + TORMapOptions.resetPoolables(); return; } @@ -1199,7 +1211,7 @@ static void bountyHunterUpdate() { // Show poolable player if (FastDestroyableSingleton.Instance != null && FastDestroyableSingleton.Instance.UseButton != null) { - foreach (PoolablePlayer pp in TORMapOptions.playerIcons.Values) pp.gameObject.SetActive(false); + TORMapOptions.resetPoolables(); if (TORMapOptions.playerIcons.ContainsKey(BountyHunter.bounty.PlayerId) && TORMapOptions.playerIcons[BountyHunter.bounty.PlayerId].gameObject != null) TORMapOptions.playerIcons[BountyHunter.bounty.PlayerId].gameObject.SetActive(true); } @@ -1217,7 +1229,7 @@ static void bountyHunterUpdate() { // Update Arrow if (BountyHunter.showArrow && BountyHunter.bounty != null) { - if (BountyHunter.arrow == null) BountyHunter.arrow = new Arrow(Color.red); + BountyHunter.arrow ??= new Arrow(Color.red); if (BountyHunter.arrowUpdateTimer <= 0f) { BountyHunter.arrow.Update(BountyHunter.bounty.transform.position); BountyHunter.arrowUpdateTimer = BountyHunter.arrowUpdateIntervall; @@ -1612,7 +1624,10 @@ static void prophetUpdate() } public static void cupidUpdate() - { + { + if (HudManagerStartPatch.cupidTimeRemainingText != null && HudManagerStartPatch.cupidTimeRemainingText.isActiveAndEnabled) + HudManagerStartPatch.cupidTimeRemainingText.enabled = false; + if (Cupid.cupid == null || Cupid.cupid.Data.IsDead || CachedPlayer.LocalPlayer.PlayerControl != Cupid.cupid) return; Cupid.timeLeft = (int)Math.Ceiling(Cupid.timeLimit - (DateTime.UtcNow - Cupid.startTime).TotalSeconds); @@ -1642,7 +1657,9 @@ public static void cupidUpdate() } public static void akujoUpdate() - { + { + if (HudManagerStartPatch.akujoTimeRemainingText != null && HudManagerStartPatch.akujoTimeRemainingText.isActiveAndEnabled) + HudManagerStartPatch.akujoTimeRemainingText.enabled = false; if (Akujo.akujo == null || Akujo.akujo.Data.IsDead || CachedPlayer.LocalPlayer.PlayerControl != Akujo.akujo) return; Akujo.timeLeft = (int)Math.Ceiling(Akujo.timeLimit - (DateTime.UtcNow - Akujo.startTime).TotalSeconds); if (Akujo.timeLeft > 0) @@ -1685,36 +1702,8 @@ public static void bomberBUpdate() BomberB.arrowUpdate(); BomberB.playerIconsUpdate(); } - } - - /*public static void ninjaUpdate() - { - if (Ninja.ninja == null) return; - if (Camouflager.camouflageTimer <= 0f && !Helpers.MushroomSabotageActive()) Ninja.ninja.setDefaultLook(); - if (Ninja.stealthed && Ninja.invisibleTimer <= 0 && Camouflager.camouflageTimer <= 0f && Ninja.ninja == CachedPlayer.LocalPlayer.PlayerControl) - { - MessageWriter invisibleWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.NinjaStealth, Hazel.SendOption.Reliable, -1); - invisibleWriter.Write(Ninja.ninja.PlayerId); - invisibleWriter.Write(byte.MaxValue); - AmongUsClient.Instance.FinishRpcImmediately(invisibleWriter); - RPCProcedure.ninjaStealth(Ninja.ninja.PlayerId, false); - } } - public static void sprinterUpdate() - { - if (Sprinter.sprinter == null) return; - if (Camouflager.camouflageTimer <= 0f && !Helpers.MushroomSabotageActive()) Sprinter.sprinter.setDefaultLook(); - if (Sprinter.sprinting && Sprinter.invisibleTimer <= 0 && Sprinter.sprinter == CachedPlayer.LocalPlayer.PlayerControl) - { - MessageWriter invisibleWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SprinterSprint, Hazel.SendOption.Reliable, -1); - invisibleWriter.Write(Sprinter.sprinter.PlayerId); - invisibleWriter.Write(byte.MaxValue); - AmongUsClient.Instance.FinishRpcImmediately(invisibleWriter); - RPCProcedure.sprinterSprint(Sprinter.sprinter.PlayerId, false); - } - }*/ - public static void fortuneTellerUpdate() { if (FortuneTeller.fortuneTeller == null) return; @@ -1736,12 +1725,6 @@ public static void fortuneTellerUpdate() } } - /*public static void serialKillerUpdate() - { - if (SerialKiller.serialKiller == null || CachedPlayer.LocalPlayer.PlayerControl != SerialKiller.serialKiller) return; - if (SerialKiller.isCountDown) HudManagerStartPatch.serialKillerButton.isEffectActive = true; - }*/ - public static void evilTrackerUpdate() { if (EvilTracker.evilTracker == null) return; @@ -1755,7 +1738,7 @@ public static void evilTrackerUpdate() public static void moriartyUpdate() { - if (Moriarty.moriarty == null || CachedPlayer.LocalPlayer.PlayerControl != Moriarty.moriarty || CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead) return; + if (Moriarty.moriarty == null || CachedPlayer.LocalPlayer.PlayerControl != Moriarty.moriarty) return; Moriarty.arrowUpdate(); } @@ -1771,7 +1754,7 @@ public static void impostorArrowUpdate() { if (FortuneTeller.arrows.FirstOrDefault()?.arrow != null) { - if (FortuneTeller.fortuneTeller == null || FortuneTeller.fortuneTeller.Data.IsDead) + if (FortuneTeller.fortuneTeller == null || FortuneTeller.fortuneTeller.Data.IsDead || !CachedPlayer.LocalPlayer.PlayerControl.Data.Role.IsImpostor) { foreach (Arrow arrows in FortuneTeller.arrows) arrows.arrow.SetActive(false); return; @@ -1918,6 +1901,7 @@ static void bloodyUpdate() { Bloody.active[entry.Key] = entry.Value - Time.fixedDeltaTime; if (entry.Value <= 0 || player.Data.IsDead) { + Bloody.bloodyKillerMap.Remove(player.PlayerId); Bloody.active.Remove(entry.Key); continue; // Skip the creation of the next blood drop, if the killer is dead or the time is up } diff --git a/TheOtherRoles/Patches/RoleAssignmentPatch.cs b/TheOtherRoles/Patches/RoleAssignmentPatch.cs index d986165..e18edf3 100644 --- a/TheOtherRoles/Patches/RoleAssignmentPatch.cs +++ b/TheOtherRoles/Patches/RoleAssignmentPatch.cs @@ -590,25 +590,29 @@ private static void assignModifiers() { //RoleId.Shifter }); + var crewPlayerMadmate = new List(players); + crewPlayerMadmate.RemoveAll(x => x.Data.Role.IsImpostor || Helpers.isNeutral(x) || x == Spy.spy || x == FortuneTeller.fortuneTeller || x == Sprinter.sprinter || x == Veteran.veteran + || x == Deputy.deputy || x == Portalmaker.portalmaker || x == TaskMaster.taskMaster || x == Sherlock.sherlock || x == Snitch.snitch || x == Teleporter.teleporter || x == Prophet.prophet); - if (rnd.Next(1, 101) <= CustomOptionHolder.madmateSpawnRate.getSelection() * 10) - { - var crewPlayerMadmate = new List(players); - crewPlayerMadmate.RemoveAll(x => x.Data.Role.IsImpostor || Helpers.isNeutral(x) || x == Spy.spy || x == FortuneTeller.fortuneTeller || x == Sprinter.sprinter || x == Veteran.veteran - || x == Deputy.deputy || x == Portalmaker.portalmaker || x == TaskMaster.taskMaster || x == Sherlock.sherlock || x == Snitch.snitch || x == Teleporter.teleporter || x == Prophet.prophet); - - // Always remember to remove the Mad Sheriff if Deputy is assigned - if (Deputy.deputy != null && Sheriff.sheriff != null) crewPlayerMadmate.RemoveAll(x => x == Sheriff.sheriff); + // Always remember to remove the Mad Sheriff if Deputy is assigned + if (Deputy.deputy != null && Sheriff.sheriff != null) crewPlayerMadmate.RemoveAll(x => x == Sheriff.sheriff); - int madmateCount = 0; - byte playerId; - while (madmateCount < CustomOptionHolder.madmateQuantity.getQuantity() && crewPlayerMadmate.Count > 0) - { - playerId = setModifierToRandomPlayer((byte)RoleId.Madmate, crewPlayerMadmate); - crewPlayerMadmate.RemoveAll(x => x.PlayerId == playerId); - madmateCount++; - modifierCount--; - } + byte playerId; + bool isFixedMadmateAssigned = !crewPlayerMadmate.Any(x => RoleInfo.getRoleInfoForPlayer(x, includeHidden: true).Any(y => y.roleId == Madmate.fixedRole)); + for (int i = 0; i < CustomOptionHolder.madmateQuantity.getQuantity(); i++) + { + if (crewPlayerMadmate.Count <= 0) break; + if (rnd.Next(1, 101) <= CustomOptionHolder.madmateSpawnRate.getSelection() * 10) + { + if (Madmate.fixedRole != RoleId.Jester && !isFixedMadmateAssigned) + { + playerId = setModifierToRandomPlayer((byte)RoleId.Madmate, crewPlayerMadmate.Where(x => RoleInfo.getRoleInfoForPlayer(x, false, true).Any(y => + y.roleId == Madmate.fixedRole)).ToList()); + } + else playerId = setModifierToRandomPlayer((byte)RoleId.Madmate, crewPlayerMadmate); + crewPlayerMadmate.RemoveAll(x => x.PlayerId == playerId); + modifierCount--; + } } if (rnd.Next(1, 101) <= CustomOptionHolder.modifierLover.getSelection() * 10) { // Assign lover diff --git a/TheOtherRoles/RPC.cs b/TheOtherRoles/RPC.cs index d89d499..b6c600b 100644 --- a/TheOtherRoles/RPC.cs +++ b/TheOtherRoles/RPC.cs @@ -946,6 +946,25 @@ public static void shifterShift(byte targetId) } } + // Specify shifting onto Lawyer/Akujo + if (player == Lawyer.lawyer && Lawyer.target != null) { + Transform playerInfoTransform = Lawyer.target.cosmetics.nameText.transform.parent.FindChild("Info"); + TMPro.TextMeshPro playerInfo = playerInfoTransform != null ? playerInfoTransform.GetComponent() : null; + if (playerInfo != null) playerInfo.text = ""; + } else if (player == Akujo.akujo) { + if (Akujo.honmei != null) { + Transform playerInfoTransform = Akujo.honmei.cosmetics.nameText.transform.parent.FindChild("Info"); + TMPro.TextMeshPro playerInfo = playerInfoTransform?.GetComponent(); + if (playerInfo != null) playerInfo.text = ""; + } if (Akujo.keeps != null) { + foreach (PlayerControl playerControl in Akujo.keeps) { + Transform playerInfoTransform = playerControl.cosmetics.nameText.transform.parent.FindChild("Info"); + TMPro.TextMeshPro playerInfo = playerInfoTransform?.GetComponent(); + if (playerInfo != null) playerInfo.text = ""; + } + } + } + // Shift role if (Mayor.mayor != null && Mayor.mayor == player) { @@ -1038,48 +1057,41 @@ public static void shifterShift(byte targetId) } if (Watcher.nicewatcher != null && Watcher.nicewatcher == player) Watcher.nicewatcher = oldShifter; - if (FortuneTeller.fortuneTeller != null && FortuneTeller.fortuneTeller == player) - { + if (FortuneTeller.fortuneTeller != null && FortuneTeller.fortuneTeller == player) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) resetPoolables(); FortuneTeller.fortuneTeller = oldShifter; FortuneTeller.onAchievementActivate(); } - if (Sherlock.sherlock != null && Sherlock.sherlock == player) - { + if (Sherlock.sherlock != null && Sherlock.sherlock == player) { Sherlock.sherlock = oldShifter; Sherlock.onAchievementActivate(); } - if (Sprinter.sprinter != null && Sprinter.sprinter == player) - { + if (Sprinter.sprinter != null && Sprinter.sprinter == player) { Sprinter.sprinter = oldShifter; Sprinter.onAchievementActivate(); } if (Veteran.veteran != null && Veteran.veteran == player) Veteran.veteran = oldShifter; - if (Yasuna.yasuna != null && Yasuna.yasuna == player) - { + if (Yasuna.yasuna != null && Yasuna.yasuna == player) { Yasuna.yasuna = oldShifter; Yasuna.yasunaOnAchievementActivate(); Yasuna.evilYasunaOnAcheivementActivate(); } if (player == TaskMaster.taskMaster) TaskMaster.taskMaster = oldShifter; - if (Teleporter.teleporter != null && Teleporter.teleporter == player) - { + if (Teleporter.teleporter != null && Teleporter.teleporter == player) { Teleporter.teleporter = oldShifter; Teleporter.onAchievementActivate(); } - if (Prophet.prophet != null && Prophet.prophet == player) - { + if (Prophet.prophet != null && Prophet.prophet == player) { Prophet.prophet = oldShifter; Prophet.onAchievementActivate(); } - if (Busker.busker != null && Busker.busker == player) - { + if (Busker.busker != null && Busker.busker == player) { Busker.busker = oldShifter; Busker.onAchievementActivate(); } - if (Noisemaker.noisemaker != null && Noisemaker.noisemaker == player) - { + if (Noisemaker.noisemaker != null && Noisemaker.noisemaker == player) { Noisemaker.noisemaker = oldShifter; Noisemaker.onAchievementActivate(); } @@ -1087,92 +1099,111 @@ public static void shifterShift(byte targetId) if (player == Godfather.godfather) Godfather.godfather = oldShifter; if (player == Mafioso.mafioso) Mafioso.mafioso = oldShifter; if (player == Janitor.janitor) Janitor.janitor = oldShifter; - if (player == Morphling.morphling) - { + if (player == Morphling.morphling) { Morphling.morphling = oldShifter; Morphling.onAchievementActivate(); } - if (player == Trickster.trickster) - { + if (player == Trickster.trickster) { Trickster.trickster = oldShifter; Trickster.onAchievementActivate(); } - if (player == Cleaner.cleaner) - { + if (player == Cleaner.cleaner) { Cleaner.cleaner = oldShifter; Cleaner.onAchievementActivate(); } - if (player == Ninja.ninja) - { + if (player == Ninja.ninja) { Ninja.ninja = oldShifter; Ninja.onAchievementActivate(); } if (player == NekoKabocha.nekoKabocha) NekoKabocha.nekoKabocha = oldShifter; - if (player == Assassin.assassin) - { + if (player == Assassin.assassin) { Assassin.assassin = oldShifter; Assassin.onAchievementActivate(); } if (player == SerialKiller.serialKiller) SerialKiller.serialKiller = oldShifter; - if (player == EvilTracker.evilTracker) EvilTracker.evilTracker = oldShifter; - if (player == EvilHacker.evilHacker) - { + if (player == EvilTracker.evilTracker) { + EvilTracker.clearAllArrow(); + EvilTracker.evilTracker = oldShifter; + } + if (player == EvilHacker.evilHacker) { EvilHacker.evilHacker = oldShifter; EvilHacker.onAchievementActivate(); } - if (player == Witch.witch) - { + if (player == Witch.witch) { Witch.witch = oldShifter; Witch.onAchievementActivate(); } - if (player == Camouflager.camouflager) - { + if (player == Camouflager.camouflager) { Camouflager.camouflager = oldShifter; Camouflager.onAchievementActivate(); } - if (player == Guesser.evilGuesser) - { + if (player == Guesser.evilGuesser) { Guesser.evilGuesser = oldShifter; Guesser.evilGuesserOnAchievementActivate(); } - if (player == Eraser.eraser) - { + if (player == Eraser.eraser) { Eraser.eraser = oldShifter; Eraser.onAchievementActivate(); } - if (player == Warlock.warlock) - { + if (player == Warlock.warlock) { Warlock.warlock = oldShifter; Warlock.onAchievementActivate(); } - if (player == BountyHunter.bountyHunter) - { + if (player == BountyHunter.bountyHunter) { + BountyHunter.clearAllArrow(); BountyHunter.bountyHunter = oldShifter; BountyHunter.onAchievementActivate(); } - if (player == Vampire.vampire) - { + if (player == Vampire.vampire) { Vampire.vampire = oldShifter; Vampire.onAchievementActivate(); } if (player == CreatedMadmate.createdMadmate) CreatedMadmate.createdMadmate = oldShifter; - if (player == Blackmailer.blackmailer) - { + if (player == Blackmailer.blackmailer) { Blackmailer.blackmailer = oldShifter; Blackmailer.onAchievementActivate(); } - if (player == MimicK.mimicK) MimicK.mimicK = oldShifter; - if (player == MimicA.mimicA) MimicA.mimicA = oldShifter; - if (player == BomberA.bomberA) BomberA.bomberA = oldShifter; - if (player == BomberB.bomberB) BomberB.bomberB = oldShifter; - if (player == Trapper.trapper) - { + if (player == MimicK.mimicK) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) { + if (MimicK.arrows.FirstOrDefault().arrow != null) MimicK.arrows.FirstOrDefault().arrow.SetActive(false); + } + player.setDefaultLook(); // set default look in case they are morphed + MimicK.mimicK = oldShifter; + } + if (player == MimicA.mimicA) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) { + if (MimicA.arrows.FirstOrDefault().arrow != null) MimicA.arrows.FirstOrDefault().arrow.SetActive(false); + } + player.setDefaultLook(); + MimicA.mimicA = oldShifter; + } + if (player == BomberA.bomberA) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) { + resetPoolables(); + if (BomberA.arrows.FirstOrDefault().arrow != null) BomberA.arrows.FirstOrDefault().arrow.SetActive(false); + } + BomberA.bomberA = oldShifter; + } + if (player == BomberB.bomberB) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) { + resetPoolables(); + if (BomberB.arrows.FirstOrDefault().arrow != null) BomberB.arrows.FirstOrDefault().arrow.SetActive(false); + } + BomberB.bomberB = oldShifter; + } + if (player == Trapper.trapper) { Trapper.trapper = oldShifter; Trapper.onAchievementActivate(); } if (player == Jester.jester) Jester.jester = oldShifter; - if (player == Arsonist.arsonist) Arsonist.arsonist = oldShifter; - if (player == Kataomoi.kataomoi) Kataomoi.kataomoi = oldShifter; + if (player == Arsonist.arsonist) { + if (CachedPlayer.LocalPlayer.PlayerControl == player) resetPoolables(); + Arsonist.arsonist = oldShifter; + } + if (player == Kataomoi.kataomoi) { + Kataomoi.resetAllArrow(); + Kataomoi.kataomoi = oldShifter; + } if (player == Opportunist.opportunist) Opportunist.opportunist = oldShifter; if (player == Moriarty.moriarty) Moriarty.moriarty = oldShifter; if (player == PlagueDoctor.plagueDoctor) PlagueDoctor.plagueDoctor = oldShifter; @@ -1181,8 +1212,7 @@ public static void shifterShift(byte targetId) if (player == Vulture.vulture) Vulture.vulture = oldShifter; if (player == Jackal.jackal) Jackal.jackal = oldShifter; if (player == Sidekick.sidekick) Sidekick.sidekick = oldShifter; - if (Jackal.formerJackals.Contains(player)) - { + if (Jackal.formerJackals.Contains(player)) { Jackal.formerJackals.Add(oldShifter); Jackal.formerJackals.RemoveAll(x => x.PlayerId == targetId); isHusk = true; @@ -1212,10 +1242,9 @@ public static void shifterShift(byte targetId) Husk.husk.RemoveAll(x => x.PlayerId == player.PlayerId); } - if (Lawyer.lawyer != null && Lawyer.target == player) - { - Lawyer.target = oldShifter; - } + if (Lawyer.lawyer != null && Lawyer.target == player) Lawyer.target = oldShifter; + if (Kataomoi.kataomoi != null && Kataomoi.target == player) + Kataomoi.target = oldShifter; if (Shifter.isNeutral) { @@ -1434,7 +1463,7 @@ public static void shareRealTasks(MessageReader reader) } /// - /// Resets all the AchievementTokenBases and reactivates the achievements + /// Resets all the AchievementTokenBases and reactivates the achievements

/// On game end the achievements will not be activated again ///
public static void resetAchievement() @@ -1462,8 +1491,8 @@ public static void fortuneTellerUsedDivine(byte fortuneTellerId, byte targetId) if (PlayerControl.LocalPlayer.Data.Role.IsImpostor) { FortuneTeller.fortuneTellerMessage(ModTranslation.getString("fortuneTellerDivinedSomeone"), 7f, Color.white); - FortuneTeller.setDivinedFlag(fortuneTeller, true); } + FortuneTeller.setDivinedFlag(fortuneTeller, true); if (Immoralist.immoralist != null && target == Immoralist.immoralist && CachedPlayer.LocalPlayer.PlayerControl == Immoralist.immoralist) { FortuneTeller.fortuneTellerMessage(ModTranslation.getString("fortuneTellerDivinedYou"), 7f, Color.white); @@ -2813,9 +2842,12 @@ public static void thiefStealsRole(byte playerId) { Jackal.formerJackals.Add(target); } if (target == Moriarty.moriarty) - { + { + Moriarty.clearAllArrow(); Moriarty.moriarty = thief; - Moriarty.formerMoriarty = target; + Moriarty.formerMoriarty = target; + Moriarty.target = null; + Moriarty.brainwashed.RemoveAll(x => x.PlayerId == thief.PlayerId); } if (target == JekyllAndHyde.jekyllAndHyde) { @@ -2872,7 +2904,8 @@ public static void thiefStealsRole(byte playerId) { Warlock.onAchievementActivate(); } if (target == BountyHunter.bountyHunter) - { + { + BountyHunter.clearAllArrow(); BountyHunter.bountyHunter = thief; BountyHunter.onAchievementActivate(); } @@ -2881,7 +2914,11 @@ public static void thiefStealsRole(byte playerId) { Ninja.ninja = thief; Ninja.onAchievementActivate(); } - if (target == EvilTracker.evilTracker) EvilTracker.evilTracker = thief; + if (target == EvilTracker.evilTracker) + { + EvilTracker.clearAllArrow(); + EvilTracker.evilTracker = thief; + } if (target == NekoKabocha.nekoKabocha && !NekoKabocha.revengeNeutral) NekoKabocha.nekoKabocha = thief; if (target == SerialKiller.serialKiller) SerialKiller.serialKiller = thief; if (target == Swapper.swapper && target.Data.Role.IsImpostor) diff --git a/TheOtherRoles/Resources/stringData.json b/TheOtherRoles/Resources/stringData.json index d5d4aa9..cefb932 100644 --- a/TheOtherRoles/Resources/stringData.json +++ b/TheOtherRoles/Resources/stringData.json @@ -808,6 +808,11 @@ "13": "\u62b9\u9664\u51b7\u5374\u65f6\u95f4", "14": "\u62b9\u9664\u51b7\u537b\u6642\u9593" }, + "eraserCooldownIncrease": { + "0": "Erase Cooldown Penalty", + "11": "\u524a\u9664\u3059\u308b\u5ea6\u306b\u8ffd\u52a0\u30af\u30fc\u30eb\u30c0\u30a6\u30f3", + "13": "\u62b9\u9664\u8005\u6bcf\u6b21\u62b9\u9664\u8ffd\u52a0\u51b7\u5374\u65f6\u95f4" + }, "eraserCanEraseAnyone": { "0": "Eraser Can Erase Anyone", "11": "\u8ab0\u3067\u3082\u30ed\u30fc\u30eb\u3092\u524a\u9664\u3067\u304d\u308b\u304b", @@ -4756,6 +4761,10 @@ "13": "\u53db\u5f92\u5728\u5b8c\u6210\u4efb\u52a1\u540e\u77e5\u9053\u5185\u9b3c", "14": "\u53db\u5f92\u5728\u5b8c\u6210\u4efb\u52d9\u5f8c\u77e5\u9053\u5167\u9b3c" }, + "madmateFixedRole": { + "0": "Fixed Role", + "13": "\u62e5\u6709\u56fa\u5b9a\u804c\u4e1a" + }, "madmateCommonTasks": { "0": "Common Tasks", "11": "\u30b3\u30e2\u30f3\u30bf\u30b9\u30af", @@ -5676,6 +5685,10 @@ "0": "Indicate Moriarty Kills", "13": "\u7279\u522b\u63d0\u793a\u83ab\u91cc\u4e9a\u8482\u51fb\u6740" }, + "moriartyTargetNone": { + "0": "None", + "13": "\u65e0\u51fb\u6740\u76ee\u6807" + }, "moriartyIndicator": { "0": "The Moriarty has killed someone!", "11": "\u30e2\u30ea\u30a2\u30fc\u30c6\u30a3\u304c\u8ab0\u304b\u3092\u6bba\u3057\u305f\uff01", diff --git a/TheOtherRoles/TheOtherRoles.cs b/TheOtherRoles/TheOtherRoles.cs index bd147de..b4851a5 100644 --- a/TheOtherRoles/TheOtherRoles.cs +++ b/TheOtherRoles/TheOtherRoles.cs @@ -1195,6 +1195,7 @@ public static class Eraser { public static PlayerControl currentTarget; public static float cooldown = 30f; public static bool canEraseAnyone = false; + public static float cooldownIncrease = 10f; public static AchievementToken acTokenChallenge; public static void onAchievementActivate() @@ -1216,6 +1217,7 @@ public static void clearAndReload() { currentTarget = null; cooldown = CustomOptionHolder.eraserCooldown.getFloat(); canEraseAnyone = CustomOptionHolder.eraserCanEraseAnyone.getBool(); + cooldownIncrease = CustomOptionHolder.eraserCooldownIncrease.getFloat(); alreadyErased = new List(); acTokenChallenge = null; } @@ -1524,9 +1526,7 @@ public static void clearAndReload() { douseTarget = null; triggerArsonistWin = false; dousedPlayers = new List(); - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } + TORMapOptions.resetPoolables(); cooldown = CustomOptionHolder.arsonistCooldown.getFloat(); duration = CustomOptionHolder.arsonistDuration.getFloat(); } @@ -1610,6 +1610,13 @@ public static void onAchievementActivate() acTokenChallenge ??= new("bountyHunter.challenge", (DateTime.UtcNow, 0, false), (val, _) => val.cleared); } + public static void clearAllArrow() { + if (CachedPlayer.LocalPlayer.PlayerControl != bountyHunter) return; + if (arrow != null && arrow.arrow != null) arrow.arrow.SetActive(false); + if (cooldownText) cooldownText.gameObject.SetActive(false); + TORMapOptions.resetPoolables(); + } + public static void clearAndReload() { arrow = new Arrow(color); bountyHunter = null; @@ -1620,9 +1627,7 @@ public static void clearAndReload() { arrow = null; if (cooldownText != null && cooldownText.gameObject != null) UnityEngine.Object.Destroy(cooldownText.gameObject); cooldownText = null; - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } + TORMapOptions.resetPoolables(); bountyDuration = CustomOptionHolder.bountyHunterBountyDuration.getFloat(); @@ -2330,7 +2335,8 @@ public static void clearAndReload() pageIndex = 1; divinedFlag = false; divineTarget = null; - acTokenImpostor = null; + acTokenImpostor = null; + TORMapOptions.resetPoolables(); } [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.OnDestroy))] @@ -2930,8 +2936,7 @@ public static void clearAndReload() playerIcons = new Dictionary(); targetText = null; partnerTargetText = null; - foreach (PoolablePlayer pp in TORMapOptions.playerIcons.Values) - pp?.gameObject?.SetActive(false); + TORMapOptions.resetPoolables(); if (arrows != null) { foreach (Arrow arrow in arrows) @@ -3083,8 +3088,7 @@ public static void clearAndReload() bombTarget = null; currentTarget = null; tmpTarget = null; - foreach (PoolablePlayer pp in TORMapOptions.playerIcons.Values) - pp?.gameObject?.SetActive(false); + TORMapOptions.resetPoolables(); if (arrows != null) { foreach (Arrow arrow in arrows) @@ -3495,6 +3499,20 @@ public static float getLoveGauge() return 1.0f - (stareCountMax == 0 ? 0f : (float)stareCount / (float)stareCountMax); } + public static void resetAllArrow() + { + if (CachedPlayer.LocalPlayer.PlayerControl != kataomoi) return; + TORMapOptions.resetPoolables(); + for (int i = 0; i < gaugeRenderer.Length; ++i) + { + if (gaugeRenderer[i] != null) + { + gaugeRenderer[i].gameObject.SetActive(false); + } + } + if (stareText != null) stareText.gameObject.SetActive(false); + } + public static void clearAndReload() { resetStalking(); @@ -3514,6 +3532,7 @@ public static void clearAndReload() triggerKataomoiWin = false; target = null; currentTarget = null; + TORMapOptions.resetPoolables(); if (stareText != null) UnityEngine.Object.Destroy(stareText); stareText = null; if (arrow != null && arrow.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); @@ -3540,7 +3559,7 @@ public static void fixedUpdate(PlayerPhysics __instance) gaugeTimer = Mathf.Max(gaugeTimer - Time.fixedDeltaTime, 0.0f); float gauge = getLoveGauge(); float nowGauge = Mathf.Lerp(baseGauge, gauge, 1.0f - gaugeTimer); - gaugeRenderer[1].transform.localPosition = new Vector3(Mathf.Lerp(-3.470784f - 1.121919f + 1f, -3.470784f + 1f, nowGauge), -2.626999f, -8.1f); + gaugeRenderer[1].transform.localPosition = new Vector3(Mathf.Lerp(-3.470784f - 1.121919f + 1.25f, -3.470784f + 1.25f, nowGauge), -2.626999f, -8.1f); gaugeRenderer[1].transform.localScale = new Vector3(nowGauge, 1, 1); } @@ -3553,8 +3572,8 @@ public static void fixedUpdate(PlayerPhysics __instance) { float elapsedTime = stalkingDuration - stalkingTimer; float alpha = Mathf.Min(elapsedTime, stalkingFadeTime) / stalkingFadeTime; - alpha = Mathf.Clamp(1f - alpha, CachedPlayer.LocalPlayer.PlayerControl == kataomoi || (CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && !(CachedPlayer.LocalPlayer.PlayerControl == Busker.busker && Busker.pseudocideFlag) - || (CachedPlayer.LocalPlayer.PlayerControl == Lighter.lighter && Lighter.canSeeInvisible)) ? 0.5f : 0f, 1f); + alpha = Mathf.Clamp(1f - alpha, CachedPlayer.LocalPlayer.PlayerControl == kataomoi || CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && !(CachedPlayer.LocalPlayer.PlayerControl == Busker.busker && Busker.pseudocideFlag) + || (CachedPlayer.LocalPlayer.PlayerControl == Lighter.lighter && Lighter.canSeeInvisible) ? 0.5f : 0f, 1f); setAlpha(alpha); } else @@ -4242,6 +4261,21 @@ public static Sprite getArrowSprite() public static void arrowUpdate() { + if (CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead) + { + if (arrows.Count > 0) { + foreach (var arrow in arrows) + if (arrow != null && arrow.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); + } + if (impostorPositionText.Count > 0) { + foreach (var p in impostorPositionText.Values) + if (p != null) UnityEngine.Object.Destroy(p.gameObject); + } + if (targetPositionText != null) UnityEngine.Object.Destroy(targetPositionText.gameObject); + target = null; + return; + } + // 前フレームからの経過時間をマイナスする updateTimer -= Time.fixedDeltaTime; @@ -4351,6 +4385,20 @@ public static void arrowUpdate() // タイマーに時間をセット updateTimer = arrowUpdateInterval; } + } + + public static void clearAllArrow() + { + if (CachedPlayer.LocalPlayer.PlayerControl != evilTracker) return; + if (arrows.Count > 0) { + foreach (var arrow in arrows) + if (arrow != null && arrow.arrow != null) arrow.arrow.SetActive(false); + } + if (impostorPositionText.Count > 0) { + foreach (var p in impostorPositionText.Values) + if (p != null) p.gameObject.SetActive(false); + } + if (targetPositionText != null) targetPositionText.gameObject.SetActive(false); } public static void clearAndReload() @@ -4513,7 +4561,6 @@ public static class Bait public static bool showKillFlash = true; public static bool reported = false; - public static bool killed = false; public static AchievementToken<(byte killerId, bool cleared)> acTokenChallenge = null; @@ -4527,7 +4574,6 @@ public static void clearAndReload() { bait = null; reported = false; - killed = false; highlightAllVents = CustomOptionHolder.baitHighlightAllVents.getBool(); reportDelay = CustomOptionHolder.baitReportDelay.getFloat(); showKillFlash = CustomOptionHolder.baitShowKillFlash.getBool(); @@ -4626,6 +4672,17 @@ public static Sprite getBrainwashIcon() public static void arrowUpdate() { + if (CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead) + { + if (arrows.Count > 0) + { + foreach (var arrow in arrows) + if (arrow != null && arrow.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); + } + if (targetPositionText != null) UnityEngine.Object.Destroy(targetPositionText.gameObject); + target = null; + return; + } // 前フレームからの経過時間をマイナスする updateTimer -= Time.fixedDeltaTime; @@ -4696,6 +4753,57 @@ public static void arrowUpdate() // タイマーに時間をセット updateTimer = arrowUpdateInterval; } + } + + public static void clearAllArrow() + { + if (CachedPlayer.LocalPlayer.PlayerControl != moriarty) return; + if (arrows.Count > 0) + { + foreach (var arrow in arrows) + if (arrow != null && arrow.arrow != null) arrow.arrow.SetActive(false); + } + if (targetPositionText != null) targetPositionText.gameObject.SetActive(false); + var obj = GameObject.Find("MoriartyText(Clone)"); + if (obj != null) obj.SetActive(false); + } + + public static void generateBrainwashText() + { + TMPro.TMP_Text text; + RoomTracker roomTracker = HudManager.Instance?.roomTracker; + GameObject gameObject = UnityEngine.Object.Instantiate(roomTracker.gameObject); + UnityEngine.Object.DestroyImmediate(gameObject.GetComponent()); + gameObject.transform.SetParent(HudManager.Instance.transform); + gameObject.transform.localPosition = new Vector3(0, -1.3f, gameObject.transform.localPosition.z); + gameObject.transform.localScale = Vector3.one * 3f; + text = gameObject.GetComponent(); + text.name = "MoriartyText(Clone)"; + PlayerControl tmpP = target; + bool done = false; + HudManager.Instance.StartCoroutine(Effects.Lerp(brainwashTime, new Action((p) => + { + if (done) + { + return; + } + if (target == null || MeetingHud.Instance != null || p == 1f) + { + if (text != null && text.gameObject) UnityEngine.Object.Destroy(text.gameObject); + if (target == tmpP) target = null; + done = true; + return; + } + else + { + string message = (brainwashTime - (p * brainwashTime)).ToString("0"); + bool even = ((int)(p * brainwashTime / 0.25f)) % 2 == 0; // Bool flips every 0.25 seconds + // string prefix = even ? "" : ""; + string prefix = ""; + text.text = prefix + message + ""; + if (text != null) text.color = even ? Color.yellow : Color.red; + } + }))); } public static void clearAndReload() @@ -4723,7 +4831,10 @@ public static void clearAndReload() if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); } - arrows = new List(); + arrows = new List(); + + var obj = GameObject.Find("MoriartyText(Clone)"); + if (obj != null) UnityEngine.Object.Destroy(obj); } } @@ -5199,20 +5310,6 @@ public static void updateDead() } } - public static bool hasInfected() - { - bool flag = false; - foreach (var item in progress) - { - if (item.Value != 0f) - { - flag = true; - break; - } - } - return flag; - } - public static string getProgressString(float progress) { // Go from green -> yellow -> red based on infection progress @@ -5781,10 +5878,36 @@ public static class Madmate public static bool canSabotage; public static int commonTasks; public static int shortTasks; - public static int longTasks; + public static int longTasks; + public static RoleId fixedRole; public static string fullName { get { return ModTranslation.getString("madmate"); } } - public static string prefix { get { return ModTranslation.getString("madmatePrefix"); } } + public static string prefix { get { return ModTranslation.getString("madmatePrefix"); } } + + public static List validRoles = new() + { + RoleId.Jester, + RoleId.Shifter, + RoleId.Mayor, + RoleId.Engineer, + RoleId.Sheriff, + RoleId.Lighter, + RoleId.Detective, + RoleId.TimeMaster, + RoleId.Medic, + RoleId.Swapper, + RoleId.Seer, + RoleId.Hacker, + RoleId.Tracker, + RoleId.SecurityGuard, + RoleId.Bait, + RoleId.Medium, + RoleId.NiceGuesser, + RoleId.NiceWatcher, + RoleId.Busker, + RoleId.Yasuna, + RoleId.Noisemaker + }; public static bool tasksComplete(PlayerControl player) { @@ -5814,7 +5937,10 @@ public static void clearAndReload() canSabotage = CustomOptionHolder.madmateCanSabotage.getBool(); shortTasks = (int)CustomOptionHolder.madmateShortTasks.getFloat(); commonTasks = (int)CustomOptionHolder.madmateCommonTasks.getFloat(); - longTasks = (int)CustomOptionHolder.madmateLongTasks.getFloat(); + longTasks = (int)CustomOptionHolder.madmateLongTasks.getFloat(); + fixedRole = TORMapOptions.gameMode == CustomGamemodes.Guesser ? validRoles.Where(x => x != RoleId.NiceGuesser).ToList()[ + CustomOptionHolder.madmateFixedRoleGuesserGamemode.getSelection()] : + validRoles[CustomOptionHolder.madmateFixedRole.getSelection()]; } } @@ -5834,7 +5960,8 @@ public static void clearAndReload() { } public static float visibility(byte playerId) { - if ((playerId == Ninja.ninja?.PlayerId && Ninja.stealthed) || (playerId == Sprinter.sprinter?.PlayerId && Sprinter.sprinting)) return 1f; + if ((playerId == Ninja.ninja?.PlayerId && Ninja.stealthed) || (playerId == Sprinter.sprinter?.PlayerId && Sprinter.sprinting) + || (playerId == Fox.fox?.PlayerId && Fox.stealthed) || (playerId == Kataomoi.kataomoi?.PlayerId && Kataomoi.isStalking())) return 1f; float visibility = 1f; if (lastMoved != null && lastMoved.ContainsKey(playerId)) { var tStill = Time.time - lastMoved[playerId];