# 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.4| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.3.4/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)
| 2021.12.14s| v3.3.1| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.3.1/TheOtherRoles.zip)
<details>
<summary>Click to show the Changelog</summary>
+**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"
- Added Security Guard mobile cams after placing all screws
- Added Lover option "Enable Lover Chat"
- Added return votes in meetings: You'll now get your votes back if your target got shot by the Guesser
-- Added New Option for Guesser: Guesser can't guess Snitch if they has done all tasks (created by Mr_Fluff)
+- Added New Option for Guesser: Guesser can't guess Snitch if they has done all tasks (created by [MaximeGillot](https://github.com/MaximeGillot)
- Added The Other Roles changelog announcement popup
- Changed that the Bounty Hunter exclude their Lover
- Changed the position of the Witch icon in meetings for better visibility
- 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
- **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:
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();
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;
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;},
() => {
if (PlayerControl.GameOptions.MapId != 1) {
if (SecurityGuard.minigame == null) {
+ byte mapId = PlayerControl.GameOptions.MapId;
var e = UnityEngine.Object.FindObjectsOfType<SystemConsole>().FirstOrDefault(x => x.gameObject.name.Contains("Surv_Panel"));
+ if (mapId == 0 || mapId == 3) e = UnityEngine.Object.FindObjectsOfType<SystemConsole>().FirstOrDefault(x => x.gameObject.name.Contains("SurvConsole"));
+ else if (mapId == 4) e = UnityEngine.Object.FindObjectsOfType<SystemConsole>().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);
}
public static CustomOption jesterSpawnRate;
public static CustomOption jesterCanCallEmergency;
+ public static CustomOption jesterHasImpostorVision;
public static CustomOption arsonistSpawnRate;
public static CustomOption arsonistCooldown;
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<byte, byte[]> blockedRolePairings = new Dictionary<byte, byte[]>();
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);
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);
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});
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;
public static ConfigEntry<bool> GhostsSeeRoles { get; set; }
public static ConfigEntry<bool> GhostsSeeVotes{ get; set; }
public static ConfigEntry<bool> ShowRoleSummary { get; set; }
+ public static ConfigEntry<bool> ShowLighterDarker { get; set; }
public static ConfigEntry<string> StreamerModeReplacementText { get; set; }
public static ConfigEntry<string> StreamerModeReplacementColor { get; set; }
public static ConfigEntry<string> Ip { get; set; }
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");
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;
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
}
}
} else {
- announcement = $@"<size=150%>Version {ver}:</size>
+ announcement = $@"<size=150%><color=#FC0303>THE OTHER ROLES</color> Version {ver}:</size>
{announcement}";
}
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;
break;
}
}
- }
- if (CustomOptionHolder.dynamicMap.getBool()) {
- // 0 = Skeld
- // 1 = Mira HQ
- // 2 = Polus
- // 3 = Dleks - deactivated
- // 4 = Airship
- List<byte> possibleMaps = new List<byte>(){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<byte> possibleMaps = new List<byte>();
+ 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;
}
}
BountyHunter.arrowUpdateTimer = 0f; // Force arrow to update
BountyHunter.bountyUpdateTimer = BountyHunter.bountyDuration;
var possibleTargets = new List<PlayerControl>();
- 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);
}
}
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) {
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);
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")})";
UncheckedMurderPlayer,
UncheckedCmdReportDeadBody,
UncheckedExilePlayer,
+ DynamicMapOption,
// Role functionality
if (target != null) target.Exiled();
}
+ public static void dynamicMapOption(byte mapId) {
+ PlayerControl.GameOptions.MapId = mapId;
+ }
+
// Role functionality
public static void engineerFixLights() {
byte reportTarget = reader.ReadByte();
RPCProcedure.uncheckedCmdReportDeadBody(reportSource, reportTarget);
break;
+ case (byte)CustomRPC.DynamicMapOption:
+ byte mapId = reader.ReadByte();
+ RPCProcedure.dynamicMapOption(mapId);
+ break;
// Role functionality
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();
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
- <Version>3.4.0</Version>
+ <Version>3.4.1</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
</PropertyGroup>