# Releases
| Among Us - Version| Mod Version | Link |
|----------|-------------|-----------------|
+| 2021.11.9.5s| v3.0.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.0.0/TheOtherRoles.zip)
| 2021.6.30s| v2.9.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.9.2/TheOtherRoles.zip)
| 2021.6.30s| v2.9.1| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.9.1/TheOtherRoles.zip)
| 2021.6.30s| v2.9.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.9.0/TheOtherRoles.zip)
<details>
<summary>Click to show the Changelog</summary>
+**Version 3.0.0**
+- Update to Among Us version v2021.11.9.5s
+- **Note:** We wanted to update as fast as possible, that's why you can't use both the Innersloth and mod roles at the same time. We'll make that possible in the future, but there are various things that need to be modified (e.g. Shifter, Guesser, ...) to make that work, so that'll take a little longer. Also, be aware that this version might contain more bugs than usual because Innersloth changed a lot of things and we might have missed some of them.
+- Ability buttons are now bind to the Q key (if it's a killing ability) or to the F key (otherwise). We'll make the binds adaptable in the future.
+- For now we removed the option "Jester Can Sabotage"
+- The Sheriff now always dies, when he tries to kill a not fully grown Mini
+
**Hotfix 2.9.2**
- Fixed a bug where the names of all players were visible during camouflage
- Fixed a bug where the Morphling didn't take over the name of its target
### **Team: Impostors**
The Mafia are a group of three Impostors.\
The Godfather works like a normal Impostor.\
-The Mafioso is an Impostor who cannot kill nor sabotage until the Godfather is dead.\
-The Janitor is an Impostor who cannot kill nor sabotage, but they can hide dead bodies instead.\
+The Mafioso is an Impostor who cannot kill until the Godfather is dead.\
+The Janitor is an Impostor who cannot kill, but they can hide dead bodies instead.\
\
**NOTE:**
- There have to be 3 Impostors activated for the mafia to spawn.
| Name | Description |
|----------|:-------------:|
| Jester Spawn Chance | -
-| Jester can call emergency meeting | Option to disable the emergency button for the Jester
-| Jester can sabotage | Option to allow the Jester to sabotage
+| Jester Can Call Emergency Meeting | Option to disable the emergency button for the Jester
-----------------------
## Arsonist
## Engineer
### **Team: Crewmates**
-The Engineer (if alive) can fix one sabotage per game from anywhere on the map.\
-The Engineer can use vents. If the Engineer is inside a vent, the Impostors will see a blue outline
-around all vents on the map (in order to warn them).
-Because of the vents the Engineer might not be able to start some tasks using the "Use" button,
-you can double-click on the tasks instead.
+The Engineer (if alive) can fix a certain amount of sabotages per game from anywhere on the map.\
+The Engineer can use vents.\
+If the Engineer is inside a vent, depending on the options the members of the team Jackal/Impostors will see a blue outline around all vents on the map (in order to warn them).
+Because of the vents the Engineer might not be able to start some tasks using the "Use" button, you can double-click on the tasks instead.\
\
**NOTE:**
- The kill button of Impostors activates if they stand next to a vent where the Engineer is. They can also kill them there. No other action (e.g. Morphling sample, Shifter shift, ...) can affect players inside vents.
| Name | Description |
|----------|:-------------:|
| Engineer Spawn Chance | -
+| Number Of Sabotage Fixes| -
+| Impostors See Vents Highlighted | -
+| Jackal and Sidekick See Vents Highlighted | -
-----------------------
## Detective
- If it gets thrown out of the ship before it turns 18, everyone loses. So think twice before you vote out a Mini.
**NOTE:**
-- Impostors can't kill the Mini (the button does not work) until it turns 18
+- If the Sheriff tries to kill the Mini before it's fully grown, he dies, no matter if the Mini is a Crewmate or Impostor
- The Sheriff can kill the Impostor Mini, but only if it's fully grown up
### Game Options
| Jackals promoted from Sidekick can create a Sidekick | Yes/No (to prevent the Jackal team from growing) |
| Jackals can make an Impostor to his Sidekick | Yes/No (to prevent a Jackal from turning an Impostor into a Sidekick, if he uses the ability on an Impostor he sees the Impostor as Sidekick, but the Impostor isn't converted to Sidekick. If this option is set to "No" Jackal and Sidekick can kill each other.) |
| Jackal and Sidekick have Impostor vision | - |
-| Jackal and Sidekick Can See Engineer Vent | - | If set to true, team Jackal will see vents highlited like Impostors if an Engineer is inside one
-----------------------
## Sidekick
public static void resetTimeMasterButton() {
timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer;
timeMasterShieldButton.isEffectActive = false;
- timeMasterShieldButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ timeMasterShieldButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
}
public static void Postfix(HudManager __instance)
}
}
},
- () => { return Engineer.engineer != null && Engineer.engineer == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
+ () => { return Engineer.engineer != null && Engineer.engineer == PlayerControl.LocalPlayer && Engineer.remainingFixes > 0 && !PlayerControl.LocalPlayer.Data.IsDead; },
() => {
bool sabotageActive = false;
foreach (PlayerTask task in PlayerControl.LocalPlayer.myTasks)
if (task.TaskType == TaskTypes.FixLights || task.TaskType == TaskTypes.RestoreOxy || task.TaskType == TaskTypes.ResetReactor || task.TaskType == TaskTypes.ResetSeismic || task.TaskType == TaskTypes.FixComms || task.TaskType == TaskTypes.StopCharles)
sabotageActive = true;
- return sabotageActive && !Engineer.usedRepair && PlayerControl.LocalPlayer.CanMove;
+ return sabotageActive && Engineer.remainingFixes > 0 && PlayerControl.LocalPlayer.CanMove;
},
() => {},
Engineer.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
// Janitor Clean
}
},
() => { return Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
- () => { return __instance.ReportButton.renderer.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
+ () => { return __instance.ReportButton.graphic.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
() => { janitorCleanButton.Timer = janitorCleanButton.MaxTimer; },
Janitor.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
// Sheriff Kill
}
byte targetId = 0;
- if ((Sheriff.currentTarget.Data.IsImpostor && (Sheriff.currentTarget != Mini.mini || Mini.isGrownUp())) ||
+ if ((Sheriff.currentTarget.Data.Role.IsImpostor && (Sheriff.currentTarget != Mini.mini || Mini.isGrownUp())) ||
(Sheriff.spyCanDieToSheriff && Spy.spy == Sheriff.currentTarget) ||
(Sheriff.canKillNeutrals && (Arsonist.arsonist == Sheriff.currentTarget || Jester.jester == Sheriff.currentTarget || Vulture.vulture == Sheriff.currentTarget)) ||
(Jackal.jackal == Sheriff.currentTarget || Sidekick.sidekick == Sheriff.currentTarget)) {
() => { return Sheriff.sheriff != null && Sheriff.sheriff == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => { return Sheriff.currentTarget && PlayerControl.LocalPlayer.CanMove; },
() => { sheriffKillButton.Timer = sheriffKillButton.MaxTimer;},
- __instance.KillButton.renderer.sprite,
- new Vector3(-1.3f, 0, 0),
+ __instance.KillButton.graphic.sprite,
+ new Vector3(0f, 1f, 0),
__instance,
KeyCode.Q
);
() => {
timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer;
timeMasterShieldButton.isEffectActive = false;
- timeMasterShieldButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ timeMasterShieldButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
},
TimeMaster.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q,
+ KeyCode.F,
true,
TimeMaster.shieldDuration,
() => { timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer; }
() => { return !Medic.usedShield && Medic.currentTarget && PlayerControl.LocalPlayer.CanMove; },
() => {},
Medic.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
() => { return Shifter.currentTarget && Shifter.futureShift == null && PlayerControl.LocalPlayer.CanMove; },
() => { },
Shifter.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
// Morphling morph
morphlingButton.Timer = morphlingButton.MaxTimer;
morphlingButton.Sprite = Morphling.getSampleSprite();
morphlingButton.isEffectActive = false;
- morphlingButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ morphlingButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
Morphling.sampledTarget = null;
},
Morphling.getSampleSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F,
true,
() => {
camouflagerButton.Timer = camouflagerButton.MaxTimer;
camouflagerButton.isEffectActive = false;
- camouflagerButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ camouflagerButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
},
Camouflager.getButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F,
true,
() => {
hackerButton.Timer = hackerButton.MaxTimer;
hackerButton.isEffectActive = false;
- hackerButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ hackerButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
},
Hacker.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q,
+ KeyCode.F,
true,
0f,
() => {
() => { return PlayerControl.LocalPlayer.CanMove && Tracker.currentTarget != null && !Tracker.usedTracker; },
() => { if(Tracker.resetTargetAfterMeeting) Tracker.resetTracked(); },
Tracker.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
vampireKillButton = new CustomButton(
() => {
- if (Helpers.handleMurderAttempt(Vampire.currentTarget)) {
+ if (Helpers.handleMurderAttempt(Vampire.vampire, Vampire.currentTarget)) {
if (Vampire.targetNearGarlic) {
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.UncheckedMurderPlayer, Hazel.SendOption.Reliable, -1);
writer.Write(Vampire.vampire.PlayerId);
HudManager.Instance.StartCoroutine(Effects.Lerp(Vampire.delay, new Action<float>((p) => { // Delayed action
if (p == 1f) {
- if (Vampire.bitten != null && !Vampire.bitten.Data.IsDead && Helpers.handleMurderAttempt(Vampire.bitten)) {
+ if (Vampire.bitten != null && !Vampire.bitten.Data.IsDead && Helpers.handleMurderAttempt(Vampire.vampire, Vampire.bitten)) {
// Perform kill
MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.VampireTryKill, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(killWriter);
},
() => { return Vampire.vampire != null && Vampire.vampire == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => {
- if (Vampire.targetNearGarlic && Vampire.canKillNearGarlics)
- vampireKillButton.killButtonManager.renderer.sprite = __instance.KillButton.renderer.sprite;
- else
- vampireKillButton.killButtonManager.renderer.sprite = Vampire.getButtonSprite();
+ if (Vampire.targetNearGarlic && Vampire.canKillNearGarlics) {
+ vampireKillButton.actionButton.graphic.sprite = __instance.KillButton.graphic.sprite;
+ vampireKillButton.showButtonText = true;
+ }
+ else {
+ vampireKillButton.actionButton.graphic.sprite = Vampire.getButtonSprite();
+ vampireKillButton.showButtonText = false;
+ }
return Vampire.currentTarget != null && PlayerControl.LocalPlayer.CanMove && (!Vampire.targetNearGarlic || Vampire.canKillNearGarlics);
},
() => {
vampireKillButton.Timer = vampireKillButton.MaxTimer;
vampireKillButton.isEffectActive = false;
- vampireKillButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ vampireKillButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
},
Vampire.getButtonSprite(),
- new Vector3(-1.3f, 0, 0),
+ new Vector3(0, 1f, 0),
__instance,
KeyCode.Q,
false,
() => { return PlayerControl.LocalPlayer.CanMove && !Vampire.localPlacedGarlic; },
() => { },
Vampire.getGarlicButtonSprite(),
- Vector3.zero,
+ new Vector3(0, -0.06f, 0),
__instance,
null,
true
() => { return Jackal.canCreateSidekick && Jackal.currentTarget != null && PlayerControl.LocalPlayer.CanMove; },
() => { jackalSidekickButton.Timer = jackalSidekickButton.MaxTimer;},
Jackal.getSidekickButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
// Jackal Kill
jackalKillButton = new CustomButton(
() => {
- if (!Helpers.handleMurderAttempt(Jackal.currentTarget)) return;
+ if (!Helpers.handleMurderAttempt(Jackal.jackal, Jackal.currentTarget)) return;
byte targetId = Jackal.currentTarget.PlayerId;
MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.JackalKill, Hazel.SendOption.Reliable, -1);
killWriter.Write(targetId);
() => { return Jackal.jackal != null && Jackal.jackal == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => { return Jackal.currentTarget && PlayerControl.LocalPlayer.CanMove; },
() => { jackalKillButton.Timer = jackalKillButton.MaxTimer;},
- __instance.KillButton.renderer.sprite,
- new Vector3(-1.3f, 0, 0),
+ __instance.KillButton.graphic.sprite,
+ new Vector3(0, 1f, 0),
__instance,
KeyCode.Q
);
// Sidekick Kill
sidekickKillButton = new CustomButton(
() => {
- if (!Helpers.handleMurderAttempt(Sidekick.currentTarget)) return;
+ if (!Helpers.handleMurderAttempt(Sidekick.sidekick, Sidekick.currentTarget)) return;
byte targetId = Sidekick.currentTarget.PlayerId;
MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SidekickKill, Hazel.SendOption.Reliable, -1);
killWriter.Write(targetId);
() => { return Sidekick.canKill && Sidekick.sidekick != null && Sidekick.sidekick == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => { return Sidekick.currentTarget && PlayerControl.LocalPlayer.CanMove; },
() => { sidekickKillButton.Timer = sidekickKillButton.MaxTimer;},
- __instance.KillButton.renderer.sprite,
- new Vector3(-1.3f, 0, 0),
+ __instance.KillButton.graphic.sprite,
+ new Vector3(0, 1f, 0),
__instance,
KeyCode.Q
);
() => {
lighterButton.Timer = lighterButton.MaxTimer;
lighterButton.isEffectActive = false;
- lighterButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ lighterButton.actionButton.graphic.color = Palette.EnabledColor;
},
Lighter.getButtonSprite(),
- new Vector3(-1.3f, 0f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q,
+ KeyCode.F,
true,
Lighter.duration,
() => { lighterButton.Timer = lighterButton.MaxTimer; }
() => { return PlayerControl.LocalPlayer.CanMove && Eraser.currentTarget != null; },
() => { eraserButton.Timer = eraserButton.MaxTimer;},
Eraser.getButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
() => { return PlayerControl.LocalPlayer.CanMove && !JackInTheBox.hasJackInTheBoxLimitReached(); },
() => { placeJackInTheBoxButton.Timer = placeJackInTheBoxButton.MaxTimer;},
Trickster.getPlaceBoxButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
() => {
lightsOutButton.Timer = lightsOutButton.MaxTimer;
lightsOutButton.isEffectActive = false;
- lightsOutButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ lightsOutButton.actionButton.graphic.color = Palette.EnabledColor;
},
Trickster.getLightsOutButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F,
true,
Trickster.lightsOutDuration,
() => { lightsOutButton.Timer = lightsOutButton.MaxTimer; }
);
+
// Cleaner Clean
cleanerCleanButton = new CustomButton(
() => {
}
},
() => { return Cleaner.cleaner != null && Cleaner.cleaner == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
- () => { return __instance.ReportButton.renderer.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
+ () => { return __instance.ReportButton.graphic.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
() => { cleanerCleanButton.Timer = cleanerCleanButton.MaxTimer; },
Cleaner.getButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
Warlock.curseVictim = Warlock.currentTarget;
warlockCurseButton.Sprite = Warlock.getCurseKillButtonSprite();
warlockCurseButton.Timer = 1f;
- } else if (Warlock.curseVictim != null && Warlock.curseVictimTarget != null && Helpers.handleMurderAttempt(Warlock.curseVictimTarget)) {
+ } else if (Warlock.curseVictim != null && Warlock.curseVictimTarget != null && Helpers.handleMurderAttempt(Warlock.warlock, Warlock.curseVictimTarget)) {
// Curse Kill
Warlock.curseKillTarget = Warlock.curseVictimTarget;
Warlock.curseVictimTarget = null;
},
Warlock.getCurseButtonSprite(),
- new Vector3(-1.3f, 1.3f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
},
() => { return SecurityGuard.securityGuard != null && SecurityGuard.securityGuard == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead && SecurityGuard.remainingScrews >= Mathf.Min(SecurityGuard.ventPrice, SecurityGuard.camPrice); },
() => {
- securityGuardButton.killButtonManager.renderer.sprite = (SecurityGuard.ventTarget == null && PlayerControl.GameOptions.MapId != 1) ? SecurityGuard.getPlaceCameraButtonSprite() : SecurityGuard.getCloseVentButtonSprite();
+ securityGuardButton.actionButton.graphic.sprite = (SecurityGuard.ventTarget == null && PlayerControl.GameOptions.MapId != 1) ? SecurityGuard.getPlaceCameraButtonSprite() : SecurityGuard.getCloseVentButtonSprite();
if (securityGuardButtonScrewsText != null) securityGuardButtonScrewsText.text = $"{SecurityGuard.remainingScrews}/{SecurityGuard.totalScrews}";
if (SecurityGuard.ventTarget != null)
},
() => { securityGuardButton.Timer = securityGuardButton.MaxTimer; },
SecurityGuard.getPlaceCameraButtonSprite(),
- new Vector3(-1.3f, 0f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q
+ KeyCode.F
);
// Security Guard button screws counter
- securityGuardButtonScrewsText = GameObject.Instantiate(securityGuardButton.killButtonManager.TimerText, securityGuardButton.killButtonManager.TimerText.transform.parent);
+ securityGuardButtonScrewsText = GameObject.Instantiate(securityGuardButton.actionButton.cooldownTimerText, securityGuardButton.actionButton.cooldownTimerText.transform.parent);
securityGuardButtonScrewsText.text = "";
securityGuardButtonScrewsText.enableWordWrapping = false;
securityGuardButtonScrewsText.transform.localScale = Vector3.one * 0.5f;
() => { return Arsonist.arsonist != null && Arsonist.arsonist == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
() => {
bool dousedEveryoneAlive = Arsonist.dousedEveryoneAlive();
- if (dousedEveryoneAlive) arsonistButton.killButtonManager.renderer.sprite = Arsonist.getIgniteSprite();
+ if (dousedEveryoneAlive) arsonistButton.actionButton.graphic.sprite = Arsonist.getIgniteSprite();
if (arsonistButton.isEffectActive && Arsonist.douseTarget != Arsonist.currentTarget) {
Arsonist.douseTarget = null;
Arsonist.douseTarget = null;
},
Arsonist.getDouseSprite(),
- new Vector3(-1.3f, 0f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q,
+ KeyCode.F,
true,
Arsonist.duration,
() => {
}
},
() => { return Vulture.vulture != null && Vulture.vulture == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; },
- () => { return __instance.ReportButton.renderer.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
+ () => { return __instance.ReportButton.graphic.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; },
() => { vultureEatButton.Timer = vultureEatButton.MaxTimer; },
Vulture.getButtonSprite(),
- new Vector3(-1.3f, 0f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
KeyCode.F
);
Medium.soulTarget = null;
},
Medium.getQuestionSprite(),
- new Vector3(-1.3f, 0f, 0f),
+ new Vector3(-1.8f, -0.06f, 0),
__instance,
- KeyCode.Q,
+ KeyCode.F,
true,
Medium.duration,
() => {
string msg = "";
int randomNumber = Medium.target.killerIfExisting?.PlayerId == Mini.mini?.PlayerId ? TheOtherRoles.rnd.Next(3) : TheOtherRoles.rnd.Next(4);
- string typeOfColor = Helpers.isLighterColor(Medium.target.killerIfExisting.Data.ColorId) ? "lighter" : "darker";
+ string typeOfColor = Helpers.isLighterColor(Medium.target.killerIfExisting.Data.DefaultOutfit.ColorId) ? "lighter" : "darker";
float timeSinceDeath = ((float)(Medium.meetingStartTime - Medium.target.timeOfDeath).TotalMilliseconds);
string name = " (" + Medium.target.player.Data.PlayerName + ")";
public static string[] presets = new string[]{"Preset 1", "Preset 2", "Preset 3", "Preset 4", "Preset 5"};
public static CustomOption presetSelection;
+ public static CustomOption activateRoles;
public static CustomOption crewmateRolesCountMin;
public static CustomOption crewmateRolesCountMax;
public static CustomOption neutralRolesCountMin;
public static CustomOption jesterSpawnRate;
public static CustomOption jesterCanCallEmergency;
- public static CustomOption jesterCanSabotage;
public static CustomOption arsonistSpawnRate;
public static CustomOption arsonistCooldown;
public static CustomOption jackalPromotedFromSidekickCanCreateSidekick;
public static CustomOption jackalCanCreateSidekickFromImpostor;
public static CustomOption jackalAndSidekickHaveImpostorVision;
- public static CustomOption jackalCanSeeEngineerVent;
public static CustomOption bountyHunterSpawnRate;
public static CustomOption bountyHunterBountyDuration;
public static CustomOption mayorSpawnRate;
public static CustomOption engineerSpawnRate;
+ public static CustomOption engineerNumberOfFixes;
+ public static CustomOption engineerHighlightForImpostors;
+ public static CustomOption engineerHighlightForTeamJackal;
public static CustomOption sheriffSpawnRate;
public static CustomOption sheriffCooldown;
// Role Options
presetSelection = CustomOption.Create(0, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Preset"), presets, null, true);
+ activateRoles = CustomOption.Create(7, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Enable Mod Roles And Block Vanilla Roles"), true, null, true);
// Using new id's for the options to not break compatibilty with older versions
crewmateRolesCountMin = CustomOption.Create(300, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Crewmate Roles"), 0f, 0f, 15f, 1f, null, true);
jesterSpawnRate = CustomOption.Create(60, cs(Jester.color, "Jester"), rates, null, true);
jesterCanCallEmergency = CustomOption.Create(61, "Jester can call emergency meeting", true, jesterSpawnRate);
- jesterCanSabotage = CustomOption.Create(62, "Jester can sabotage", true, 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);
jackalPromotedFromSidekickCanCreateSidekick = CustomOption.Create(228, "Jackals Promoted From Sidekick Can Create A Sidekick", true, jackalSpawnRate);
jackalCanCreateSidekickFromImpostor = CustomOption.Create(229, "Jackals Can Make An Impostor To His Sidekick", true, jackalSpawnRate);
jackalAndSidekickHaveImpostorVision = CustomOption.Create(430, "Jackal And Sidekick Have Impostor Vision", false, jackalSpawnRate);
- jackalCanSeeEngineerVent = CustomOption.Create(431, "Jackal Can See If Engineer Is In A Vent", false, jackalSpawnRate);
vultureSpawnRate = CustomOption.Create(340, cs(Vulture.color, "Vulture"), rates, null, true);
vultureCooldown = CustomOption.Create(341, "Vulture Cooldown", 15f, 10f, 60f, 2.5f, vultureSpawnRate);
mayorSpawnRate = CustomOption.Create(80, cs(Mayor.color, "Mayor"), rates, null, true);
engineerSpawnRate = CustomOption.Create(90, cs(Engineer.color, "Engineer"), rates, null, true);
+ engineerNumberOfFixes = CustomOption.Create(91, "Number Of Sabotage Fixes", 1f, 0f, 3f, 1f, engineerSpawnRate);
+ engineerHighlightForImpostors = CustomOption.Create(92, "Impostors See Vents Highlighted", true, engineerSpawnRate);
+ engineerHighlightForTeamJackal = CustomOption.Create(93, "Jackal and Sidekick See Vents Highlighted ", true, engineerSpawnRate);
sheriffSpawnRate = CustomOption.Create(100, cs(Sheriff.color, "Sheriff"), rates, null, true);
sheriffCooldown = CustomOption.Create(101, "Sheriff Cooldown", 30f, 10f, 60f, 2.5f, sheriffSpawnRate);
[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Start))]
class GameOptionsMenuStartPatch {
public static void Postfix(GameOptionsMenu __instance) {
+ if (GameObject.Find("TORSettings") != null) { // Settings setup has already been performed, fixing the title of the tab and returning
+ GameObject.Find("TORSettings").transform.FindChild("GameGroup").FindChild("Text").GetComponent<TMPro.TextMeshPro>().SetText("The Other Roles Settings");
+ return;
+ }
+
+ // Setup TOR tab
var template = UnityEngine.Object.FindObjectsOfType<StringOption>().FirstOrDefault();
if (template == null) return;
+ var gameSettings = GameObject.Find("Game Settings");
+ var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
+ var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
+ var torMenu = torSettings.transform.FindChild("GameGroup").FindChild("SliderInner").GetComponent<GameOptionsMenu>();
+ torSettings.name = "TORSettings";
+
+ var roleTab = GameObject.Find("RoleTab");
+ var gameTab = GameObject.Find("GameTab");
+
+ var torTab = UnityEngine.Object.Instantiate(roleTab, roleTab.transform.parent);
+ var torTabHighlight = torTab.transform.FindChild("Hat Button").FindChild("Tab Background").GetComponent<SpriteRenderer>();
+ torTab.transform.FindChild("Hat Button").FindChild("Icon").GetComponent<SpriteRenderer>().sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.TabIcon.png", 100f);
+
+ gameTab.transform.position += Vector3.left * 0.5f;
+ torTab.transform.position += Vector3.right * 0.5f;
+ roleTab.transform.position += Vector3.left * 0.5f;
+
+ var tabs = new GameObject[]{gameTab, roleTab, torTab};
+ for (int i = 0; i < tabs.Length; i++) {
+ var button = tabs[i].GetComponentInChildren<PassiveButton>();
+ if (button == null) continue;
+ int copiedIndex = i;
+ button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
+ button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() => {
+ gameSettingMenu.RegularGameSettings.SetActive(false);
+ gameSettingMenu.RolesSettings.gameObject.SetActive(false);
+ torSettings.gameObject.SetActive(false);
+ gameSettingMenu.GameSettingsHightlight.enabled = false;
+ gameSettingMenu.RolesSettingsHightlight.enabled = false;
+ torTabHighlight.enabled = false;
+ if (copiedIndex == 0) {
+ gameSettingMenu.RegularGameSettings.SetActive(true);
+ gameSettingMenu.GameSettingsHightlight.enabled = true;
+ } else if (copiedIndex == 1) {
+ gameSettingMenu.RolesSettings.gameObject.SetActive(true);
+ gameSettingMenu.RolesSettingsHightlight.enabled = true;
+ } else if (copiedIndex == 2) {
+ torSettings.gameObject.SetActive(true);
+ torTabHighlight.enabled = true;
+ }
+ }));
+ }
+
+ foreach (OptionBehaviour option in torMenu.GetComponentsInChildren<OptionBehaviour>())
+ UnityEngine.Object.Destroy(option.gameObject);
+ List<OptionBehaviour> torOptions = new List<OptionBehaviour>();
- List<OptionBehaviour> allOptions = __instance.Children.ToList();
for (int i = 0; i < CustomOption.options.Count; i++) {
CustomOption option = CustomOption.options[i];
if (option.optionBehaviour == null) {
- StringOption stringOption = UnityEngine.Object.Instantiate(template, template.transform.parent);
- allOptions.Add(stringOption);
-
+ StringOption stringOption = UnityEngine.Object.Instantiate(template, torMenu.transform);
+ torOptions.Add(stringOption);
stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => {});
stringOption.TitleText.text = option.name;
stringOption.Value = stringOption.oldValue = option.selection;
}
option.optionBehaviour.gameObject.SetActive(true);
}
-
- var commonTasksOption = allOptions.FirstOrDefault(x => x.name == "NumCommonTasks").TryCast<NumberOption>();
+
+ torMenu.Children = torOptions.ToArray();
+ torSettings.gameObject.SetActive(false);
+
+ // Adapt task count for main options
+
+ var commonTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumCommonTasks").TryCast<NumberOption>();
if(commonTasksOption != null) commonTasksOption.ValidRange = new FloatRange(0f, 4f);
- var shortTasksOption = allOptions.FirstOrDefault(x => x.name == "NumShortTasks").TryCast<NumberOption>();
+ var shortTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumShortTasks").TryCast<NumberOption>();
if(shortTasksOption != null) shortTasksOption.ValidRange = new FloatRange(0f, 23f);
- var longTasksOption = allOptions.FirstOrDefault(x => x.name == "NumLongTasks").TryCast<NumberOption>();
+ var longTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumLongTasks").TryCast<NumberOption>();
if(longTasksOption != null) longTasksOption.ValidRange = new FloatRange(0f, 15f);
-
- __instance.Children = allOptions.ToArray();
}
}
{
private static float timer = 1f;
public static void Postfix(GameOptionsMenu __instance) {
+ if (__instance.Children.Length < 100) return; // TODO: Introduce a cleaner way to seperate the TOR settings from the game settings
+
__instance.GetComponentInParent<Scroller>().YBounds.max = -0.5F + __instance.Children.Length * 0.55F;
timer += Time.deltaTime;
if (timer < 0.1f) return;
timer = 0f;
- float offset = -7.85f;
+ float offset = 2.75f;
foreach (CustomOption option in CustomOption.options) {
if (option?.optionBehaviour != null && option.optionBehaviour.gameObject != null) {
bool enabled = true;
}
}
- [HarmonyPatch(typeof(GameSettingMenu), "OnEnable")]
- class GameSettingMenuPatch {
+ [HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))]
+ class GameSettingMenuStartPatch {
public static void Prefix(GameSettingMenu __instance) {
__instance.HideForOnline = new Transform[]{};
}
public static void Postfix(GameSettingMenu __instance) {
+ // Setup mapNameTransform
var mapNameTransform = __instance.AllItems.FirstOrDefault(x => x.gameObject.activeSelf && x.name.Equals("MapName", StringComparison.OrdinalIgnoreCase));
if (mapNameTransform == null) return;
var options = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Collections.Generic.KeyValuePair<string, int>>();
- for (int i = 0; i < GameOptionsData.MapNames.Length; i++) {
+ for (int i = 0; i < Constants.MapNames.Length; i++) {
var kvp = new Il2CppSystem.Collections.Generic.KeyValuePair<string, int>();
- kvp.key = GameOptionsData.MapNames[i];
+ kvp.key = Constants.MapNames[i];
kvp.value = i;
options.Add(kvp);
}
var hudString = sb.ToString();
- int defaultSettingsLines = 19;
- int roleSettingsLines = defaultSettingsLines + 37;
- int detailedSettingsP1 = roleSettingsLines + 37;
- int detailedSettingsP2 = detailedSettingsP1 + 38;
+ int defaultSettingsLines = 23;
+ int roleSettingsLines = defaultSettingsLines + 38;
+ int detailedSettingsP1 = roleSettingsLines + 40;
+ int detailedSettingsP2 = detailedSettingsP1 + 42;
+ int detailedSettingsP3 = detailedSettingsP2 + 42;
int end1 = hudString.TakeWhile(c => (defaultSettingsLines -= (c == '\n' ? 1 : 0)) > 0).Count();
int end2 = hudString.TakeWhile(c => (roleSettingsLines -= (c == '\n' ? 1 : 0)) > 0).Count();
int end3 = hudString.TakeWhile(c => (detailedSettingsP1 -= (c == '\n' ? 1 : 0)) > 0).Count();
int end4 = hudString.TakeWhile(c => (detailedSettingsP2 -= (c == '\n' ? 1 : 0)) > 0).Count();
+ int end5 = hudString.TakeWhile(c => (detailedSettingsP3 -= (c == '\n' ? 1 : 0)) > 0).Count();
int counter = TheOtherRolesPlugin.optionsPage;
if (counter == 0) {
hudString = hudString.Substring(0, end1) + "\n";
} else if (counter == 1) {
hudString = hudString.Substring(end1 + 1, end2 - end1);
// Temporary fix, should add a new CustomOption for spaces
- int gap = 1;
+ int gap = 2;
int index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index, "\n");
- gap = 5;
+ gap = 6;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index, "\n");
- gap = 18;
+ gap = 19;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index + 1, "\n");
- gap = 23;
+ gap = 24;
index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count();
hudString = hudString.Insert(index + 1, "\n");
} else if (counter == 2) {
} else if (counter == 3) {
hudString = hudString.Substring(end3 + 1, end4 - end3);
} else if (counter == 4) {
- hudString = hudString.Substring(end4 + 1);
+ hudString = hudString.Substring(end4 + 1, end5 - end4);
+ } else if (counter == 5) {
+ hudString = hudString.Substring(end5 + 1);
}
- hudString += $"\n Press tab for more... ({counter+1}/5)";
+ hudString += $"\n Press tab for more... ({counter+1}/6)";
__result = hudString;
}
}
public static void Postfix(KeyboardJoystick __instance)
{
if(Input.GetKeyDown(KeyCode.Tab)) {
- TheOtherRolesPlugin.optionsPage = (TheOtherRolesPlugin.optionsPage + 1) % 5;
+ TheOtherRolesPlugin.optionsPage = (TheOtherRolesPlugin.optionsPage + 1) % 6;
}
}
}
return res;
}
- public static bool handleMurderAttempt(PlayerControl target, bool isMeetingStart = false) {
+ public static bool handleMurderAttempt(PlayerControl killer, PlayerControl target, bool isMeetingStart = false) {
// Block impostor shielded kill
if (Medic.shielded != null && Medic.shielded == target) {
- MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1);
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.shieldedMurderAttempt();
// Block Time Master with time shield kill
else if (TimeMaster.shieldActive && TimeMaster.timeMaster != null && TimeMaster.timeMaster == target) {
if (!isMeetingStart) { // Only rewind the attempt was not called because a meeting startet
- MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.TimeMasterRewindTime, Hazel.SendOption.Reliable, -1);
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.TimeMasterRewindTime, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.timeMasterRewindTime();
}
public static void handleVampireBiteOnBodyReport() {
// Murder the bitten player before the meeting starts or reset the bitten player
- if (Vampire.bitten != null && !Vampire.bitten.Data.IsDead && Helpers.handleMurderAttempt(Vampire.bitten, true)) {
+ if (Vampire.bitten != null && !Vampire.bitten.Data.IsDead && Helpers.handleMurderAttempt(Vampire.vampire, Vampire.bitten, true)) {
MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.VampireTryKill, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(killWriter);
RPCProcedure.vampireTryKill();
else if (!MapOptions.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.IsImpostor && (target.Data.IsImpostor || target == Spy.spy)) 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)) 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
return true;
}
public static void setDefaultLook(this PlayerControl target) {
- target.setLook(target.Data.PlayerName, target.Data.ColorId, target.Data.HatId, target.Data.SkinId, target.Data.PetId);
+ target.setLook(target.Data.PlayerName, target.Data.DefaultOutfit.ColorId, target.Data.DefaultOutfit.HatId, target.Data.DefaultOutfit.VisorId, target.Data.DefaultOutfit.SkinId, target.Data.DefaultOutfit.PetId);
}
- public static void setLook(this PlayerControl target, String playerName, int colorId, uint hatId, uint skinId, uint petId) {
- target.nameText.text = hidePlayerName(PlayerControl.LocalPlayer, target) ? "" : playerName;
- target.myRend.material.SetColor("_BackColor", Palette.ShadowColors[colorId]);
- target.myRend.material.SetColor("_BodyColor", Palette.PlayerColors[colorId]);
- target.HatRenderer.SetHat(hatId, colorId);
- target.nameText.transform.localPosition = new Vector3(0f, ((hatId == 0U) ? 0.7f : 1.05f) * 2f, -0.5f);
+ public static void setLook(this PlayerControl target, String playerName, int colorId, string hatId, string visorId, string skinId, string petId) {
+ target.RawSetColor(colorId);
+ target.RawSetVisor(visorId);
+ target.RawSetHat(hatId, colorId);
+ target.RawSetName(hidePlayerName(PlayerControl.LocalPlayer, target) ? "" : playerName);
- SkinData nextSkin = DestroyableSingleton<HatManager>.Instance.AllSkins[(int)skinId];
+ SkinData nextSkin = DestroyableSingleton<HatManager>.Instance.GetSkinById(skinId);
PlayerPhysics playerPhysics = target.MyPhysics;
AnimationClip clip = null;
var spriteAnim = playerPhysics.Skin.animator;
spriteAnim.m_animator.Update(0f);
if (target.CurrentPet) UnityEngine.Object.Destroy(target.CurrentPet.gameObject);
- target.CurrentPet = UnityEngine.Object.Instantiate<PetBehaviour>(DestroyableSingleton<HatManager>.Instance.AllPets[(int)petId]);
+ target.CurrentPet = UnityEngine.Object.Instantiate<PetBehaviour>(DestroyableSingleton<HatManager>.Instance.GetPetById(petId).PetPrefab);
target.CurrentPet.transform.position = target.transform.position;
target.CurrentPet.Source = target;
target.CurrentPet.Visible = target.Visible;
PlayerControl.SetPlayerMaterialColors(colorId, target.CurrentPet.rend);
}
+
+ public static bool roleCanUseVents(this PlayerControl player) {
+ bool roleCouldUse = false;
+ if (Engineer.engineer != null && Engineer.engineer == player)
+ roleCouldUse = true;
+ else if (Jackal.canUseVents && Jackal.jackal != null && Jackal.jackal == player)
+ roleCouldUse = true;
+ else if (Sidekick.canUseVents && Sidekick.sidekick != null && Sidekick.sidekick == player)
+ roleCouldUse = true;
+ else if (Spy.canEnterVents && Spy.spy != null && Spy.spy == player)
+ roleCouldUse = true;
+ else if (Vulture.canUseVents && Vulture.vulture != null && Vulture.vulture == player)
+ roleCouldUse = true;
+ else if (player.Data?.Role != null && player.Data.Role.CanVent) {
+ if (Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer)
+ roleCouldUse = false;
+ else if (Mafioso.mafioso != null && Mafioso.mafioso == PlayerControl.LocalPlayer && Godfather.godfather != null && !Godfather.godfather.Data.IsDead)
+ roleCouldUse = false;
+ else
+ roleCouldUse = true;
+ }
+ return roleCouldUse;
+ }
}
}
public class TheOtherRolesPlugin : BasePlugin
{
public const string Id = "me.eisbison.theotherroles";
- public const string VersionString = "2.9.2";
+ public const string VersionString = "3.0.0";
public static System.Version Version = System.Version.Parse(VersionString);
+ internal static BepInEx.Logging.ManualLogSource Logger;
public Harmony Harmony { get; } = new Harmony(Id);
public static TheOtherRolesPlugin Instance;
}
public override void Load() {
-
+ Logger = Log;
DebugMode = Config.Bind("Custom", "Enable Debug Mode", false);
StreamerMode = Config.Bind("Custom", "Enable Streamer Mode", false);
GhostsSeeTasks = Config.Bind("Custom", "Ghosts See Remaining Tasks", true);
playerControl.NetTransform.enabled = false;
playerControl.SetName(RandomString(10));
playerControl.SetColor((byte) random.Next(Palette.PlayerColors.Length));
- playerControl.SetHat((uint) random.Next(HatManager.Instance.AllHats.Count), playerControl.Data.ColorId);
- playerControl.SetPet((uint) random.Next(HatManager.Instance.AllPets.Count));
- playerControl.SetSkin((uint) random.Next(HatManager.Instance.AllSkins.Count));
GameData.Instance.RpcSetTasks(playerControl.PlayerId, new byte[0]);
}
private static class PlayerControlCheckColorPatch {
private static bool isTaken(PlayerControl player, uint color) {
foreach (GameData.PlayerInfo p in GameData.Instance.AllPlayers)
- if (!p.Disconnected && p.PlayerId != player.PlayerId && p.ColorId == color)
+ if (!p.Disconnected && p.PlayerId != player.PlayerId && p.DefaultOutfit.ColorId == color)
return true;
return false;
}
public string condition { get; set;}
public Sprite FlipImage { get; set;}
public Sprite BackFlipImage { get; set;}
-
- public bool isUnlocked() {
- if (condition == null || condition.ToLower() == "none")
- return true;
- return false;
- }
}
public class CustomHat {
}
}
- HatBehaviour hat = new HatBehaviour();
+ HatBehaviour hat = ScriptableObject.CreateInstance<HatBehaviour>();
hat.MainImage = CreateHatSprite(ch.resource, fromDisk);
if (ch.backresource != null) {
hat.BackImage = CreateHatSprite(ch.backresource, fromDisk);
hat.InFront = !ch.behind;
hat.NoBounce = !ch.bounce;
hat.ChipOffset = new Vector2(0f, 0.2f);
+ hat.Free = true;
if (ch.adaptive && hatShader != null)
hat.AltShader = hatShader;
if (RUNNING) return;
RUNNING = true; // prevent simultanious execution
try {
- if (!LOADED) {
- Assembly assembly = Assembly.GetExecutingAssembly();
- string hatres = $"{assembly.GetName().Name}.Resources.CustomHats";
- string[] hats = (from r in assembly.GetManifestResourceNames()
- where r.StartsWith(hatres) && r.EndsWith(".png")
- select r).ToArray<string>();
-
- List<CustomHat> customhats = createCustomHatDetails(hats);
- foreach (CustomHat ch in customhats)
- __instance.AllHats.Add(CreateHatBehaviour(ch));
- }
while (CustomHatLoader.hatdetails.Count > 0) {
__instance.AllHats.Add(CreateHatBehaviour(CustomHatLoader.hatdetails[0]));
CustomHatLoader.hatdetails.RemoveAt(0);
}
}
- [HarmonyPatch(typeof(HatParent), nameof(HatParent.SetHat), new System.Type[] { typeof(uint), typeof(int) })]
+ [HarmonyPatch(typeof(HatParent), nameof(HatParent.SetHat), new System.Type[] { typeof(HatBehaviour), typeof(int) })]
private static class HatParentSetHatPatch {
- static void Postfix(HatParent __instance, [HarmonyArgument(0)]uint hatId, [HarmonyArgument(1)]int color) {
+ static void Postfix(HatParent __instance, HatBehaviour hat, int color) {
if (DestroyableSingleton<TutorialManager>.InstanceExists) {
try {
string filePath = Path.GetDirectoryName(Application.dataPath) + @"\TheOtherHats\Test";
}
}
- private static List<TMPro.TMP_Text> hatsTabCustomTexts = new List<TMPro.TMP_Text>();
-
[HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))]
public class HatsTabOnEnablePatch {
public static string innerslothPackageName = "Innersloth Hats";
TMPro.TMP_Text title = UnityEngine.Object.Instantiate<TMPro.TMP_Text>(textTemplate, __instance.scroller.Inner);
title.transform.localPosition = new Vector3(2.25f, YStart, -1f);
title.transform.localScale = Vector3.one * 1.5f;
- // title.currentFontSize
title.fontSize *= 0.5f;
title.enableAutoSizing = false;
__instance.StartCoroutine(Effects.Lerp(0.1f, new System.Action<float>((p) => { title.SetText(packageName); })));
offset -= 0.8f * __instance.YOffset;
- hatsTabCustomTexts.Add(title);
}
for (int i = 0; i < hats.Count; i++) {
HatBehaviour hat = hats[i].Item1;
float xpos = __instance.XRange.Lerp((i % __instance.NumPerRow) / (__instance.NumPerRow - 1f));
float ypos = offset - (i / __instance.NumPerRow) * (isDefaultPackage ? 1f : 1.5f) * __instance.YOffset;
ColorChip colorChip = UnityEngine.Object.Instantiate<ColorChip>(__instance.ColorTabPrefab, __instance.scroller.Inner);
- if (ext != null) {
- Transform background = colorChip.transform.FindChild("Background");
- Transform foreground = colorChip.transform.FindChild("ForeGround");
+ if (ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard) {
+ colorChip.Button.OnMouseOver.AddListener((UnityEngine.Events.UnityAction)(() => __instance.SelectHat(hat)));
+ colorChip.Button.OnMouseOut.AddListener((UnityEngine.Events.UnityAction)(() => __instance.SelectHat(DestroyableSingleton<HatManager>.Instance.GetHatById(SaveManager.LastHat))));
+ colorChip.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() => __instance.ClickEquip()));
+ } else {
+ colorChip.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() => __instance.SelectHat(hat)));
+ }
+ colorChip.Button.ClickMask = __instance.scroller.Hitbox;
+ Transform background = colorChip.transform.FindChild("Background");
+ Transform foreground = colorChip.transform.FindChild("ForeGround");
+ if (ext != null) {
if (background != null) {
- background.localScale = new Vector3(1, 1.5f, 1);
background.localPosition = Vector3.down * 0.243f;
+ background.localScale = new Vector3(background.localScale.x, 0.8f, background.localScale.y);
}
if (foreground != null) {
foreground.localPosition = Vector3.down * 0.243f;
if (textTemplate != null) {
TMPro.TMP_Text description = UnityEngine.Object.Instantiate<TMPro.TMP_Text>(textTemplate, colorChip.transform);
- description.transform.localPosition = new Vector3(0f, -0.75f, -1f);
- description.transform.localScale = Vector3.one * 0.7f;
+ description.transform.localPosition = new Vector3(0f, -0.65f, -1f);
+ description.alignment = TMPro.TextAlignmentOptions.Center;
+ description.transform.localScale = Vector3.one * 0.65f;
__instance.StartCoroutine(Effects.Lerp(0.1f, new System.Action<float>((p) => { description.SetText($"{hat.name}\nby {ext.author}"); })));
- hatsTabCustomTexts.Add(description);
- }
-
- if (!ext.isUnlocked()) { // Hat is locked
- UnityEngine.Object.Destroy(colorChip.Button);
- var overlay = UnityEngine.Object.Instantiate(colorChip.InUseForeground, colorChip.transform);
- overlay.SetActive(true);
}
}
colorChip.transform.localPosition = new Vector3(xpos, ypos, -1f);
- colorChip.Button.OnClick.AddListener((UnityEngine.Events.UnityAction)(() => { __instance.SelectHat(hat); }));
- colorChip.Inner.SetHat(hat, PlayerControl.LocalPlayer.Data.ColorId);
+ colorChip.Inner.SetHat(hat, PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId);
colorChip.Inner.transform.localPosition = hat.ChipOffset;
colorChip.Tag = hat;
+ colorChip.SelectionHighlight.gameObject.SetActive(false);
__instance.ColorChips.Add(colorChip);
}
- return offset - ((hats.Count - 1) / __instance.NumPerRow) * (isDefaultPackage ? 1f : 1.5f) * __instance.YOffset - 0.85f;
+ return offset - ((hats.Count - 1) / __instance.NumPerRow) * (isDefaultPackage ? 1f : 1.5f) * __instance.YOffset - 1.75f;
}
- public static bool Prefix(HatsTab __instance) {
- PlayerControl.SetPlayerMaterialColors(PlayerControl.LocalPlayer.Data.ColorId, __instance.DemoImage);
- __instance.HatImage.SetHat(SaveManager.LastHat, PlayerControl.LocalPlayer.Data.ColorId);
- PlayerControl.SetSkinImage(SaveManager.LastSkin, __instance.SkinImage);
- PlayerControl.SetPetImage(SaveManager.LastPet, PlayerControl.LocalPlayer.Data.ColorId, __instance.PetImage);
+ public static void Postfix(HatsTab __instance) {
+ for (int i = 0; i < __instance.scroller.Inner.childCount; i++)
+ UnityEngine.Object.Destroy(__instance.scroller.Inner.GetChild(i).gameObject);
+ __instance.ColorChips = new Il2CppSystem.Collections.Generic.List<ColorChip>();
HatBehaviour[] unlockedHats = DestroyableSingleton<HatManager>.Instance.GetUnlockedHats();
Dictionary<string, List<System.Tuple<HatBehaviour, HatExtension>>> packages = new Dictionary<string, List<System.Tuple<HatBehaviour, HatExtension>>>();
- hatsTabCustomTexts = new List<TMPro.TMP_Text>();
foreach (HatBehaviour hatBehaviour in unlockedHats) {
HatExtension ext = hatBehaviour.getHatExtension();
}
float YOffset = __instance.YStart;
-
- var hatButton = GameObject.Find("HatButton");
-
- if (hatButton != null && hatButton.transform.FindChild("ButtonText_TMP") != null) {
- textTemplate = hatButton.transform.FindChild("ButtonText_TMP").GetComponent<TMPro.TMP_Text>();
- }
+ textTemplate = GameObject.Find("HatsGroup").transform.FindChild("Text").GetComponent<TMPro.TMP_Text>();
var orderedKeys = packages.Keys.OrderBy((string x) => {
if (x == innerslothPackageName) return 1000;
YOffset = createHatPackage(value, key, YOffset, __instance);
}
- // __instance.scroller.YBounds.max = -(__instance.YStart - (float)(unlockedHats.Length / this.NumPerRow) * this.YOffset) - 3f;
- // __instance.scroller.YBounds.max = YOffset * -0.875f; // probably needs to fix up the entire messed math to solve this correctly
- __instance.scroller.YBounds.max = -(YOffset + 4.1f);
- return false;
+ __instance.scroller.YBounds.max = -(YOffset + 4.1f);
}
}
- [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.Update))]
- public class HatsTabUpdatePatch {
- public static void Postfix(HatsTab __instance) {
- // Manually hide all custom TMPro.TMP_Text objects that are outside the ScrollRect
- foreach (TMPro.TMP_Text customText in hatsTabCustomTexts) {
- if (customText != null && customText.transform != null && customText.gameObject != null) {
- bool active = customText.transform.position.y <= 3.75f && customText.transform.position.y >= 0.3f;
- float epsilon = Mathf.Min(Mathf.Abs(customText.transform.position.y - 3.75f), Mathf.Abs(customText.transform.position.y - 0.35f));
- if (active != customText.gameObject.active && epsilon > 0.1f) customText.gameObject.SetActive(active);
- }
- }
- }
- }
}
public class CustomHatLoader {
Update(target);
}
- public void Update(Vector3 target)
+ public void Update(Vector3 target, Color? color = null)
{
if (arrow == null) return;
oldTarget = target;
+ if (color.HasValue) image.color = color.Value;
+
Camera main = Camera.main;
Vector2 vector = target - main.transform.position;
float num = vector.magnitude / (main.orthographicSize * perc);
public class CustomButton
{
public static List<CustomButton> buttons = new List<CustomButton>();
- public KillButtonManager killButtonManager;
+ public ActionButton actionButton;
public Vector3 PositionOffset;
public float MaxTimer = float.MaxValue;
public float Timer = 0f;
private Action OnEffectEnds;
public bool HasEffect;
public bool isEffectActive = false;
- private bool showButtonText = false;
+ public bool showButtonText = false;
public float EffectDuration;
public Sprite Sprite;
private HudManager hudManager;
this.hotkey = hotkey;
Timer = 16.2f;
buttons.Add(this);
- killButtonManager = UnityEngine.Object.Instantiate(hudManager.KillButton, hudManager.transform);
- this.showButtonText = killButtonManager.renderer.sprite == Sprite;
- PassiveButton button = killButtonManager.GetComponent<PassiveButton>();
+ actionButton = UnityEngine.Object.Instantiate(hudManager.KillButton, hudManager.KillButton.transform.parent);
+ PassiveButton button = actionButton.GetComponent<PassiveButton>();
+ this.showButtonText = actionButton.graphic.sprite == Sprite;
button.OnClick = new Button.ButtonClickedEvent();
button.OnClick.AddListener((UnityEngine.Events.UnityAction)onClickEvent);
{
if (this.Timer < 0f && HasButton() && CouldUse())
{
- killButtonManager.renderer.color = new Color(1f, 1f, 1f, 0.3f);
+ actionButton.graphic.color = new Color(1f, 1f, 1f, 0.3f);
this.OnClick();
if (this.HasEffect && !this.isEffectActive) {
this.Timer = this.EffectDuration;
- killButtonManager.TimerText.color = new Color(0F, 0.8F, 0F);
+ actionButton.cooldownTimerText.color = new Color(0F, 0.8F, 0F);
this.isEffectActive = true;
}
}
public static void HudUpdate()
{
- buttons.RemoveAll(item => item.killButtonManager == null);
+ buttons.RemoveAll(item => item.actionButton == null);
for (int i = 0; i < buttons.Count; i++)
{
}
public static void MeetingEndedUpdate() {
- buttons.RemoveAll(item => item.killButtonManager == null);
+ buttons.RemoveAll(item => item.actionButton == null);
for (int i = 0; i < buttons.Count; i++)
{
try
public void setActive(bool isActive) {
if (isActive) {
- killButtonManager.gameObject.SetActive(true);
- killButtonManager.renderer.enabled = true;
+ actionButton.gameObject.SetActive(true);
+ actionButton.graphic.enabled = true;
} else {
- killButtonManager.gameObject.SetActive(false);
- killButtonManager.renderer.enabled = false;
+ actionButton.gameObject.SetActive(false);
+ actionButton.graphic.enabled = false;
}
}
}
setActive(hudManager.UseButton.isActiveAndEnabled);
- killButtonManager.renderer.sprite = Sprite;
- killButtonManager.killText.enabled = showButtonText; // Only show the text if it's a kill button
+ actionButton.graphic.sprite = Sprite;
+ actionButton.buttonLabelText.enabled = showButtonText; // Only show the text if it's a kill button
if (hudManager.UseButton != null) {
Vector3 pos = hudManager.UseButton.transform.localPosition;
if (mirror) pos = new Vector3(-pos.x, pos.y, pos.z);
- killButtonManager.transform.localPosition = pos + PositionOffset;
- if (hudManager.KillButton != null) hudManager.KillButton.transform.localPosition = hudManager.UseButton.transform.localPosition - new Vector3(1.3f, 0, 0); // Align the kill button (because it's on another position depending on the screen resolution)
+ actionButton.transform.localPosition = pos + PositionOffset;
}
if (CouldUse()) {
- killButtonManager.renderer.color = killButtonManager.killText.color = Palette.EnabledColor;
- killButtonManager.renderer.material.SetFloat("_Desat", 0f);
+ actionButton.graphic.color = actionButton.buttonLabelText.color = Palette.EnabledColor;
+ actionButton.graphic.material.SetFloat("_Desat", 0f);
} else {
- killButtonManager.renderer.color = killButtonManager.killText.color = Palette.DisabledClear;
- killButtonManager.renderer.material.SetFloat("_Desat", 1f);
+ actionButton.graphic.color = actionButton.buttonLabelText.color = Palette.DisabledClear;
+ actionButton.graphic.material.SetFloat("_Desat", 1f);
}
if (Timer >= 0) {
if (Timer <= 0 && HasEffect && isEffectActive) {
isEffectActive = false;
- killButtonManager.TimerText.color = Palette.EnabledColor;
+ actionButton.cooldownTimerText.color = Palette.EnabledColor;
OnEffectEnds();
}
- killButtonManager.SetCoolDown(Timer, (HasEffect && isEffectActive) ? EffectDuration : MaxTimer);
+ actionButton.SetCoolDown(Timer, (HasEffect && isEffectActive) ? EffectDuration : MaxTimer);
// Trigger OnClickEvent if the hotkey is being pressed down
if (hotkey.HasValue && Input.GetKeyDown(hotkey.Value)) onClickEvent();
if (anonymousFootprints)
this.color = Palette.PlayerColors[6];
else
- this.color = Palette.PlayerColors[(int) player.Data.ColorId];
+ this.color = Palette.PlayerColors[(int) player.Data.DefaultOutfit.ColorId];
footprint = new GameObject("Footprint");
Vector3 position = new Vector3(player.transform.position.x, player.transform.position.y, player.transform.position.z + 1f);
Color c = color;
if (!anonymousFootprints && owner != null) {
if (owner == Morphling.morphling && Morphling.morphTimer > 0 && Morphling.morphTarget?.Data != null)
- c = Palette.ShadowColors[Morphling.morphTarget.Data.ColorId];
+ c = Palette.ShadowColors[Morphling.morphTarget.Data.DefaultOutfit.ColorId];
else if (Camouflager.camouflageTimer > 0)
c = Palette.PlayerColors[6];
}
private static ToggleButtonBehaviour showRoleSummaryButton;
public static float xOffset = 1.75f;
- public static float yOffset = -0.5f;
+ public static float yOffset = -0.25f;
private static void updateToggle(ToggleButtonBehaviour button, string text, bool on) {
if (button == null || button.gameObject == null) return;
public static void Postfix(OptionsMenuBehaviour __instance) {
if (__instance.CensorChatButton != null) {
- if (origin == null) origin = __instance.CensorChatButton.transform.localPosition + Vector3.up * 0.25f;
+ if (origin == null) origin = __instance.CensorChatButton.transform.localPosition + Vector3.up * 0.075f;
__instance.CensorChatButton.transform.localPosition = origin.Value + Vector3.left * xOffset;
- __instance.CensorChatButton.transform.localScale = Vector3.one * 2f / 3f;
+ __instance.CensorChatButton.transform.localScale = Vector3.one * 0.5f;
}
if ((streamerModeButton == null || streamerModeButton.gameObject == null)) {
[HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnGameEnd))]
public class OnGameEndPatch {
private static GameOverReason gameOverReason;
- public static void Prefix(AmongUsClient __instance, [HarmonyArgument(0)]ref GameOverReason reason, [HarmonyArgument(1)]bool showAd) {
- gameOverReason = reason;
- if ((int)reason >= 10) reason = GameOverReason.ImpostorByKill;
+ public static void Prefix(AmongUsClient __instance, [HarmonyArgument(0)]ref EndGameResult endGameResult) {
+ gameOverReason = endGameResult.GameOverReason;
+ if ((int)endGameResult.GameOverReason >= 10) endGameResult.GameOverReason = GameOverReason.ImpostorByKill;
}
- public static void Postfix(AmongUsClient __instance, [HarmonyArgument(0)]ref GameOverReason reason, [HarmonyArgument(1)]bool showAd) {
+ public static void Postfix(AmongUsClient __instance, [HarmonyArgument(0)]ref EndGameResult endGameResult) {
AdditionalTempData.clear();
foreach(var playerControl in PlayerControl.AllPlayerControls) {
List<WinningPlayerData> winnersToRemove = new List<WinningPlayerData>();
foreach (WinningPlayerData winner in TempData.winners) {
- if (notWinners.Any(x => x.Data.PlayerName == winner.Name)) winnersToRemove.Add(winner);
+ if (notWinners.Any(x => x.Data.PlayerName == winner.PlayerName)) winnersToRemove.Add(winner);
}
foreach (var winner in winnersToRemove) TempData.winners.Remove(winner);
if (p == null) continue;
if (p == Lovers.lover1 || p == Lovers.lover2)
TempData.winners.Add(new WinningPlayerData(p.Data));
- else if (p != Jester.jester && p != Jackal.jackal && p != Sidekick.sidekick && p != Arsonist.arsonist && !Jackal.formerJackals.Contains(p) && !p.Data.IsImpostor)
+ else if (p != Jester.jester && p != Jackal.jackal && p != Sidekick.sidekick && p != Arsonist.arsonist && !Jackal.formerJackals.Contains(p) && !p.Data.Role.IsImpostor)
TempData.winners.Add(new WinningPlayerData(p.Data));
}
}
if (MapOptions.showRoleSummary) {
var position = Camera.main.ViewportToWorldPoint(new Vector3(0f, 1f, Camera.main.nearClipPlane));
GameObject roleSummary = UnityEngine.Object.Instantiate(__instance.WinText.gameObject);
- roleSummary.transform.position = new Vector3(__instance.ExitButton.transform.position.x + 0.1f, position.y - 0.1f, -14f);
+ roleSummary.transform.position = new Vector3(__instance.Navigation.ExitButton.transform.position.x + 0.1f, position.y - 0.1f, -14f);
roleSummary.transform.localScale = new Vector3(1f, 1f, 1f);
var roleSummaryText = new StringBuilder();
bool lover = isLover(playerInfo);
if (lover) numLoversAlive++;
- if (playerInfo.IsImpostor) {
+ if (playerInfo.Role.IsImpostor) {
numImpostorsAlive++;
if (lover) impLover = true;
}
static void WrapUpPostfix(GameData.PlayerInfo exiled) {
// Mini exile lose condition
- if (exiled != null && Mini.mini != null && Mini.mini.PlayerId == exiled.PlayerId && !Mini.isGrownUp() && !Mini.mini.Data.IsImpostor) {
+ if (exiled != null && Mini.mini != null && Mini.mini.PlayerId == exiled.PlayerId && !Mini.isGrownUp() && !Mini.mini.Data.Role.IsImpostor) {
Mini.triggerMiniLose = true;
}
// Jester win condition
CustomButton.MeetingEndedUpdate();
// Mini set adapted cooldown
- if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.IsImpostor) {
+ if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.Role.IsImpostor) {
var multiplier = Mini.isGrownUp() ? 0.66f : 2f;
Mini.mini.SetKillTimer(PlayerControl.GameOptions.KillCooldown * multiplier);
}
public class GameStartManagerUpdatePatch {
private static bool update = false;
private static string currentText = "";
- private static int kc = 0;
- private static KeyCode[] ks = new [] { KeyCode.UpArrow, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow, KeyCode.LeftArrow, KeyCode.RightArrow, KeyCode.B, KeyCode.A, KeyCode.Return };
public static void Prefix(GameStartManager __instance) {
if (!AmongUsClient.Instance.AmHost || !GameData.Instance) return; // Not host or no instance
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.versionHandshake(TheOtherRolesPlugin.Version.Major, TheOtherRolesPlugin.Version.Minor, TheOtherRolesPlugin.Version.Build, TheOtherRolesPlugin.Version.Revision, Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId, AmongUsClient.Instance.ClientId);
}
-
- if(kc < ks.Length && Input.GetKeyDown(ks[kc])) {
- kc++;
- } else if(Input.anyKeyDown) {
- kc = 0;
- }
-
- if(kc == ks.Length) {
- kc = 0;
-
- // Random Color
- byte colorId = (byte)TheOtherRoles.rnd.Next(0, Palette.PlayerColors.Length);
- SaveManager.BodyColor = (byte)colorId;
- if (PlayerControl.LocalPlayer) PlayerControl.LocalPlayer.CmdCheckColor(colorId);
-
- // Random Hat
- var hats = HatManager.Instance.GetUnlockedHats();
- var unlockedHatIndex = TheOtherRoles.rnd.Next(0, hats.Length);
- var hatId = (uint)HatManager.Instance.AllHats.IndexOf(hats[unlockedHatIndex]);
- if (PlayerControl.LocalPlayer) PlayerControl.LocalPlayer.RpcSetHat(hatId);
-
- // Random Skin
- var skins = HatManager.Instance.GetUnlockedSkins();
- var unlockedSkinIndex = TheOtherRoles.rnd.Next(0, skins.Length);
- var skinId = (uint)HatManager.Instance.AllSkins.IndexOf(skins[unlockedSkinIndex]);
- if (PlayerControl.LocalPlayer) PlayerControl.LocalPlayer.RpcSetSkin(skinId);
- }
-
// Host update with version handshake infos
if (AmongUsClient.Instance.AmHost) {
foreach (PlayerControl p in PlayerControl.AllPlayerControls) {
GameData.PlayerInfo data = p.Data;
PoolablePlayer player = UnityEngine.Object.Instantiate<PoolablePlayer>(__instance.PlayerPrefab, HudManager.Instance.transform);
- PlayerControl.SetPlayerMaterialColors(data.ColorId, player.Body);
- DestroyableSingleton<HatManager>.Instance.SetSkin(player.Skin.layer, data.SkinId);
- player.HatSlot.SetHat(data.HatId, data.ColorId);
- PlayerControl.SetPetImage(data.PetId, data.ColorId, player.PetSlot);
+ PlayerControl.SetPlayerMaterialColors(data.DefaultOutfit.ColorId, player.Body);
+ DestroyableSingleton<HatManager>.Instance.SetSkin(player.Skin.layer, data.DefaultOutfit.SkinId);
+ player.HatSlot.SetHat(data.DefaultOutfit.HatId, data.DefaultOutfit.ColorId);
+ PlayerControl.SetPetImage(data.DefaultOutfit.PetId, data.DefaultOutfit.ColorId, player.PetSlot);
player.NameText.text = data.PlayerName;
player.SetFlipX(true);
MapOptions.playerIcons[p.PlayerId] = player;
BountyHunter.bountyUpdateTimer = 0f;
if (HudManager.Instance != null) {
Vector3 bottomLeft = new Vector3(-HudManager.Instance.UseButton.transform.localPosition.x, HudManager.Instance.UseButton.transform.localPosition.y, HudManager.Instance.UseButton.transform.localPosition.z) + new Vector3(-0.25f, 1f, 0);
- BountyHunter.cooldownText = UnityEngine.Object.Instantiate<TMPro.TextMeshPro>(HudManager.Instance.KillButton.TimerText, HudManager.Instance.transform);
+ BountyHunter.cooldownText = UnityEngine.Object.Instantiate<TMPro.TextMeshPro>(HudManager.Instance.KillButton.cooldownTimerText, HudManager.Instance.transform);
BountyHunter.cooldownText.alignment = TMPro.TextAlignmentOptions.Center;
BountyHunter.cooldownText.transform.localPosition = bottomLeft + new Vector3(0f, -1f, -1f);
BountyHunter.cooldownText.gameObject.SetActive(true);
[HarmonyPatch]
class IntroPatch {
- public static void setupIntroTeam(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
+ public static void setupIntroTeamIcons(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
// Intro solo teams
if (PlayerControl.LocalPlayer == Jester.jester || PlayerControl.LocalPlayer == Jackal.jackal || PlayerControl.LocalPlayer == Arsonist.arsonist || PlayerControl.LocalPlayer == Vulture.vulture) {
var soloTeam = new Il2CppSystem.Collections.Generic.List<PlayerControl>();
}
// Add the Spy to the Impostor team (for the Impostors)
- if (Spy.spy != null && PlayerControl.LocalPlayer.Data.IsImpostor) {
+ if (Spy.spy != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor) {
List<PlayerControl> players = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList();
var fakeImpostorTeam = new Il2CppSystem.Collections.Generic.List<PlayerControl>();
foreach (PlayerControl p in players) {
- if (p == Spy.spy || p.Data.IsImpostor)
+ if (p == Spy.spy || p.Data.Role.IsImpostor)
fakeImpostorTeam.Add(p);
}
yourTeam = fakeImpostorTeam;
}
}
- public static void setupIntroRole(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
+ public static void setupIntroTeam(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
List<RoleInfo> infos = RoleInfo.getRoleInfoForPlayer(PlayerControl.LocalPlayer);
RoleInfo roleInfo = infos.Where(info => info.roleId != RoleId.Lover).FirstOrDefault();
+ if (roleInfo == null) return;
+ if (roleInfo.isNeutral) {
+ var neutralColor = new Color32(76, 84, 78, 255);
+ __instance.BackgroundBar.material.color = neutralColor;
+ __instance.TeamTitle.text = "Neutral";
+ __instance.TeamTitle.color = neutralColor;
+ }
+ }
+
+ [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.SetUpRoleText))]
+ class SetUpRoleTextPatch {
+ public static void Postfix(IntroCutscene __instance) {
+ if (!CustomOptionHolder.activateRoles.getBool()) return; // Don't override the intro of the vanilla roles
+
+ List<RoleInfo> infos = RoleInfo.getRoleInfoForPlayer(PlayerControl.LocalPlayer);
+ RoleInfo roleInfo = infos.Where(info => info.roleId != RoleId.Lover).FirstOrDefault();
- if (roleInfo != null) {
- __instance.Title.text = roleInfo.name;
- __instance.ImpostorText.gameObject.SetActive(true);
- __instance.ImpostorText.text = roleInfo.introDescription;
- if (roleInfo.roleId != RoleId.Crewmate && roleInfo.roleId != RoleId.Impostor) {
- // For native Crewmate or Impostor do not modify the colors
- __instance.Title.color = roleInfo.color;
- __instance.BackgroundBar.material.color = roleInfo.color;
+ if (roleInfo != null) {
+ __instance.RoleText.text = roleInfo.name;
+ __instance.RoleText.color = roleInfo.color;
+ __instance.RoleBlurbText.text = roleInfo.introDescription;
+ __instance.RoleBlurbText.color = roleInfo.color;
}
- }
- if (infos.Any(info => info.roleId == RoleId.Lover)) {
- var loversText = UnityEngine.Object.Instantiate<TMPro.TextMeshPro>(__instance.ImpostorText, __instance.ImpostorText.transform.parent);
- loversText.transform.localPosition += Vector3.down * 3f;
- PlayerControl otherLover = PlayerControl.LocalPlayer == Lovers.lover1 ? Lovers.lover2 : Lovers.lover1;
- loversText.text = Helpers.cs(Lovers.color, $"♥ You are in love with {otherLover?.Data?.PlayerName ?? ""} ♥");
+ if (infos.Any(info => info.roleId == RoleId.Lover)) {
+ PlayerControl otherLover = PlayerControl.LocalPlayer == Lovers.lover1 ? Lovers.lover2 : Lovers.lover1;
+ __instance.RoleBlurbText.text += Helpers.cs(Lovers.color, $"\n♥ You are in love with {otherLover?.Data?.PlayerName ?? ""} ♥");
+ }
}
}
[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.BeginCrewmate))]
class BeginCrewmatePatch {
public static void Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroTeam(__instance, ref yourTeam);
+ setupIntroTeamIcons(__instance, ref yourTeam);
}
public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroRole(__instance, ref yourTeam);
+ setupIntroTeam(__instance, ref yourTeam);
}
}
[HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.BeginImpostor))]
class BeginImpostorPatch {
public static void Prefix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroTeam(__instance, ref yourTeam);
+ setupIntroTeamIcons(__instance, ref yourTeam);
}
public static void Postfix(IntroCutscene __instance, ref Il2CppSystem.Collections.Generic.List<PlayerControl> yourTeam) {
- setupIntroRole(__instance, ref yourTeam);
+ setupIntroTeam(__instance, ref yourTeam);
}
}
}
public static bool Prefix(MeetingHud __instance, [HarmonyArgument(0)]GameData.PlayerInfo voterPlayer, [HarmonyArgument(1)]int index, [HarmonyArgument(2)]Transform parent) {
SpriteRenderer spriteRenderer = UnityEngine.Object.Instantiate<SpriteRenderer>(__instance.PlayerVotePrefab);
if (!PlayerControl.GameOptions.AnonymousVotes || (PlayerControl.LocalPlayer.Data.IsDead && MapOptions.ghostsSeeVotes))
- PlayerControl.SetPlayerMaterialColors(voterPlayer.ColorId, spriteRenderer);
+ PlayerControl.SetPlayerMaterialColors(voterPlayer.DefaultOutfit.ColorId, spriteRenderer);
else
PlayerControl.SetPlayerMaterialColors(Palette.DisabledGrey, spriteRenderer);
spriteRenderer.transform.SetParent(parent);
if (guesserUI != null || !(__instance.state == MeetingHud.VoteStates.Voted || __instance.state == MeetingHud.VoteStates.NotVoted)) return;
__instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(false));
- Transform container = UnityEngine.Object.Instantiate(__instance.transform.FindChild("Background"), __instance.transform);
- container.FindChild("BlackBG").gameObject.SetActive(false);
+ Transform container = UnityEngine.Object.Instantiate(__instance.transform.FindChild("PhoneUI"), __instance.transform);
container.transform.localPosition = new Vector3(0, 0, -5f);
guesserUI = container.gameObject;
for (int i = 0; i < allPlayers.Count; i++)
{
GameData.PlayerInfo playerInfo = allPlayers[i];
- if (!playerInfo.Disconnected && playerInfo.PlayerId != targetingPlayer.PlayerId && !playerInfo.IsDead && (!onlyCrewmates || !playerInfo.IsImpostor))
+ if (!playerInfo.Disconnected && playerInfo.PlayerId != targetingPlayer.PlayerId && !playerInfo.IsDead && (!onlyCrewmates || !playerInfo.Role.IsImpostor))
{
PlayerControl @object = playerInfo.Object;
if(untargetablePlayers != null && untargetablePlayers.Any(x => x == @object)) {
}
static void engineerUpdate() {
- if ((Jackal.canSeeEngineerVent && (PlayerControl.LocalPlayer == Jackal.jackal || PlayerControl.LocalPlayer == Sidekick.sidekick)) || PlayerControl.LocalPlayer.Data.IsImpostor && ShipStatus.Instance?.AllVents != null) {
+ bool jackalHighlight = Engineer.highlightForTeamJackal && (PlayerControl.LocalPlayer == Jackal.jackal || PlayerControl.LocalPlayer == Sidekick.sidekick);
+ bool impostorHighlight = Engineer.highlightForImpostors && PlayerControl.LocalPlayer.Data.Role.IsImpostor;
+ if ((jackalHighlight || impostorHighlight) && ShipStatus.Instance?.AllVents != null) {
foreach (Vent vent in ShipStatus.Instance.AllVents) {
try {
if (vent?.myRend?.material != null) {
}
static void impostorSetTarget() {
- if (!PlayerControl.LocalPlayer.Data.IsImpostor ||!PlayerControl.LocalPlayer.CanMove || PlayerControl.LocalPlayer.Data.IsDead) { // !isImpostor || !canMove || isDead
+ if (!PlayerControl.LocalPlayer.Data.Role.IsImpostor ||!PlayerControl.LocalPlayer.CanMove || PlayerControl.LocalPlayer.Data.IsDead) { // !isImpostor || !canMove || isDead
HudManager.Instance.KillButton.SetTarget(null);
return;
}
var (playerCompleted, playerTotal) = TasksHandler.taskInfo(Snitch.snitch.Data);
int numberOfTasks = playerTotal - playerCompleted;
- if (numberOfTasks <= Snitch.taskCountForReveal && (PlayerControl.LocalPlayer.Data.IsImpostor || (Snitch.includeTeamJackal && (PlayerControl.LocalPlayer == Jackal.jackal || PlayerControl.LocalPlayer == Sidekick.sidekick)))) {
+ if (numberOfTasks <= Snitch.taskCountForReveal && (PlayerControl.LocalPlayer.Data.Role.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.IsDead && (p.Data.IsImpostor || (Snitch.includeTeamJackal && (p == Jackal.jackal || p == Sidekick.sidekick)))) {
+ bool arrowForImp = p.Data.Role.IsImpostor;
+ bool arrowForTeamJackal = Snitch.includeTeamJackal && (p == Jackal.jackal || p == Sidekick.sidekick);
+
+ if (!p.Data.IsDead && (arrowForImp || arrowForTeamJackal)) {
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));
+ 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);
+ Snitch.localArrows[arrowIndex].Update(p.transform.position, (arrowForTeamJackal && Snitch.teamJackalUseDifferentArrowColor ? Jackal.color : Palette.ImpostorRed));
}
arrowIndex++;
}
BountyHunter.bountyUpdateTimer = BountyHunter.bountyDuration;
var possibleTargets = new List<PlayerControl>();
foreach (PlayerControl p in PlayerControl.AllPlayerControls) {
- if (!p.Data.IsDead && !p.Data.Disconnected && p != p.Data.IsImpostor && p != Spy.spy && (p != Mini.mini || Mini.isGrownUp())) possibleTargets.Add(p);
+ if (!p.Data.IsDead && !p.Data.Disconnected && p != p.Data.Role.IsImpostor && p != Spy.spy && (p != Mini.mini || Mini.isGrownUp())) possibleTargets.Add(p);
}
BountyHunter.bounty = possibleTargets[TheOtherRoles.rnd.Next(0, possibleTargets.Count)];
if (BountyHunter.bounty == null) return;
Camouflager.resetCamouflage();
if (Morphling.morphTimer > 0f && Morphling.morphling != null && Morphling.morphTarget != null) {
PlayerControl target = Morphling.morphTarget;
- Morphling.morphling.setLook(target.Data.PlayerName, target.Data.ColorId, target.Data.HatId, target.Data.SkinId, target.Data.PetId);
+ Morphling.morphling.setLook(target.Data.PlayerName, target.Data.DefaultOutfit.ColorId, target.Data.DefaultOutfit.HatId, target.Data.DefaultOutfit.VisorId, target.Data.DefaultOutfit.SkinId, target.Data.DefaultOutfit.PetId);
}
}
Helpers.handleVampireBiteOnBodyReport();
}
}
- [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcMurderPlayer))]
+ [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckMurder))]
class RpcMurderPlayer {
- public static bool Prefix([HarmonyArgument(0)]PlayerControl target) {
- if (Helpers.handleMurderAttempt(target)) { // Custom checks
- if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini || BountyHunter.bountyHunter != null && PlayerControl.LocalPlayer == BountyHunter.bountyHunter) { // Not checked by official servers
- MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.UncheckedMurderPlayer, Hazel.SendOption.Reliable, -1);
- writer.Write(PlayerControl.LocalPlayer.PlayerId);
+ public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)]PlayerControl target) {
+ PlayerControl killer = __instance;
+ if (AmongUsClient.Instance.IsGameOver || !AmongUsClient.Instance.AmHost) return false;
+ if (!target || killer.Data.IsDead || killer.Data.Disconnected) return false; // Allow non Impostor kills compared to vanilla code
+ if (target.Data == null || target.Data.IsDead) return false; // Allow killing players in vents compared to vanilla code
+
+ if (Helpers.handleMurderAttempt(killer, target)) { // Custom checks
+ if (Mini.mini != null && killer == Mini.mini || BountyHunter.bountyHunter != null && killer == BountyHunter.bountyHunter) { // Not checked by official servers
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.UncheckedMurderPlayer, Hazel.SendOption.Reliable, -1);
+ writer.Write(killer.PlayerId);
writer.Write(target.PlayerId);
AmongUsClient.Instance.FinishRpcImmediately(writer);
- RPCProcedure.uncheckedMurderPlayer(PlayerControl.LocalPlayer.PlayerId, target.PlayerId);
+ RPCProcedure.uncheckedMurderPlayer(killer.PlayerId, target.PlayerId);
} else { // Checked by official servers
- return true;
+ killer.RpcMurderPlayer(target);
}
}
return false;
if (timeSinceDeath < Detective.reportNameDuration * 1000) {
msg = $"Body Report: The killer appears to be {deadPlayer.killerIfExisting.name}!";
} else if (timeSinceDeath < Detective.reportColorDuration * 1000) {
- var typeOfColor = Helpers.isLighterColor(deadPlayer.killerIfExisting.Data.ColorId) ? "lighter" : "darker";
+ var typeOfColor = Helpers.isLighterColor(deadPlayer.killerIfExisting.Data.DefaultOutfit.ColorId) ? "lighter" : "darker";
msg = $"Body Report: The killer appears to be a {typeOfColor} color!";
} else {
msg = $"Body Report: The corpse is too old to gain information from!";
public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)]PlayerControl target)
{
// Allow everyone to murder players
- resetToCrewmate = !__instance.Data.IsImpostor;
+ resetToCrewmate = !__instance.Data.Role.IsImpostor;
resetToDead = __instance.Data.IsDead;
- __instance.Data.IsImpostor = true;
+ __instance.Data.Role.TeamType = RoleTeamTypes.Impostor;
__instance.Data.IsDead = false;
}
GameHistory.deadPlayers.Add(deadPlayer);
// Reset killer to crewmate if resetToCrewmate
- if (resetToCrewmate) __instance.Data.IsImpostor = false;
+ if (resetToCrewmate) __instance.Data.Role.TeamType = RoleTeamTypes.Crewmate;
if (resetToDead) __instance.Data.IsDead = true;
// Remove fake tasks when player dies
}
// Mini set adapted kill cooldown
- if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.IsImpostor && Mini.mini == __instance) {
+ if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.Role.IsImpostor && Mini.mini == __instance) {
var multiplier = Mini.isGrownUp() ? 0.66f : 2f;
Mini.mini.SetKillTimer(PlayerControl.GameOptions.KillCooldown * multiplier);
}
if (PlayerControl.GameOptions.KillCooldown <= 0f) return false;
float multiplier = 1f;
float addition = 0f;
- if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.IsImpostor) multiplier = Mini.isGrownUp() ? 0.66f : 2f;
+ if (Mini.mini != null && PlayerControl.LocalPlayer == Mini.mini && Mini.mini.Data.Role.IsImpostor) multiplier = Mini.isGrownUp() ? 0.66f : 2f;
if (BountyHunter.bountyHunter != null && PlayerControl.LocalPlayer == BountyHunter.bountyHunter) addition = BountyHunter.punishmentTime;
__instance.killTimer = Mathf.Clamp(time, 0f, PlayerControl.GameOptions.KillCooldown * multiplier + addition);
}
}
}
-
- [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CanMove), MethodType.Getter)]
- class PlayerControlCanMovePatch {
- public static bool Prefix(PlayerControl __instance, ref bool __result)
- {
- __result = __instance.moveable &&
- !Minigame.Instance &&
- (!DestroyableSingleton<HudManager>.InstanceExists || (!DestroyableSingleton<HudManager>.Instance.Chat.IsOpen && !DestroyableSingleton<HudManager>.Instance.KillOverlay.IsOpen && !DestroyableSingleton<HudManager>.Instance.GameMenu.IsOpen)) &&
- (!MapBehaviour.Instance || !MapBehaviour.Instance.IsOpenStopped) &&
- !MeetingHud.Instance &&
- !CustomPlayerMenu.Instance &&
- !ExileController.Instance &&
- !IntroCutscene.Instance;
- return false;
- }
- }
}
private static TextBoxTMP ipField;
private static TextBoxTMP portField;
- public static void Postfix(RegionMenu __instance)
- {
+ public static void Postfix(RegionMenu __instance) {
var template = DestroyableSingleton<JoinGameButton>.Instance;
+ if (template == null || template.GameIdText == null) return;
if (ipField == null || ipField.gameObject == null) {
ipField = UnityEngine.Object.Instantiate(template.GameIdText, __instance.transform);
ipField.gameObject.name = "IpTextBox";
- UnityEngine.Object.DestroyImmediate(ipField.transform.FindChild("arrowEnter").gameObject);
+ var arrow = ipField.transform.FindChild("arrowEnter");
+ if (arrow == null || arrow.gameObject == null) return;
+ UnityEngine.Object.DestroyImmediate(arrow.gameObject);
ipField.transform.localPosition = new Vector3(0, -1f, -100f);
ipField.characterLimit = 30;
__instance.ChooseOption(ServerManager.DefaultRegions[ServerManager.DefaultRegions.Length - 1]);
}
}
+
if (portField == null || portField.gameObject == null) {
portField = UnityEngine.Object.Instantiate(template.GameIdText, __instance.transform);
portField.gameObject.name = "PortTextBox";
- UnityEngine.Object.DestroyImmediate(portField.transform.FindChild("arrowEnter").gameObject);
+ var arrow = portField.transform.FindChild("arrowEnter");
+ if (arrow == null || arrow.gameObject == null) return;
+ UnityEngine.Object.DestroyImmediate(arrow.gameObject);
portField.transform.localPosition = new Vector3(0, -1.75f, -100f);
portField.characterLimit = 5;
using static TheOtherRoles.TheOtherRoles;
namespace TheOtherRoles.Patches {
- [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSetInfected))]
- class SetInfectedPatch
- {
+ [HarmonyPatch(typeof(RoleOptionsData), nameof(RoleOptionsData.GetNumPerGame))]
+ class RoleOptionsDataGetNumPerGamePatch{
+ public static void Postfix(ref int __result) {
+ if (CustomOptionHolder.activateRoles.getBool()) __result = 0; // Deactivate Vanilla Roles if the mod roles are active
+ }
+ }
- public static void Postfix([HarmonyArgument(0)]Il2CppReferenceArray<GameData.PlayerInfo> infected)
- {
+ [HarmonyPatch(typeof(RoleManager), nameof(RoleManager.SelectRoles))]
+ class RoleManagerSelectRolesPatch {
+ public static void Postfix() {
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ResetVaribles, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.resetVariables();
- if (!DestroyableSingleton<TutorialManager>.InstanceExists) // Don't assign Roles in Tutorial
+ if (!DestroyableSingleton<TutorialManager>.InstanceExists && CustomOptionHolder.activateRoles.getBool()) // Don't assign Roles in Tutorial or if deactivated
assignRoles();
}
private static RoleAssignmentData getRoleAssignmentData() {
// Get the players that we want to assign the roles to. Crewmate and Neutral roles are assigned to natural crewmates. Impostor roles to impostors.
List<PlayerControl> crewmates = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList();
- crewmates.RemoveAll(x => x.Data.IsImpostor);
+ crewmates.RemoveAll(x => x.Data.Role.IsImpostor);
List<PlayerControl> impostors = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList();
- impostors.RemoveAll(x => !x.Data.IsImpostor);
+ impostors.RemoveAll(x => !x.Data.Role.IsImpostor);
var crewmateMin = CustomOptionHolder.crewmateRolesCountMin.getSelection();
var crewmateMax = CustomOptionHolder.crewmateRolesCountMax.getSelection();
if (player == null || player.IsDead) // IsDead
__result = __instance.MaxLightRadius;
- else if (player.IsImpostor
+ 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
if (Morphling.morphTimer > 0f && Morphling.morphling == player && Morphling.morphTarget != null) playerName = Morphling.morphTarget.Data.PlayerName; // Temporary hotfix for the Morphling's name
player.nameText.text = Helpers.hidePlayerName(PlayerControl.LocalPlayer, player) ? "" : playerName;
- if (PlayerControl.LocalPlayer.Data.IsImpostor && player.Data.IsImpostor) {
+ if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && player.Data.Role.IsImpostor) {
player.nameText.color = Palette.ImpostorRed;
} else {
player.nameText.color = Color.white;
PlayerControl playerControl = playersById.ContainsKey((byte)player.TargetPlayerId) ? playersById[(byte)player.TargetPlayerId] : null;
if (playerControl != null) {
player.NameText.text = playerControl.Data.PlayerName;
- if (PlayerControl.LocalPlayer.Data.IsImpostor && playerControl.Data.IsImpostor) {
+ if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && playerControl.Data.Role.IsImpostor) {
player.NameText.color = Palette.ImpostorRed;
} else {
player.NameText.color = Color.white;
}
}
}
- if (PlayerControl.LocalPlayer.Data.IsImpostor) {
+ if (PlayerControl.LocalPlayer.Data.Role.IsImpostor) {
List<PlayerControl> impostors = PlayerControl.AllPlayerControls.ToArray().ToList();
- impostors.RemoveAll(x => !x.Data.IsImpostor);
+ impostors.RemoveAll(x => !x.Data.Role.IsImpostor);
foreach (PlayerControl player in impostors)
player.nameText.color = Palette.ImpostorRed;
if (MeetingHud.Instance != null)
foreach (PlayerVoteArea player in MeetingHud.Instance.playerStates) {
PlayerControl playerControl = Helpers.playerById((byte)player.TargetPlayerId);
- if (playerControl != null && playerControl.Data.IsImpostor)
+ if (playerControl != null && playerControl.Data.Role.IsImpostor)
player.NameText.color = Palette.ImpostorRed;
}
}
} else if (Arsonist.arsonist != null && Arsonist.arsonist == PlayerControl.LocalPlayer) {
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);
+ setPlayerNameColor(Guesser.guesser, Guesser.guesser.Data.Role.IsImpostor ? Palette.ImpostorRed : Guesser.color);
} else if (Bait.bait != null && Bait.bait == PlayerControl.LocalPlayer) {
setPlayerNameColor(Bait.bait, Bait.color);
} else if (Vulture.vulture != null && Vulture.vulture == PlayerControl.LocalPlayer) {
}
// No else if here, as the Impostors need the Spy name to be colored
- if (Spy.spy != null && PlayerControl.LocalPlayer.Data.IsImpostor) {
+ if (Spy.spy != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor) {
setPlayerNameColor(Spy.spy, Spy.color);
}
static void setNameTags() {
// Mafia
- if (PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer.Data.IsImpostor) {
+ if (PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer.Data.Role.IsImpostor) {
foreach (PlayerControl player in PlayerControl.AllPlayerControls)
if (Godfather.godfather != null && Godfather.godfather == player)
player.nameText.text = player.Data.PlayerName + " (G)";
}
static void updateImpostorKillButton(HudManager __instance) {
- if (!PlayerControl.LocalPlayer.Data.IsImpostor) return;
+ if (!PlayerControl.LocalPlayer.Data.Role.IsImpostor) return;
bool enabled = true;
if (Vampire.vampire != null && Vampire.vampire == PlayerControl.LocalPlayer)
enabled = false;
enabled = false;
else if (Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer)
enabled = false;
- enabled &= __instance.UseButton.isActiveAndEnabled;
- __instance.KillButton.gameObject.SetActive(enabled);
- __instance.KillButton.renderer.enabled = enabled;
- __instance.KillButton.isActive = enabled;
- __instance.KillButton.enabled = enabled;
+ if (enabled) __instance.KillButton.Show();
+ else __instance.KillButton.Hide();
}
static void Postfix(HudManager __instance)
namespace TheOtherRoles.Patches {
- [HarmonyPatch(typeof(Vent), "CanUse")]
+ [HarmonyPatch(typeof(Vent), nameof(Vent.CanUse))]
public static class VentCanUsePatch
{
public static bool Prefix(Vent __instance, ref float __result, [HarmonyArgument(0)] GameData.PlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
float num = float.MaxValue;
PlayerControl @object = pc.Object;
-
- bool roleCouldUse = false;
- if (Engineer.engineer != null && Engineer.engineer == @object)
- roleCouldUse = true;
- else if (Jackal.canUseVents && Jackal.jackal != null && Jackal.jackal == @object)
- roleCouldUse = true;
- else if (Sidekick.canUseVents && Sidekick.sidekick != null && Sidekick.sidekick == @object)
- roleCouldUse = true;
- else if (Spy.canEnterVents && Spy.spy != null && Spy.spy == @object)
- roleCouldUse = true;
- else if (Vulture.canUseVents && Vulture.vulture != null && Vulture.vulture == @object)
- roleCouldUse = true;
- else if (pc.IsImpostor) {
- if (Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer)
- roleCouldUse = false;
- else if (Mafioso.mafioso != null && Mafioso.mafioso == PlayerControl.LocalPlayer && Godfather.godfather != null && !Godfather.godfather.Data.IsDead)
- roleCouldUse = false;
- else
- roleCouldUse = true;
- }
+ bool roleCouldUse = @object.roleCanUseVents();
var usableDistance = __instance.UsableDistance;
if (__instance.name.StartsWith("JackInTheBoxVent_")) {
}
}
- [HarmonyPatch(typeof(Vent), "Use")]
+ [HarmonyPatch(typeof(Vent), nameof(Vent.Use))]
public static class VentUsePatch {
public static bool Prefix(Vent __instance) {
bool canUse;
}
}
- [HarmonyPatch(typeof(UseButtonManager), nameof(UseButtonManager.SetTarget))]
- class UseButtonSetTargetPatch {
- static void Postfix(UseButtonManager __instance) {
- // Trickster render special vent button
- if (__instance.currentTarget != null && Trickster.trickster != null && Trickster.trickster == PlayerControl.LocalPlayer) {
- Vent possibleVent = __instance.currentTarget.TryCast<Vent>();
- if (possibleVent != null && possibleVent.gameObject != null) {
- var useButton = __instance.currentButtonShown;
- if (possibleVent.gameObject.name.StartsWith("JackInTheBoxVent_")) {
- useButton.graphic.sprite = Trickster.getTricksterVentButtonSprite();
- useButton.text.enabled = false; // clear text;
- } else {
- useButton.graphic.sprite = DestroyableSingleton<TranslationController>.Instance.GetImage(ImageNames.VentButton);
- useButton.text.enabled = false;
- }
- }
- }
-
- // Jester sabotage
- if (Jester.canSabotage && Jester.jester != null && Jester.jester == PlayerControl.LocalPlayer && PlayerControl.LocalPlayer.CanMove) {
- var useButton = __instance.currentButtonShown;
- if (!Jester.jester.Data.IsDead && __instance.currentTarget == null) { // no target, so sabotage
- useButton.graphic.sprite = DestroyableSingleton<TranslationController>.Instance.GetImage(ImageNames.SabotageButton);
- useButton.graphic.color = UseButtonManager.EnabledColor;
- useButton.text.enabled = false;
- } else {
- useButton.graphic.sprite = DestroyableSingleton<TranslationController>.Instance.GetImage(ImageNames.UseButton);
- useButton.text.enabled = false;
- }
+ [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
+ class VentButtonVisibilityPatch {
+ static void Postfix(PlayerControl __instance) {
+ if (__instance.AmOwner && __instance.roleCanUseVents() && HudManager.Instance.ReportButton.isActiveAndEnabled) {
+ HudManager.Instance.ImpostorVentButton.Show();
}
+ }
+ }
- // Mafia sabotage button render patch
- bool blockSabotageJanitor = (Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer);
- bool blockSabotageMafioso = (Mafioso.mafioso != null && Mafioso.mafioso == PlayerControl.LocalPlayer && Godfather.godfather != null && !Godfather.godfather.Data.IsDead);
- if (__instance.currentTarget == null && (blockSabotageJanitor || blockSabotageMafioso)) {
- var useButton = __instance.currentButtonShown;
- useButton.graphic.sprite = DestroyableSingleton<TranslationController>.Instance.GetImage(ImageNames.UseButton);
- useButton.graphic.color = UseButtonManager.DisabledColor;
- useButton.text.enabled = false;
+ [HarmonyPatch(typeof(VentButton), nameof(VentButton.SetTarget))]
+ class VentButtonSetTargetPatch {
+ static void Postfix(VentButton __instance) {
+ // Trickster render special vent button
+ if (Trickster.trickster != null && Trickster.trickster == PlayerControl.LocalPlayer) {
+ if (__instance.currentTarget != null && __instance.currentTarget.gameObject != null && __instance.currentTarget.gameObject.name.StartsWith("JackInTheBoxVent_"))
+ __instance.graphic.sprite = Trickster.getTricksterVentButtonSprite();
+ else
+ __instance.graphic.sprite = DestroyableSingleton<TranslationController>.Instance.GetImage(ImageNames.VentButton);
}
-
}
}
-
- [HarmonyPatch(typeof(UseButtonManager), nameof(UseButtonManager.DoClick))]
- class UseButtonDoClickPatch {
- static bool Prefix(UseButtonManager __instance) {
- if (__instance.currentTarget != null) return true;
- // Jester sabotage
- if (Jester.canSabotage && Jester.jester != null && Jester.jester == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead) {
- Action<MapBehaviour> action = m => m.ShowInfectedMap() ;
- DestroyableSingleton<HudManager>.Instance.ShowMap(action);
- return false;
- }
- // Mafia sabotage button click patch
+
+ [HarmonyPatch(typeof(SabotageButton), nameof(SabotageButton.Refresh))]
+ class SabotageButtonRefreshPatch {
+ static void Postfix() {
+ // Mafia disable sabotage button for Janitor and sometimes for Mafioso
bool blockSabotageJanitor = (Janitor.janitor != null && Janitor.janitor == PlayerControl.LocalPlayer);
bool blockSabotageMafioso = (Mafioso.mafioso != null && Mafioso.mafioso == PlayerControl.LocalPlayer && Godfather.godfather != null && !Godfather.godfather.Data.IsDead);
- if (blockSabotageJanitor || blockSabotageMafioso) return false;
-
- return true;
+ if (blockSabotageJanitor || blockSabotageMafioso) {
+ HudManager.Instance.SabotageButton.SetDisabled();
+ }
}
}
if (component) {
GameData.PlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
if (playerInfo != null) {
- var color = Palette.PlayerColors[playerInfo.ColorId];
+ var color = Palette.PlayerColors[playerInfo.DefaultOutfit.ColorId];
if (Hacker.onlyColorType)
- color = Helpers.isLighterColor(playerInfo.ColorId) ? Palette.PlayerColors[7] : Palette.PlayerColors[6];
+ color = Helpers.isLighterColor(playerInfo.DefaultOutfit.ColorId) ? Palette.PlayerColors[7] : Palette.PlayerColors[6];
roomColors.Add(color);
}
}
public static void forceEnd() {
foreach (PlayerControl player in PlayerControl.AllPlayerControls)
{
- if (!player.Data.IsImpostor)
+ if (!player.Data.Role.IsImpostor)
{
player.RemoveInfected();
player.MurderPlayer(player);
}
public static void engineerUsedRepair() {
- Engineer.usedRepair = true;
+ Engineer.remainingFixes--;
}
public static void cleanBody(byte playerId) {
Shifter.clearAndReload();
// Suicide (exile) when impostor or impostor variants
- if (player.Data.IsImpostor || player == Jackal.jackal || player == Sidekick.sidekick || Jackal.formerJackals.Contains(player) || player == Jester.jester || player == Arsonist.arsonist || player == Vulture.vulture) {
+ if (player.Data.Role.IsImpostor || player == Jackal.jackal || player == Sidekick.sidekick || Jackal.formerJackals.Contains(player) || player == Jester.jester || player == Arsonist.arsonist || player == Vulture.vulture) {
oldShifter.Exiled();
return;
}
Morphling.morphTimer = Morphling.duration;
Morphling.morphTarget = target;
if (Camouflager.camouflageTimer <= 0f)
- Morphling.morphling.setLook(target.Data.PlayerName, target.Data.ColorId, target.Data.HatId, target.Data.SkinId, target.Data.PetId);
+ Morphling.morphling.setLook(target.Data.PlayerName, target.Data.DefaultOutfit.ColorId, target.Data.DefaultOutfit.HatId, target.Data.DefaultOutfit.VisorId, target.Data.DefaultOutfit.SkinId, target.Data.DefaultOutfit.PetId);
}
public static void camouflagerCamouflage() {
Camouflager.camouflageTimer = Camouflager.duration;
foreach (PlayerControl player in PlayerControl.AllPlayerControls)
- player.setLook("", 6, 0, 0, 0);
+ player.setLook("", 6, "", "", "", "");
}
public static void vampireSetBitten(byte targetId, byte reset) {
{
if (player.PlayerId == targetId)
{
- if (!Jackal.canCreateSidekickFromImpostor && player.Data.IsImpostor) {
+ if (!Jackal.canCreateSidekickFromImpostor && player.Data.Role.IsImpostor) {
Jackal.fakeSidekick = player;
} else {
player.RemoveInfected();
public static void lightsOut() {
Trickster.lightsOutTimer = Trickster.lightsOutDuration;
// If the local player is impostor indicate lights out
- if(PlayerControl.LocalPlayer.Data.IsImpostor) {
+ if(PlayerControl.LocalPlayer.Data.Role.IsImpostor) {
new CustomMessage("Lights are out", Trickster.lightsOutDuration);
}
}
public string introDescription;
public string shortDescription;
public RoleId roleId;
+ public bool isNeutral;
- RoleInfo(string name, Color color, string introDescription, string shortDescription, RoleId roleId) {
+ RoleInfo(string name, Color color, string introDescription, string shortDescription, RoleId roleId, bool isNeutral = false) {
this.color = color;
this.name = name;
this.introDescription = introDescription;
this.shortDescription = shortDescription;
this.roleId = roleId;
+ this.isNeutral = isNeutral;
}
- public static RoleInfo jester = new RoleInfo("Jester", Jester.color, "Get voted out", "Get voted out", RoleId.Jester);
+ public static RoleInfo jester = new RoleInfo("Jester", Jester.color, "Get voted out", "Get voted out", RoleId.Jester, true);
public static RoleInfo mayor = new RoleInfo("Mayor", Mayor.color, "Your vote counts twice", "Your vote counts twice", RoleId.Mayor);
public static RoleInfo engineer = new RoleInfo("Engineer", Engineer.color, "Maintain important systems on the ship", "Repair the ship", RoleId.Engineer);
public static RoleInfo sheriff = new RoleInfo("Sheriff", Sheriff.color, "Shoot the <color=#FF1919FF>Impostors</color>", "Shoot the Impostors", RoleId.Sheriff);
public static RoleInfo evilMini = new RoleInfo("Evil Mini", Palette.ImpostorRed, "No one will harm you until you grow up", "No one will harm you", RoleId.Mini);
public static RoleInfo tracker = new RoleInfo("Tracker", Tracker.color, "Track the <color=#FF1919FF>Impostors</color> down", "Track the Impostors down", RoleId.Tracker);
public static RoleInfo snitch = new RoleInfo("Snitch", Snitch.color, "Finish your tasks to find the <color=#FF1919FF>Impostors</color>", "Finish your tasks", RoleId.Snitch);
- public static RoleInfo jackal = new RoleInfo("Jackal", Jackal.color, "Kill all Crewmates and <color=#FF1919FF>Impostors</color> to win", "Kill everyone", RoleId.Jackal);
- public static RoleInfo sidekick = new RoleInfo("Sidekick", Sidekick.color, "Help your Jackal to kill everyone", "Help your Jackal to kill everyone", RoleId.Sidekick);
+ public static RoleInfo jackal = new RoleInfo("Jackal", Jackal.color, "Kill all Crewmates and <color=#FF1919FF>Impostors</color> to win", "Kill everyone", RoleId.Jackal, true);
+ public static RoleInfo sidekick = new RoleInfo("Sidekick", Sidekick.color, "Help your Jackal to kill everyone", "Help your Jackal to kill everyone", RoleId.Sidekick, true);
public static RoleInfo spy = new RoleInfo("Spy", Spy.color, "Confuse the <color=#FF1919FF>Impostors</color>", "Confuse the Impostors", RoleId.Spy);
public static RoleInfo securityGuard = new RoleInfo("Security Guard", SecurityGuard.color, "Seal vents and place cameras", "Seal vents and place cameras", RoleId.SecurityGuard);
- public static RoleInfo arsonist = new RoleInfo("Arsonist", Arsonist.color, "Let them burn", "Let them burn", RoleId.Arsonist);
+ public static RoleInfo arsonist = new RoleInfo("Arsonist", Arsonist.color, "Let them burn", "Let them burn", RoleId.Arsonist, true);
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 vulture = new RoleInfo("Vulture", Vulture.color, "Eat Corpses to win", "Eat dead bodies", RoleId.Vulture);
+ public static RoleInfo vulture = new RoleInfo("Vulture", Vulture.color, "Eat Corpses to win", "Eat dead bodies", RoleId.Vulture, true);
public static RoleInfo medium = new RoleInfo("Medium", Medium.color, "Question the souls of the dead to gain informations", "Question the souls", RoleId.Medium);
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);
if (p == Swapper.swapper) infos.Add(swapper);
if (p == Seer.seer) infos.Add(seer);
if (p == Hacker.hacker) infos.Add(hacker);
- if (p == Mini.mini) infos.Add(p.Data.IsImpostor ? evilMini : niceMini);
+ if (p == Mini.mini) infos.Add(p.Data.Role.IsImpostor ? evilMini : niceMini);
if (p == Tracker.tracker) infos.Add(tracker);
if (p == Snitch.snitch) infos.Add(snitch);
if (p == Jackal.jackal || (Jackal.formerJackals != null && Jackal.formerJackals.Any(x => x.PlayerId == p.PlayerId))) infos.Add(jackal);
if (p == Spy.spy) infos.Add(spy);
if (p == SecurityGuard.securityGuard) infos.Add(securityGuard);
if (p == Arsonist.arsonist) infos.Add(arsonist);
- if (p == Guesser.guesser) infos.Add(p.Data.IsImpostor ? badGuesser : goodGuesser);
+ if (p == Guesser.guesser) infos.Add(p.Data.Role.IsImpostor ? badGuesser : goodGuesser);
if (p == BountyHunter.bountyHunter) infos.Add(bountyHunter);
if (p == Bait.bait) infos.Add(bait);
if (p == Vulture.vulture) infos.Add(vulture);
if (p == Medium.medium) infos.Add(medium);
// Default roles
- if (infos.Count == 0 && p.Data.IsImpostor) infos.Add(impostor); // Just Impostor
- if (infos.Count == 0 && !p.Data.IsImpostor) infos.Add(crewmate); // Just Crewmate
+ if (infos.Count == 0 && p.Data.Role.IsImpostor) infos.Add(impostor); // Just Impostor
+ if (infos.Count == 0 && !p.Data.Role.IsImpostor) infos.Add(crewmate); // Just Crewmate
// Modifier
if (p == Lovers.lover1|| p == Lovers.lover2) infos.Add(lover);
if (!playerInfo.Disconnected && playerInfo.Tasks != null &&
playerInfo.Object &&
(PlayerControl.GameOptions.GhostsDoTasks || !playerInfo.IsDead) &&
- !playerInfo.IsImpostor &&
+ playerInfo.Role && playerInfo.Role.TasksCountTowardProgress &&
!playerInfo.Object.hasFakeTasks()
) {
public static bool triggerJesterWin = false;
public static bool canCallEmergency = true;
- public static bool canSabotage = true;
public static void clearAndReload() {
jester = null;
triggerJesterWin = false;
canCallEmergency = CustomOptionHolder.jesterCanCallEmergency.getBool();
- canSabotage = CustomOptionHolder.jesterCanSabotage.getBool();
}
}
public static class Engineer {
public static PlayerControl engineer;
public static Color color = new Color32(0, 40, 245, byte.MaxValue);
- public static bool usedRepair;
private static Sprite buttonSprite;
+ public static int remainingFixes = 1;
+ public static bool highlightForImpostors = true;
+ public static bool highlightForTeamJackal = true;
+
public static Sprite getButtonSprite() {
if (buttonSprite) return buttonSprite;
buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.RepairButton.png", 115f);
public static void clearAndReload() {
engineer = null;
- usedRepair = false;
+ remainingFixes = Mathf.RoundToInt(CustomOptionHolder.engineerNumberOfFixes.getFloat());
+ highlightForImpostors = CustomOptionHolder.engineerHighlightForImpostors.getBool();
+ highlightForTeamJackal = CustomOptionHolder.engineerHighlightForTeamJackal.getBool();
}
}
public static bool existingWithKiller() {
return existing() && (lover1 == Jackal.jackal || lover2 == Jackal.jackal
|| lover1 == Sidekick.sidekick || lover2 == Sidekick.sidekick
- || lover1.Data.IsImpostor || lover2.Data.IsImpostor);
+ || lover1.Data.Role.IsImpostor || lover2.Data.Role.IsImpostor);
}
public static bool hasAliveKillingLover(this PlayerControl player) {
public static bool jackalPromotedFromSidekickCanCreateSidekick = true;
public static bool canCreateSidekickFromImpostor = true;
public static bool hasImpostorVision = false;
- public static bool canSeeEngineerVent = false;
public static Sprite getSidekickButtonSprite() {
if (buttonSprite) return buttonSprite;
canCreateSidekickFromImpostor = CustomOptionHolder.jackalCanCreateSidekickFromImpostor.getBool();
formerJackals.Clear();
hasImpostorVision = CustomOptionHolder.jackalAndSidekickHaveImpostorVision.getBool();
- canSeeEngineerVent = CustomOptionHolder.jackalCanSeeEngineerVent.getBool();
}
}
public static void resetCurse() {
HudManagerStartPatch.warlockCurseButton.Timer = HudManagerStartPatch.warlockCurseButton.MaxTimer;
HudManagerStartPatch.warlockCurseButton.Sprite = Warlock.getCurseButtonSprite();
- HudManagerStartPatch.warlockCurseButton.killButtonManager.TimerText.color = Palette.EnabledColor;
+ HudManagerStartPatch.warlockCurseButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
currentTarget = null;
curseVictim = null;
curseVictimTarget = null;
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
- <Version>2.9.2</Version>
+ <Version>3.0.0</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
</PropertyGroup>