From: dwd0tcom Date: Wed, 15 Dec 2021 18:07:17 +0000 (+0100) Subject: bump version X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=31643a24e783b1ffb2243a872c01aa5e029bc368;p=rhonda%2Ftheotherroles.git bump version --- diff --git a/.gitignore b/.gitignore index 375e88d..44db07a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .vs .vscode/tasks.json -TODO -.DS_Store +TODO \ No newline at end of file diff --git a/Images/.DS_Store b/Images/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Images/.DS_Store differ diff --git a/README.md b/README.md index 63f644c..5f4cce4 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein # Releases | Among Us - Version| Mod Version | Link | |----------|-------------|-----------------| +| 2021.12.14s| v3.3.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.3.0/TheOtherRoles.zip) | 2021.11.9.5s| v3.2.4| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.2.4/TheOtherRoles.zip) | 2021.11.9.5s| v3.2.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.2.3/TheOtherRoles.zip) | 2021.11.9.5s| v3.2.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v3.2.2/TheOtherRoles.zip) @@ -88,6 +89,17 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein
Click to show the Changelog +**Version 3.3.0** +- Update to Among Us version 2021.12.14s +- Fixed a bug where the Pursuer won if the Pursuer was the last killed or voted player +- Fixed a bug where the option "Enable Mod Roles And Block Vanilla Roles" was not set correctly +- New option for the Guesser "Evil Guesser can guess spy" +- New option for the Guesser "Other Guesser Spawn Rate" +- New ability for the Hacker "Mobile Gadgets" (including vitals & admin table) +- New option for the Hacker "Max Mobile Gadget Charges" +- New option for the Hacker "Number Of Tasks Needed For Recharging" +- Fixed some UI bugs during the meeting + **Version 3.2.4** - Fixed a bug where the Vampire teleported when the bitten player died - The settings UI has been improved by [Amsyar Rasyiq](https://github.com/amsyarasyiq) @@ -825,6 +837,8 @@ Depending on the options, the Guesser can't guess the shielded player and depend | Guesser Can Shoot Multiple Times Per Meeting| - | Guesses Visible In Ghost Chat| - | Guesses Ignore The Medic Shield| - +| Evil Guesser Can Guess The Spy| - +| Other Guesser Spawn Rate| - ----------------------- @@ -1035,6 +1049,7 @@ If the Hacker activates the "Hacker mode", the Hacker gets more information than Otherwise they see the same information as everyone else. **Admin table:** The Hacker can see the colors (or color types) of the players on the table.\ **Vitals**: The Hacker can see how long dead players have been dead for.\ +The Hacker can access his mobile gadgets (vitals & admin table), with a maximum of charges (uses) and a configurable amount of tasks needed to recharge.\ \ **NOTE:** - If the Morphling morphs or the Camouflager camouflages, the colors on the admin table change accordingly @@ -1048,6 +1063,8 @@ Otherwise they see the same information as everyone else. | Hacker Cooldown| - | Hacker Duration | Sets how long the "Hacker mode" remains active | Hacker Only Sees Color Type | Sets if the Hacker sees the player colors on the admin table or only white/gray (for Lighter and darker colors) +| Max Mobile Gadget Charges| - +| Number Of Tasks Needed For Recharging | Number of tasks to get a charge ----------------------- diff --git a/TheOtherRoles/Buttons.cs b/TheOtherRoles/Buttons.cs index 9c9f252..7f46775 100644 --- a/TheOtherRoles/Buttons.cs +++ b/TheOtherRoles/Buttons.cs @@ -4,6 +4,7 @@ using System; using UnityEngine; using static TheOtherRoles.TheOtherRoles; using TheOtherRoles.Objects; +using System.Linq; namespace TheOtherRoles { @@ -19,6 +20,8 @@ namespace TheOtherRoles private static CustomButton morphlingButton; private static CustomButton camouflagerButton; private static CustomButton hackerButton; + private static CustomButton hackerVitalsButton; + private static CustomButton hackerAdminTableButton; private static CustomButton trackerTrackPlayerButton; private static CustomButton trackerTrackCorpsesButton; private static CustomButton vampireKillButton; @@ -41,6 +44,8 @@ namespace TheOtherRoles public static TMPro.TMP_Text securityGuardButtonScrewsText; public static TMPro.TMP_Text pursuerButtonBlanksText; + public static TMPro.TMP_Text hackerAdminTableChargesText; + public static TMPro.TMP_Text hackerVitalsChargesText; public static void setCustomButtonCooldowns() { engineerRepairButton.MaxTimer = 0f; @@ -52,6 +57,8 @@ namespace TheOtherRoles morphlingButton.MaxTimer = Morphling.cooldown; camouflagerButton.MaxTimer = Camouflager.cooldown; hackerButton.MaxTimer = Hacker.cooldown; + hackerVitalsButton.MaxTimer = Hacker.cooldown; + hackerAdminTableButton.MaxTimer = Hacker.cooldown; vampireKillButton.MaxTimer = Vampire.cooldown; trackerTrackPlayerButton.MaxTimer = 0f; garlicButton.MaxTimer = 0f; @@ -74,6 +81,8 @@ namespace TheOtherRoles timeMasterShieldButton.EffectDuration = TimeMaster.shieldDuration; hackerButton.EffectDuration = Hacker.duration; + hackerVitalsButton.EffectDuration = Hacker.duration; + hackerAdminTableButton.EffectDuration = Hacker.duration; vampireKillButton.EffectDuration = Vampire.delay; lighterButton.EffectDuration = Lighter.duration; camouflagerButton.EffectDuration = Camouflager.duration; @@ -352,16 +361,97 @@ namespace TheOtherRoles hackerButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; }, Hacker.getButtonSprite(), - new Vector3(-1.8f, -0.06f, 0), + new Vector3(0f, 1f, 0), __instance, KeyCode.F, true, 0f, - () => { - hackerButton.Timer = hackerButton.MaxTimer; - } + () => { hackerButton.Timer = hackerButton.MaxTimer;} ); + hackerAdminTableButton = new CustomButton( + () => { + if (!MapBehaviour.Instance || !MapBehaviour.Instance.isActiveAndEnabled) + DestroyableSingleton.Instance.ShowMap((System.Action)(m => m.ShowCountOverlay())); + + Hacker.chargesAdminTable--; + }, + () => { return Hacker.hacker != null && Hacker.hacker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead;}, + () => { + if (hackerAdminTableChargesText != null) hackerAdminTableChargesText.text = $"{Hacker.chargesAdminTable} / {Hacker.toolsNumber}"; + return PlayerControl.LocalPlayer.CanMove && Hacker.chargesAdminTable > 0; + }, + () => { + hackerAdminTableButton.Timer = hackerAdminTableButton.MaxTimer; + hackerAdminTableButton.isEffectActive = false; + hackerAdminTableButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + }, + Hacker.getAdminSprite(), + new Vector3(-1.8f, -0.06f, 0), + __instance, + KeyCode.Q, + true, + 0f, + () => { + hackerAdminTableButton.Timer = hackerAdminTableButton.MaxTimer; + if (MapBehaviour.Instance && MapBehaviour.Instance.isActiveAndEnabled) MapBehaviour.Instance.Close(); + }, + PlayerControl.GameOptions.MapId == 3, + "ADMIN" + ); + + // Hacker Admin Table Charges + hackerAdminTableChargesText = GameObject.Instantiate(hackerAdminTableButton.actionButton.cooldownTimerText, hackerAdminTableButton.actionButton.cooldownTimerText.transform.parent); + hackerAdminTableChargesText.text = ""; + hackerAdminTableChargesText.enableWordWrapping = false; + hackerAdminTableChargesText.transform.localScale = Vector3.one * 0.5f; + hackerAdminTableChargesText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + + hackerVitalsButton = new CustomButton( + () => { + if (!Minigame.Instance) { + if (Hacker.vitals == null) { + var e = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name.Contains("panel_vitals")); + if (e == null || Camera.main == null) return; + Hacker.vitals = UnityEngine.Object.Instantiate(e.MinigamePrefab, Camera.main.transform, false); + } + Hacker.vitals.transform.SetParent(Camera.main.transform, false); + Hacker.vitals.transform.localPosition = new Vector3(0.0f, 0.0f, -50f); + Hacker.vitals.Begin(null); + } + Hacker.chargesVitals--; + }, + () => { return Hacker.hacker != null && Hacker.hacker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead;}, + () => { + if (hackerVitalsChargesText != null) hackerVitalsChargesText.text = $"{Hacker.chargesVitals} / {Hacker.toolsNumber}"; + return PlayerControl.LocalPlayer.CanMove && Hacker.chargesVitals > 0; + }, + () => { + hackerVitalsButton.Timer = hackerVitalsButton.MaxTimer; + hackerVitalsButton.isEffectActive = false; + hackerVitalsButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + }, + Hacker.getVitalsSprite(), + new Vector3(-2.7f, -0.06f, 0), + __instance, + KeyCode.Q, + true, + 0f, + () => { + hackerVitalsButton.Timer = hackerVitalsButton.MaxTimer; + if (Minigame.Instance) Hacker.vitals.ForceClose(); + }, + false, + "VITALS" + ); + + // Hacker Vitals Charges + hackerVitalsChargesText = GameObject.Instantiate(hackerVitalsButton.actionButton.cooldownTimerText, hackerVitalsButton.actionButton.cooldownTimerText.transform.parent); + hackerVitalsChargesText.text = ""; + hackerVitalsChargesText.enableWordWrapping = false; + hackerVitalsChargesText.transform.localScale = Vector3.one * 0.5f; + hackerVitalsChargesText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + // Tracker button trackerTrackPlayerButton = new CustomButton( () => { diff --git a/TheOtherRoles/CustomOptionHolder.cs b/TheOtherRoles/CustomOptionHolder.cs index 0545db7..e574e55 100644 --- a/TheOtherRoles/CustomOptionHolder.cs +++ b/TheOtherRoles/CustomOptionHolder.cs @@ -57,6 +57,8 @@ namespace TheOtherRoles { public static CustomOption guesserHasMultipleShotsPerMeeting; public static CustomOption guesserShowInfoInGhostChat; public static CustomOption guesserKillsThroughShield; + public static CustomOption guesserEvilCanKillSpy; + public static CustomOption guesserSpawnBothRate; public static CustomOption jesterSpawnRate; public static CustomOption jesterCanCallEmergency; @@ -143,6 +145,8 @@ namespace TheOtherRoles { public static CustomOption hackerCooldown; public static CustomOption hackerHackeringDuration; public static CustomOption hackerOnlyColorType; + public static CustomOption hackerToolsNumber; + public static CustomOption hackerRechargeTasksNumber; public static CustomOption trackerSpawnRate; public static CustomOption trackerUpdateIntervall; @@ -228,7 +232,7 @@ namespace TheOtherRoles { // 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); + activateRoles = CustomOption.Create(1, 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); @@ -299,6 +303,8 @@ namespace TheOtherRoles { guesserHasMultipleShotsPerMeeting = CustomOption.Create(313, "Guesser Can Shoot Multiple Times Per Meeting", false, guesserSpawnRate); guesserShowInfoInGhostChat = CustomOption.Create(314, "Guesses Visible In Ghost Chat", true, guesserSpawnRate); guesserKillsThroughShield = CustomOption.Create(315, "Guesses Ignore The Medic Shield", true, guesserSpawnRate); + guesserEvilCanKillSpy = CustomOption.Create(316, "Evil Guesser Can Guess The Spy", true, guesserSpawnRate); + guesserSpawnBothRate = CustomOption.Create(317, "Other Guesser Spawn Rate", rates, guesserSpawnRate); jesterSpawnRate = CustomOption.Create(60, cs(Jester.color, "Jester"), rates, null, true); jesterCanCallEmergency = CustomOption.Create(61, "Jester can call emergency meeting", true, jesterSpawnRate); @@ -385,6 +391,8 @@ namespace TheOtherRoles { hackerCooldown = CustomOption.Create(171, "Hacker Cooldown", 30f, 0f, 60f, 5f, hackerSpawnRate); hackerHackeringDuration = CustomOption.Create(172, "Hacker Duration", 10f, 2.5f, 60f, 2.5f, hackerSpawnRate); hackerOnlyColorType = CustomOption.Create(173, "Hacker Only Sees Color Type", false, hackerSpawnRate); + hackerToolsNumber = CustomOption.Create(174, "Max Mobile Gadget Charges", 5f, 1f, 30f, 1f, hackerSpawnRate); + hackerRechargeTasksNumber = CustomOption.Create(175, "Number Of Tasks Needed For Recharging", 2f, 1f, 5f, 1f, hackerSpawnRate); trackerSpawnRate = CustomOption.Create(200, cs(Tracker.color, "Tracker"), rates, null, true); trackerUpdateIntervall = CustomOption.Create(201, "Tracker Update Intervall", 5f, 2.5f, 30f, 2.5f, trackerSpawnRate); diff --git a/TheOtherRoles/Main.cs b/TheOtherRoles/Main.cs index 43033ad..b0ca0da 100644 --- a/TheOtherRoles/Main.cs +++ b/TheOtherRoles/Main.cs @@ -21,7 +21,7 @@ namespace TheOtherRoles public class TheOtherRolesPlugin : BasePlugin { public const string Id = "me.eisbison.theotherroles"; - public const string VersionString = "3.2.4"; + public const string VersionString = "3.3.0"; public static System.Version Version = System.Version.Parse(VersionString); internal static BepInEx.Logging.ManualLogSource Logger; diff --git a/TheOtherRoles/Modules/CustomHats.cs b/TheOtherRoles/Modules/CustomHats.cs index d46d26b..b94279b 100644 --- a/TheOtherRoles/Modules/CustomHats.cs +++ b/TheOtherRoles/Modules/CustomHats.cs @@ -357,7 +357,7 @@ namespace TheOtherRoles.Modules { YOffset = createHatPackage(value, key, YOffset, __instance); } - __instance.scroller.YBounds.max = -(YOffset + 4.1f); + __instance.scroller.ContentYBounds.max = -(YOffset + 4.1f); } } diff --git a/TheOtherRoles/Modules/CustomOptions.cs b/TheOtherRoles/Modules/CustomOptions.cs index c18c9c4..7590699 100644 --- a/TheOtherRoles/Modules/CustomOptions.cs +++ b/TheOtherRoles/Modules/CustomOptions.cs @@ -263,7 +263,7 @@ namespace TheOtherRoles { 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().YBounds.max = -0.5F + __instance.Children.Length * 0.55F; + __instance.GetComponentInParent().ContentYBounds.max = -0.5F + __instance.Children.Length * 0.55F; timer += Time.deltaTime; if (timer < 0.1f) return; timer = 0f; diff --git a/TheOtherRoles/Objects/CustomButton.cs b/TheOtherRoles/Objects/CustomButton.cs index 1d6f19f..4cf49c6 100644 --- a/TheOtherRoles/Objects/CustomButton.cs +++ b/TheOtherRoles/Objects/CustomButton.cs @@ -26,8 +26,9 @@ namespace TheOtherRoles.Objects { private HudManager hudManager; private bool mirror; private KeyCode? hotkey; + private string buttonText; - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool HasEffect, float EffectDuration, Action OnEffectEnds, bool mirror = false) + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool HasEffect, float EffectDuration, Action OnEffectEnds, bool mirror = false, string buttonText = "") { this.hudManager = hudManager; this.OnClick = OnClick; @@ -41,21 +42,22 @@ namespace TheOtherRoles.Objects { this.Sprite = Sprite; this.mirror = mirror; this.hotkey = hotkey; + this.buttonText = buttonText; Timer = 16.2f; buttons.Add(this); actionButton = UnityEngine.Object.Instantiate(hudManager.KillButton, hudManager.KillButton.transform.parent); PassiveButton button = actionButton.GetComponent(); - this.showButtonText = actionButton.graphic.sprite == Sprite; + this.showButtonText = (actionButton.graphic.sprite == Sprite || buttonText != ""); button.OnClick = new Button.ButtonClickedEvent(); button.OnClick.AddListener((UnityEngine.Events.UnityAction)onClickEvent); setActive(false); } - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool mirror = false) - : this(OnClick, HasButton, CouldUse, OnMeetingEnds, Sprite, PositionOffset, hudManager, hotkey, false, 0f, () => {}, mirror) { } + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool mirror = false, string buttonText = "") + : this(OnClick, HasButton, CouldUse, OnMeetingEnds, Sprite, PositionOffset, hudManager, hotkey, false, 0f, () => {}, mirror, buttonText) { } - void onClickEvent() + public void onClickEvent() { if (this.Timer < 0f && HasButton() && CouldUse()) { @@ -137,6 +139,9 @@ namespace TheOtherRoles.Objects { setActive(hudManager.UseButton.isActiveAndEnabled); actionButton.graphic.sprite = Sprite; + if (showButtonText && buttonText != ""){ + actionButton.OverrideText(buttonText); + } actionButton.buttonLabelText.enabled = showButtonText; // Only show the text if it's a kill button if (hudManager.UseButton != null) { Vector3 pos = hudManager.UseButton.transform.localPosition; diff --git a/TheOtherRoles/Patches/CredentialsPatch.cs b/TheOtherRoles/Patches/CredentialsPatch.cs index 034bc15..ad47709 100644 --- a/TheOtherRoles/Patches/CredentialsPatch.cs +++ b/TheOtherRoles/Patches/CredentialsPatch.cs @@ -19,6 +19,7 @@ Button design by Bavari"; $@"Modded by Eisbison, Thunderstorm584, EndOfFile & Mallöris Design by Bavari"; + public static string contributorsCredentials = "GitHub Contributors: Alex2911, amsyarasyiq, gendelo3"; [HarmonyPatch(typeof(VersionShower), nameof(VersionShower.Start))] diff --git a/TheOtherRoles/Patches/EndGamePatch.cs b/TheOtherRoles/Patches/EndGamePatch.cs index 21732d4..371b2c4 100644 --- a/TheOtherRoles/Patches/EndGamePatch.cs +++ b/TheOtherRoles/Patches/EndGamePatch.cs @@ -208,7 +208,7 @@ namespace TheOtherRoles.Patches { } // Possible Additional winner: Pursuer - if (Pursuer.pursuer != null && !Pursuer.pursuer.Data.IsDead) { + if (Pursuer.pursuer != null && !Pursuer.pursuer.Data.IsDead && !Pursuer.notAckedExiled) { if (!TempData.winners.ToArray().Any(x => x.PlayerName == Pursuer.pursuer.Data.PlayerName)) TempData.winners.Add(new WinningPlayerData(Pursuer.pursuer.Data)); AdditionalTempData.additionalWinConditions.Add(WinCondition.AdditionalAlivePursuerWin); diff --git a/TheOtherRoles/Patches/MeetingPatch.cs b/TheOtherRoles/Patches/MeetingPatch.cs index e9c09cd..f5a8352 100644 --- a/TheOtherRoles/Patches/MeetingPatch.cs +++ b/TheOtherRoles/Patches/MeetingPatch.cs @@ -170,10 +170,15 @@ namespace TheOtherRoles.Patches { Swapper.playerId1 = Byte.MaxValue; Swapper.playerId2 = Byte.MaxValue; - // Lovers save next to be exiled, because RPC of ending game comes before RPC of exiled + // Lovers & Pursuer save next to be exiled, because RPC of ending game comes before RPC of exiled Lovers.notAckedExiledIsLover = false; - if (exiled != null) + Pursuer.notAckedExiled = false; + if (exiled != null) { Lovers.notAckedExiledIsLover = ((Lovers.lover1 != null && Lovers.lover1.PlayerId == exiled.PlayerId) || (Lovers.lover2 != null && Lovers.lover2.PlayerId == exiled.PlayerId)); + Pursuer.notAckedExiled = (Pursuer.pursuer != null && Pursuer.pursuer.PlayerId == exiled.PlayerId); + } + + } } @@ -253,7 +258,8 @@ namespace TheOtherRoles.Patches { Transform selectedButton = null; foreach (RoleInfo roleInfo in RoleInfo.allRoleInfos) { - if (roleInfo.roleId == RoleId.Lover || roleInfo.roleId == RoleId.Guesser || roleInfo == RoleInfo.niceMini) continue; // Not guessable roles + RoleId guesserRole = (Guesser.niceGuesser != null && PlayerControl.LocalPlayer.PlayerId == Guesser.niceGuesser.PlayerId) ? RoleId.NiceGuesser : RoleId.EvilGuesser; + if (roleInfo.roleId == RoleId.Lover || roleInfo.roleId == guesserRole || roleInfo == RoleInfo.niceMini || (!Guesser.evilGuesserCanGuessSpy && guesserRole == RoleId.EvilGuesser && roleInfo.roleId == RoleId.Spy)) continue; // Not guessable roles Transform buttonParent = (new GameObject()).transform; buttonParent.SetParent(container); Transform button = UnityEngine.Object.Instantiate(buttonTemplate, buttonParent); @@ -277,10 +283,10 @@ namespace TheOtherRoles.Patches { buttons.ForEach(x => x.GetComponent().color = x == selectedButton ? Color.red : Color.white); } else { PlayerControl focusedTarget = Helpers.playerById((byte)__instance.playerStates[buttonTarget].TargetPlayerId); - if (!(__instance.state == MeetingHud.VoteStates.Voted || __instance.state == MeetingHud.VoteStates.NotVoted) || focusedTarget == null || Guesser.remainingShots <= 0 ) return; + if (!(__instance.state == MeetingHud.VoteStates.Voted || __instance.state == MeetingHud.VoteStates.NotVoted) || focusedTarget == null || Guesser.remainingShots(PlayerControl.LocalPlayer.PlayerId) <= 0 ) return; if (!Guesser.killsThroughShield && focusedTarget == Medic.shielded) { // Depending on the options, shooting the shielded player will not allow the guess, notifiy everyone about the kill attempt and close the window - __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true)); + __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true)); UnityEngine.Object.Destroy(container.gameObject); MessageWriter murderAttemptWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1); @@ -297,18 +303,19 @@ namespace TheOtherRoles.Patches { // Reset the GUI __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true)); UnityEngine.Object.Destroy(container.gameObject); - if (Guesser.hasMultipleShotsPerMeeting && Guesser.remainingShots > 1 && dyingTarget != PlayerControl.LocalPlayer) + if (Guesser.hasMultipleShotsPerMeeting && Guesser.remainingShots(PlayerControl.LocalPlayer.PlayerId) > 1 && dyingTarget != PlayerControl.LocalPlayer) __instance.playerStates.ToList().ForEach(x => { if (x.TargetPlayerId == dyingTarget.PlayerId && x.transform.FindChild("ShootButton") != null) UnityEngine.Object.Destroy(x.transform.FindChild("ShootButton").gameObject); }); else __instance.playerStates.ToList().ForEach(x => { if (x.transform.FindChild("ShootButton") != null) UnityEngine.Object.Destroy(x.transform.FindChild("ShootButton").gameObject); }); // Shoot player and send chat info if activated MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.GuesserShoot, Hazel.SendOption.Reliable, -1); + writer.Write(PlayerControl.LocalPlayer.PlayerId); writer.Write(dyingTarget.PlayerId); writer.Write(focusedTarget.PlayerId); writer.Write((byte)roleInfo.roleId); AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.guesserShoot(dyingTarget.PlayerId, focusedTarget.PlayerId, (byte)roleInfo.roleId); + RPCProcedure.guesserShoot(PlayerControl.LocalPlayer.PlayerId, dyingTarget.PlayerId, focusedTarget.PlayerId, (byte)roleInfo.roleId); } })); @@ -320,7 +327,7 @@ namespace TheOtherRoles.Patches { [HarmonyPatch(typeof(PlayerVoteArea), nameof(PlayerVoteArea.Select))] class PlayerVoteAreaSelectPatch { static bool Prefix(MeetingHud __instance) { - return !(PlayerControl.LocalPlayer != null && PlayerControl.LocalPlayer == Guesser.guesser && guesserUI != null); + return !(PlayerControl.LocalPlayer != null && Guesser.isGuesser(PlayerControl.LocalPlayer.PlayerId) && guesserUI != null); } } @@ -354,6 +361,13 @@ namespace TheOtherRoles.Patches { } } + //Fix visor in Meetings + foreach (PlayerVoteArea pva in __instance.playerStates) { + if(pva.PlayerIcon != null && pva.PlayerIcon.VisorSlot != null){ + pva.PlayerIcon.VisorSlot.transform.position += new Vector3(0, 0, -1f); + } + } + // Add overlay for spelled players if (Witch.witch != null && Witch.futureSpelled != null) { foreach (PlayerVoteArea pva in __instance.playerStates) { @@ -368,10 +382,10 @@ namespace TheOtherRoles.Patches { } // Add Guesser Buttons - if (Guesser.guesser != null && PlayerControl.LocalPlayer == Guesser.guesser && !Guesser.guesser.Data.IsDead && Guesser.remainingShots > 0) { + if (Guesser.isGuesser(PlayerControl.LocalPlayer.PlayerId) && !PlayerControl.LocalPlayer.Data.IsDead && Guesser.remainingShots(PlayerControl.LocalPlayer.PlayerId) > 0) { for (int i = 0; i < __instance.playerStates.Length; i++) { PlayerVoteArea playerVoteArea = __instance.playerStates[i]; - if (playerVoteArea.AmDead || playerVoteArea.TargetPlayerId == Guesser.guesser.PlayerId) continue; + if (playerVoteArea.AmDead || playerVoteArea.TargetPlayerId == PlayerControl.LocalPlayer.PlayerId) continue; GameObject template = playerVoteArea.Buttons.transform.Find("CancelButton").gameObject; GameObject targetBox = UnityEngine.Object.Instantiate(template, playerVoteArea.transform); diff --git a/TheOtherRoles/Patches/PlayerControlPatch.cs b/TheOtherRoles/Patches/PlayerControlPatch.cs index 5f79851..7398da8 100644 --- a/TheOtherRoles/Patches/PlayerControlPatch.cs +++ b/TheOtherRoles/Patches/PlayerControlPatch.cs @@ -387,11 +387,17 @@ namespace TheOtherRoles.Patches { TMPro.TextMeshPro meetingInfo = meetingInfoTransform != null ? meetingInfoTransform.GetComponent() : null; if (meetingInfo == null && playerVoteArea != null) { meetingInfo = UnityEngine.Object.Instantiate(playerVoteArea.NameText, playerVoteArea.NameText.transform.parent); - meetingInfo.transform.localPosition += Vector3.down * 0.20f; - meetingInfo.fontSize *= 0.75f; + meetingInfo.transform.localPosition += Vector3.down * 0.10f; + meetingInfo.fontSize *= 0.60f; meetingInfo.gameObject.name = "Info"; } + // Set player name higher to align in middle + if (meetingInfo != null && playerVoteArea != null) { + var playerName = playerVoteArea.NameText; + playerName.transform.localPosition = new Vector3(0.3384f, (0.0311f + 0.0683f), -0.1f); + } + var (tasksCompleted, tasksTotal) = TasksHandler.taskInfo(p.Data); string roleNames = RoleInfo.GetRolesString(p, true); string taskInfo = tasksTotal > 0 ? $"({tasksCompleted}/{tasksTotal})" : ""; @@ -676,6 +682,16 @@ namespace TheOtherRoles.Patches { } } + public static void hackerUpdate() { + if (Hacker.hacker == null || PlayerControl.LocalPlayer != Hacker.hacker || Hacker.hacker.Data.IsDead) return; + var (playerCompleted, _) = TasksHandler.taskInfo(Hacker.hacker.Data); + if (playerCompleted == Hacker.rechargedTasks) { + Hacker.rechargedTasks += Hacker.rechargeTasksNumber; + if (Hacker.toolsNumber > Hacker.chargesVitals) Hacker.chargesVitals++; + if (Hacker.toolsNumber > Hacker.chargesAdminTable) Hacker.chargesAdminTable++; + } + } + static void pursuerSetTarget() { if (Pursuer.pursuer == null || Pursuer.pursuer != PlayerControl.LocalPlayer) return; Pursuer.target = setTarget(); @@ -767,6 +783,7 @@ namespace TheOtherRoles.Patches { pursuerSetTarget(); // Witch witchSetTarget(); + hackerUpdate(); } } } diff --git a/TheOtherRoles/Patches/RoleAssignmentPatch.cs b/TheOtherRoles/Patches/RoleAssignmentPatch.cs index f2bd6e4..2afc83e 100644 --- a/TheOtherRoles/Patches/RoleAssignmentPatch.cs +++ b/TheOtherRoles/Patches/RoleAssignmentPatch.cs @@ -161,9 +161,11 @@ namespace TheOtherRoles.Patches { // Assign Guesser (chance to be impostor based on setting) if (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && rnd.Next(1, 101) <= CustomOptionHolder.guesserIsImpGuesserRate.getSelection() * 10) { - data.impSettings.Add((byte)RoleId.Guesser, CustomOptionHolder.guesserSpawnRate.getSelection()); + data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnRate.getSelection()); + if (data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); // Second guesser } else if (data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { - data.crewSettings.Add((byte)RoleId.Guesser, CustomOptionHolder.guesserSpawnRate.getSelection()); + data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnRate.getSelection()); + if (data.impostors.Count > 0 && data.maxImpostorRoles > 0) data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); // Second guesser } } diff --git a/TheOtherRoles/Patches/UpdatePatch.cs b/TheOtherRoles/Patches/UpdatePatch.cs index d081c1b..d31cb9c 100644 --- a/TheOtherRoles/Patches/UpdatePatch.cs +++ b/TheOtherRoles/Patches/UpdatePatch.cs @@ -107,8 +107,10 @@ namespace TheOtherRoles.Patches { setPlayerNameColor(SecurityGuard.securityGuard, SecurityGuard.color); } 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.Role.IsImpostor ? Palette.ImpostorRed : Guesser.color); + } else if (Guesser.niceGuesser != null && Guesser.niceGuesser == PlayerControl.LocalPlayer) { + setPlayerNameColor(Guesser.niceGuesser, Guesser.color); + } else if (Guesser.evilGuesser != null && Guesser.evilGuesser == PlayerControl.LocalPlayer) { + setPlayerNameColor(Guesser.evilGuesser, Palette.ImpostorRed); } else if (Bait.bait != null && Bait.bait == PlayerControl.LocalPlayer) { setPlayerNameColor(Bait.bait, Bait.color); } else if (Vulture.vulture != null && Vulture.vulture == PlayerControl.LocalPlayer) { diff --git a/TheOtherRoles/Patches/UsablesPatch.cs b/TheOtherRoles/Patches/UsablesPatch.cs index 5ccd09e..6cfa5ab 100644 --- a/TheOtherRoles/Patches/UsablesPatch.cs +++ b/TheOtherRoles/Patches/UsablesPatch.cs @@ -253,6 +253,13 @@ namespace TheOtherRoles.Patches { } } + + //Fix Visor in Vitals + foreach (VitalsPanel panel in __instance.vitals) { + if (panel.PlayerIcon != null && panel.PlayerIcon.Skin != null) { + panel.PlayerIcon.Skin.transform.position = new Vector3(0, 0, 0f); + } + } } } diff --git a/TheOtherRoles/RPC.cs b/TheOtherRoles/RPC.cs index d550f9b..fef6356 100644 --- a/TheOtherRoles/RPC.cs +++ b/TheOtherRoles/RPC.cs @@ -45,7 +45,8 @@ namespace TheOtherRoles Warlock, SecurityGuard, Arsonist, - Guesser, + EvilGuesser, + NiceGuesser, BountyHunter, Bait, Vulture, @@ -243,8 +244,11 @@ namespace TheOtherRoles case RoleId.Arsonist: Arsonist.arsonist = player; break; - case RoleId.Guesser: - Guesser.guesser = player; + case RoleId.EvilGuesser: + Guesser.evilGuesser = player; + break; + case RoleId.NiceGuesser: + Guesser.niceGuesser = player; break; case RoleId.BountyHunter: BountyHunter.bountyHunter = player; @@ -453,8 +457,8 @@ namespace TheOtherRoles Spy.spy = oldShifter; if (SecurityGuard.securityGuard != null && SecurityGuard.securityGuard == player) SecurityGuard.securityGuard = oldShifter; - if (Guesser.guesser != null && Guesser.guesser == player) - Guesser.guesser = oldShifter; + if (Guesser.niceGuesser != null && Guesser.niceGuesser == player) + Guesser.niceGuesser = oldShifter; if (Bait.bait != null && Bait.bait == player) { Bait.bait = oldShifter; if (Bait.bait.Data.IsDead) Bait.reported = true; @@ -583,7 +587,7 @@ namespace TheOtherRoles // Other roles if (player == Jester.jester) Jester.clearAndReload(); if (player == Arsonist.arsonist) Arsonist.clearAndReload(); - if (player == Guesser.guesser) Guesser.clearAndReload(); + if (Guesser.isGuesser(player.PlayerId)) Guesser.clear(player.PlayerId); if (!ignoreLovers && (player == Lovers.lover1 || player == Lovers.lover2)) { // The whole Lover couple is being erased Lovers.clearAndReload(); } @@ -719,14 +723,14 @@ namespace TheOtherRoles } } - public static void guesserShoot(byte dyingTargetId, byte guessedTargetId, byte guessedRoleId) { + public static void guesserShoot(byte killerId, byte dyingTargetId, byte guessedTargetId, byte guessedRoleId) { PlayerControl dyingTarget = Helpers.playerById(dyingTargetId); if (dyingTarget == null ) return; dyingTarget.Exiled(); PlayerControl dyingLoverPartner = Lovers.bothDie ? dyingTarget.getPartner() : null; // Lover check byte partnerId = dyingLoverPartner != null ? dyingLoverPartner.PlayerId : dyingTargetId; - Guesser.remainingShots = Mathf.Max(0, Guesser.remainingShots - 1); + Guesser.remainingShots(killerId, true); if (Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(dyingTarget.KillSfx, false, 0.8f); if (MeetingHud.Instance) { foreach (PlayerVoteArea pva in MeetingHud.Instance.playerStates) { @@ -738,9 +742,10 @@ namespace TheOtherRoles if (AmongUsClient.Instance.AmHost) MeetingHud.Instance.CheckForEndVoting(); } - if (HudManager.Instance != null && Guesser.guesser != null) + PlayerControl guesser = Helpers.playerById(killerId); + if (HudManager.Instance != null && guesser != null) if (PlayerControl.LocalPlayer == dyingTarget) - HudManager.Instance.KillOverlay.ShowKillAnimation(Guesser.guesser.Data, dyingTarget.Data); + HudManager.Instance.KillOverlay.ShowKillAnimation(guesser.Data, dyingTarget.Data); else if (dyingLoverPartner != null && PlayerControl.LocalPlayer == dyingLoverPartner) HudManager.Instance.KillOverlay.ShowKillAnimation(dyingLoverPartner.Data, dyingLoverPartner.Data); @@ -749,7 +754,7 @@ namespace TheOtherRoles RoleInfo roleInfo = RoleInfo.allRoleInfos.FirstOrDefault(x => (byte)x.roleId == guessedRoleId); string msg = $"Guesser guessed the role {roleInfo?.name ?? ""} for {guessedTarget.Data.PlayerName}!"; if (AmongUsClient.Instance.AmClient && DestroyableSingleton.Instance) - DestroyableSingleton.Instance.Chat.AddChat(Guesser.guesser, msg); + DestroyableSingleton.Instance.Chat.AddChat(guesser, msg); if (msg.IndexOf("who", StringComparison.OrdinalIgnoreCase) >= 0) DestroyableSingleton.Instance.SendWho(); } @@ -909,10 +914,11 @@ namespace TheOtherRoles RPCProcedure.arsonistWin(); break; case (byte)CustomRPC.GuesserShoot: + byte killerId = reader.ReadByte(); byte dyingTarget = reader.ReadByte(); byte guessedTarget = reader.ReadByte(); byte guessedRoleId = reader.ReadByte(); - RPCProcedure.guesserShoot(dyingTarget, guessedTarget, guessedRoleId); + RPCProcedure.guesserShoot(killerId, dyingTarget, guessedTarget, guessedRoleId); break; case (byte)CustomRPC.VultureWin: RPCProcedure.vultureWin(); diff --git a/TheOtherRoles/RoleInfo.cs b/TheOtherRoles/RoleInfo.cs index 3e4196b..04bbdf6 100644 --- a/TheOtherRoles/RoleInfo.cs +++ b/TheOtherRoles/RoleInfo.cs @@ -56,8 +56,8 @@ namespace TheOtherRoles public static RoleInfo spy = new RoleInfo("Spy", Spy.color, "Confuse the Impostors", "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, 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 goodGuesser = new RoleInfo("Nice Guesser", Guesser.color, "Guess and shoot", "Guess and shoot", RoleId.NiceGuesser); + public static RoleInfo badGuesser = new RoleInfo("Evil Guesser", Palette.ImpostorRed, "Guess and shoot", "Guess and shoot", RoleId.EvilGuesser); 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, true); public static RoleInfo medium = new RoleInfo("Medium", Medium.color, "Question the souls of the dead to gain informations", "Question the souls", RoleId.Medium); @@ -150,7 +150,8 @@ namespace TheOtherRoles 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.Role.IsImpostor ? badGuesser : goodGuesser); + if (p == Guesser.niceGuesser) infos.Add(goodGuesser); + if (p == Guesser.evilGuesser) infos.Add(badGuesser); if (p == BountyHunter.bountyHunter) infos.Add(bountyHunter); if (p == Bait.bait) infos.Add(bait); if (p == Vulture.vulture) infos.Add(vulture); diff --git a/TheOtherRoles/TheOtherRoles.cs b/TheOtherRoles/TheOtherRoles.cs index 93a08c4..320fde3 100644 --- a/TheOtherRoles/TheOtherRoles.cs +++ b/TheOtherRoles/TheOtherRoles.cs @@ -478,26 +478,58 @@ namespace TheOtherRoles public static class Hacker { public static PlayerControl hacker; + public static Minigame vitals = null; public static Color color = new Color32(117, 250, 76, byte.MaxValue); public static float cooldown = 30f; public static float duration = 10f; + public static float toolsNumber = 5f; public static bool onlyColorType = false; public static float hackerTimer = 0f; + public static int rechargeTasksNumber = 2; + public static int rechargedTasks = 2; + public static int chargesVitals = 1; + public static int chargesAdminTable = 1; private static Sprite buttonSprite; + private static Sprite vitalsSprite; + private static Sprite adminSprite; + public static Sprite getButtonSprite() { if (buttonSprite) return buttonSprite; buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HackerButton.png", 115f); return buttonSprite; } + public static Sprite getVitalsSprite() { + if (vitalsSprite) return vitalsSprite; + vitalsSprite = HudManager.Instance.UseButton.fastUseSettings[ImageNames.VitalsButton].Image; + return vitalsSprite; + } + + public static Sprite getAdminSprite() { + byte mapId = PlayerControl.GameOptions.MapId; + UseButtonSettings button = HudManager.Instance.UseButton.fastUseSettings[ImageNames.PolusAdminButton]; // Polus + if (mapId == 0 || mapId == 3) button = HudManager.Instance.UseButton.fastUseSettings[ImageNames.AdminMapButton]; // Skeld || Dleks + else if (mapId == 1) button = HudManager.Instance.UseButton.fastUseSettings[ImageNames.MIRAAdminButton]; // Mira HQ + else if (mapId == 4) button = HudManager.Instance.UseButton.fastUseSettings[ImageNames.AirshipAdminButton]; // Airship + adminSprite = button.Image; + return adminSprite; + } + public static void clearAndReload() { hacker = null; + vitals = null; hackerTimer = 0f; + adminSprite = null; cooldown = CustomOptionHolder.hackerCooldown.getFloat(); duration = CustomOptionHolder.hackerHackeringDuration.getFloat(); onlyColorType = CustomOptionHolder.hackerOnlyColorType.getBool(); + toolsNumber = CustomOptionHolder.hackerToolsNumber.getFloat(); + rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.hackerRechargeTasksNumber.getFloat()); + rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.hackerRechargeTasksNumber.getFloat()); + chargesVitals = Mathf.RoundToInt(CustomOptionHolder.hackerToolsNumber.getFloat()) / 2; + chargesAdminTable = Mathf.RoundToInt(CustomOptionHolder.hackerToolsNumber.getFloat()) / 2; } } @@ -969,14 +1001,17 @@ namespace TheOtherRoles } public static class Guesser { - public static PlayerControl guesser; + public static PlayerControl niceGuesser; + public static PlayerControl evilGuesser; public static Color color = new Color32(255, 255, 0, byte.MaxValue); private static Sprite targetSprite; - public static int remainingShots = 2; + public static int remainingShotsEvilGuesser = 2; + public static int remainingShotsNiceGuesser = 2; public static bool hasMultipleShotsPerMeeting = false; public static bool showInfoInGhostChat = true; public static bool killsThroughShield = true; + public static bool evilGuesserCanGuessSpy = true; public static Sprite getTargetSprite() { if (targetSprite) return targetSprite; @@ -984,13 +1019,37 @@ namespace TheOtherRoles return targetSprite; } + public static bool isGuesser (byte playerId) { + if ((niceGuesser != null && niceGuesser.PlayerId == playerId) || (evilGuesser != null && evilGuesser.PlayerId == playerId)) return true; + return false; + } + + public static void clear (byte playerId) { + if (niceGuesser != null && niceGuesser.PlayerId == playerId) niceGuesser = null; + else if (evilGuesser != null && evilGuesser.PlayerId == playerId) evilGuesser = null; + } + + public static int remainingShots(byte playerId, bool shoot = false) { + int remainingShots = remainingShotsEvilGuesser; + if (niceGuesser.PlayerId == playerId) { + remainingShots = remainingShotsNiceGuesser; + if (shoot) remainingShotsNiceGuesser = Mathf.Max(0, remainingShotsNiceGuesser - 1); + } else if (shoot) { + remainingShotsEvilGuesser = Mathf.Max(0, remainingShotsEvilGuesser - 1); + } + return remainingShots; + } + public static void clearAndReload() { - guesser = null; - - remainingShots = Mathf.RoundToInt(CustomOptionHolder.guesserNumberOfShots.getFloat()); + niceGuesser = null; + evilGuesser = null; + + remainingShotsEvilGuesser = Mathf.RoundToInt(CustomOptionHolder.guesserNumberOfShots.getFloat()); + remainingShotsNiceGuesser = Mathf.RoundToInt(CustomOptionHolder.guesserNumberOfShots.getFloat()); hasMultipleShotsPerMeeting = CustomOptionHolder.guesserHasMultipleShotsPerMeeting.getBool(); showInfoInGhostChat = CustomOptionHolder.guesserShowInfoInGhostChat.getBool(); killsThroughShield = CustomOptionHolder.guesserKillsThroughShield.getBool(); + evilGuesserCanGuessSpy = CustomOptionHolder.guesserEvilCanKillSpy.getBool(); } } @@ -1170,6 +1229,7 @@ namespace TheOtherRoles public static List blankedList = new List(); public static int blanks = 0; public static Sprite blank; + public static bool notAckedExiled = false; public static float cooldown = 30f; public static int blanksNumber = 5; @@ -1185,6 +1245,7 @@ namespace TheOtherRoles target = null; blankedList = new List(); blanks = 0; + notAckedExiled = false; cooldown = CustomOptionHolder.pursuerCooldown.getFloat(); blanksNumber = Mathf.RoundToInt(CustomOptionHolder.pursuerBlanksNumber.getFloat()); diff --git a/TheOtherRoles/TheOtherRoles.csproj b/TheOtherRoles/TheOtherRoles.csproj index 6e0becc..bf6f4d3 100644 --- a/TheOtherRoles/TheOtherRoles.csproj +++ b/TheOtherRoles/TheOtherRoles.csproj @@ -1,7 +1,7 @@ netstandard2.1 - 3.2.4 + 3.3.0 TheOtherRoles Eisbison