From: Eisbison Date: Fri, 26 Mar 2021 11:11:31 +0000 (+0100) Subject: Update source code X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=30084dec6a3a07828e62f20aa104a487e80afab8;p=rhonda%2Ftheotherroles.git Update source code --- diff --git a/Source Code/Arrow.cs b/Source Code/Arrow.cs new file mode 100644 index 0000000..a4d0360 --- /dev/null +++ b/Source Code/Arrow.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using UnityEngine; +using static TheOtherRoles.TheOtherRoles; + +namespace TheOtherRoles{ + public class Arrow { + public float perc = 0.925f; + public SpriteRenderer image; + public GameObject arrow; + private Vector3 oldTarget; + + private static Sprite sprite; + public static Sprite getSprite() { + if (sprite) return sprite; + sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Arrow.png", 200f); + return sprite; + } + + + public Arrow(Color color) { + arrow = new GameObject("Arrow"); + arrow.layer = 5; + image = arrow.AddComponent(); + image.sprite = getSprite(); + image.color = color; + } + + public void Update() { + Vector3 target = oldTarget; + if (target == null) target = Vector3.zero; + Update(target); + } + + public void Update(Vector3 target) + { + if (arrow == null) return; + oldTarget = target; + + Camera main = Camera.main; + Vector2 vector = target - main.transform.position; + float num = vector.magnitude / (main.orthographicSize * perc); + image.enabled = ((double)num > 0.3); + Vector2 vector2 = main.WorldToViewportPoint(target); + if (Between(vector2.x, 0f, 1f) && Between(vector2.y, 0f, 1f)) + { + arrow.transform.position = target - (Vector3)vector.normalized * 0.6f; + float num2 = Mathf.Clamp(num, 0f, 1f); + arrow.transform.localScale = new Vector3(num2, num2, num2); + } + else + { + Vector2 vector3 = new Vector2(Mathf.Clamp(vector2.x * 2f - 1f, -1f, 1f), Mathf.Clamp(vector2.y * 2f - 1f, -1f, 1f)); + float orthographicSize = main.orthographicSize; + float num3 = main.orthographicSize * main.aspect; + Vector3 vector4 = new Vector3(Mathf.LerpUnclamped(0f, num3 * 0.88f, vector3.x), Mathf.LerpUnclamped(0f, orthographicSize * 0.79f, vector3.y), 0f); + arrow.transform.position = main.transform.position + vector4; + arrow.transform.localScale = Vector3.one; + } + + LookAt2d(arrow.transform, target); + } + + private void LookAt2d(Transform transform, Vector3 target) { + Vector3 vector = target - transform.position; + vector.Normalize(); + float num = Mathf.Atan2(vector.y, vector.x); + if (transform.lossyScale.x < 0f) + num += 3.1415927f; + transform.rotation = Quaternion.Euler(0f, 0f, num * 57.29578f); + } + + private bool Between(float value, float min, float max) { + return value > min && value < max; + } + } +} \ No newline at end of file diff --git a/Source Code/BonusRoles.cs b/Source Code/BonusRoles.cs deleted file mode 100644 index 8684017..0000000 --- a/Source Code/BonusRoles.cs +++ /dev/null @@ -1,438 +0,0 @@ -using System.Net; -using System.Linq; -using BepInEx; -using BepInEx.Configuration; -using BepInEx.IL2CPP; -using HarmonyLib; -using Hazel; -using Reactor; -using System; -using System.Collections.Generic; -using System.Collections; -using System.IO; -using UnityEngine; -using Reactor.Unstrip; -using Reactor.Extensions; - -namespace BonusRoles -{ - [HarmonyPatch] - public static class BonusRoles - { - public static System.Random rnd = new System.Random((int)DateTime.Now.Ticks); - - public static void clearAndReloadRoles() { - Jester.clearAndReload(); - Mayor.clearAndReload(); - Engineer.clearAndReload(); - Sheriff.clearAndReload(); - Lighter.clearAndReload(); - Godfather.clearAndReload(); - Mafioso.clearAndReload(); - Janitor.clearAndReload(); - Detective.clearAndReload(); - TimeMaster.clearAndReload(); - Medic.clearAndReload(); - Shifter.clearAndReload(); - Swapper.clearAndReload(); - Lovers.clearAndReload(); - Seer.clearAndReload(); - Morphling.clearAndReload(); - Camouflager.clearAndReload(); - Spy.clearAndReload(); - Child.clearAndReload(); - } - - public static class Jester { - public static PlayerControl jester; - public static Color color = new Color(255f / 255f, 84f / 255f, 167f / 255f, 1); - - public static void clearAndReload() { - jester = null; - } - } - - public static class Mayor { - public static PlayerControl mayor; - public static Color color = new Color(105f / 255f, 58f / 255f, 58f / 255f, 1); - - public static void clearAndReload() { - mayor = null; - } - } - - public static class Engineer { - public static PlayerControl engineer; - public static Color color = new Color(98f / 255f, 216f / 255f, 240f / 255f, 1); - public static bool usedRepair; - private static Sprite buttonSprite; - - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.RepairButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - engineer = null; - usedRepair = false; - } - } - - public static class Godfather { - public static PlayerControl godfather; - public static Color color = Palette.ImpostorRed; - - public static void clearAndReload() { - godfather = null; - } - } - - public static class Mafioso { - public static PlayerControl mafioso; - public static Color color = Palette.ImpostorRed; - - public static void clearAndReload() { - mafioso = null; - } - } - - - public static class Janitor { - public static PlayerControl janitor; - public static Color color = Palette.ImpostorRed; - - public static float cooldown = float.MaxValue; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.CleanButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - janitor = null; - cooldown = BonusRolesPlugin.janitorCooldown.GetValue(); - } - } - - public static class Sheriff { - public static PlayerControl sheriff; - public static Color color = new Color(255f / 255f, 204f / 255f, 0f / 255f, 1); - - public static float cooldown = float.MaxValue; - public static bool jesterCanDieToSheriff = false; - - public static PlayerControl currentTarget; - - public static void clearAndReload() { - sheriff = null; - currentTarget = null; - cooldown = BonusRolesPlugin.sheriffCooldown.GetValue(); - jesterCanDieToSheriff = BonusRolesPlugin.jesterCanDieToSheriff.GetValue(); - } - } - - public static class Lighter { - public static PlayerControl lighter; - public static Color color = new Color(250f / 255f, 204f / 255f, 37f / 255f, 1); - - public static float lighterVision = 2f; - - public static void clearAndReload() { - lighter = null; - lighterVision = BonusRolesPlugin.lighterVision.GetValue(); - } - } - - public static class Detective { - public static PlayerControl detective; - public static Color color = new Color(2f / 255f, 61f / 255f, 156f / 255f, 1); - - public static float footprintIntervall = 1f; - public static float footprintDuration = 1f; - public static bool anonymousFootprints = false; - - public static float timer = 1f; - - public static void clearAndReload() { - detective = null; - anonymousFootprints = BonusRolesPlugin.detectiveAnonymousFootprints.GetValue(); - footprintIntervall = BonusRolesPlugin.detectiveFootprintIntervall.GetValue(); - footprintDuration = BonusRolesPlugin.detectiveFootprintDuration.GetValue(); - timer = footprintIntervall; - } - } - } - - public static class TimeMaster { - public static PlayerControl timeMaster; - public static Color color = new Color(114f / 255f, 234f / 255f, 247f / 255f, 1); - - public static bool reviveDuringRewind = false; - public static float rewindTime = 3f; - public static float cooldown = float.MaxValue; - - public static bool isRewinding = false; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.RewindButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - timeMaster = null; - isRewinding = false; - reviveDuringRewind = BonusRolesPlugin.timeMasterReviveDuringRewind.GetValue(); - rewindTime = BonusRolesPlugin.timeMasterRewindTime.GetValue(); - cooldown = BonusRolesPlugin.timeMasterCooldown.GetValue(); - } - } - - public static class Medic { - public static PlayerControl medic; - public static PlayerControl shielded; - public static Color color = new Color(0f / 255f, 80f / 255f, 105f / 255f, 1); - public static bool usedShield; - - public static float reportNameDuration = 10f; - public static float reportColorDuration = 20f; - public static int showShielded = 0; - public static bool showAttemptToShielded = false; - - public static Color shieldedColor = new Color(0f / 255f, 221f / 255f, 255f / 255f, 1); - public static PlayerControl currentTarget; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.ShieldButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - medic = null; - shielded = null; - currentTarget = null; - usedShield = false; - shieldedColor = new Color(0f / 255f, 221f / 255f, 255f / 255f, 1); - reportNameDuration = BonusRolesPlugin.medicReportNameDuration.GetValue(); - reportColorDuration = BonusRolesPlugin.medicReportColorDuration.GetValue(); - showShielded = BonusRolesPlugin.medicShowShielded.GetValue(); - showAttemptToShielded = BonusRolesPlugin.medicShowAttemptToShielded.GetValue(); - } - } - - public static class Shifter { - public static PlayerControl shifter; - public static Color color = new Color(90f / 255f, 90f / 255f, 90f / 255f, 1); - - public static float cooldown = float.MaxValue; - - public static PlayerControl currentTarget; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.ShiftButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - shifter = null; - currentTarget = null; - cooldown = BonusRolesPlugin.shifterCooldown.GetValue(); - } - } - - public static class Swapper { - public static PlayerControl swapper; - public static Color color = new Color(240f / 255f, 128f / 255f, 72f / 255f, 1); - private static Sprite spriteCheck; - - public static byte playerId1 = Byte.MaxValue; - public static byte playerId2 = Byte.MaxValue; - - public static Sprite getCheckSprite() { - if (spriteCheck) return spriteCheck; - spriteCheck = Helpers.loadSpriteFromResources("BonusRoles.Resources.SwapperCheck.png", 150f); - return spriteCheck; - } - - public static void clearAndReload() { - swapper = null; - playerId1 = Byte.MaxValue; - playerId2 = Byte.MaxValue; - } - } - - public static class Lovers { - public static PlayerControl lover1; - public static PlayerControl lover2; - public static Color color = new Color(252f / 255f, 3f / 255f, 190f / 255f, 1); - - public static bool bothDie = true; - // Lovers save if next to be exiled is a lover, because RPC of ending game comes before RPC of exiled - public static bool notAckedExiledIsLover = false; - - public static bool existingAndAlive() { - return lover1 != null && lover2 != null && !lover1.Data.IsDead && !lover2.Data.IsDead && !notAckedExiledIsLover; // ADD NOT ACKED IS LOVER - } - - public static bool existingWithImpLover() { - return lover1 != null && lover2 != null && (lover1.Data.IsImpostor || lover2.Data.IsImpostor); - } - - public static void clearAndReload() { - lover1 = null; - lover2 = null; - notAckedExiledIsLover = false; - bothDie = BonusRolesPlugin.loversBothDie.GetValue(); - } - } - - public static class Seer { - public static PlayerControl seer; - public static Color color = new Color(60f / 255f, 181f / 255f, 100f / 255f, 1); - public static Dictionary revealedPlayers = new Dictionary(); - - public static float cooldown = float.MaxValue; - public static int kindOfInfo = 0; - public static int playersWithNotification = 0; - public static float chanceOfSeeingRight = 100; - - public static PlayerControl currentTarget; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.SeerButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - seer = null; - revealedPlayers = new Dictionary(); - cooldown = BonusRolesPlugin.seerCooldown.GetValue(); - kindOfInfo = BonusRolesPlugin.seerKindOfInfo.GetValue(); - playersWithNotification = BonusRolesPlugin.seerPlayersWithNotification.GetValue(); - chanceOfSeeingRight = BonusRolesPlugin.seerChanceOfSeeingRight.GetValue(); - } - } - - public static class Morphling { - public static PlayerControl morphling; - public static Color color = Palette.ImpostorRed; - private static Sprite sampleSprite; - private static Sprite morphSprite; - - public static float cooldown = float.MaxValue; - - public static PlayerControl currentTarget; - public static PlayerControl sampledTarget; - public static PlayerControl morphTarget; - public static float morphTimer = 0f; - - - public static void clearAndReload() { - morphling = null; - currentTarget = null; - sampledTarget = null; - morphTarget = null; - morphTimer = 0f; - cooldown = BonusRolesPlugin.morphlingCooldown.GetValue(); - } - - public static Sprite getSampleSprite() { - if (sampleSprite) return sampleSprite; - sampleSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.SampleButton.png", 100f); - return sampleSprite; - } - - public static Sprite getMorphSprite() { - if (morphSprite) return morphSprite; - morphSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.MorphButton.png", 100f); - return morphSprite; - } - } - - public static class Camouflager { - public static PlayerControl camouflager; - public static Color color = Palette.ImpostorRed; - - public static float cooldown = float.MaxValue; - public static float camouflageTimer = 0f; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.CamoButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - camouflager = null; - camouflageTimer = 0f; - cooldown = BonusRolesPlugin.camouflagerCooldown.GetValue(); - } - } - - public static class Spy { - public static PlayerControl spy; - private static Sprite adminTableIcon; - public static Color color = new Color(252f / 255f, 90f / 255f, 30f / 255f, 1); - - public static float cooldown = float.MaxValue; - public static float duration = 10f; - - public static float spyTimer = 0f; - - public static Sprite getAdminTableIconSprite() { - if (adminTableIcon) return adminTableIcon; - adminTableIcon = Helpers.loadSpriteFromResources("BonusRoles.Resources.AdminTableIcon.png", 350f); - return adminTableIcon; - } - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.SpyButton.png", 100f); - return buttonSprite; - } - - public static void clearAndReload() { - spy = null; - spyTimer = 0f; - cooldown = BonusRolesPlugin.spyCooldown.GetValue(); - duration = BonusRolesPlugin.spySpyingDuration.GetValue(); - } - } - - public static class Child { - public static PlayerControl child; - public static Color color = Color.white; - - public static float growingUpDuration = float.MaxValue; - public static DateTime timeOfGrowthStart = DateTime.UtcNow; - - public static void clearAndReload() { - child = null; - growingUpDuration = BonusRolesPlugin.childGrowingUpDuration.GetValue(); - timeOfGrowthStart = DateTime.UtcNow; - } - - public static float growingProgress() { - if (timeOfGrowthStart == null) return 0f; - - float timeSinceStart = (float)(DateTime.UtcNow - timeOfGrowthStart).TotalMilliseconds; - return Mathf.Clamp(timeSinceStart/(growingUpDuration*1000), 0f, 1f); - } - - public static bool isGrownUp() { - return growingProgress() == 1f; - } - } -} \ No newline at end of file diff --git a/Source Code/BonusRoles.csproj b/Source Code/BonusRoles.csproj deleted file mode 100644 index 803c675..0000000 --- a/Source Code/BonusRoles.csproj +++ /dev/null @@ -1,52 +0,0 @@ - - - netstandard2.1 - 1.0.0 - NuclearPowered/Mappings:0.2.0 - - TheOtherRoles - Eisbison - - - - 2021.3.5s - $(DefineConstants);STEAM - - - - 2021.3.5i - $(DefineConstants);ITCH - - - - - - - - - - - $(AmongUs)\BepInEx\plugins\Essentials-$(GameVersion).dll - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source Code/Buttons.cs b/Source Code/Buttons.cs index 55d2620..fc16fec 100644 --- a/Source Code/Buttons.cs +++ b/Source Code/Buttons.cs @@ -4,13 +4,13 @@ using System; using System.IO; using System.Net.Http; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; using Reactor.Extensions; using System.Collections.Generic; using System.Linq; using UnhollowerBaseLib; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(HudManager), nameof(HudManager.Start))] static class HudManagerStartPatch @@ -25,6 +25,9 @@ namespace BonusRoles private static CustomButton morphlingButton; private static CustomButton camouflagerButton; private static CustomButton spyButton; + private static CustomButton trackerButton; + private static CustomButton vampireKillButton; + private static CustomButton garlicButton; public static void setCustomButtonCooldowns() { engineerRepairButton.MaxTimer = 0f; @@ -37,8 +40,12 @@ namespace BonusRoles morphlingButton.MaxTimer = Morphling.cooldown; camouflagerButton.MaxTimer = Camouflager.cooldown; spyButton.MaxTimer = Spy.cooldown; + vampireKillButton.MaxTimer = PlayerControl.GameOptions.KillCooldown; + trackerButton.MaxTimer = 0f; + garlicButton.MaxTimer = 0f; spyButton.EffectDuration = Spy.duration; + vampireKillButton.EffectDuration= Vampire.delay; } public static void Postfix(HudManager __instance) @@ -80,7 +87,7 @@ namespace BonusRoles }, () => {}, Engineer.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -115,7 +122,7 @@ namespace BonusRoles () => { return __instance.ReportButton.renderer.color == Palette.EnabledColor && PlayerControl.LocalPlayer.CanMove; }, () => { janitorCleanButton.Timer = janitorCleanButton.MaxTimer;}, Janitor.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -148,7 +155,7 @@ namespace BonusRoles () => { return Sheriff.currentTarget && PlayerControl.LocalPlayer.CanMove; }, () => { sheriffKillButton.Timer = sheriffKillButton.MaxTimer;}, __instance.KillButton.renderer.sprite, - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -164,7 +171,7 @@ namespace BonusRoles () => { return PlayerControl.LocalPlayer.CanMove; }, () => { timeMasterRewindTimeButton.Timer = timeMasterRewindTimeButton.MaxTimer;}, TimeMaster.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -182,7 +189,7 @@ namespace BonusRoles () => { return !Medic.usedShield && Medic.currentTarget && PlayerControl.LocalPlayer.CanMove; }, () => {}, Medic.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -202,7 +209,7 @@ namespace BonusRoles () => { return Shifter.currentTarget && PlayerControl.LocalPlayer.CanMove; }, () => { shifterShiftButton.Timer = shifterShiftButton.MaxTimer; }, Shifter.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -232,7 +239,7 @@ namespace BonusRoles () => { return Seer.currentTarget && PlayerControl.LocalPlayer.CanMove; }, () => {}, Seer.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance ); @@ -262,7 +269,7 @@ namespace BonusRoles Morphling.sampledTarget = null; }, Morphling.getSampleSprite(), - new Vector3(0f, 1.3f, 0f), + new Vector3(-1.3f, 1.3f, 0f), __instance, true, 10f, @@ -287,7 +294,7 @@ namespace BonusRoles camouflagerButton.killButtonManager.TimerText.Color = Palette.EnabledColor; }, Camouflager.getButtonSprite(), - new Vector3(0f, 1.3f, 0f), + new Vector3(-1.3f, 1.3f, 0f), __instance, true, 10f, @@ -307,7 +314,7 @@ namespace BonusRoles spyButton.killButtonManager.TimerText.Color = Palette.EnabledColor; }, Spy.getButtonSprite(), - Vector3.zero, + new Vector3(-1.3f, 0, 0), __instance, true, 0f, @@ -315,6 +322,87 @@ namespace BonusRoles spyButton.Timer = spyButton.MaxTimer; } ); + + // Tracker button + trackerButton = new CustomButton( + () => { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.TrackerUsedTracker, Hazel.SendOption.None, -1); + writer.Write(Tracker.currentTarget.PlayerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + RPCProcedure.trackerUsedTracker(Tracker.currentTarget.PlayerId); + }, + () => { return Tracker.tracker != null && Tracker.tracker == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; }, + () => { return PlayerControl.LocalPlayer.CanMove && Tracker.currentTarget != null && !Tracker.usedTracker; }, + () => { }, + Tracker.getButtonSprite(), + new Vector3(-1.3f, 0, 0), + __instance + ); + + vampireKillButton = new CustomButton( + () => { + if (Helpers.handleMurderAttempt(Vampire.currentTarget)) { + if (Vampire.targetNearGarlic) { + PlayerControl.LocalPlayer.RpcMurderPlayer(Vampire.currentTarget); + vampireKillButton.HasEffect = false; // Block effect on this click + vampireKillButton.Timer = vampireKillButton.MaxTimer; + } else { + Vampire.bitten = Vampire.currentTarget; + Reactor.Coroutines.Start(Vampire.killWithDelay()); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.VampireBiteNotification, Hazel.SendOption.None, -1); + writer.Write(Vampire.bitten.PlayerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + RPCProcedure.vampireBiteNotification(Vampire.bitten.PlayerId); + vampireKillButton.HasEffect = true; // Trigger effect on this click + } + } else { + vampireKillButton.HasEffect = false; // Block effect if no action was fired + } + }, + () => { return Vampire.vampire != null && Vampire.vampire == PlayerControl.LocalPlayer && !PlayerControl.LocalPlayer.Data.IsDead; }, + () => { + if (Vampire.targetNearGarlic) + vampireKillButton.killButtonManager.renderer.sprite = __instance.KillButton.renderer.sprite; + else + vampireKillButton.killButtonManager.renderer.sprite = Vampire.getButtonSprite(); + return Vampire.currentTarget != null && PlayerControl.LocalPlayer.CanMove; + }, + () => { + vampireKillButton.Timer = vampireKillButton.MaxTimer; + vampireKillButton.isEffectActive = false; + vampireKillButton.killButtonManager.TimerText.Color = Palette.EnabledColor; + }, + Vampire.getButtonSprite(), + new Vector3(-1.3f, 0, 0), + __instance, + false, + 0f, + () => { + vampireKillButton.Timer = vampireKillButton.MaxTimer; + } + ); + + garlicButton = new CustomButton( + () => { + Vampire.localPlacedGarlic = true; + var pos = PlayerControl.LocalPlayer.transform.position; + byte[] buff = new byte[sizeof(float) * 2]; + Buffer.BlockCopy(BitConverter.GetBytes(pos.x), 0, buff, 0*sizeof(float), sizeof(float)); + Buffer.BlockCopy(BitConverter.GetBytes(pos.y), 0, buff, 1*sizeof(float), sizeof(float)); + + MessageWriter writer = AmongUsClient.Instance.StartRpc(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.PlaceGarlic, Hazel.SendOption.None); + writer.WriteBytesAndSize(buff); + writer.EndMessage(); + RPCProcedure.placeGarlic(buff); + }, + () => { return !Vampire.localPlacedGarlic && !PlayerControl.LocalPlayer.Data.IsDead && Vampire.garlicsActive; }, + () => { return PlayerControl.LocalPlayer.CanMove && !Vampire.localPlacedGarlic; }, + () => { }, + Vampire.getGarlicButtonSprite(), + Vector3.zero, + __instance, + true + ); } } } \ No newline at end of file diff --git a/Source Code/CredentialsPatch.cs b/Source Code/CredentialsPatch.cs index e104d9e..9b4394f 100644 --- a/Source Code/CredentialsPatch.cs +++ b/Source Code/CredentialsPatch.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(VersionShower), nameof(VersionShower.Start))] public static class VersionShowerPatch @@ -13,9 +13,9 @@ namespace BonusRoles static void Postfix(VersionShower __instance) { string spacer = new String('\n', 15); if (__instance.text.Text.Contains(spacer)) - __instance.text.Text += "\n[FFFFFFFF]- Loaded [FCCE03FF]TheOtherRoles[FFFFFFFF] v1.5\n by [FCCE03FF]Eisbison"; + __instance.text.Text += "\n[FFFFFFFF]- Loaded [FCCE03FF]TheOtherRoles[FFFFFFFF] v1.7\n by [FCCE03FF]Eisbison"; else - __instance.text.Text += spacer + "[FFFFFFFF]- Loaded [FCCE03FF]TheOtherRoles[FFFFFFFF] v1.5\n by [FCCE03FF]Eisbison"; + __instance.text.Text += spacer + "[FFFFFFFF]- Loaded [FCCE03FF]TheOtherRoles[FFFFFFFF] v1.7\n by [FCCE03FF]Eisbison"; } } diff --git a/Source Code/CustomButton.cs b/Source Code/CustomButton.cs index 0f3aae1..7f1b7c0 100644 --- a/Source Code/CustomButton.cs +++ b/Source Code/CustomButton.cs @@ -23,8 +23,9 @@ public class CustomButton public float EffectDuration; public Sprite Sprite; private HudManager hudManager; + private bool mirror; - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, bool HasEffect, float EffectDuration, Action OnEffectEnds) + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, bool HasEffect, float EffectDuration, Action OnEffectEnds, bool mirror = false) { this.hudManager = hudManager; this.OnClick = OnClick; @@ -36,6 +37,7 @@ public class CustomButton this.EffectDuration = EffectDuration; this.OnEffectEnds = OnEffectEnds; this.Sprite = Sprite; + this.mirror = mirror; Timer = 16.2f; buttons.Add(this); killButtonManager = UnityEngine.Object.Instantiate(hudManager.KillButton, hudManager.transform); @@ -60,8 +62,8 @@ public class CustomButton setActive(false); } - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager) - : this(OnClick, HasButton, CouldUse, OnMeetingEnds, Sprite, PositionOffset, hudManager, false, 0f, () => {}) { } + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, bool mirror = false) + : this(OnClick, HasButton, CouldUse, OnMeetingEnds, Sprite, PositionOffset, hudManager, false, 0f, () => {}, mirror) { } public static void HudUpdate() { @@ -132,15 +134,12 @@ public class CustomButton setActive(hudManager.UseButton.isActiveAndEnabled); killButtonManager.renderer.sprite = Sprite; - - if (killButtonManager.transform.position == hudManager.KillButton.transform.position) - { - Vector3 vector = killButtonManager.transform.localPosition; - vector += new Vector3(PositionOffset.x, PositionOffset.y); - killButtonManager.transform.localPosition = vector; + 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) } - - if (CouldUse()) { killButtonManager.renderer.color = Palette.EnabledColor; killButtonManager.renderer.material.SetFloat("_Desat", 0f); diff --git a/Source Code/EndGamePatch.cs b/Source Code/EndGamePatch.cs index 0ad3017..1118476 100644 --- a/Source Code/EndGamePatch.cs +++ b/Source Code/EndGamePatch.cs @@ -1,7 +1,7 @@ using HarmonyLib; -using static BonusRoles.BonusRoles; -using static BonusRoles.GameHistory; +using static TheOtherRoles.TheOtherRoles; +using static TheOtherRoles.GameHistory; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -11,13 +11,14 @@ using UnhollowerBaseLib; using System; using System.Text; -namespace BonusRoles { +namespace TheOtherRoles { enum WinCondition { Default, LoversTeamWin, LoversSoloWin, JesterWin, - ChildDied + BountyHunterWin, + JesterAndBountyHunterWin } static class AdditionalTempData { @@ -55,24 +56,26 @@ namespace BonusRoles { if (jesterWinner != null) TempData.winners.Remove(jesterWinner); } - - // Child win condition (should be implemented using a proper GameOverReason in the future) - if (Child.child != null && Child.child.Data.IsImpostor) { - AdditionalTempData.winCondition = WinCondition.ChildDied; + // Jester and Bounty Hunter win condition (should be implemented using a proper GameOverReason in the future) + bool jesterWin = Jester.jester != null && Jester.jester.Data.IsImpostor; + bool bountyHunterWin = BountyHunter.bountyHunter != null && BountyHunter.bountyHunter.Data.IsImpostor; + if (jesterWin || bountyHunterWin) { TempData.winners = new Il2CppSystem.Collections.Generic.List(); - WinningPlayerData wpd = new WinningPlayerData(Child.child.Data); - wpd.IsImpostor = false; - wpd.IsYou = false; - TempData.winners.Add(wpd); - } - - // Jester win condition (should be implemented using a proper GameOverReason in the future) - else if (Jester.jester != null && Jester.jester.Data.IsImpostor) { - AdditionalTempData.winCondition = WinCondition.JesterWin; - TempData.winners = new Il2CppSystem.Collections.Generic.List(); - WinningPlayerData wpd = new WinningPlayerData(Jester.jester.Data); - wpd.IsImpostor = false; - TempData.winners.Add(wpd); + if (jesterWin) { + WinningPlayerData wpd = new WinningPlayerData(Jester.jester.Data); + wpd.IsImpostor = false; + TempData.winners.Add(wpd); + AdditionalTempData.winCondition = WinCondition.JesterWin; + } + if (bountyHunterWin) { + WinningPlayerData wpd = new WinningPlayerData(BountyHunter.bountyHunter.Data); + wpd.IsImpostor = false; + TempData.winners.Add(wpd); + if (AdditionalTempData.winCondition == WinCondition.JesterWin) + AdditionalTempData.winCondition = WinCondition.JesterAndBountyHunterWin; + else + AdditionalTempData.winCondition = WinCondition.BountyHunterWin; + } } // Lovers win conditions (should be implemented using a proper GameOverReason in the future) @@ -106,14 +109,18 @@ namespace BonusRoles { TextRenderer textRenderer = bonusText.GetComponent(); textRenderer.Text = ""; - if (AdditionalTempData.winCondition == WinCondition.ChildDied) { - textRenderer.Text = "Child Died"; - textRenderer.Color = Child.color; - } - else if (AdditionalTempData.winCondition == WinCondition.JesterWin) { + if (AdditionalTempData.winCondition == WinCondition.JesterWin) { textRenderer.Text = "Jester Wins"; textRenderer.Color = Jester.color; } + else if (AdditionalTempData.winCondition == WinCondition.BountyHunterWin) { + textRenderer.Text = "Bounty Hunter Wins"; + textRenderer.Color = BountyHunter.color; + } + else if (AdditionalTempData.winCondition == WinCondition.JesterAndBountyHunterWin) { + textRenderer.Text = "[AD653BFF]Bounty Hunter[FFFFFFFF] and [FF54A7FF]Jester[FFFFFFFF] Win"; + textRenderer.Color = Color.white; + } else if (AdditionalTempData.winCondition == WinCondition.LoversTeamWin) { if (AdditionalTempData.localIsLover) { __instance.WinText.Text = "Double Victory"; diff --git a/Source Code/Footprint.cs b/Source Code/Footprint.cs index 7cc24c8..ac41abc 100644 --- a/Source Code/Footprint.cs +++ b/Source Code/Footprint.cs @@ -2,9 +2,9 @@ using System; using System.Collections.Generic; using System.Collections; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; -namespace BonusRoles{ +namespace TheOtherRoles{ class Footprint { private static List footprints = new List(); private static Sprite sprite; @@ -14,7 +14,7 @@ namespace BonusRoles{ public static Sprite getFootprintSprite() { if (sprite) return sprite; - sprite = Helpers.loadSpriteFromResources("BonusRoles.Resources.Footprint.png", 600f); + sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Footprint.png", 600f); return sprite; } @@ -45,9 +45,7 @@ namespace BonusRoles{ IEnumerator CoFadeOutAndDestroy(float duration) { - for (float t = 0f; t < duration; t += Time.deltaTime) - { - // Check not null since if game ends, this access throws an error + for (float t = 0f; t < duration; t += Time.deltaTime) { if (spriteRenderer) spriteRenderer.color = new Color(color.r, color.g, color.b, Mathf.Clamp(1f - t/duration, 0f, 1f)); yield return null; diff --git a/Source Code/GameHistory.cs b/Source Code/GameHistory.cs index 933e195..f4b6633 100644 --- a/Source Code/GameHistory.cs +++ b/Source Code/GameHistory.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.Collections; using System; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; -namespace BonusRoles{ +namespace TheOtherRoles{ public class DeadPlayer { public PlayerControl player; diff --git a/Source Code/GameOptionsPatch.cs b/Source Code/GameOptionsPatch.cs index 5e592b4..046762b 100644 --- a/Source Code/GameOptionsPatch.cs +++ b/Source Code/GameOptionsPatch.cs @@ -3,13 +3,15 @@ using System; using System.IO; using System.Net.Http; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; using Reactor.Extensions; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Text; +using Essentials.Options; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPriority(Priority.Low)] [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Update))] @@ -20,4 +22,57 @@ namespace BonusRoles __instance.GetComponentInParent().YBounds.max = -0.5F + __instance.Children.Length * 0.5F; } } + + [HarmonyPatch(typeof(KeyboardJoystick), nameof(KeyboardJoystick.Update))] + public static class GameOptionsNextPagePatch + { + private static readonly System.Random random = new System.Random((int)DateTime.Now.Ticks); + private static List bots = new List(); + + public static void Postfix(KeyboardJoystick __instance) + { + if(Input.GetKeyDown(KeyCode.Tab)) { + TheOtherRolesPlugin.optionsPage = (TheOtherRolesPlugin.optionsPage + 1) % 3; + } + } + } + + [HarmonyPatch(typeof(GameOptionsData), "NHJLMAAHKJF")] + class GameOptionsDataPatch + { + + private static void Postfix(ref string __result) + { + StringBuilder stringBuilder = new StringBuilder(__result); + foreach (CustomOption customOption in TheOtherRolesPlugin.options) { + stringBuilder.AppendLine(string.Format("{0}[]: {1}", customOption.Name, customOption)); + } + var hudString = stringBuilder.ToString(); + + int defaultSettingsLines = 19; + int roleSettingsLines = 19 + 22; + 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 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 = 2; + int index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count(); + hudString = hudString.Insert(index, "\n"); + gap = 7; + index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count(); + hudString = hudString.Insert(index + 1, "\n"); + gap = 11; + index = hudString.TakeWhile(c => (gap -= (c == '\n' ? 1 : 0)) > 0).Count(); + hudString = hudString.Insert(index + 1, "\n"); + } else if (counter == 2) { + hudString = hudString.Substring(end2 + 1); + } + hudString += "\n Press tab for more..."; + __result = hudString; + } + } } \ No newline at end of file diff --git a/Source Code/Garlic.cs b/Source Code/Garlic.cs new file mode 100644 index 0000000..d2f6f6a --- /dev/null +++ b/Source Code/Garlic.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using UnityEngine; +using static TheOtherRoles.TheOtherRoles; + +namespace TheOtherRoles{ + class Garlic { + public static List garlics = new List(); + + public GameObject garlic; + private GameObject background; + + private static Sprite garlicSprite; + public static Sprite getGarlicSprite() { + if (garlicSprite) return garlicSprite; + garlicSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Garlic.png", 300f); + return garlicSprite; + } + + private static Sprite backgroundSprite; + public static Sprite getBackgroundSprite() { + if (backgroundSprite) return backgroundSprite; + backgroundSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.GarlicBackground.png", 60f); + return backgroundSprite; + } + + public Garlic(Vector2 p) { + garlic = new GameObject("Garlic"); + background = new GameObject("Background"); + background.transform.SetParent(garlic.transform); + Vector3 position = new Vector3(p.x, p.y, PlayerControl.LocalPlayer.transform.position.z + 1f); + garlic.transform.position = position; + garlic.transform.localPosition = position; + background.transform.localPosition = new Vector3(0 , 0, 0.01f); + + var garlicRenderer = garlic.AddComponent(); + garlicRenderer.sprite = getGarlicSprite(); + var backgroundRenderer = background.AddComponent(); + backgroundRenderer.sprite = getBackgroundSprite(); + + + garlic.SetActive(true); + garlics.Add(this); + } + + public static void clearGarlics() { + garlics = new List(); + } + + public static void UpdateAll() { + foreach (Garlic garlic in garlics) { + if (garlic != null) + garlic.Update(); + } + } + + public void Update() { + if (background != null) + background.transform.Rotate(Vector3.forward * 6 * Time.deltaTime); + } + } +} \ No newline at end of file diff --git a/Source Code/Helpers.cs b/Source Code/Helpers.cs index 3b35483..590473d 100644 --- a/Source Code/Helpers.cs +++ b/Source Code/Helpers.cs @@ -7,9 +7,11 @@ using System.Collections; using Reactor.Unstrip; using UnhollowerBaseLib; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; +using HarmonyLib; +using Hazel; -namespace BonusRoles { +namespace TheOtherRoles { public static class Helpers { public static Sprite LoadSpriteFromEmbeddedResources(string resource, float PixelPerUnit) { @@ -107,6 +109,25 @@ namespace BonusRoles { if (renderer != null) renderer.enabled = false; } + + public static bool handleMurderAttempt(PlayerControl target, bool notifyOthers = true) { + // Block impostor shielded kill + if (Medic.shielded != null && Medic.shielded == target) { + if (notifyOthers) { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.None, -1); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + RPCProcedure.shieldedMurderAttempt(); + + return false; + } + // Block impostor not fully grown child kill + else if (Child.child != null && target == Child.child && !Child.isGrownUp()) { + return false; + } + return true; + } + public static IEnumerator Slide2D(Transform target, Vector2 source, Vector2 dest, float duration = 0.75f) { Vector3 temp = default(Vector3); @@ -186,6 +207,11 @@ namespace BonusRoles { c = Camouflager.color; g = false; } + else if (Vampire.vampire != null && p == Vampire.vampire) { + r = "Vampire"; + c = Vampire.color; + g = false; + } else if (Detective.detective != null && p == Detective.detective) { r = "Detective"; c = Detective.color; @@ -229,6 +255,19 @@ namespace BonusRoles { r = "Child"; c = Child.color; } + else if (BountyHunter.bountyHunter != null && p == BountyHunter.bountyHunter) { + r = "Bounty Hunter"; + c = BountyHunter.color; + g = false; + } + else if (Tracker.tracker != null && p == Tracker.tracker) { + r = "Tracker"; + c = Tracker.color; + } + else if (Snitch.snitch != null && p == Snitch.snitch) { + r = "Snitch"; + c = Snitch.color; + } else if (p.Data.IsImpostor) { // Just Impostor r = "Impostor"; c = Palette.ImpostorRed; diff --git a/Source Code/IntroPatch.cs b/Source Code/IntroPatch.cs index 451b71a..42495f3 100644 --- a/Source Code/IntroPatch.cs +++ b/Source Code/IntroPatch.cs @@ -1,10 +1,10 @@ using HarmonyLib; using System; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; using UnityEngine; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(IntroCutscene.CoBegin__d), nameof(IntroCutscene.CoBegin__d.MoveNext))] class IntroPatch @@ -88,6 +88,14 @@ namespace BonusRoles __instance.__this.ImpostorText.Text = "Camouflage and kill the crewmates"; __instance.__this.BackgroundBar.material.color = Camouflager.color; } + else if (PlayerControl.LocalPlayer == Vampire.vampire) + { + __instance.__this.ImpostorText.gameObject.SetActive(true); + __instance.__this.Title.Text = "Vampire"; + __instance.__this.Title.Color = Vampire.color; + __instance.__this.ImpostorText.Text = "Kill the crewmates with your bites"; + __instance.__this.BackgroundBar.material.color = Vampire.color; + } else if (PlayerControl.LocalPlayer == Sheriff.sheriff) { __instance.__this.Title.Text = "Sheriff"; @@ -167,6 +175,27 @@ namespace BonusRoles __instance.__this.ImpostorText.Text = "No one will harm you until you grow up"; __instance.__this.BackgroundBar.material.color = Child.color; } + else if (PlayerControl.LocalPlayer == BountyHunter.bountyHunter) + { + __instance.__this.Title.Text = "Bounty Hunter"; + __instance.__this.Title.Color = BountyHunter.color; + __instance.__this.ImpostorText.Text = "Hunt [ED653BFF]" + BountyHunter.target?.Data?.PlayerName + "[FFFFFFFF] down"; + __instance.__this.BackgroundBar.material.color = BountyHunter.color; + } + else if (PlayerControl.LocalPlayer == Tracker.tracker) + { + __instance.__this.Title.Text = "Tracker"; + __instance.__this.Title.Color = Tracker.color; + __instance.__this.ImpostorText.Text = "Track the [FF1919FF]Impostors[FFFFFFFF] down"; + __instance.__this.BackgroundBar.material.color = Tracker.color; + } + else if (PlayerControl.LocalPlayer == Snitch.snitch) + { + __instance.__this.Title.Text = "Snitch"; + __instance.__this.Title.Color = Snitch.color; + __instance.__this.ImpostorText.Text = "Finish your tasks to find the [FF1919FF]Impostors[FFFFFFFF]"; + __instance.__this.BackgroundBar.material.color = Snitch.color; + } } } } diff --git a/Source Code/Main.cs b/Source Code/Main.cs index 158d00a..f1b189c 100644 --- a/Source Code/Main.cs +++ b/Source Code/Main.cs @@ -6,81 +6,172 @@ using Hazel; using Reactor; using System.Collections.Generic; using Essentials.Options; -using UnityEngine; using System.Linq; using System.Net; using System.IO; using System; using System.Reflection; using UnhollowerBaseLib; +using UnityEngine; +using static TheOtherRoles.TheOtherRoles; -namespace BonusRoles +namespace TheOtherRoles { [BepInPlugin(Id)] [BepInProcess("Among Us.exe")] [BepInDependency(ReactorPlugin.Id)] - public class BonusRolesPlugin : BasePlugin + public class TheOtherRolesPlugin : BasePlugin { - public const string Id = "me.eisbison.bonusroles"; + public const string Id = "me.eisbison.theotherroles"; public Harmony Harmony { get; } = new Harmony(Id); - // Role spawn chances - public static CustomNumberOption mafiaSpawnChance = CustomOption.AddNumber("Mafia Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption loversSpawnChance = CustomOption.AddNumber("Lovers Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption morphlingSpawnChance = CustomOption.AddNumber("Morphling Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption camouflagerSpawnChance = CustomOption.AddNumber("Camouflager Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption jesterSpawnChance = CustomOption.AddNumber("Jester Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption mayorSpawnChance = CustomOption.AddNumber("Mayor Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption engineerSpawnChance = CustomOption.AddNumber("Engineer Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption sheriffSpawnChance = CustomOption.AddNumber("Sheriff Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption lighterSpawnChance = CustomOption.AddNumber("Lighter Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption detectiveSpawnChance = CustomOption.AddNumber("Detective Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption timeMasterSpawnChance = CustomOption.AddNumber("Time Master Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption medicSpawnChance = CustomOption.AddNumber("Medic Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption shifterSpawnChance = CustomOption.AddNumber("Shifter Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption swapperSpawnChance = CustomOption.AddNumber("Swapper Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption seerSpawnChance = CustomOption.AddNumber("Seer Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption spySpawnChance = CustomOption.AddNumber("Spy Spawn Chance", 100, 0, 100, 10); - public static CustomNumberOption childSpawnChance = CustomOption.AddNumber("Child Spawn Chance", 100, 0, 100, 10); + // Roles + public static int num = 0; + public static string[] rates = new string[]{"0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"}; + + public static CustomNumberOption crewmateRolesCount = CustomOption.AddNumber(num++.ToString(), "[CCCC00FF]Number Of Crewmate/Neutral Roles", 10, 0, 10, 0.5f); + public static CustomNumberOption impostorRolesCount = CustomOption.AddNumber(num++.ToString(), "[CCCC00FF]Number Of Impostor Roles", 3, 0, 3, 0.5f); + + public static CustomStringOption mafiaSpawnRate = CustomOption.AddString(num++.ToString(), cs(Janitor.color) + "Mafia", rates); + public static CustomStringOption morphlingSpawnRate = CustomOption.AddString(num++.ToString(), cs(Morphling.color) + "Morphling", rates); + public static CustomStringOption camouflagerSpawnRate = CustomOption.AddString(num++.ToString(), cs(Camouflager.color) + "Camouflager", rates); + public static CustomStringOption vampireSpawnRate = CustomOption.AddString(num++.ToString(), cs(Vampire.color) + "Vampire", rates); + + public static CustomStringOption loversSpawnRate = CustomOption.AddString(num++.ToString(), cs(Lovers.color) + "Lovers", rates); + public static CustomStringOption jesterSpawnRate = CustomOption.AddString(num++.ToString(), cs(Jester.color) + "Jester", rates); + public static CustomStringOption shifterSpawnRate = CustomOption.AddString(num++.ToString(), cs(Shifter.color) + "Shifter", rates); + + public static CustomStringOption mayorSpawnRate = CustomOption.AddString(num++.ToString(), cs(Mayor.color) + "Mayor", rates); + public static CustomStringOption engineerSpawnRate = CustomOption.AddString(num++.ToString(), cs(Engineer.color) + "Engineer", rates); + public static CustomStringOption sheriffSpawnRate = CustomOption.AddString(num++.ToString(), cs(Sheriff.color) + "Sheriff", rates); + public static CustomStringOption lighterSpawnRate = CustomOption.AddString(num++.ToString(), cs(Lighter.color) + "Lighter", rates); + public static CustomStringOption detectiveSpawnRate = CustomOption.AddString(num++.ToString(), cs(Detective.color) + "Detective", rates); + public static CustomStringOption timeMasterSpawnRate = CustomOption.AddString(num++.ToString(), cs(TimeMaster.color) + "Time Master", rates); + public static CustomStringOption medicSpawnRate = CustomOption.AddString(num++.ToString(), cs(Medic.color) + "Medic", rates); + public static CustomStringOption swapperSpawnRate = CustomOption.AddString(num++.ToString(), cs(Swapper.color) + "Swapper", rates); + public static CustomStringOption seerSpawnRate = CustomOption.AddString(num++.ToString(), cs(Seer.color) + "Seer", rates); + public static CustomStringOption spySpawnRate = CustomOption.AddString(num++.ToString(), cs(Spy.color) + "Spy", rates); + public static CustomStringOption childSpawnRate = CustomOption.AddString(num++.ToString(), cs(Child.color) + "Child", rates); + // public static CustomStringOption bountyHunterSpawnRate = CustomOption.AddString(num++.ToString(), cs(BountyHunter.color) + "Bounty Hunter", rates); + public static CustomStringOption trackerSpawnRate = CustomOption.AddString(num++.ToString(), cs(Tracker.color) + "Tracker", rates); + public static CustomStringOption snitchSpawnRate = CustomOption.AddString(num++.ToString(), cs(Snitch.color) + "Snitch", rates); // Role settings - public static CustomNumberOption janitorCooldown = CustomOption.AddNumber("Janitor Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomNumberOption morphlingCooldown = CustomOption.AddNumber("Morphling Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomNumberOption camouflagerCooldown = CustomOption.AddNumber("Camouflager Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomToggleOption loversBothDie = CustomOption.AddToggle("Both Lovers Die", true); - public static CustomNumberOption sheriffCooldown = CustomOption.AddNumber("Sheriff Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomToggleOption jesterCanDieToSheriff = CustomOption.AddToggle("Jester Can Die To Sheriff", false); - public static CustomNumberOption lighterVision = CustomOption.AddNumber("Lighter Vision", 2f, 0.25f, 5f, 0.25f); - public static CustomToggleOption detectiveAnonymousFootprints = CustomOption.AddToggle("Anonymous Footprints", false); - public static CustomNumberOption detectiveFootprintIntervall = CustomOption.AddNumber("Footprint Intervall", 0.5f, 0.25f, 10f, 0.25f); - public static CustomNumberOption detectiveFootprintDuration = CustomOption.AddNumber("Footprint Duration", 5f, 0.25f, 10f, 0.25f); - public static CustomNumberOption timeMasterCooldown = CustomOption.AddNumber("Time Master Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomNumberOption timeMasterRewindTime = CustomOption.AddNumber("Rewind Time", 3f, 1f, 10f, 1f); - public static CustomToggleOption timeMasterReviveDuringRewind = CustomOption.AddToggle("Revive During Rewind", false); - public static CustomNumberOption medicReportNameDuration = CustomOption.AddNumber("Time Where Medic Reports Will Have Name", 10, 0, 60, 2.5f); - public static CustomNumberOption medicReportColorDuration = CustomOption.AddNumber("Time Where Medic Reports Will Have Color Type", 20, 0, 120, 2.5f); - public static CustomStringOption medicShowShielded = CustomOption.AddString("Show Shielded Player", new string[] {"Everyone", "Shielded + Medic", "Medic"}); - public static CustomToggleOption medicShowAttemptToShielded = CustomOption.AddToggle("Shielded Player Sees Murder Attempt", false); - public static CustomNumberOption shifterCooldown = CustomOption.AddNumber("Shifter Cooldown", 30f, 10f, 60f, 2.5f); - public static CustomNumberOption seerCooldown = CustomOption.AddNumber("Seer Cooldown (No Reset After Meeting)", 15f, 30f, 180f, 15f); - public static CustomNumberOption seerChanceOfSeeingRight = CustomOption.AddNumber("Seer Chance Of Seeing Right", 100, 0, 100, 5); - public static CustomStringOption seerKindOfInfo = CustomOption.AddString("Info That Seer Reveals", new string[] {"Role", "Good/Bad"}); - public static CustomStringOption seerPlayersWithNotification = CustomOption.AddString("Players That See When They Are Being Revealed", new string[] {"Everyone", "The Good", "The Bad", "Nobody"}); - public static CustomNumberOption spyCooldown = CustomOption.AddNumber("Spy Cooldown", 30f, 10f, 120f, 5f); - public static CustomNumberOption spySpyingDuration = CustomOption.AddNumber("Spy Duration", 10f, 2.5f, 60f, 2.5f); - public static CustomNumberOption childGrowingUpDuration = CustomOption.AddNumber("Child Growing Up Duration", 400f, 100f, 1500f, 100f); + public static CustomNumberOption janitorCooldown = CustomOption.AddNumber(num++.ToString(), "Janitor Cooldown", 30f, 10f, 60f, 2.5f); + public static CustomNumberOption morphlingCooldown = CustomOption.AddNumber(num++.ToString(), "Morphling Cooldown", 30f, 10f, 60f, 2.5f); + public static CustomNumberOption camouflagerCooldown = CustomOption.AddNumber(num++.ToString(), "Camouflager Cooldown", 30f, 10f, 60f, 2.5f); + public static CustomNumberOption vampireKillDelay = CustomOption.AddNumber(num++.ToString(), "Vampire Kill Delay", 10f, 2.5f, 30f, 2.5f); + + public static CustomToggleOption loversBothDie = CustomOption.AddToggle(num++.ToString(), "Both Lovers Die", true); + public static CustomNumberOption shifterCooldown = CustomOption.AddNumber(num++.ToString(), "Shifter Cooldown", 30f, 10f, 60f, 2.5f); + + public static CustomNumberOption sheriffCooldown = CustomOption.AddNumber(num++.ToString(), "Sheriff Cooldown", 30f, 10f, 60f, 2.5f); + public static CustomToggleOption jesterCanDieToSheriff = CustomOption.AddToggle(num++.ToString(), "Jester Can Die To Sheriff", false); + public static CustomNumberOption lighterVision = CustomOption.AddNumber(num++.ToString(), "Lighter Vision", 2f, 0.25f, 5f, 0.25f); + public static CustomToggleOption detectiveAnonymousFootprints = CustomOption.AddToggle(num++.ToString(), "Anonymous Footprints", false); + public static CustomNumberOption detectiveFootprintIntervall = CustomOption.AddNumber(num++.ToString(), "Footprint Intervall", 0.5f, 0.25f, 10f, 0.25f); + public static CustomNumberOption detectiveFootprintDuration = CustomOption.AddNumber(num++.ToString(), "Footprint Duration", 5f, 0.25f, 10f, 0.25f); + public static CustomNumberOption timeMasterCooldown = CustomOption.AddNumber(num++.ToString(), "Time Master Cooldown", 30f, 10f, 60f, 2.5f); + public static CustomNumberOption timeMasterRewindTime = CustomOption.AddNumber(num++.ToString(), "Rewind Time", 3f, 1f, 10f, 1f); + public static CustomToggleOption timeMasterReviveDuringRewind = CustomOption.AddToggle(num++.ToString(), "Revive During Rewind", false); + public static CustomNumberOption medicReportNameDuration = CustomOption.AddNumber(num++.ToString(), "Time Where Medic Reports Will Have Name", 10, 0, 60, 2.5f); + public static CustomNumberOption medicReportColorDuration = CustomOption.AddNumber(num++.ToString(), "Time Where Medic Reports Will Have Color Type", 20, 0, 120, 2.5f); + public static CustomStringOption medicShowShielded = CustomOption.AddString(num++.ToString(), "Show Shielded Player", new string[] {"Everyone", "Shielded + Medic", "Medic"}); + public static CustomToggleOption medicShowAttemptToShielded = CustomOption.AddToggle(num++.ToString(), "Shielded Player Sees Murder Attempt", false); + public static CustomNumberOption seerCooldown = CustomOption.AddNumber(num++.ToString(), "Seer Cooldown (No Reset After Meeting)", 15f, 30f, 180f, 15f); + public static CustomNumberOption seerChanceOfSeeingRight = CustomOption.AddNumber(num++.ToString(), "Seer Chance Of Seeing Right", 100, 0, 100, 5); + public static CustomStringOption seerKindOfInfo = CustomOption.AddString(num++.ToString(), "Info That Seer Reveals", new string[] {"Role", "Good/Bad"}); + public static CustomStringOption seerPlayersWithNotification = CustomOption.AddString(num++.ToString(), "Players That See When They Are Being Revealed", new string[] {"Everyone", "The Good", "The Bad", "Nobody"}); + public static CustomNumberOption spyCooldown = CustomOption.AddNumber(num++.ToString(), "Spy Cooldown", 30f, 10f, 120f, 5f); + public static CustomNumberOption spySpyingDuration = CustomOption.AddNumber(num++.ToString(), "Spy Duration", 10f, 2.5f, 60f, 2.5f); + public static CustomNumberOption childGrowingUpDuration = CustomOption.AddNumber(num++.ToString(), "Child Growing Up Duration", 400f, 100f, 1500f, 100f); + // public static CustomToggleOption bountyHunterNotifyBounty = CustomOption.AddToggle(num++.ToString(), "Bounty Gets Notified", true); + public static CustomNumberOption trackerUpdateIntervall = CustomOption.AddNumber(num++.ToString(), "Tracker Update Intervall", 5f, 2.5f, 30f, 2.5f); + public static CustomNumberOption snitchLeftTasksForImpostors = CustomOption.AddNumber(num++.ToString(), "Task Count Where Impostors See Snitch", 1f, 0f, 5f, 1f); + + public static List options = new List(); + public static int optionsPage = 1; public static ConfigEntry DebugMode { get; private set; } - - - public override void Load() - { + public override void Load() { DebugMode = Config.Bind("Custom", "Enable Debug Mode", false); CustomOption.ShamelessPlug = false; Harmony.PatchAll(); } + + public static string cs(Color c) { + return string.Format("[{0:X2}{1:X2}{2:X2}{3:X2}]", ToByte(c.r), ToByte(c.g), ToByte(c.b), ToByte(c.a)); + } + + private static byte ToByte(float f) { + f = Mathf.Clamp01(f); + return (byte)(f * 255); + } + + public TheOtherRolesPlugin() { + options = new List() { + crewmateRolesCount, + impostorRolesCount, + + mafiaSpawnRate, + morphlingSpawnRate, + camouflagerSpawnRate, + vampireSpawnRate, + + loversSpawnRate, + jesterSpawnRate, + shifterSpawnRate, + + mayorSpawnRate, + engineerSpawnRate, + sheriffSpawnRate, + lighterSpawnRate, + detectiveSpawnRate, + timeMasterSpawnRate, + medicSpawnRate, + swapperSpawnRate, + seerSpawnRate, + spySpawnRate, + childSpawnRate, + // bountyHunterSpawnRate, + trackerSpawnRate, + snitchSpawnRate, + + janitorCooldown, + morphlingCooldown, + camouflagerCooldown, + vampireKillDelay, + + loversBothDie, + shifterCooldown, + + sheriffCooldown, + jesterCanDieToSheriff, + lighterVision, + detectiveAnonymousFootprints, + detectiveFootprintIntervall, + detectiveFootprintDuration, + timeMasterCooldown, + timeMasterRewindTime, + timeMasterReviveDuringRewind, + medicReportNameDuration, + medicReportColorDuration, + medicShowShielded, + medicShowAttemptToShielded, + seerCooldown, + seerChanceOfSeeingRight, + seerKindOfInfo, + seerPlayersWithNotification, + spyCooldown, + spySpyingDuration, + childGrowingUpDuration, + // bountyHunterNotifyBounty, + trackerUpdateIntervall, + snitchLeftTasksForImpostors + }; + } } // Deactivate bans, since I always leave my local testing game and ban myself @@ -102,7 +193,7 @@ namespace BonusRoles public static void Postfix(KeyboardJoystick __instance) { - if (!BonusRolesPlugin.DebugMode.Value) return; + if (!TheOtherRolesPlugin.DebugMode.Value) return; // Spawn dummys if (Input.GetKeyDown(KeyCode.F)) { diff --git a/Source Code/MeetingPatch.cs b/Source Code/MeetingPatch.cs index aa6f565..152c01c 100644 --- a/Source Code/MeetingPatch.cs +++ b/Source Code/MeetingPatch.cs @@ -3,13 +3,13 @@ using Hazel; using System.Collections.Generic; using System.Linq; using UnhollowerBaseLib; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; using System.Collections; using System; using System.Text; using UnityEngine; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(MeetingHud), "CalculateVotes")] class MeetingCalculateVotesPatch { @@ -258,6 +258,17 @@ namespace BonusRoles } } + [HarmonyPatch(typeof(ExileController), "Begin")] + class ExileBeginPatch { + public static void Prefix(ref GameData.PlayerInfo IHDMFDEEDEL, bool DCHFIBODGIL) { + // Prevent growing Child exile + if (Child.child != null && IHDMFDEEDEL != null && IHDMFDEEDEL.PlayerId == Child.child.PlayerId && !Child.isGrownUp()) { + IHDMFDEEDEL = null; + } + } + } + + [HarmonyPatch(typeof(UnityEngine.Object), nameof(UnityEngine.Object.Destroy), new Type[] { typeof(UnityEngine.Object) })] class MeetingExiledEndPatch { @@ -268,20 +279,15 @@ namespace BonusRoles // Reset custom button timers where necessary CustomButton.MeetingEndedUpdate(); - // Jester win condition - if (Jester.jester != null && ExileController.Instance.exiled != null && ExileController.Instance.exiled.PlayerId == Jester.jester.PlayerId) - { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.JesterWin, Hazel.SendOption.None, -1); - AmongUsClient.Instance.FinishRpcImmediately(writer); - - RPCProcedure.jesterWin(); - } - - // Child win condition - if (Child.child != null && ExileController.Instance.exiled != null && ExileController.Instance.exiled.PlayerId == Child.child.PlayerId && !Child.isGrownUp()) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ChildDied, Hazel.SendOption.None, -1); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.childDied(); + // Jester and Bounty Hunter win condition + if (ExileController.Instance.exiled != null) { + byte exiledId = ExileController.Instance.exiled.PlayerId; + if ((Jester.jester != null && Jester.jester.PlayerId == exiledId) || (BountyHunter.bountyHunter != null && !BountyHunter.bountyHunter.Data.IsDead && BountyHunter.target != null && BountyHunter.target.PlayerId == exiledId)) { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.JesterBountyHunterWin, Hazel.SendOption.None, -1); + writer.Write(exiledId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + RPCProcedure.jesterBountyHunterWin(exiledId); + } } } } @@ -327,6 +333,12 @@ namespace BonusRoles __result = ExileController.Instance.exiled.PlayerName + " was The Spy."; else if(Child.child != null && ExileController.Instance.exiled.Object.PlayerId == Child.child.PlayerId) __result = ExileController.Instance.exiled.PlayerName + " was The Child."; + else if(BountyHunter.bountyHunter != null && ExileController.Instance.exiled.Object.PlayerId == BountyHunter.bountyHunter.PlayerId) + __result = ExileController.Instance.exiled.PlayerName + " was The Bounty Hunter."; + else if(Tracker.tracker != null && ExileController.Instance.exiled.Object.PlayerId == Tracker.tracker.PlayerId) + __result = ExileController.Instance.exiled.PlayerName + " was The Tracker."; + else if(Snitch.snitch != null && ExileController.Instance.exiled.Object.PlayerId == Snitch.snitch.PlayerId) + __result = ExileController.Instance.exiled.PlayerName + " was The Snitch."; else __result = ExileController.Instance.exiled.PlayerName + " was not The Impostor."; } @@ -346,6 +358,8 @@ namespace BonusRoles __result = ExileController.Instance.exiled.PlayerName + " was The ImpLover."; else if(Lovers.lover2 != null && ExileController.Instance.exiled.Object.PlayerId == Lovers.lover2.PlayerId) __result = ExileController.Instance.exiled.PlayerName + " was The ImpLover."; + else if(Vampire.vampire != null && ExileController.Instance.exiled.Object.PlayerId == Vampire.vampire.PlayerId) + __result = ExileController.Instance.exiled.PlayerName + " was The Vamipre."; } // Hide number of remaining impostors on Jester win diff --git a/Source Code/PlayerControlPatch.cs b/Source Code/PlayerControlPatch.cs index 010d591..ba58753 100644 --- a/Source Code/PlayerControlPatch.cs +++ b/Source Code/PlayerControlPatch.cs @@ -5,11 +5,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using static BonusRoles.BonusRoles; -using static BonusRoles.GameHistory; +using static TheOtherRoles.TheOtherRoles; +using static TheOtherRoles.GameHistory; using UnityEngine; -namespace BonusRoles { +namespace TheOtherRoles { [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))] public static class PlayerControlFixedUpdatePatch { @@ -44,7 +44,7 @@ namespace BonusRoles { } } - static PlayerControl setAnyRoleTarget() { + static PlayerControl setTarget(bool onlyCrewmates = false, bool targetPlayersInVents = false) { PlayerControl result = null; float num = GameOptionsData.KillDistances[Mathf.Clamp(PlayerControl.GameOptions.KillDistance, 0, 2)]; if (!ShipStatus.Instance) return result; @@ -54,10 +54,10 @@ namespace BonusRoles { for (int i = 0; i < allPlayers.Count; i++) { GameData.PlayerInfo playerInfo = allPlayers[i]; - if (!playerInfo.Disconnected && playerInfo.PlayerId != PlayerControl.LocalPlayer.PlayerId && !playerInfo.IsDead) + if (!playerInfo.Disconnected && playerInfo.PlayerId != PlayerControl.LocalPlayer.PlayerId && !playerInfo.IsDead && (!onlyCrewmates || !playerInfo.IsImpostor)) { PlayerControl @object = playerInfo.Object; - if (@object && !@object.inVent) + if (@object && (!@object.inVent || targetPlayersInVents)) { Vector2 vector = @object.GetTruePosition() - truePosition; float magnitude = vector.magnitude; @@ -74,30 +74,34 @@ namespace BonusRoles { static void medicSetTarget() { if (Medic.medic == null || Medic.medic != PlayerControl.LocalPlayer) return; - Medic.currentTarget = setAnyRoleTarget(); + Medic.currentTarget = setTarget(); } static void shifterSetTarget() { if (Shifter.shifter == null || Shifter.shifter != PlayerControl.LocalPlayer) return; - Shifter.currentTarget = setAnyRoleTarget(); + Shifter.currentTarget = setTarget(); } static void morphlingSetTarget() { if (Morphling.morphling == null || Morphling.morphling != PlayerControl.LocalPlayer) return; - Morphling.currentTarget = setAnyRoleTarget(); + Morphling.currentTarget = setTarget(); } static void sheriffSetTarget() { if (Sheriff.sheriff == null || Sheriff.sheriff != PlayerControl.LocalPlayer) return; - Sheriff.currentTarget = setAnyRoleTarget(); + Sheriff.currentTarget = setTarget(); } static void seerSetTarget() { if (Seer.seer == null || Seer.seer != PlayerControl.LocalPlayer) return; - Seer.currentTarget = setAnyRoleTarget(); + Seer.currentTarget = setTarget(); if (Seer.currentTarget != null && Seer.revealedPlayers.Keys.Any(p => p.Data.PlayerId == Seer.currentTarget.Data.PlayerId)) Seer.currentTarget = null; // Remove target if already revealed + } + static void trackerSetTarget() { + if (Tracker.tracker == null || Tracker.tracker != PlayerControl.LocalPlayer) return; + Tracker.currentTarget = setTarget(); } static void detectiveSetFootPrints() { @@ -107,12 +111,74 @@ namespace BonusRoles { if (Detective.timer <= 0f) { Detective.timer = Detective.footprintIntervall; foreach (PlayerControl player in PlayerControl.AllPlayerControls) { - if (player != null && player != PlayerControl.LocalPlayer && !player.Data.IsDead) { + if (player != null && player != PlayerControl.LocalPlayer && !player.Data.IsDead && !player.inVent) { new Footprint(Detective.footprintDuration, Detective.anonymousFootprints, player); } } } + } + + static void vampireSetTarget() { + if (Vampire.vampire == null || Vampire.vampire != PlayerControl.LocalPlayer) return; + PlayerControl target = setTarget(true, true); + bool targetNearGarlic = false; + if (target != null) { + foreach (Garlic garlic in Garlic.garlics) { + if (Vector2.Distance(garlic.garlic.transform.position, target.transform.position) <= 1.91f) { + targetNearGarlic = true; + } + } + } + Vampire.targetNearGarlic = targetNearGarlic; + Vampire.currentTarget = target; + } + + static void engineerUpdate() { + if (PlayerControl.LocalPlayer.Data.IsImpostor && Engineer.engineer != null) { + foreach (Vent vent in ShipStatus.Instance.AllVents) { + if (vent.Field_7?.material != null) { + if (Engineer.engineer.inVent) { + vent.Field_7.material.SetFloat("_Outline", 1f); + vent.Field_7.material.SetColor("_OutlineColor", Engineer.color); + } else if (vent.Field_7.material.GetColor("_AddColor") != Color.red) { + vent.Field_7.material.SetFloat("_Outline", 0); + } + } + } + } + } + + static void trackerUpdate() { + if (Tracker.tracker == null || Tracker.tracked == null) return; + + if (Tracker.arrow?.arrow != null && PlayerControl.LocalPlayer != Tracker.tracker) { + Tracker.arrow.arrow.SetActive(false); + return; + } + + if (Tracker.arrow?.arrow != null && Tracker.tracked != null) { + Tracker.timeUntilUpdate -= Time.fixedDeltaTime; + + if (Tracker.timeUntilUpdate <= 0f) { + bool trackedOnMap = !Tracker.tracked.Data.IsDead; + System.Console.WriteLine("Update"); + Vector3 position = Tracker.tracked.transform.position; + if (!trackedOnMap) { // Check for dead body + DeadBody body = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(b => b.ParentId == Tracker.tracked.PlayerId); + if (body != null) { + trackedOnMap = true; + position = body.transform.position; + System.Console.WriteLine("DeadBody"); + } + } + Tracker.arrow.Update(position); + Tracker.arrow.arrow.SetActive(trackedOnMap); + Tracker.timeUntilUpdate = Tracker.updateIntervall; + } else { + Tracker.arrow.Update(); + } + } } public static void Postfix(PlayerControl __instance) { @@ -133,26 +199,42 @@ namespace BonusRoles { seerSetTarget(); // Detective detectiveSetFootPrints(); + // Tracker + trackerSetTarget(); + // Vampire + vampireSetTarget(); + Garlic.UpdateAll(); + // Engineer + engineerUpdate(); + // Tracker + trackerUpdate(); } } } + [HarmonyPatch(typeof(HudManager), nameof(HudManager.OpenMeetingRoom))] + class StartMeetingHostPatch { + public static void Prefix(PlayerControl __instance) { + // Perform vampire bite kill before the meeting starts for HOST + if (!MeetingHud.Instance && AmongUsClient.Instance.AmHost) + RPCProcedure.vampireTryKill(); + } + } + + [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CoStartMeeting))] + class StartMeetingClientPatch { + public static void Prefix(PlayerControl __instance) { + // Perform vampire bite kill before the meeting starts for CLIENTS + if (AmongUsClient.Instance.AmClient) + RPCProcedure.vampireTryKill(); + } + } + [HarmonyPatch(typeof(KillButtonManager), nameof(KillButtonManager.PerformKill))] class PerformKillPatch { public static bool Prefix(KillButtonManager __instance) { - // Block impostor shielded kill - if (Medic.shielded != null && Medic.shielded == __instance.CurrentTarget) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.None, -1); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.shieldedMurderAttempt(); - return false; - } - // Block impostor not fully grown child kill - else if (Child.child != null && __instance.CurrentTarget == Child.child && !Child.isGrownUp()) { - return false; - } - return true; + return Helpers.handleMurderAttempt(__instance.CurrentTarget); } } @@ -212,38 +294,23 @@ namespace BonusRoles { [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.MurderPlayer))] public static class MurderPlayerPatch { - public static void Prefix(PlayerControl __instance, PlayerControl PAIBDFDMIGK, out bool __state) - { - // __state denotes if the player performing the murder needs to be reset to crewmate - __state = false; + public static bool resetToCrewmate = false; - // Allow Sheriff to kill "as crewmate" by assigning the impostor role - if (Sheriff.sheriff != null && __instance == Sheriff.sheriff) { - __instance.Data.IsImpostor = true; - __state = true; - } - // Allow Shifter to suicide - else if (Shifter.shifter != null && __instance == Shifter.shifter) { - __instance.Data.IsImpostor = true; - __state = true; - } - // Allow Lover which is no impostor to suicide - else if ((Lovers.lover1 != null && __instance == Lovers.lover1) || (Lovers.lover2 != null && __instance == Lovers.lover2)) { - if (!__instance.Data.IsImpostor) { - __instance.Data.IsImpostor = true; - __state = true; - } - } + public static void Prefix(PlayerControl __instance, PlayerControl PAIBDFDMIGK) + { + // Allow everyone to murder players + resetToCrewmate = !__instance.Data.IsImpostor; + __instance.Data.IsImpostor = true; } - public static void Postfix(PlayerControl __instance, PlayerControl PAIBDFDMIGK, bool __state) + public static void Postfix(PlayerControl __instance, PlayerControl PAIBDFDMIGK) { // Collect dead player info DeadPlayer deadPlayer = new DeadPlayer(PAIBDFDMIGK, DateTime.UtcNow, DeathReason.Kill, __instance); GameHistory.deadPlayers.Add(deadPlayer); - // Reset killer to crewmate if __state - if (__state) __instance.Data.IsImpostor = false; + // Reset killer to crewmate if resetToCrewmate + if (resetToCrewmate) __instance.Data.IsImpostor = false; // Lover suicide trigger on murder if ((Lovers.lover1 != null && PAIBDFDMIGK == Lovers.lover1) || (Lovers.lover2 != null && PAIBDFDMIGK == Lovers.lover2)) { @@ -279,7 +346,6 @@ namespace BonusRoles { RPCProcedure.loverSuicide(otherLover.PlayerId); } } - } } } diff --git a/Source Code/RPC.cs b/Source Code/RPC.cs index 0672cea..49c8898 100644 --- a/Source Code/RPC.cs +++ b/Source Code/RPC.cs @@ -1,37 +1,41 @@ using HarmonyLib; using Hazel; -using static BonusRoles.BonusRoles; -using static BonusRoles.HudManagerStartPatch; -using static BonusRoles.GameHistory; +using static TheOtherRoles.TheOtherRoles; +using static TheOtherRoles.HudManagerStartPatch; +using static TheOtherRoles.GameHistory; using System.Collections.Generic; using System.Collections; using System.Linq; using UnityEngine; using System; -namespace BonusRoles +namespace TheOtherRoles { enum RoleId { - Jester = 0, - Mayor = 1, - Engineer = 2, - Sheriff = 3, - Lighter = 4, - Godfather = 5, - Mafioso = 6, - Janitor = 7, - Detective = 8, - TimeMaster = 9, - Medic = 10, - Shifter = 11, - Swapper = 12, - Lover1 = 13, - Lover2 = 14, - Seer = 15, - Morphling = 16, - Camouflager = 17, - Spy = 18, - Child = 19, + Jester, + Mayor, + Engineer, + Sheriff, + Lighter, + Godfather, + Mafioso, + Janitor, + Detective, + TimeMaster, + Medic, + Shifter, + Swapper, + Lover1, + Lover2, + Seer, + Morphling, + Camouflager, + Spy, + Child, + BountyHunter, + Tracker, + Vampire, + Snitch } enum CustomRPC @@ -44,7 +48,7 @@ namespace BonusRoles // Role functionality - JesterWin = 80, + JesterBountyHunterWin = 80, EngineerFixLights = 81, EngineerUsedRepair = 82, JanitorClean = 83, @@ -58,8 +62,12 @@ namespace BonusRoles SeerReveal = 91, MorphlingMorph = 92, CamouflagerCamouflage = 93, - ChildDied = 94, + TrackerUsedTracker = 94, LoverSuicide = 95, + SetBountyHunterTarget = 96, + VampireBiteNotification = 97, + VampireTryKill = 98, + PlaceGarlic = 99, } public static class RPCProcedure { @@ -67,6 +75,7 @@ namespace BonusRoles // Main Controls public static void resetVariables() { + Garlic.clearGarlics(); clearAndReloadRoles(); clearGameHistory(); setCustomButtonCooldowns(); @@ -148,19 +157,45 @@ namespace BonusRoles case RoleId.Child: Child.child = player; break; + case RoleId.BountyHunter: + BountyHunter.bountyHunter = player; + break; + case RoleId.Tracker: + Tracker.tracker = player; + break; + case RoleId.Vampire: + Vampire.vampire = player; + break; + case RoleId.Snitch: + Snitch.snitch = player; + break; } } } // Role functionality - public static void jesterWin() { - Jester.jester.Revive(); - Jester.jester.Data.IsDead = false; - Jester.jester.Data.IsImpostor = true; + public static void jesterBountyHunterWin(byte exiledId) { + PlayerControl exiled = Helpers.playerById(exiledId); + if (exiled == null) return; + + bool jesterWin = false; + bool bountyHunterWin = false; + + if (Jester.jester != null && exiled == Jester.jester) { + Jester.jester.Revive(); + Jester.jester.Data.IsDead = false; + Jester.jester.Data.IsImpostor = true; + jesterWin = true; + } + if (BountyHunter.bountyHunter != null && !BountyHunter.bountyHunter.Data.IsDead && BountyHunter.target == exiled) { + BountyHunter.bountyHunter.Data.IsImpostor = true; + bountyHunterWin = true; + } + foreach (PlayerControl player in PlayerControl.AllPlayerControls) { - if (player != Jester.jester) + if (player != null && player != Jester.jester && player != BountyHunter.bountyHunter) { player.RemoveInfected(); player.Die(DeathReason.Exile); @@ -168,6 +203,17 @@ namespace BonusRoles player.Data.IsImpostor = false; } } + if (jesterWin && !bountyHunterWin && BountyHunter.bountyHunter != null) { + BountyHunter.bountyHunter.RemoveInfected(); + BountyHunter.bountyHunter.Die(DeathReason.Exile); + BountyHunter.bountyHunter.Data.IsDead = true; + BountyHunter.bountyHunter.Data.IsImpostor = false; + } else if (bountyHunterWin && !jesterWin && Jester.jester != null) { + Jester.jester.RemoveInfected(); + Jester.jester.Die(DeathReason.Exile); + Jester.jester.Data.IsDead = true; + Jester.jester.Data.IsImpostor = false; + } } public static void engineerFixLights() { @@ -315,7 +361,13 @@ namespace BonusRoles Spy.spy = oldShifter; } else if (Child.child != null && Child.child == player) { Child.child = oldShifter; - } else { // Crewmate + } else if (BountyHunter.bountyHunter != null && BountyHunter.bountyHunter == player) { + BountyHunter.bountyHunter = oldShifter; + } else if (Tracker.tracker != null && Tracker.tracker == player) { + Tracker.tracker = oldShifter; + } else if (Snitch.snitch != null && Snitch.snitch == player) { + Snitch.snitch = oldShifter; + }else { // Crewmate } Shifter.shifter = player; @@ -378,29 +430,51 @@ namespace BonusRoles Camouflager.camouflageTimer = 10f; } - public static void childDied() { - Child.child.Revive(); - Child.child.Data.IsDead = false; - Child.child.Data.IsImpostor = true; - foreach (PlayerControl player in PlayerControl.AllPlayerControls) - { - if (player != null && player != Child.child) - { - player.RemoveInfected(); - player.Die(DeathReason.Exile); - player.Data.IsDead = true; - player.Data.IsImpostor = false; - } - } - } - public static void loverSuicide(byte remainingLoverId) { if (Lovers.lover1 != null && !Lovers.lover1.Data.IsDead && Lovers.lover1.PlayerId == remainingLoverId) { Lovers.lover1.MurderPlayer(Lovers.lover1); } else if (Lovers.lover2 != null && !Lovers.lover2.Data.IsDead && Lovers.lover2.PlayerId == remainingLoverId) { Lovers.lover2.MurderPlayer(Lovers.lover2); } - } + } + + public static void setBountyHunterTarget(byte targetId) { + foreach (PlayerControl player in PlayerControl.AllPlayerControls) + if (player.PlayerId == targetId) + BountyHunter.target = player; + } + + public static void vampireBiteNotification(byte targetId) { + if (Vampire.vampire == null) return; + foreach (PlayerControl player in PlayerControl.AllPlayerControls) { + if (player.PlayerId == targetId && !player.Data.IsDead) { + Vampire.bitten = player; + } + } + } + + public static void vampireTryKill() { + if (Vampire.vampire == null || Vampire.bitten == null) return; + + if (!Vampire.bitten.Data.IsDead && Helpers.handleMurderAttempt(Vampire.bitten, false)) { + Vampire.bitten.MurderPlayer(Vampire.bitten); // Suicide because of the kill animation teleport + } + Vampire.bitten = null; + } + + public static void placeGarlic(byte[] buff) { + Vector3 position = Vector3.zero; + position.x = BitConverter.ToSingle(buff, 0*sizeof(float)); + position.y = BitConverter.ToSingle(buff, 1*sizeof(float)); + new Garlic(position); + } + + public static void trackerUsedTracker(byte targetId) { + Tracker.usedTracker = true; + foreach (PlayerControl player in PlayerControl.AllPlayerControls) + if (player.PlayerId == targetId) + Tracker.tracked = player; + } } [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.HandleRpc))] @@ -429,8 +503,8 @@ namespace BonusRoles // Role functionality - case (byte)CustomRPC.JesterWin: - RPCProcedure.jesterWin(); + case (byte)CustomRPC.JesterBountyHunterWin: + RPCProcedure.jesterBountyHunterWin(HFPCBBHJIPJ.ReadByte()); break; case (byte)CustomRPC.EngineerFixLights: RPCProcedure.engineerFixLights(); @@ -475,12 +549,24 @@ namespace BonusRoles case (byte)CustomRPC.CamouflagerCamouflage: RPCProcedure.camouflagerCamouflage(); break; - case (byte)CustomRPC.ChildDied: - RPCProcedure.childDied(); - break; case (byte)CustomRPC.LoverSuicide: RPCProcedure.loverSuicide(HFPCBBHJIPJ.ReadByte()); break; + case (byte)CustomRPC.SetBountyHunterTarget: + RPCProcedure.setBountyHunterTarget(HFPCBBHJIPJ.ReadByte()); + break; + case (byte)CustomRPC.VampireBiteNotification: + RPCProcedure.vampireBiteNotification(HFPCBBHJIPJ.ReadByte()); + break; + case (byte)CustomRPC.VampireTryKill: + RPCProcedure.vampireTryKill(); + break; + case (byte)CustomRPC.PlaceGarlic: + RPCProcedure.placeGarlic(HFPCBBHJIPJ.ReadBytesAndSize()); + break; + case (byte)CustomRPC.TrackerUsedTracker: + RPCProcedure.trackerUsedTracker(HFPCBBHJIPJ.ReadByte()); + break; } } } diff --git a/Source Code/RoleAssignmentPatch.cs b/Source Code/RoleAssignmentPatch.cs index 2a82376..ab6b3b5 100644 --- a/Source Code/RoleAssignmentPatch.cs +++ b/Source Code/RoleAssignmentPatch.cs @@ -3,19 +3,25 @@ using Hazel; using System.Collections.Generic; using System.Linq; using UnhollowerBaseLib; +using UnityEngine; using System; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSetInfected))] class SetInfectedPatch { + private static void setRoleToRandomPlayer(byte roleId, List playerList) { var index = rnd.Next(0, playerList.Count); byte playerId = playerList[index].PlayerId; playerList.RemoveAt(index); + setRoleToPlayer(roleId, playerId); + } + + private static void setRoleToPlayer(byte roleId, byte playerId) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.None, -1); writer.Write(roleId); writer.Write(playerId); @@ -34,59 +40,126 @@ namespace BonusRoles List impostors = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList(); impostors.RemoveAll(x => !x.Data.IsImpostor); - // Special roles impostors can be converted to - if (impostors.Count >= 3 && (rnd.Next(1, 101) <= BonusRolesPlugin.mafiaSpawnChance.GetValue())) { + float crewCountSettings = TheOtherRolesPlugin.crewmateRolesCount.GetValue(); + float impCountSettings = TheOtherRolesPlugin.impostorRolesCount.GetValue(); + + if (crewCountSettings % 1 == 0.5f) crewCountSettings += 0.5f * (rnd.Next(2) * 2 - 1); + if (impCountSettings % 1 == 0.5f) impCountSettings += 0.5f * (rnd.Next(2) * 2 - 1); + + int maxCrewmateRoles = Mathf.Min(crewmates.Count, Mathf.RoundToInt(crewCountSettings)); + int maxImpostorRoles = Mathf.Min(impostors.Count, Mathf.RoundToInt(impCountSettings)); + + Dictionary impSettings = new Dictionary(); + Dictionary crewSettings = new Dictionary(); + + impSettings.Add((byte)RoleId.Morphling, TheOtherRolesPlugin.morphlingSpawnRate.GetValue()); + impSettings.Add((byte)RoleId.Camouflager, TheOtherRolesPlugin.camouflagerSpawnRate.GetValue()); + impSettings.Add((byte)RoleId.Vampire, TheOtherRolesPlugin.vampireSpawnRate.GetValue()); + + crewSettings.Add((byte)RoleId.Jester, TheOtherRolesPlugin.jesterSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Mayor, TheOtherRolesPlugin.mayorSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Engineer, TheOtherRolesPlugin.engineerSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Sheriff, TheOtherRolesPlugin.sheriffSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Lighter, TheOtherRolesPlugin.lighterSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Detective, TheOtherRolesPlugin.detectiveSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.TimeMaster, TheOtherRolesPlugin.timeMasterSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Medic, TheOtherRolesPlugin.medicSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Shifter, TheOtherRolesPlugin.shifterSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Swapper,TheOtherRolesPlugin.swapperSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Seer, TheOtherRolesPlugin.seerSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Spy, TheOtherRolesPlugin.spySpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Child, TheOtherRolesPlugin.childSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Tracker, TheOtherRolesPlugin.trackerSpawnRate.GetValue()); + crewSettings.Add((byte)RoleId.Snitch, TheOtherRolesPlugin.snitchSpawnRate.GetValue()); + // crewSettings.Add((byte)RoleId.BountyHunter, TheOtherRolesPlugin.bountyHunterSpawnRate.GetValue()); BOUNTY HUNTER + + // Set multiple player roles + if (impostors.Count >= 3 && maxImpostorRoles >= 3 && (rnd.Next(1, 101) <= TheOtherRolesPlugin.mafiaSpawnRate.GetValue() * 10)) { setRoleToRandomPlayer((byte)RoleId.Godfather, impostors); setRoleToRandomPlayer((byte)RoleId.Janitor, impostors); setRoleToRandomPlayer((byte)RoleId.Mafioso, impostors); + maxImpostorRoles -= 3; } - // Special roles that involve crewmates and impostors - if (rnd.Next(1, 101) <= BonusRolesPlugin.loversSpawnChance.GetValue()) - { - if (impostors.Count > 0 && crewmates.Count > 0 && rnd.Next(1, 101) <= 33) { + if (rnd.Next(1, 101) <= TheOtherRolesPlugin.loversSpawnRate.GetValue() * 10) { + if (impostors.Count > 0 && crewmates.Count > 0 && maxCrewmateRoles > 0 && maxImpostorRoles > 0 && rnd.Next(1, 101) <= 33) { setRoleToRandomPlayer((byte)RoleId.Lover1, impostors); - setRoleToRandomPlayer((byte)RoleId.Lover2, crewmates); - } else if (crewmates.Count >= 2) { + setRoleToRandomPlayer((byte)RoleId.Lover2, crewmates); + maxCrewmateRoles--; + maxImpostorRoles--; + } else if (crewmates.Count >= 2 && maxCrewmateRoles >= 2) { setRoleToRandomPlayer((byte)RoleId.Lover1, crewmates); setRoleToRandomPlayer((byte)RoleId.Lover2, crewmates); + maxCrewmateRoles -= 2; } } - // Special roles impostors can be converted to - if (impostors.Count >= 1 && (rnd.Next(1, 101) <= BonusRolesPlugin.morphlingSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Morphling, impostors); + // Set tickets and always active roles - if (impostors.Count >= 1 && (rnd.Next(1, 101) <= BonusRolesPlugin.camouflagerSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Camouflager, impostors); - - // Special roles crewmates can be converted to - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.jesterSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Jester, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.mayorSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Mayor, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.engineerSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Engineer, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.sheriffSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Sheriff, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.lighterSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Lighter, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.detectiveSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Detective, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.timeMasterSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.TimeMaster, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.medicSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Medic, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.shifterSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Shifter, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.swapperSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Swapper, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.seerSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Seer, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.spySpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Spy, crewmates); - if (crewmates.Count > 0 && (rnd.Next(1, 101) <= BonusRolesPlugin.childSpawnChance.GetValue())) - setRoleToRandomPlayer((byte)RoleId.Child, crewmates); + List crewTickets = new List(); + List impTickets = new List(); + + foreach (KeyValuePair entry in crewSettings) { + if (entry.Value == 0) { // Never + } else if (entry.Value == 10) { // Always + if (crewmates.Count > 0 && maxCrewmateRoles > 0) { + setRoleToRandomPlayer(entry.Key, crewmates); + maxCrewmateRoles--; + } + } else { // Other + for (int i = 0; i < entry.Value; i++) crewTickets.Add(entry.Key); + } + } + + foreach (KeyValuePair entry in impSettings) { + if (entry.Value == 0) { // Never + } else if (entry.Value == 10) { // Always + if (impostors.Count > 0 && maxImpostorRoles > 0) { + setRoleToRandomPlayer(entry.Key, impostors); + maxImpostorRoles--; + } + } else { // Other + for (int i = 0; i < entry.Value; i++) impTickets.Add(entry.Key); + } + } + + // Set solo player roles + + for (int i = 0; i < maxCrewmateRoles; i++) { + if (crewTickets.Count > 0 && crewmates.Count > 0) { + var index = rnd.Next(0, crewTickets.Count); + byte roleId = crewTickets[index]; + crewTickets.RemoveAll(x => x == roleId); + setRoleToRandomPlayer(roleId, crewmates); + } + } + + for (int i = 0; i < maxImpostorRoles; i++) { + if (impTickets.Count > 0 && impostors.Count > 0) { + var index = rnd.Next(0, impTickets.Count); + byte roleId = impTickets[index]; + impTickets.RemoveAll(x => x == roleId); + setRoleToRandomPlayer(roleId, impostors); + } + } + + // if (crewmates.Count > 0 && (rnd.Next(1, 101) <= TheOtherRolesPlugin.bountyHunterSpawnRate.GetValue())) { + // List availableTargets = PlayerControl.AllPlayerControls.ToArray().ToList(); + // var bountyHunterIndex = rnd.Next(0, crewmates.Count); + // byte bountyHunterId = crewmates[bountyHunterIndex].PlayerId; + + // availableTargets.RemoveAll(x => x.Data.IsImpostor || x.PlayerId == bountyHunterId); + + // if (availableTargets.Count > 0) { + // byte targetId = availableTargets[rnd.Next(0, availableTargets.Count)].PlayerId; + // crewmates.RemoveAt(bountyHunterIndex); + // setRoleToPlayer((byte)RoleId.BountyHunter, bountyHunterId); + // writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetBountyHunterTarget, Hazel.SendOption.None, -1); + // writer.Write(targetId); + // AmongUsClient.Instance.FinishRpcImmediately(writer); + // RPCProcedure.setBountyHunterTarget(targetId); + // } + // } } } } diff --git a/Source Code/ShipStatusPatch.cs b/Source Code/ShipStatusPatch.cs index 6636cc2..c6ed7fb 100644 --- a/Source Code/ShipStatusPatch.cs +++ b/Source Code/ShipStatusPatch.cs @@ -1,8 +1,8 @@ using HarmonyLib; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; -namespace BonusRoles { +namespace TheOtherRoles { [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CalculateLightRadius))] public class ShipStatusPatch { diff --git a/Source Code/TheOtherRoles.cs b/Source Code/TheOtherRoles.cs new file mode 100644 index 0000000..cf70fc2 --- /dev/null +++ b/Source Code/TheOtherRoles.cs @@ -0,0 +1,545 @@ +using System.Net; +using System.Linq; +using BepInEx; +using BepInEx.Configuration; +using BepInEx.IL2CPP; +using HarmonyLib; +using Hazel; +using Reactor; +using System; +using System.Collections.Generic; +using System.Collections; +using System.IO; +using UnityEngine; +using Reactor.Unstrip; +using Reactor.Extensions; + +namespace TheOtherRoles +{ + [HarmonyPatch] + public static class TheOtherRoles + { + public static System.Random rnd = new System.Random((int)DateTime.Now.Ticks); + + public static void clearAndReloadRoles() { + Jester.clearAndReload(); + Mayor.clearAndReload(); + Engineer.clearAndReload(); + Sheriff.clearAndReload(); + Lighter.clearAndReload(); + Godfather.clearAndReload(); + Mafioso.clearAndReload(); + Janitor.clearAndReload(); + Detective.clearAndReload(); + TimeMaster.clearAndReload(); + Medic.clearAndReload(); + Shifter.clearAndReload(); + Swapper.clearAndReload(); + Lovers.clearAndReload(); + Seer.clearAndReload(); + Morphling.clearAndReload(); + Camouflager.clearAndReload(); + Spy.clearAndReload(); + Child.clearAndReload(); + BountyHunter.clearAndReload(); + Tracker.clearAndReload(); + Vampire.clearAndReload(); + Snitch.clearAndReload(); + } + + public static class Jester { + public static PlayerControl jester; + public static Color color = new Color(255f / 255f, 84f / 255f, 167f / 255f, 1); + + public static void clearAndReload() { + jester = null; + } + } + + public static class Mayor { + public static PlayerControl mayor; + public static Color color = new Color(105f / 255f, 58f / 255f, 58f / 255f, 1); + + public static void clearAndReload() { + mayor = null; + } + } + + public static class Engineer { + public static PlayerControl engineer; + public static Color color = new Color(98f / 255f, 216f / 255f, 240f / 255f, 1); + public static bool usedRepair; + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.RepairButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + engineer = null; + usedRepair = false; + } + } + + public static class Godfather { + public static PlayerControl godfather; + public static Color color = Palette.ImpostorRed; + + public static void clearAndReload() { + godfather = null; + } + } + + public static class Mafioso { + public static PlayerControl mafioso; + public static Color color = Palette.ImpostorRed; + + public static void clearAndReload() { + mafioso = null; + } + } + + + public static class Janitor { + public static PlayerControl janitor; + public static Color color = Palette.ImpostorRed; + + public static float cooldown = float.MaxValue; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CleanButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + janitor = null; + cooldown = TheOtherRolesPlugin.janitorCooldown.GetValue(); + } + } + + public static class Sheriff { + public static PlayerControl sheriff; + public static Color color = new Color(255f / 255f, 204f / 255f, 0f / 255f, 1); + + public static float cooldown = float.MaxValue; + public static bool jesterCanDieToSheriff = false; + + public static PlayerControl currentTarget; + + public static void clearAndReload() { + sheriff = null; + currentTarget = null; + cooldown = TheOtherRolesPlugin.sheriffCooldown.GetValue(); + jesterCanDieToSheriff = TheOtherRolesPlugin.jesterCanDieToSheriff.GetValue(); + } + } + + public static class Lighter { + public static PlayerControl lighter; + public static Color color = new Color(250f / 255f, 204f / 255f, 37f / 255f, 1); + + public static float lighterVision = 2f; + + public static void clearAndReload() { + lighter = null; + lighterVision = TheOtherRolesPlugin.lighterVision.GetValue(); + } + } + + public static class Detective { + public static PlayerControl detective; + public static Color color = new Color(2f / 255f, 61f / 255f, 156f / 255f, 1); + + public static float footprintIntervall = 1f; + public static float footprintDuration = 1f; + public static bool anonymousFootprints = false; + + public static float timer = 1f; + + public static void clearAndReload() { + detective = null; + anonymousFootprints = TheOtherRolesPlugin.detectiveAnonymousFootprints.GetValue(); + footprintIntervall = TheOtherRolesPlugin.detectiveFootprintIntervall.GetValue(); + footprintDuration = TheOtherRolesPlugin.detectiveFootprintDuration.GetValue(); + timer = footprintIntervall; + } + } + } + + public static class TimeMaster { + public static PlayerControl timeMaster; + public static Color color = new Color(114f / 255f, 234f / 255f, 247f / 255f, 1); + + public static bool reviveDuringRewind = false; + public static float rewindTime = 3f; + public static float cooldown = float.MaxValue; + + public static bool isRewinding = false; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.RewindButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + timeMaster = null; + isRewinding = false; + reviveDuringRewind = TheOtherRolesPlugin.timeMasterReviveDuringRewind.GetValue(); + rewindTime = TheOtherRolesPlugin.timeMasterRewindTime.GetValue(); + cooldown = TheOtherRolesPlugin.timeMasterCooldown.GetValue(); + } + } + + public static class Medic { + public static PlayerControl medic; + public static PlayerControl shielded; + public static Color color = new Color(0f / 255f, 80f / 255f, 105f / 255f, 1); + public static bool usedShield; + + public static float reportNameDuration = 10f; + public static float reportColorDuration = 20f; + public static int showShielded = 0; + public static bool showAttemptToShielded = false; + + public static Color shieldedColor = new Color(0f / 255f, 221f / 255f, 255f / 255f, 1); + public static PlayerControl currentTarget; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.ShieldButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + medic = null; + shielded = null; + currentTarget = null; + usedShield = false; + shieldedColor = new Color(0f / 255f, 221f / 255f, 255f / 255f, 1); + reportNameDuration = TheOtherRolesPlugin.medicReportNameDuration.GetValue(); + reportColorDuration = TheOtherRolesPlugin.medicReportColorDuration.GetValue(); + showShielded = TheOtherRolesPlugin.medicShowShielded.GetValue(); + showAttemptToShielded = TheOtherRolesPlugin.medicShowAttemptToShielded.GetValue(); + } + } + + public static class Shifter { + public static PlayerControl shifter; + public static Color color = new Color(90f / 255f, 90f / 255f, 90f / 255f, 1); + + public static float cooldown = float.MaxValue; + + public static PlayerControl currentTarget; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.ShiftButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + shifter = null; + currentTarget = null; + cooldown = TheOtherRolesPlugin.shifterCooldown.GetValue(); + } + } + + public static class Swapper { + public static PlayerControl swapper; + public static Color color = new Color(240f / 255f, 128f / 255f, 72f / 255f, 1); + private static Sprite spriteCheck; + + public static byte playerId1 = Byte.MaxValue; + public static byte playerId2 = Byte.MaxValue; + + public static Sprite getCheckSprite() { + if (spriteCheck) return spriteCheck; + spriteCheck = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.SwapperCheck.png", 150f); + return spriteCheck; + } + + public static void clearAndReload() { + swapper = null; + playerId1 = Byte.MaxValue; + playerId2 = Byte.MaxValue; + } + } + + public static class Lovers { + public static PlayerControl lover1; + public static PlayerControl lover2; + public static Color color = new Color(252f / 255f, 3f / 255f, 190f / 255f, 1); + + public static bool bothDie = true; + // Lovers save if next to be exiled is a lover, because RPC of ending game comes before RPC of exiled + public static bool notAckedExiledIsLover = false; + + public static bool existingAndAlive() { + return lover1 != null && lover2 != null && !lover1.Data.IsDead && !lover2.Data.IsDead && !notAckedExiledIsLover; // ADD NOT ACKED IS LOVER + } + + public static bool existingWithImpLover() { + return lover1 != null && lover2 != null && (lover1.Data.IsImpostor || lover2.Data.IsImpostor); + } + + public static void clearAndReload() { + lover1 = null; + lover2 = null; + notAckedExiledIsLover = false; + bothDie = TheOtherRolesPlugin.loversBothDie.GetValue(); + } + } + + public static class Seer { + public static PlayerControl seer; + public static Color color = new Color(60f / 255f, 181f / 255f, 100f / 255f, 1); + public static Dictionary revealedPlayers = new Dictionary(); + + public static float cooldown = float.MaxValue; + public static int kindOfInfo = 0; + public static int playersWithNotification = 0; + public static float chanceOfSeeingRight = 100; + + public static PlayerControl currentTarget; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.SeerButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + seer = null; + revealedPlayers = new Dictionary(); + cooldown = TheOtherRolesPlugin.seerCooldown.GetValue(); + kindOfInfo = TheOtherRolesPlugin.seerKindOfInfo.GetValue(); + playersWithNotification = TheOtherRolesPlugin.seerPlayersWithNotification.GetValue(); + chanceOfSeeingRight = TheOtherRolesPlugin.seerChanceOfSeeingRight.GetValue(); + } + } + + public static class Morphling { + public static PlayerControl morphling; + public static Color color = Palette.ImpostorRed; + private static Sprite sampleSprite; + private static Sprite morphSprite; + + public static float cooldown = float.MaxValue; + + public static PlayerControl currentTarget; + public static PlayerControl sampledTarget; + public static PlayerControl morphTarget; + public static float morphTimer = 0f; + + + public static void clearAndReload() { + morphling = null; + currentTarget = null; + sampledTarget = null; + morphTarget = null; + morphTimer = 0f; + cooldown = TheOtherRolesPlugin.morphlingCooldown.GetValue(); + } + + public static Sprite getSampleSprite() { + if (sampleSprite) return sampleSprite; + sampleSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.SampleButton.png", 100f); + return sampleSprite; + } + + public static Sprite getMorphSprite() { + if (morphSprite) return morphSprite; + morphSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.MorphButton.png", 100f); + return morphSprite; + } + } + + public static class Camouflager { + public static PlayerControl camouflager; + public static Color color = Palette.ImpostorRed; + + public static float cooldown = float.MaxValue; + public static float camouflageTimer = 0f; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CamoButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + camouflager = null; + camouflageTimer = 0f; + cooldown = TheOtherRolesPlugin.camouflagerCooldown.GetValue(); + } + } + + public static class Spy { + public static PlayerControl spy; + private static Sprite adminTableIcon; + public static Color color = new Color(252f / 255f, 90f / 255f, 30f / 255f, 1); + + public static float cooldown = float.MaxValue; + public static float duration = 10f; + + public static float spyTimer = 0f; + + public static Sprite getAdminTableIconSprite() { + if (adminTableIcon) return adminTableIcon; + adminTableIcon = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.AdminTableIcon.png", 350f); + return adminTableIcon; + } + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.SpyButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + spy = null; + spyTimer = 0f; + cooldown = TheOtherRolesPlugin.spyCooldown.GetValue(); + duration = TheOtherRolesPlugin.spySpyingDuration.GetValue(); + } + } + + public static class Child { + public static PlayerControl child; + public static Color color = Color.white; + + public static float growingUpDuration = float.MaxValue; + public static DateTime timeOfGrowthStart = DateTime.UtcNow; + + public static void clearAndReload() { + child = null; + growingUpDuration = TheOtherRolesPlugin.childGrowingUpDuration.GetValue(); + timeOfGrowthStart = DateTime.UtcNow; + } + + public static float growingProgress() { + if (timeOfGrowthStart == null) return 0f; + + float timeSinceStart = (float)(DateTime.UtcNow - timeOfGrowthStart).TotalMilliseconds; + return Mathf.Clamp(timeSinceStart/(growingUpDuration*1000), 0f, 1f); + } + + public static bool isGrownUp() { + return growingProgress() == 1f; + } + } + + public static class BountyHunter { + public static PlayerControl bountyHunter; + public static Color color = new Color(237f / 255f, 101f / 255f, 59f / 255f, 1); + + public static bool notifyBounty = true; + public static PlayerControl target; + + public static void clearAndReload() { + bountyHunter = null; + target = null; + // notifyBounty = TheOtherRolesPlugin.bountyHunterNotifyBounty.GetValue(); + } + } + + public static class Tracker { + public static PlayerControl tracker; + public static Color color = new Color(117f / 255f, 209f / 255f, 255f / 255f, 1); + + public static float updateIntervall = 5f; + + public static PlayerControl currentTarget; + public static PlayerControl tracked; + public static bool usedTracker = false; + public static float timeUntilUpdate = 0f; + public static Arrow arrow = new Arrow(Color.blue); + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.TrackerButton.png", 100f); + return buttonSprite; + } + + public static void clearAndReload() { + tracker = null; + currentTarget = null; + tracked = null; + usedTracker = false; + timeUntilUpdate = 0f; + updateIntervall = TheOtherRolesPlugin.trackerUpdateIntervall.GetValue(); + arrow = new Arrow(Color.blue); + if (arrow.arrow != null) arrow.arrow.SetActive(false); + } + } + + public static class Vampire { + public static PlayerControl vampire; + public static Color color = Palette.ImpostorRed; + + public static float delay = 10f; + public static bool localPlacedGarlic = false; + public static bool garlicsActive = true; + + public static PlayerControl currentTarget; + public static PlayerControl bitten; + public static bool targetNearGarlic = false; + + private static Sprite buttonSprite; + public static Sprite getButtonSprite() { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.VampireButton.png", 100f); + return buttonSprite; + } + + private static Sprite garlicButtonSprite; + public static Sprite getGarlicButtonSprite() { + if (garlicButtonSprite) return garlicButtonSprite; + garlicButtonSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.GarlicButton.png", 100f); + return garlicButtonSprite; + } + + public static IEnumerator killWithDelay() { + yield return new WaitForSeconds(delay); + MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.VampireTryKill, Hazel.SendOption.None, -1); + AmongUsClient.Instance.FinishRpcImmediately(killWriter); + RPCProcedure.vampireTryKill(); + } + + public static void clearAndReload() { + vampire = null; + bitten = null; + targetNearGarlic = false; + localPlacedGarlic = false; + currentTarget = null; + garlicsActive = TheOtherRolesPlugin.vampireSpawnRate.GetValue() > 0; + delay = TheOtherRolesPlugin.vampireKillDelay.GetValue(); + } + } + + public static class Snitch { + public static PlayerControl snitch; + public static Color color = new Color(227f / 255f, 251f / 255f, 47f / 255f, 1); + + public static List localArrows = new List(); + public static int taskCountForImpostors = 1; + + public static void clearAndReload() { + localArrows = new List(); + taskCountForImpostors = Mathf.RoundToInt(TheOtherRolesPlugin.snitchLeftTasksForImpostors.GetValue()); + snitch = null; + } + } +} \ No newline at end of file diff --git a/Source Code/TheOtherRoles.csproj b/Source Code/TheOtherRoles.csproj new file mode 100644 index 0000000..c0e534e --- /dev/null +++ b/Source Code/TheOtherRoles.csproj @@ -0,0 +1,58 @@ + + + netstandard2.1 + 1.0.0 + NuclearPowered/Mappings:0.2.0 + + TheOtherRoles + Eibison + + + + 2021.3.5s + $(DefineConstants);STEAM + + + + 2021.3.5i + $(DefineConstants);ITCH + + + + + + + + + + + $(AmongUs)\BepInEx\plugins\Essentials-$(GameVersion).dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source Code/UpdatePatch.cs b/Source Code/UpdatePatch.cs index d5dc2e6..6d20ef6 100644 --- a/Source Code/UpdatePatch.cs +++ b/Source Code/UpdatePatch.cs @@ -3,12 +3,12 @@ using System; using System.IO; using System.Net.Http; using UnityEngine; -using static BonusRoles.BonusRoles; +using static TheOtherRoles.TheOtherRoles; using Reactor.Extensions; using System.Collections.Generic; using System.Linq; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] class HudManagerUpdatePatch @@ -89,9 +89,17 @@ namespace BonusRoles setPlayerNameColor(Seer.seer, Seer.color); else if (Spy.spy != null && Spy.spy == PlayerControl.LocalPlayer) setPlayerNameColor(Spy.spy, Spy.color); + else if (BountyHunter.bountyHunter != null && BountyHunter.target != null && BountyHunter.bountyHunter == PlayerControl.LocalPlayer) { + setPlayerNameColor(BountyHunter.bountyHunter, BountyHunter.color); + setPlayerNameColor(BountyHunter.target, BountyHunter.color); + } + else if (Tracker.tracker != null && Tracker.tracker == PlayerControl.LocalPlayer) + setPlayerNameColor(Tracker.tracker, Tracker.color); + else if (Snitch.snitch != null && Snitch.snitch == PlayerControl.LocalPlayer) + setPlayerNameColor(Snitch.snitch, Snitch.color); // Crewmate roles with no changes: Child - // Impostor roles with no changes: Morphling, Camouflager, Godfather, Janitor and Mafioso + // Impostor roles with no changes: Morphling, Camouflager, Vampire, Godfather, Janitor and Mafioso } static void setMafiaNameTags() { @@ -333,6 +341,61 @@ namespace BonusRoles } } + public static void bountyHunterUpdate() { + if (BountyHunter.bountyHunter == null || BountyHunter.target == null) return; + + if (BountyHunter.notifyBounty && PlayerControl.LocalPlayer == BountyHunter.target) { + string suffix = "[AD653BFF] (Bounty)[FFFFFFFF]"; + PlayerControl.LocalPlayer.nameText.Text += suffix; + if (MeetingHud.Instance != null) + foreach (PlayerVoteArea player in MeetingHud.Instance.playerStates) + if (player.NameText != null && PlayerControl.LocalPlayer.PlayerId == player.TargetPlayerId) + player.NameText.Text += suffix; + } + } + + static void vampireDeactivateKillButton(HudManager __instance) { + if (Vampire.vampire != null && Vampire.vampire == PlayerControl.LocalPlayer) { + __instance.KillButton.gameObject.SetActive(false); + __instance.KillButton.renderer.enabled = false; + __instance.KillButton.isActive = false; + __instance.KillButton.enabled = false; + } + } + + static void snitchUpdate() { + if (Snitch.snitch == null) return; + + foreach (Arrow arrow in Snitch.localArrows) arrow.arrow.SetActive(false); + if (Snitch.snitch.Data.IsDead) return; + + int numberOfTasks = 0; + foreach (PlayerTask t in Snitch.snitch.myTasks) { + if (t.TaskType != TaskTypes.FixComms && t.TaskType != TaskTypes.FixLights && t.TaskType != TaskTypes.ResetReactor && t.TaskType != TaskTypes.ResetSeismic && t.TaskType != TaskTypes.RestoreOxy) + if (!t.IsComplete) numberOfTasks++; + } + + if (PlayerControl.LocalPlayer.Data.IsImpostor && numberOfTasks <= Snitch.taskCountForImpostors) { + if (Snitch.localArrows.Count == 0) Snitch.localArrows.Add(new Arrow(Color.blue)); + if (Snitch.localArrows.Count != 0 && Snitch.localArrows[0] != null) { + Snitch.localArrows[0].arrow.SetActive(true); + Snitch.localArrows[0].Update(Snitch.snitch.transform.position); + } + } else if (PlayerControl.LocalPlayer == Snitch.snitch && numberOfTasks == 0) { + int arrowIndex = 0; + foreach (PlayerControl p in PlayerControl.AllPlayerControls) { + if (p.Data.IsImpostor && !p.Data.IsDead) { + if (arrowIndex >= Snitch.localArrows.Count) Snitch.localArrows.Add(new Arrow(Color.blue)); + if (arrowIndex < Snitch.localArrows.Count && Snitch.localArrows[arrowIndex] != null) { + Snitch.localArrows[arrowIndex].arrow.SetActive(true); + Snitch.localArrows[arrowIndex].Update(p.transform.position); + } + arrowIndex++; + } + } + } + } + static void Postfix(HudManager __instance) { if (AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started) return; @@ -356,9 +419,16 @@ namespace BonusRoles seerUpdate(); // Spy update(); spyUpdate(); - + // Camouflager and Morphling camouflageAndMorphActions(); + // Child childUpdate(); + // Bounty Hunter + bountyHunterUpdate(); + // Vampire + vampireDeactivateKillButton(__instance); + // Snitch + snitchUpdate(); } } } \ No newline at end of file diff --git a/Source Code/UsablesPatch.cs b/Source Code/UsablesPatch.cs index 5146a49..fb0415f 100644 --- a/Source Code/UsablesPatch.cs +++ b/Source Code/UsablesPatch.cs @@ -4,12 +4,12 @@ using System.IO; using System.Net.Http; using UnityEngine; using System.Linq; -using static BonusRoles.BonusRoles; -using static BonusRoles.GameHistory; +using static TheOtherRoles.TheOtherRoles; +using static TheOtherRoles.GameHistory; using Reactor.Extensions; using System.Collections.Generic; -namespace BonusRoles +namespace TheOtherRoles { [HarmonyPatch(typeof(Vent), "CanUse")]