| | [Swapper](#swapper) | | |
| | [Time Master](#time-master) | | |
| | [Tracker](#tracker) | | |
+| | [Bait](#bait) | |
The [Role Assignment](#role-assignment) sections explains how the roles are being distributed among the players.
# Releases
| Among Us - Version| Mod Version | Link |
|----------|-------------|-----------------|
-| **2021.6.30s**| v2.7.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.7.3/TheOtherRoles.zip)
+| 2021.6.30s| v2.8.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.8.0/TheOtherRoles.zip)
+| 2021.6.30s| v2.7.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.7.3/TheOtherRoles.zip)
| 2021.6.15s| v2.7.1| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.7.1/TheOtherRoles.zip)
| 2021.6.15s| v2.7.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.7.0/TheOtherRoles.zip)
| 2021.5.25.2s| v2.6.7| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.6.7/TheOtherRoles.zip)
<details>
<summary>Click to show the Changelog</summary>
+**Version 2.8.0**
+- **New Role:** [Bait](#bait) created by [Mallöris](https://github.com/Mallaris)
+- Added Tracker Option: "Tracker Reset Target After Meeting" (feature created by [MaximeGillot](https://github.com/MaximeGillot))
+- Added Snitch Options: "Include Team Jackal" and "Use Different Arrow Color For Team Jackal" (feature created by [Mallöris](https://github.com/Mallaris))
+- Added Medic Option: "Shield Will Be Set After Next Meeting" (feature created by [Mallöris](https://github.com/Mallaris))
+
**Version 2.7.3**
- Updated to Among Us v2021.6.30
- Updated BepInEx version
**NOTE:**
- If the shielded player is a Lover and the other Lover dies, they nevertheless kill themselves.
- If the Shifter has a shield or their target has a Shield, the shielded player switches.
+- Shields set after the next meeting, will be set before a possible shift is being performed.
### Game Options
| Medic Spawn Chance | - | -
| Show Shielded Player | Sets who sees if a player has a shield | "Everyone", "Shielded + Medic", "Medic"
| Shielded Player Sees Murder Attempt| Whether a shielded player sees if someone tries to kill him | True/false |
+| Shield Will Be Set After Next Meeting | - | True/false
-----------------------
## Mayor
## Tracker
### **Team: Crewmates**
-The Tracker can select one player in a game and tracks this player for the rest of the game.
+The Tracker can select one player to track.
+Depending on the options the Tracker can track a different person after each meeting or the Tracker tracks the same person for the whole game.
An arrow points to the last tracked position of the player.
The arrow updates it's position every few seconds (configurable).
|----------|:-------------:|
| Tracker Spawn Chance | -
| Tracker Update Intervall | Sets how often the position is being updated
+| Tracker Reset Target After Meeting | -
-----------------------
## Snitch
### **Team: Crewmates**
-When the Snitch finishes all the tasks, arrows will appear (only visible to the Snitch) that point to the Impostors.
-When the Snitch has one task left (configurable) the Snitch will be revealed to the Impostors, also with an arrow.
+When the Snitch finishes all the tasks, arrows will appear (only visible to the Snitch) that point to the Impostors (depending on the options also to members of team Jackal).
+When the Snitch has one task left (configurable) the Snitch will be revealed to the Impostors (depending on the options also to members of team Jackal) with an arrow pointing to the Snitch.
### Game Options
| Name | Description
|----------|:-------------:|
| Snitch Spawn Chance | -
-| Task Count Where Impostors See Snitch | -
+| Task Count Where The Snitch Will Be Revealed | -
+| Include Team Jackal | -
+| Use Different Arrow Color For Team Jackal | -
-----------------------
## Jackal
| Number Of Screws Per Vent | The number of screws it takes to seal a vent
-----------------------
+## Bait
+### **Team: Crewmates**
+\
+Created by [Mallöris](https://github.com/Mallaris)\
+\
+The Bait is a Crewmate that if killed, forces the killer to self report the body (you can configure a delay in the options).
+Additionally, the Bait can see if someone is inside a vent (depending on the options the exact vent gets
+an outline or all vents do).
+
+### Game Options
+| Name | Description
+|----------|:-------------:|
+| Bait Spawn Chance | -
+| Bait Highlight All Vents | If set to true, all vents will be highlighted if a player is inside of one of them. If set to false, only the vents where players are siting in will be highlighted.
+| Bait Report Delay | -
# Source code
It's bad I know, this is a side project and my second week of modding. So there are no best practices around here.
() => {
medicShieldButton.Timer = 0f;
- MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.MedicSetShielded, Hazel.SendOption.Reliable, -1);
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, Medic.setShieldAfterMeeting ? (byte)CustomRPC.SetFutureShielded : (byte)CustomRPC.MedicSetShielded, Hazel.SendOption.Reliable, -1);
writer.Write(Medic.currentTarget.PlayerId);
AmongUsClient.Instance.FinishRpcImmediately(writer);
- RPCProcedure.medicSetShielded(Medic.currentTarget.PlayerId);
+ if (Medic.setShieldAfterMeeting)
+ RPCProcedure.setFutureShielded(Medic.currentTarget.PlayerId);
+ else
+ RPCProcedure.medicSetShielded(Medic.currentTarget.PlayerId);
},
() => { return Medic.medic != null && Medic.medic == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => { return !Medic.usedShield && Medic.currentTarget && PlayerControl.LocalPlayer.CanMove; },
},
() => { return Tracker.tracker != null && Tracker.tracker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => { return PlayerControl.LocalPlayer.CanMove && Tracker.currentTarget != null && !Tracker.usedTracker; },
- () => { },
+ () => { if(Tracker.resetTargetAfterMeeting) Tracker.resetTracked(); },
Tracker.getButtonSprite(),
new Vector3(-1.3f, 0, 0),
__instance,
public static CustomOption medicSpawnRate;
public static CustomOption medicShowShielded;
public static CustomOption medicShowAttemptToShielded;
+ public static CustomOption medicSetShieldAfterMeeting;
public static CustomOption swapperSpawnRate;
public static CustomOption swapperCanCallEmergency;
public static CustomOption trackerSpawnRate;
public static CustomOption trackerUpdateIntervall;
+ public static CustomOption trackerResetTargetAfterMeeting;
public static CustomOption snitchSpawnRate;
- public static CustomOption snitchLeftTasksForImpostors;
+ public static CustomOption snitchLeftTasksForReveal;
+ public static CustomOption snitchIncludeTeamJackal;
+ public static CustomOption snitchTeamJackalUseDifferentArrowColor;
public static CustomOption spySpawnRate;
public static CustomOption spyCanDieToSheriff;
public static CustomOption securityGuardCamPrice;
public static CustomOption securityGuardVentPrice;
+ public static CustomOption baitSpawnRate;
+ public static CustomOption baitHighlightAllVents;
+ public static CustomOption baitReportDelay;
+
public static CustomOption maxNumberOfMeetings;
public static CustomOption blockSkippingInEmergencyMeetings;
public static CustomOption noVoteIsSelfVote;
medicSpawnRate = CustomOption.Create(140, cs(Medic.color, "Medic"), rates, null, true);
medicShowShielded = CustomOption.Create(143, "Show Shielded Player", new string[] {"Everyone", "Shielded + Medic", "Medic"}, medicSpawnRate);
medicShowAttemptToShielded = CustomOption.Create(144, "Shielded Player Sees Murder Attempt", false, medicSpawnRate);
+ medicSetShieldAfterMeeting = CustomOption.Create(145, "Shield Will Be Set After The Next Meeting", false, medicSpawnRate);
swapperSpawnRate = CustomOption.Create(150, cs(Swapper.color, "Swapper"), rates, null, true);
swapperCanCallEmergency = CustomOption.Create(151, "Swapper can call emergency meeting", false, swapperSpawnRate);
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);
-
+ trackerResetTargetAfterMeeting = CustomOption.Create(202, "Tracker Reset Target After Meeting", false, trackerSpawnRate);
snitchSpawnRate = CustomOption.Create(210, cs(Snitch.color, "Snitch"), rates, null, true);
- snitchLeftTasksForImpostors = CustomOption.Create(211, "Task Count Where Impostors See Snitch", 1f, 0f, 5f, 1f, snitchSpawnRate);
+ snitchLeftTasksForReveal = CustomOption.Create(211, "Task Count Where The Snitch Will Be Revealed", 1f, 0f, 5f, 1f, snitchSpawnRate);
+ snitchIncludeTeamJackal = CustomOption.Create(212, "Include Team Jackal", false, snitchSpawnRate);
+ snitchTeamJackalUseDifferentArrowColor = CustomOption.Create(213, "Use Different Arrow Color For Team Jackal", true, snitchIncludeTeamJackal);
spySpawnRate = CustomOption.Create(240, cs(Spy.color, "Spy"), rates, null, true);
spyCanDieToSheriff = CustomOption.Create(241, "Spy Can Die To Sheriff", false, spySpawnRate);
securityGuardCamPrice = CustomOption.Create(283, "Number Of Screws Per Cam", 2f, 1f, 15f, 1f, securityGuardSpawnRate);
securityGuardVentPrice = CustomOption.Create(284, "Number Of Screws Per Vent", 1f, 1f, 15f, 1f, securityGuardSpawnRate);
+ baitSpawnRate = CustomOption.Create(330, cs(Bait.color, "Bait"), rates, null, true);
+ baitHighlightAllVents = CustomOption.Create(331, "Highlight All Vents If A Vent Is Occupied", false, baitSpawnRate);
+ baitReportDelay = CustomOption.Create(332, "Bait Report Delay", 0f, 0f, 10f, 1f, baitSpawnRate);
+
// Other options
maxNumberOfMeetings = CustomOption.Create(3, "Number Of Meetings (excluding Mayor meeting)", 10, 0, 15, 1, null, true);
blockSkippingInEmergencyMeetings = CustomOption.Create(4, "Block Skipping In Emergency Meetings", false);
var hudString = sb.ToString();
int defaultSettingsLines = 19;
- int roleSettingsLines = defaultSettingsLines + 34;
+ int roleSettingsLines = defaultSettingsLines + 35;
int detailedSettingsP1 = roleSettingsLines + 37;
int detailedSettingsP2 = detailedSettingsP1 + 38;
int end1 = hudString.TakeWhile(c => (defaultSettingsLines -= (c == '\n' ? 1 : 0)) > 0).Count();
return true;
}
-
public static void refreshRoleDescription(PlayerControl player) {
if (player == null) return;
public class TheOtherRolesPlugin : BasePlugin
{
public const string Id = "me.eisbison.theotherroles";
- public const string VersionString = "2.7.3";
+ public const string VersionString = "2.8.0";
public static System.Version Version = System.Version.Parse(VersionString);
public Harmony Harmony { get; } = new Harmony(Id);
__instance.AddChat(PlayerControl.LocalPlayer, "Changed color succesfully");;
}
}
+
+ if (text.ToLower().StartsWith("/tp ") && PlayerControl.LocalPlayer.Data.IsDead) {
+ string playerName = text.Substring(4).ToLower();
+ PlayerControl target = PlayerControl.AllPlayerControls.ToArray().ToList().FirstOrDefault(x => x.Data.PlayerName.ToLower().Equals(playerName));
+ if (target != null) {
+ PlayerControl.LocalPlayer.transform.position = target.transform.position;
+ handled = true;
+ }
+ }
+
if (handled) {
__instance.TextArea.Clear();
__instance.quickChatMenu.ResetGlyphs();
[HarmonyPatch(typeof(ExileController), "Begin")]
class ExileControllerBeginPatch {
public static void Prefix(ExileController __instance, [HarmonyArgument(0)]ref GameData.PlayerInfo exiled, [HarmonyArgument(1)]bool tie) {
+ // Medic shield
+ if (Medic.medic != null && AmongUsClient.Instance.AmHost && Medic.futureShielded != null && !Medic.medic.Data.IsDead) { // We need to send the RPC from the host here, to make sure that the order of shifting and setting the shield is correct(for that reason the futureShifted and futureShielded are being synced)
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.MedicSetShielded, Hazel.SendOption.Reliable, -1);
+ writer.Write(Medic.futureShielded.PlayerId);
+ AmongUsClient.Instance.FinishRpcImmediately(writer);
+ RPCProcedure.medicSetShielded(Medic.futureShielded.PlayerId);
+ }
+
// Shifter shift
if (Shifter.shifter != null && AmongUsClient.Instance.AmHost && Shifter.futureShift != null) { // We need to send the RPC from the host here, to make sure that the order of shifting and erasing is correct (for that reason the futureShifted and futureErased are being synced)
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShifterShift, Hazel.SendOption.Reliable, -1);
}
}
// Swapper swap votes
- if (Swapper.swapper != null && !Swapper.swapper.isDead) { // Don't swap if swapper is dead
+ if (Swapper.swapper != null && !Swapper.swapper.Data.IsDead) {
PlayerVoteArea swapped1 = null;
PlayerVoteArea swapped2 = null;
foreach (PlayerVoteArea playerVoteArea in __instance.playerStates) {
static bool Prefix(MeetingHud __instance, Il2CppStructArray<MeetingHud.VoterState> states) {
// Swapper swap
- if (Swapper.swapper != null && !Swapper.swapper.isDead) { // Don'T swap if dead
- PlayerVoteArea swapped1 = null;
- PlayerVoteArea swapped2 = null;
- foreach (PlayerVoteArea playerVoteArea in __instance.playerStates) {
- if (playerVoteArea.TargetPlayerId == Swapper.playerId1) swapped1 = playerVoteArea;
- if (playerVoteArea.TargetPlayerId == Swapper.playerId2) swapped2 = playerVoteArea;
- }
- bool doSwap = swapped1 != null && swapped2 != null;
- if (doSwap) {
- __instance.StartCoroutine(Effects.Slide3D(swapped1.transform, swapped1.transform.localPosition, swapped2.transform.localPosition, 1.5f));
- __instance.StartCoroutine(Effects.Slide3D(swapped2.transform, swapped2.transform.localPosition, swapped1.transform.localPosition, 1.5f));
- }
+
+ PlayerVoteArea swapped1 = null;
+ PlayerVoteArea swapped2 = null;
+ foreach (PlayerVoteArea playerVoteArea in __instance.playerStates) {
+ if (playerVoteArea.TargetPlayerId == Swapper.playerId1) swapped1 = playerVoteArea;
+ if (playerVoteArea.TargetPlayerId == Swapper.playerId2) swapped2 = playerVoteArea;
+ }
+ bool doSwap = swapped1 != null && swapped2 != null && Swapper.swapper != null && !Swapper.swapper.Data.IsDead;
+ if (doSwap) {
+ __instance.StartCoroutine(Effects.Slide3D(swapped1.transform, swapped1.transform.localPosition, swapped2.transform.localPosition, 1.5f));
+ __instance.StartCoroutine(Effects.Slide3D(swapped2.transform, swapped2.transform.localPosition, swapped1.transform.localPosition, 1.5f));
}
var (playerCompleted, playerTotal) = TasksHandler.taskInfo(Snitch.snitch.Data);
int numberOfTasks = playerTotal - playerCompleted;
- if (PlayerControl.LocalPlayer.Data.IsImpostor && numberOfTasks <= Snitch.taskCountForImpostors)
- {
+ if (numberOfTasks <= Snitch.taskCountForReveal && (PlayerControl.LocalPlayer.Data.IsImpostor || (Snitch.includeTeamJackal && (PlayerControl.LocalPlayer == Jackal.jackal || PlayerControl.LocalPlayer == Sidekick.sidekick)))) {
if (Snitch.localArrows.Count == 0) Snitch.localArrows.Add(new Arrow(Color.blue));
if (Snitch.localArrows.Count != 0 && Snitch.localArrows[0] != null)
{
int arrowIndex = 0;
foreach (PlayerControl p in PlayerControl.AllPlayerControls)
{
- if (p.Data.IsImpostor && !p.Data.IsDead)
- {
- if (arrowIndex >= Snitch.localArrows.Count) Snitch.localArrows.Add(new Arrow(Color.blue));
- if (arrowIndex < Snitch.localArrows.Count && Snitch.localArrows[arrowIndex] != null)
- {
+ if (!p.Data.IsDead && (p.Data.IsImpostor || (Snitch.includeTeamJackal && (p == Jackal.jackal || p == Sidekick.sidekick)))) {
+ if (arrowIndex >= Snitch.localArrows.Count) {
+ if (Snitch.teamJackalUseDifferentArrowColor && (p == Jackal.jackal || p == Sidekick.sidekick)) Snitch.localArrows.Add(new Arrow(Jackal.color));
+ else Snitch.localArrows.Add(new Arrow(Palette.ImpostorRed));
+ }
+ if (arrowIndex < Snitch.localArrows.Count && Snitch.localArrows[arrowIndex] != null) {
Snitch.localArrows[arrowIndex].arrow.SetActive(true);
Snitch.localArrows[arrowIndex].Update(p.transform.position);
}
}
}
+ static void baitUpdate() {
+ if (Bait.bait == null || Bait.bait != PlayerControl.LocalPlayer) return;
+
+ // Bait report
+ if (Bait.bait.Data.IsDead && !Bait.reported) {
+ Bait.reportDelay -= Time.fixedDeltaTime;
+ DeadPlayer deadPlayer = deadPlayers?.Where(x => x.player?.PlayerId == Bait.bait.PlayerId)?.FirstOrDefault();
+ if (deadPlayer.killerIfExisting != null && Bait.reportDelay <= 0f) {
+ deadPlayer.killerIfExisting.CmdReportDeadBody(Bait.bait.Data);
+ Bait.reported = true;
+ }
+ }
+
+ // Bait Vents
+ if (ShipStatus.Instance?.AllVents != null) {
+ var ventsWithPlayers = new List<int>();
+ foreach (PlayerControl player in PlayerControl.AllPlayerControls) {
+ if (player.inVent) {
+ Vent target = ShipStatus.Instance.AllVents.OrderBy(x => Vector2.Distance(x.transform.position, player.GetTruePosition())).FirstOrDefault();
+ if (target != null) ventsWithPlayers.Add(target.Id);
+ }
+ }
+
+ foreach (Vent vent in ShipStatus.Instance.AllVents) {
+ if (vent.myRend == null || vent.myRend.material == null) continue;
+ if (ventsWithPlayers.Contains(vent.Id) || (ventsWithPlayers.Count > 0 && Bait.highlightAllVents)) {
+ vent.myRend.material.SetFloat("_Outline", 1f);
+ vent.myRend.material.SetColor("_OutlineColor", Color.yellow);
+ } else {
+ vent.myRend.material.SetFloat("_Outline", 0);
+ }
+ }
+ }
+ }
+
public static void Postfix(PlayerControl __instance) {
if (AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started) return;
snitchUpdate();
// BountyHunter
bountyHunterUpdate();
+ // Bait
+ baitUpdate();
}
}
}
crewSettings.Add((byte)RoleId.Hacker, CustomOptionHolder.hackerSpawnRate.getSelection());
crewSettings.Add((byte)RoleId.Tracker, CustomOptionHolder.trackerSpawnRate.getSelection());
crewSettings.Add((byte)RoleId.Snitch, CustomOptionHolder.snitchSpawnRate.getSelection());
+ crewSettings.Add((byte)RoleId.Bait, CustomOptionHolder.baitSpawnRate.getSelection());
if (impostors.Count > 1) {
// Only add Spy if more than 1 impostor as the spy role is otherwise useless
crewSettings.Add((byte)RoleId.Spy, CustomOptionHolder.spySpawnRate.getSelection());
setPlayerNameColor(Arsonist.arsonist, Arsonist.color);
} else if (Guesser.guesser != null && Guesser.guesser == PlayerControl.LocalPlayer) {
setPlayerNameColor(Guesser.guesser, Guesser.guesser.Data.IsImpostor ? Palette.ImpostorRed : Guesser.color);
+ } else if (Bait.bait != null && Bait.bait == PlayerControl.LocalPlayer) {
+ setPlayerNameColor(Bait.bait, Bait.color);
}
// No else if here, as a Lover of team Jackal needs the colors
Arsonist,
Guesser,
BountyHunter,
+ Bait,
Crewmate,
Impostor
}
VersionHandshake,
UseUncheckedVent,
UncheckedMurderPlayer,
+
// Role functionality
EngineerFixLights = 81,
ErasePlayerRoles,
SetFutureErased,
SetFutureShifted,
+ SetFutureShielded,
PlaceJackInTheBox,
LightsOut,
WarlockCurseKill,
case RoleId.BountyHunter:
BountyHunter.bountyHunter = player;
break;
+ case RoleId.Bait:
+ Bait.bait = player;
+ break;
}
}
}
public static void medicSetShielded(byte shieldedId) {
Medic.usedShield = true;
- foreach (PlayerControl player in PlayerControl.AllPlayerControls)
- if (player.PlayerId == shieldedId)
- Medic.shielded = player;
+ Medic.shielded = Helpers.playerById(shieldedId);
+ Medic.futureShielded = null;
}
public static void shieldedMurderAttempt() {
SecurityGuard.securityGuard = oldShifter;
if (Guesser.guesser != null && Guesser.guesser == player)
Guesser.guesser = oldShifter;
+ if (Bait.bait != null && Bait.bait == player)
+ Bait.bait = oldShifter;
// Set cooldowns to max for both players
if (PlayerControl.LocalPlayer == oldShifter || PlayerControl.LocalPlayer == player)
if (player == Swapper.swapper) Swapper.clearAndReload();
if (player == Spy.spy) Spy.clearAndReload();
if (player == SecurityGuard.securityGuard) SecurityGuard.clearAndReload();
+ if (player == Bait.bait) Bait.clearAndReload();
// Impostor roles
if (player == Morphling.morphling) Morphling.clearAndReload();
public static void setFutureShifted(byte playerId) {
Shifter.futureShift = Helpers.playerById(playerId);
}
+
+ public static void setFutureShielded(byte playerId) {
+ Medic.futureShielded = Helpers.playerById(playerId);
+ Medic.usedShield = true;
+ }
public static void placeJackInTheBox(byte[] buff) {
Vector3 position = Vector3.zero;
case (byte)CustomRPC.SetFutureShifted:
RPCProcedure.setFutureShifted(reader.ReadByte());
break;
+ case (byte)CustomRPC.SetFutureShielded:
+ RPCProcedure.setFutureShielded(reader.ReadByte());
+ break;
case (byte)CustomRPC.PlaceJackInTheBox:
RPCProcedure.placeJackInTheBox(reader.ReadBytesAndSize());
break;
public static RoleInfo arsonist = new RoleInfo("Arsonist", Arsonist.color, "Let them burn", "Let them burn", RoleId.Arsonist);
public static RoleInfo goodGuesser = new RoleInfo("Nice Guesser", Guesser.color, "Guess and shoot", "Guess and shoot", RoleId.Guesser);
public static RoleInfo badGuesser = new RoleInfo("Evil Guesser", Palette.ImpostorRed, "Guess and shoot", "Guess and shoot", RoleId.Guesser);
+ public static RoleInfo bait = new RoleInfo("Bait", Bait.color, "Bait your enemies", "Bait your enemies", RoleId.Bait);
public static RoleInfo impostor = new RoleInfo("Impostor", Palette.ImpostorRed, Helpers.cs(Palette.ImpostorRed, "Sabotage and kill everyone"), "Sabotage and kill everyone", RoleId.Impostor);
public static RoleInfo crewmate = new RoleInfo("Crewmate", Color.white, "Find the Impostors", "Find the Impostors", RoleId.Crewmate);
public static RoleInfo lover = new RoleInfo("Lover", Lovers.color, $"You are in love", $"You are in love", RoleId.Lover);
snitch,
spy,
securityGuard,
- bountyHunter
+ bountyHunter,
+ bait
};
public static List<RoleInfo> getRoleInfoForPlayer(PlayerControl p) {
if (p == Arsonist.arsonist) infos.Add(arsonist);
if (p == Guesser.guesser) infos.Add(p.Data.IsImpostor ? badGuesser : goodGuesser);
if (p == BountyHunter.bountyHunter) infos.Add(bountyHunter);
+ if (p == Bait.bait) infos.Add(bait);
// Default roles
if (infos.Count == 0 && p.Data.IsImpostor) infos.Add(impostor); // Just Impostor
Arsonist.clearAndReload();
Guesser.clearAndReload();
BountyHunter.clearAndReload();
+ Bait.clearAndReload();
}
public static class Jester {
public static class Medic {
public static PlayerControl medic;
public static PlayerControl shielded;
+ public static PlayerControl futureShielded;
+
public static Color color = new Color32(126, 251, 194, byte.MaxValue);
public static bool usedShield;
public static int showShielded = 0;
public static bool showAttemptToShielded = false;
+ public static bool setShieldAfterMeeting = false;
public static Color shieldedColor = new Color32(0, 221, 255, byte.MaxValue);
public static PlayerControl currentTarget;
public static void clearAndReload() {
medic = null;
shielded = null;
+ futureShielded = null;
currentTarget = null;
usedShield = false;
showShielded = CustomOptionHolder.medicShowShielded.getSelection();
showAttemptToShielded = CustomOptionHolder.medicShowAttemptToShielded.getBool();
+ setShieldAfterMeeting = CustomOptionHolder.medicSetShieldAfterMeeting.getBool();
}
}
public static Color color = new Color32(100, 58, 220, byte.MaxValue);
public static float updateIntervall = 5f;
+ public static bool resetTargetAfterMeeting = false;
public static PlayerControl currentTarget;
public static PlayerControl tracked;
return buttonSprite;
}
- public static void clearAndReload() {
- tracker = null;
- currentTarget = null;
- tracked = null;
+ public static void resetTracked() {
+ currentTarget = tracked = null;
usedTracker = false;
- timeUntilUpdate = 0f;
- updateIntervall = CustomOptionHolder.trackerUpdateIntervall.getFloat();
if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow);
arrow = new Arrow(Color.blue);
if (arrow.arrow != null) arrow.arrow.SetActive(false);
}
+
+ public static void clearAndReload() {
+ tracker = null;
+ resetTracked();
+ timeUntilUpdate = 0f;
+ updateIntervall = CustomOptionHolder.trackerUpdateIntervall.getFloat();
+ resetTargetAfterMeeting = CustomOptionHolder.trackerResetTargetAfterMeeting.getBool();
+ }
}
public static class Vampire {
public static Color color = new Color32(184, 251, 79, byte.MaxValue);
public static List<Arrow> localArrows = new List<Arrow>();
- public static int taskCountForImpostors = 1;
+ public static int taskCountForReveal = 1;
+ public static bool includeTeamJackal = false;
+ public static bool teamJackalUseDifferentArrowColor = true;
+
public static void clearAndReload() {
if (localArrows != null) {
UnityEngine.Object.Destroy(arrow.arrow);
}
localArrows = new List<Arrow>();
- taskCountForImpostors = Mathf.RoundToInt(CustomOptionHolder.snitchLeftTasksForImpostors.getFloat());
+ taskCountForReveal = Mathf.RoundToInt(CustomOptionHolder.snitchLeftTasksForReveal.getFloat());
+ includeTeamJackal = CustomOptionHolder.snitchIncludeTeamJackal.getBool();
+ teamJackalUseDifferentArrowColor = CustomOptionHolder.snitchTeamJackalUseDifferentArrowColor.getBool();
snitch = null;
}
}
arrowUpdateIntervall = CustomOptionHolder.bountyHunterArrowUpdateIntervall.getFloat();
}
}
+
+ public static class Bait {
+ public static PlayerControl bait;
+ public static Color color = new Color32(0, 247, 255, byte.MaxValue);
+
+ public static bool highlightAllVents = false;
+ public static float reportDelay = 0f;
+
+ public static bool reported = false;
+
+ public static void clearAndReload() {
+ bait = null;
+ reported = false;
+ highlightAllVents = CustomOptionHolder.baitHighlightAllVents.getBool();
+ reportDelay = CustomOptionHolder.baitReportDelay.getFloat();
+ }
+ }
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
- <Version>2.7.3</Version>
+ <Version>2.8.0</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
</PropertyGroup>
<PropertyGroup>
- <GameVersion>2021.6.15</GameVersion>
<DefineConstants>$(DefineConstants);STEAM</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>