diff --git a/README.md b/README.md index 33dd89812..65f9e341a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein # Releases | Among Us - Version| Mod Version | Link | |----------|-------------|-----------------| +| 2021.12.15s| v3.4.1| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.1/TheOtherRoles.zip) | 2021.12.15s| v3.4.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.4.0/TheOtherRoles.zip) | 2021.12.15s| v3.3.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.3.3/TheOtherRoles.zip) | 2021.12.15s| v3.3.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.3.2/TheOtherRoles.zip) @@ -96,6 +97,16 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein
Click to show the Changelog +**Version 3.4.1** +- Added a new mod option "Show Lighter/Darker" for meetings +- Added options for choosing which maps are enabled for random maps thanks [EvilScum](https://github.com/JustASysAdmin) +- Added Jester option "Jester Has Impostor Vision" thanks [EvilScum](https://github.com/JustASysAdmin) +- Fixed a bug where the Bounty Hunter had no bounty +- Fixed a bug where the Guesser & Sheriff were not assigned properly (fingers crossed) +- Fixed a bug where Hacker buttons didn't work as intended with "random map" option +- Fixed a bug where the Security Guard could not access cams on Skeld, dlekS & Airship +- Changed Tracker update intervall to a minimum of 1 thanks [LaicosVK](https://github.com/LaicosVK) + **Version 3.4.0** - Added new Role [Deputy](#deputy) thanks [gendelo3](https://github.com/gendelo3) - Added Hacker option "Cant Move During Mobile Gadget Duration" @@ -109,7 +120,6 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein - Fixed a bug where the spy had a white name for Impostors in chat - Fixed a bug where the Guesser and Swapper UI in meetings was behind the visor cosmetics - **Version 3.3.3** - Fixed a bug where a guessed Guesser could guess - Fixed a bug where buttons were visible during the meeting @@ -565,6 +575,7 @@ The mod adds a few new settings to Among Us (in addition to the role settings): - **Dleks:** You are now able to select the Dleks map. - **Task Counts:** You are now able to select more tasks. - **Role Summary:** When a game ends there will be a list of all players and their roles and their task progress +- **Darker/Lighter:** Displays color type of each player in meetings ### Task Count Limits per map You can configure: diff --git a/TheOtherRoles/Buttons.cs b/TheOtherRoles/Buttons.cs index 2687284f1..0fca0e40b 100644 --- a/TheOtherRoles/Buttons.cs +++ b/TheOtherRoles/Buttons.cs @@ -185,7 +185,6 @@ public static void Postfix(HudManager __instance) engineerRepairButton = new CustomButton( () => { engineerRepairButton.Timer = 0f; - MessageWriter usedRepairWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.EngineerUsedRepair, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(usedRepairWriter); RPCProcedure.engineerUsedRepair(); @@ -462,7 +461,7 @@ public static void Postfix(HudManager __instance) Hacker.hackerTimer = Hacker.duration; }, () => { return Hacker.hacker != null && Hacker.hacker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; }, - () => { return PlayerControl.LocalPlayer.CanMove; }, + () => { return true; }, () => { hackerButton.Timer = hackerButton.MaxTimer; hackerButton.isEffectActive = false; @@ -484,7 +483,6 @@ public static void Postfix(HudManager __instance) if (Hacker.cantMove) PlayerControl.LocalPlayer.moveable = false; PlayerControl.LocalPlayer.NetTransform.Halt(); // Stop current movement - Hacker.chargesAdminTable--; }, () => { return Hacker.hacker != null && Hacker.hacker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead;}, @@ -982,7 +980,10 @@ public static void Postfix(HudManager __instance) () => { if (PlayerControl.GameOptions.MapId != 1) { if (SecurityGuard.minigame == null) { + byte mapId = PlayerControl.GameOptions.MapId; var e = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name.Contains("Surv_Panel")); + if (mapId == 0 || mapId == 3) e = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name.Contains("SurvConsole")); + else if (mapId == 4) e = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name.Contains("task_cams")); if (e == null || Camera.main == null) return; SecurityGuard.minigame = UnityEngine.Object.Instantiate(e.MinigamePrefab, Camera.main.transform, false); } diff --git a/TheOtherRoles/CustomOptionHolder.cs b/TheOtherRoles/CustomOptionHolder.cs index c9c80f6fd..1089c27e0 100644 --- a/TheOtherRoles/CustomOptionHolder.cs +++ b/TheOtherRoles/CustomOptionHolder.cs @@ -64,6 +64,7 @@ public class CustomOptionHolder { public static CustomOption jesterSpawnRate; public static CustomOption jesterCanCallEmergency; + public static CustomOption jesterHasImpostorVision; public static CustomOption arsonistSpawnRate; public static CustomOption arsonistCooldown; @@ -229,7 +230,13 @@ public class CustomOptionHolder { public static CustomOption noVoteIsSelfVote; public static CustomOption hidePlayerNames; public static CustomOption allowParallelMedBayScans; + public static CustomOption dynamicMap; + public static CustomOption dynamicMapEnableSkeld; + public static CustomOption dynamicMapEnableMira; + public static CustomOption dynamicMapEnablePolus; + public static CustomOption dynamicMapEnableDleks; + public static CustomOption dynamicMapEnableAirShip; internal static Dictionary blockedRolePairings = new Dictionary(); @@ -324,7 +331,8 @@ public static void Load() { guesserCantGuessSnitchIfTaksDone = CustomOption.Create(318, "Guesser Can't Guess Snitch When Tasks Completed", true, guesserSpawnRate); jesterSpawnRate = CustomOption.Create(60, cs(Jester.color, "Jester"), rates, null, true); - jesterCanCallEmergency = CustomOption.Create(61, "Jester can call emergency meeting", true, jesterSpawnRate); + jesterCanCallEmergency = CustomOption.Create(61, "Jester Can Call Emergency Meeting", true, jesterSpawnRate); + jesterCanCallEmergency = CustomOption.Create(62, "Jester Has Impostor Vision", false, jesterSpawnRate); arsonistSpawnRate = CustomOption.Create(290, cs(Arsonist.color, "Arsonist"), rates, null, true); arsonistCooldown = CustomOption.Create(291, "Arsonist Cooldown", 12.5f, 2.5f, 60f, 2.5f, arsonistSpawnRate); @@ -420,7 +428,7 @@ public static void Load() { hackerNoMove = CustomOption.Create(176, "Cant Move During Mobile Gadget Duration", true, hackerSpawnRate); trackerSpawnRate = CustomOption.Create(200, cs(Tracker.color, "Tracker"), rates, null, true); - trackerUpdateIntervall = CustomOption.Create(201, "Tracker Update Intervall", 5f, 2.5f, 30f, 2.5f, trackerSpawnRate); + trackerUpdateIntervall = CustomOption.Create(201, "Tracker Update Intervall", 5f, 1f, 30f, 1f, trackerSpawnRate); trackerResetTargetAfterMeeting = CustomOption.Create(202, "Tracker Reset Target After Meeting", false, trackerSpawnRate); trackerCanTrackCorpses = CustomOption.Create(203, "Tracker Can Track Corpses", true, trackerSpawnRate); trackerCorpsesTrackingCooldown = CustomOption.Create(204, "Corpses Tracking Cooldown", 30f, 5f, 120f, 5f, trackerCanTrackCorpses); @@ -463,7 +471,13 @@ public static void Load() { noVoteIsSelfVote = CustomOption.Create(5, "No Vote Is Self Vote", false, blockSkippingInEmergencyMeetings); hidePlayerNames = CustomOption.Create(6, "Hide Player Names", false); allowParallelMedBayScans = CustomOption.Create(7, "Allow Parallel MedBay Scans", false); + dynamicMap = CustomOption.Create(8, "Play On A Random Map", false, null, false); + dynamicMapEnableSkeld = CustomOption.Create(501, "Enable Skeld Rotation", true, dynamicMap, false); + dynamicMapEnableMira = CustomOption.Create(502, "Enable Mira Rotation", true, dynamicMap, false); + dynamicMapEnablePolus = CustomOption.Create(503, "Enable Polus Rotation", true, dynamicMap, false); + dynamicMapEnableAirShip = CustomOption.Create(504, "Enable Airship Rotation", true, dynamicMap, false); + dynamicMapEnableDleks = CustomOption.Create(505, "Enable dlekS Rotation", false, dynamicMap, false); blockedRolePairings.Add((byte)RoleId.Vampire, new [] { (byte)RoleId.Warlock}); blockedRolePairings.Add((byte)RoleId.Warlock, new [] { (byte)RoleId.Vampire}); diff --git a/TheOtherRoles/Main.cs b/TheOtherRoles/Main.cs index a9c62020d..b70e32f9c 100644 --- a/TheOtherRoles/Main.cs +++ b/TheOtherRoles/Main.cs @@ -22,8 +22,7 @@ public class TheOtherRolesPlugin : BasePlugin { public const string Id = "me.eisbison.theotherroles"; - public const string VersionString = "3.4.0"; - + public const string VersionString = "3.4.1"; public static System.Version Version = System.Version.Parse(VersionString); internal static BepInEx.Logging.ManualLogSource Logger; @@ -39,6 +38,7 @@ public class TheOtherRolesPlugin : BasePlugin public static ConfigEntry GhostsSeeRoles { get; set; } public static ConfigEntry GhostsSeeVotes{ get; set; } public static ConfigEntry ShowRoleSummary { get; set; } + public static ConfigEntry ShowLighterDarker { get; set; } public static ConfigEntry StreamerModeReplacementText { get; set; } public static ConfigEntry StreamerModeReplacementColor { get; set; } public static ConfigEntry Ip { get; set; } @@ -66,6 +66,7 @@ public override void Load() { GhostsSeeRoles = Config.Bind("Custom", "Ghosts See Roles", true); GhostsSeeVotes = Config.Bind("Custom", "Ghosts See Votes", true); ShowRoleSummary = Config.Bind("Custom", "Show Role Summary", true); + ShowLighterDarker = Config.Bind("Custom", "Show Lighter / Darker", true); ShowPopUpVersion = Config.Bind("Custom", "Show PopUp", "0"); StreamerModeReplacementText = Config.Bind("Custom", "Streamer Mode Replacement Text", "\n\nThe Other Roles"); StreamerModeReplacementColor = Config.Bind("Custom", "Streamer Mode Replacement Text Hex Color", "#87AAF5FF"); diff --git a/TheOtherRoles/MapOptions.cs b/TheOtherRoles/MapOptions.cs index 94531fe7d..2c69f53df 100644 --- a/TheOtherRoles/MapOptions.cs +++ b/TheOtherRoles/MapOptions.cs @@ -16,6 +16,7 @@ static class MapOptions { public static bool ghostsSeeVotes = true; public static bool showRoleSummary = true; public static bool allowParallelMedBayScans = false; + public static bool showLighterDarker = true; // Updating values public static int meetingsCount = 0; @@ -38,6 +39,7 @@ public static void clearAndReloadMapOptions() { ghostsSeeTasks = TheOtherRolesPlugin.GhostsSeeTasks.Value; ghostsSeeVotes = TheOtherRolesPlugin.GhostsSeeVotes.Value; showRoleSummary = TheOtherRolesPlugin.ShowRoleSummary.Value; + showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value; } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/TheOtherRoles/Modules/ModUpdater.cs b/TheOtherRoles/Modules/ModUpdater.cs index 512a6c1c2..87b9b5bc2 100644 --- a/TheOtherRoles/Modules/ModUpdater.cs +++ b/TheOtherRoles/Modules/ModUpdater.cs @@ -158,7 +158,7 @@ update to v{ver} is available } } } else { - announcement = $@"Version {ver}: + announcement = $@"THE OTHER ROLES Version {ver}: {announcement}"; } diff --git a/TheOtherRoles/Patches/ClientOptionsPatch.cs b/TheOtherRoles/Patches/ClientOptionsPatch.cs index 2e50869ae..9f5a77bcf 100644 --- a/TheOtherRoles/Patches/ClientOptionsPatch.cs +++ b/TheOtherRoles/Patches/ClientOptionsPatch.cs @@ -19,6 +19,7 @@ public static class ClientOptionsPatch new SelectionBehaviour("Ghosts Can See Votes", () => MapOptions.ghostsSeeVotes = TheOtherRolesPlugin.GhostsSeeVotes.Value = !TheOtherRolesPlugin.GhostsSeeVotes.Value, TheOtherRolesPlugin.GhostsSeeVotes.Value), new SelectionBehaviour("Ghosts Can See Roles", () => MapOptions.ghostsSeeRoles = TheOtherRolesPlugin.GhostsSeeRoles.Value = !TheOtherRolesPlugin.GhostsSeeRoles.Value, TheOtherRolesPlugin.GhostsSeeRoles.Value), new SelectionBehaviour("Show Role Summary", () => MapOptions.showRoleSummary = TheOtherRolesPlugin.ShowRoleSummary.Value = !TheOtherRolesPlugin.ShowRoleSummary.Value, TheOtherRolesPlugin.ShowRoleSummary.Value), + new SelectionBehaviour("Show Lighter / Darker", () => MapOptions.showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value = !TheOtherRolesPlugin.ShowLighterDarker.Value, TheOtherRolesPlugin.ShowLighterDarker.Value), }; private static GameObject popUp; diff --git a/TheOtherRoles/Patches/GameStartManagerPatch.cs b/TheOtherRoles/Patches/GameStartManagerPatch.cs index 0f895fb95..5229a8123 100644 --- a/TheOtherRoles/Patches/GameStartManagerPatch.cs +++ b/TheOtherRoles/Patches/GameStartManagerPatch.cs @@ -158,18 +158,32 @@ public static bool Prefix(GameStartManager __instance) { break; } } - } - if (CustomOptionHolder.dynamicMap.getBool()) { - // 0 = Skeld - // 1 = Mira HQ - // 2 = Polus - // 3 = Dleks - deactivated - // 4 = Airship - List possibleMaps = new List(){0, 1, 2, 4}; - PlayerControl.GameOptions.MapId = possibleMaps[TheOtherRoles.rnd.Next(possibleMaps.Count)]; + if (CustomOptionHolder.dynamicMap.getBool() && continueStart) { + // 0 = Skeld + // 1 = Mira HQ + // 2 = Polus + // 3 = Dleks - deactivated + // 4 = Airship + List possibleMaps = new List(); + if (CustomOptionHolder.dynamicMapEnableSkeld.getBool()) + possibleMaps.Add(0); + if (CustomOptionHolder.dynamicMapEnableMira.getBool()) + possibleMaps.Add(1); + if (CustomOptionHolder.dynamicMapEnablePolus.getBool()) + possibleMaps.Add(2); + if (CustomOptionHolder.dynamicMapEnableDleks.getBool()) + possibleMaps.Add(3); + if (CustomOptionHolder.dynamicMapEnableAirShip.getBool()) + possibleMaps.Add(4); + byte chosenMapId = possibleMaps[TheOtherRoles.rnd.Next(possibleMaps.Count)]; + + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.DynamicMapOption, Hazel.SendOption.Reliable, -1); + writer.Write(chosenMapId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + RPCProcedure.dynamicMapOption(chosenMapId); + } } - return continueStart; } } diff --git a/TheOtherRoles/Patches/PlayerControlPatch.cs b/TheOtherRoles/Patches/PlayerControlPatch.cs index c9667ba29..cbc9e8da4 100644 --- a/TheOtherRoles/Patches/PlayerControlPatch.cs +++ b/TheOtherRoles/Patches/PlayerControlPatch.cs @@ -565,7 +565,6 @@ static void bountyHunterUpdate() { BountyHunter.arrowUpdateTimer = 0f; // Force arrow to update BountyHunter.bountyUpdateTimer = BountyHunter.bountyDuration; var possibleTargets = new List(); - if (Lovers.getPartner(BountyHunter.bountyHunter) != null) foreach (PlayerControl p in PlayerControl.AllPlayerControls) { if (!p.Data.IsDead && !p.Data.Disconnected && p != p.Data.Role.IsImpostor && p != Spy.spy && (p != Mini.mini || Mini.isGrownUp()) && (Lovers.getPartner(BountyHunter.bountyHunter) == null || p != Lovers.getPartner(BountyHunter.bountyHunter))) possibleTargets.Add(p); } diff --git a/TheOtherRoles/Patches/RoleAssignmentPatch.cs b/TheOtherRoles/Patches/RoleAssignmentPatch.cs index cf672a533..c642d1c38 100644 --- a/TheOtherRoles/Patches/RoleAssignmentPatch.cs +++ b/TheOtherRoles/Patches/RoleAssignmentPatch.cs @@ -235,110 +235,75 @@ private static void assignEnsuredRoles(RoleAssignmentData data) { } private static void assignDependentRoles(RoleAssignmentData data) { + // Roles that prob have a dependent role + bool guesserFlag = CustomOptionHolder.guesserSpawnBothRate.getSelection() > 0 && CustomOptionHolder.guesserSpawnRate.getSelection() > 0; + bool sheriffFlag = CustomOptionHolder.deputySpawnRate.getSelection() > 0 && CustomOptionHolder.sheriffSpawnRate.getSelection() > 0; + if (!guesserFlag && !sheriffFlag) return; // assignDependentRoles is not needed + + int crew = data.crewmates.Count < data.maxCrewmateRoles ? data.crewmates.Count : data.maxCrewmateRoles; // Max number of crew loops + int imp = data.impostors.Count < data.maxImpostorRoles ? data.impostors.Count : data.maxImpostorRoles; // Max number of imp loops + int crewSteps = crew / data.crewSettings.Keys.Count(); // Avarage crewvalues deducted after each loop + int impSteps = imp / data.impSettings.Keys.Count(); // Avarage impvalues deducted after each loop + + // set to false if needed, otherwise we can skip the loop + bool isSheriff = !sheriffFlag; + bool isGuesser = !guesserFlag; + + bool isEvilGuesser = (rnd.Next(1, 101) <= CustomOptionHolder.guesserIsImpGuesserRate.getSelection() * 10); + + // --- Simulate Crew & Imp ticket system --- + while (crew > 0 && (!isSheriff || (!isEvilGuesser && !isGuesser))) { + if (!isSheriff && rnd.Next(crewValues) < CustomOptionHolder.sheriffSpawnRate.getSelection()) isSheriff = true; + if (!isEvilGuesser && !isGuesser && rnd.Next(crewValues) < CustomOptionHolder.guesserSpawnRate.getSelection()) isGuesser = true; + crew--; + crewValues -= crewSteps; + } + while (imp > 0 && (isEvilGuesser && !isGuesser)) { + if (rnd.Next(crewValues) < CustomOptionHolder.guesserSpawnRate.getSelection()) isGuesser = true; + imp--; + impValues -= impSteps; + } - int crew = data.crewmates.Count < data.maxCrewmateRoles ? data.crewmates.Count : data.maxCrewmateRoles; - int imp = data.impostors.Count < data.maxImpostorRoles ? data.impostors.Count : data.maxImpostorRoles; - int leftCrewRolesCount = crew - data.crewSettings.Where(x => x.Value != 0 && x.Value != 10).ToList().Count; - int leftImpRolesCount = imp - data.impSettings.Where(x => x.Value != 0 && x.Value != 10).ToList().Count; - - // Other Guesser - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() > 0) { - bool isEvilGuesser = (rnd.Next(1, 101) <= CustomOptionHolder.guesserIsImpGuesserRate.getSelection() * 10); - int guesserSpawnValues = isEvilGuesser ? impValues : crewValues; - - if (Guesser.evilGuesser != null || Guesser.niceGuesser != null) { - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10) { // Force both Guesser - if (Guesser.niceGuesser == null && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Other Guesser = Nice Guesser - byte niceGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == niceGuesser); - data.maxCrewmateRoles--; - leftCrewRolesCount--; - } - else if (Guesser.evilGuesser == null && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Other Guesser = Evil Guesser - byte evilGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); - data.impostors.ToList().RemoveAll(x => x.PlayerId == evilGuesser); - data.maxImpostorRoles--; - leftImpRolesCount--; - } - } - else if (Guesser.niceGuesser == null && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Dont force, add other guesser (nice) to pool - data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); - crewValues += CustomOptionHolder.guesserSpawnBothRate.getSelection(); - leftCrewRolesCount--; - } - else if (Guesser.evilGuesser == null && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Dont force, add other guesser (evil) to pool - data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); - impValues += CustomOptionHolder.guesserSpawnBothRate.getSelection(); - leftImpRolesCount--; - } - } - else if ((CustomOptionHolder.guesserSpawnRate.getSelection() < 10 && rnd.Next(guesserSpawnValues + CustomOptionHolder.guesserSpawnRate.getSelection()) < CustomOptionHolder.guesserSpawnRate.getSelection()) - || (isEvilGuesser && leftImpRolesCount > 0) || - (!isEvilGuesser && leftCrewRolesCount > 0)) { // Guesser is < 100%, but won the lottery or there are roles left to assign - if (isEvilGuesser && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Add Evil Guesser - byte evilGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); - data.impostors.ToList().RemoveAll(x => x.PlayerId == evilGuesser); - data.maxImpostorRoles--; - leftImpRolesCount--; - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force Other Guesser (nice) - byte niceGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == niceGuesser); - data.maxCrewmateRoles--; - leftCrewRolesCount--; - } - else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) { // Dont force, add other guesser (nice) to pool - data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); - crewValues += CustomOptionHolder.guesserSpawnBothRate.getSelection(); - leftCrewRolesCount--; - } - } - else if (!isEvilGuesser && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Add Nice Guesser - byte niceGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == niceGuesser); - data.maxCrewmateRoles--; - leftCrewRolesCount--; - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Force Other Guesser (evil) - byte evilGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); - data.impostors.ToList().RemoveAll(x => x.PlayerId == evilGuesser); - data.maxImpostorRoles--; - leftImpRolesCount--; - } - else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) { // Dont force, add other guesser (evil) to pool - data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); - impValues += CustomOptionHolder.guesserSpawnBothRate.getSelection(); - leftImpRolesCount--; - } - } - } + // --- Assign Main Roles if they won the lottery --- + if (isSheriff && Sheriff.sheriff == null && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0 && sheriffFlag) { // Set Sheriff cause he won the lottery + byte sheriff = setRoleToRandomPlayer((byte)RoleId.Sheriff, data.crewmates); + data.crewmates.ToList().RemoveAll(x => x.PlayerId == sheriff); + data.maxCrewmateRoles--; + } + if (!isEvilGuesser && isGuesser && Guesser.niceGuesser == null && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0 && guesserFlag) { // Set Nice Guesser cause he won the lottery + byte niceGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); + data.crewmates.ToList().RemoveAll(x => x.PlayerId == niceGuesser); + data.maxCrewmateRoles--; + } else if (isEvilGuesser && isGuesser && Guesser.evilGuesser == null && data.impostors.Count > 0 && data.maxImpostorRoles > 0 && guesserFlag) { // Set Evil Guesser cause he won the lottery + byte evilGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); + data.impostors.ToList().RemoveAll(x => x.PlayerId == evilGuesser); + data.maxImpostorRoles--; } - // Deputy - if (CustomOptionHolder.deputySpawnRate.getSelection() > 0 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { - if (Sheriff.sheriff != null) { - if (CustomOptionHolder.deputySpawnRate.getSelection() == 10) { // Force Deputy - byte deputy = setRoleToRandomPlayer((byte)RoleId.Deputy, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == deputy); - data.maxCrewmateRoles--; - } else if (CustomOptionHolder.deputySpawnRate.getSelection() < 10) { // Dont force, add Deputy to pool - data.crewSettings.Add((byte)RoleId.Deputy, CustomOptionHolder.deputySpawnRate.getSelection()); - } - } else if ((CustomOptionHolder.sheriffSpawnRate.getSelection() < 10 && rnd.Next(crewValues + CustomOptionHolder.sheriffSpawnRate.getSelection()) < CustomOptionHolder.sheriffSpawnRate.getSelection()) - || leftCrewRolesCount > 0) { // Sheriff is < 100%, but won the lottery or there are roles left to assign - byte sheriff = setRoleToRandomPlayer((byte)RoleId.Sheriff, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == sheriff); + // --- Assign Dependent Roles if main role exists --- + if (Sheriff.sheriff != null) { // Deputy + if (CustomOptionHolder.deputySpawnRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force Deputy + byte deputy = setRoleToRandomPlayer((byte)RoleId.Deputy, data.crewmates); + data.crewmates.ToList().RemoveAll(x => x.PlayerId == deputy); + data.maxCrewmateRoles--; + } else if (CustomOptionHolder.deputySpawnRate.getSelection() < 10) // Dont force, add Deputy to the ticket system + data.crewSettings.Add((byte)RoleId.Deputy, CustomOptionHolder.deputySpawnRate.getSelection()); + } + if (!isEvilGuesser && Guesser.niceGuesser != null) { // Other Guesser (evil) + if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Force other guesser (evil) + byte bothGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); + data.impostors.ToList().RemoveAll(x => x.PlayerId == bothGuesser); + data.maxImpostorRoles--; + } else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) // Dont force, add Guesser (evil) to the ticket system + data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); + } else if (isEvilGuesser && Guesser.evilGuesser != null) { // ELSE other Guesser (nice) + if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force other guesser (nice) + byte bothGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); + data.crewmates.ToList().RemoveAll(x => x.PlayerId == bothGuesser); data.maxCrewmateRoles--; - leftCrewRolesCount--; - if (CustomOptionHolder.deputySpawnRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force Deputy - byte deputy = setRoleToRandomPlayer((byte)RoleId.Deputy, data.crewmates); - data.crewmates.ToList().RemoveAll(x => x.PlayerId == deputy); - data.maxCrewmateRoles--; - leftCrewRolesCount--; - } else { // Dont force, add Deputy to pool - data.crewSettings.Add((byte)RoleId.Deputy, CustomOptionHolder.deputySpawnRate.getSelection()); - crewValues += CustomOptionHolder.deputySpawnRate.getSelection(); - leftCrewRolesCount--; - } } + else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) // Dont force, add Guesser (nice) to the ticket system + data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); } } private static void assignChanceRoles(RoleAssignmentData data) { diff --git a/TheOtherRoles/Patches/ShipStatusPatch.cs b/TheOtherRoles/Patches/ShipStatusPatch.cs index 23fbcc42e..896239a45 100644 --- a/TheOtherRoles/Patches/ShipStatusPatch.cs +++ b/TheOtherRoles/Patches/ShipStatusPatch.cs @@ -22,7 +22,8 @@ public static bool Prefix(ref float __result, ShipStatus __instance, [HarmonyArg else if (player.Role.IsImpostor || (Jackal.jackal != null && Jackal.jackal.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)) // Impostor, Jackal/Sidekick or Spy with Impostor vision + || (Spy.spy != null && Spy.spy.PlayerId == player.PlayerId && Spy.hasImpostorVision) + || (Jester.jester != null && Jester.jester.PlayerId == player.PlayerId && Jester.hasImpostorVision)) // Impostor, Jackal/Sidekick, Spy or Jester with Impostor vision __result = __instance.MaxLightRadius * PlayerControl.GameOptions.ImpostorLightMod; else if (Lighter.lighter != null && Lighter.lighter.PlayerId == player.PlayerId && Lighter.lighterTimer > 0f) // if player is Lighter and Lighter has his ability active __result = Mathf.Lerp(__instance.MaxLightRadius * Lighter.lighterModeLightsOffVision, __instance.MaxLightRadius * Lighter.lighterModeLightsOnVision, num); diff --git a/TheOtherRoles/Patches/UpdatePatch.cs b/TheOtherRoles/Patches/UpdatePatch.cs index 34243014b..cb4955103 100644 --- a/TheOtherRoles/Patches/UpdatePatch.cs +++ b/TheOtherRoles/Patches/UpdatePatch.cs @@ -196,9 +196,9 @@ static void setNameTags() { player.NameText.text += suffix; } - // Hacker and Detective - if (PlayerControl.LocalPlayer != null && !PlayerControl.LocalPlayer.Data.IsDead && (PlayerControl.LocalPlayer == Hacker.hacker || PlayerControl.LocalPlayer == Detective.detective || PlayerControl.LocalPlayer == Medium.medium)) { - if (MeetingHud.Instance != null) { + // Display lighter / darker color for all alive players + if (PlayerControl.LocalPlayer != null && !PlayerControl.LocalPlayer.Data.IsDead) { + if (MeetingHud.Instance != null && MapOptions.showLighterDarker) { foreach (PlayerVoteArea player in MeetingHud.Instance.playerStates) { var target = Helpers.playerById(player.TargetPlayerId); if (target != null) player.NameText.text += $" ({(Helpers.isLighterColor(target.Data.DefaultOutfit.ColorId) ? "L" : "D")})"; diff --git a/TheOtherRoles/RPC.cs b/TheOtherRoles/RPC.cs index 207a4ffa2..5a0201374 100644 --- a/TheOtherRoles/RPC.cs +++ b/TheOtherRoles/RPC.cs @@ -72,6 +72,7 @@ enum CustomRPC UncheckedMurderPlayer, UncheckedCmdReportDeadBody, UncheckedExilePlayer, + DynamicMapOption, // Role functionality @@ -325,6 +326,10 @@ public static void uncheckedExilePlayer(byte targetId) { if (target != null) target.Exiled(); } + public static void dynamicMapOption(byte mapId) { + PlayerControl.GameOptions.MapId = mapId; + } + // Role functionality public static void engineerFixLights() { @@ -866,6 +871,10 @@ static void Postfix([HarmonyArgument(0)]byte callId, [HarmonyArgument(1)]Message byte reportTarget = reader.ReadByte(); RPCProcedure.uncheckedCmdReportDeadBody(reportSource, reportTarget); break; + case (byte)CustomRPC.DynamicMapOption: + byte mapId = reader.ReadByte(); + RPCProcedure.dynamicMapOption(mapId); + break; // Role functionality diff --git a/TheOtherRoles/TheOtherRoles.cs b/TheOtherRoles/TheOtherRoles.cs index da9785a8f..298b52e3e 100644 --- a/TheOtherRoles/TheOtherRoles.cs +++ b/TheOtherRoles/TheOtherRoles.cs @@ -68,11 +68,13 @@ public static class Jester { public static bool triggerJesterWin = false; public static bool canCallEmergency = true; + public static bool hasImpostorVision = false; public static void clearAndReload() { jester = null; triggerJesterWin = false; canCallEmergency = CustomOptionHolder.jesterCanCallEmergency.getBool(); + hasImpostorVision = CustomOptionHolder.jesterHasImpostorVision.getBool(); } } diff --git a/TheOtherRoles/TheOtherRoles.csproj b/TheOtherRoles/TheOtherRoles.csproj index aebc258d8..a7c3121d9 100644 --- a/TheOtherRoles/TheOtherRoles.csproj +++ b/TheOtherRoles/TheOtherRoles.csproj @@ -1,7 +1,7 @@ netstandard2.1 - 3.4.0 + 3.4.1 TheOtherRoles Eisbison