diff --git a/BetterOtherRoles/BetterOtherRoles.cs b/BetterOtherRoles/BetterOtherRoles.cs index 1a9ebef..b809457 100644 --- a/BetterOtherRoles/BetterOtherRoles.cs +++ b/BetterOtherRoles/BetterOtherRoles.cs @@ -1,2231 +1,77 @@ -using System.Linq; using HarmonyLib; using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using BetterOtherRoles.Objects; -using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; -using static BetterOtherRoles.BetterOtherRoles; -using AmongUs.Data; -using Hazel; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Roles; -namespace BetterOtherRoles -{ - [HarmonyPatch] - public static class BetterOtherRoles - { - public static readonly System.Random Rnd = new System.Random((int)DateTime.Now.Ticks); - - public static void clearAndReloadRoles() { - Jester.clearAndReload(); - Mayor.clearAndReload(); - Portalmaker.clearAndReload(); - Engineer.clearAndReload(); - Sheriff.clearAndReload(); - Deputy.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(); - Hacker.clearAndReload(); - Tracker.clearAndReload(); - Vampire.clearAndReload(); - Snitch.clearAndReload(); - Jackal.clearAndReload(); - Sidekick.clearAndReload(); - Eraser.clearAndReload(); - Spy.clearAndReload(); - Trickster.clearAndReload(); - Cleaner.clearAndReload(); - Warlock.clearAndReload(); - SecurityGuard.clearAndReload(); - Arsonist.clearAndReload(); - BountyHunter.clearAndReload(); - Vulture.clearAndReload(); - Medium.clearAndReload(); - Lawyer.clearAndReload(); - Pursuer.clearAndReload(); - Witch.clearAndReload(); - Ninja.clearAndReload(); - Thief.clearAndReload(); - Trapper.clearAndReload(); - Bomber.clearAndReload(); - Fallen.ClearAndReload(); - Undertaker.ClearAndReload(); - StickyBomber.ClearAndReload(); - - // Modifier - Bait.clearAndReload(); - Bloody.clearAndReload(); - AntiTeleport.clearAndReload(); - Tiebreaker.clearAndReload(); - Sunglasses.clearAndReload(); - Mini.clearAndReload(); - Vip.clearAndReload(); - Invert.clearAndReload(); - Chameleon.clearAndReload(); - - // Gamemodes - HandleGuesser.clearAndReload(); - HideNSeek.clearAndReload(); - - } - - public static class Jester { - public static PlayerControl jester; - public static Color color = new Color32(236, 98, 165, byte.MaxValue); - - public static bool triggerJesterWin = false; - public static bool canCallEmergency = true; - public static bool hasImpostorVision = false; - - public static void clearAndReload() { - jester = null; - triggerJesterWin = false; - canCallEmergency = CustomOptionHolder.jesterCanCallEmergency.getBool(); - hasImpostorVision = CustomOptionHolder.jesterHasImpostorVision.getBool(); - } - } - - public static class Portalmaker { - public static PlayerControl portalmaker; - public static Color color = new Color32(69, 69, 169, byte.MaxValue); - - public static float cooldown; - public static float usePortalCooldown; - public static bool logOnlyHasColors; - public static bool logShowsTime; - public static bool canPortalFromAnywhere; - - private static Sprite placePortalButtonSprite; - private static Sprite usePortalButtonSprite; - private static Sprite usePortalSpecialButtonSprite1; - private static Sprite usePortalSpecialButtonSprite2; - private static Sprite logSprite; - - public static Sprite getPlacePortalButtonSprite() { - if (placePortalButtonSprite) return placePortalButtonSprite; - placePortalButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlacePortalButton.png", 115f); - return placePortalButtonSprite; - } - - public static Sprite getUsePortalButtonSprite() { - if (usePortalButtonSprite) return usePortalButtonSprite; - usePortalButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalButton.png", 115f); - return usePortalButtonSprite; - } - - public static Sprite getUsePortalSpecialButtonSprite(bool first) { - if (first) { - if (usePortalSpecialButtonSprite1) return usePortalSpecialButtonSprite1; - usePortalSpecialButtonSprite1 = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalSpecialButton1.png", 115f); - return usePortalSpecialButtonSprite1; - } else { - if (usePortalSpecialButtonSprite2) return usePortalSpecialButtonSprite2; - usePortalSpecialButtonSprite2 = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalSpecialButton2.png", 115f); - return usePortalSpecialButtonSprite2; - } - } - - public static Sprite getLogSprite() { - if (logSprite) return logSprite; - logSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.DoorLogsButton].Image; - return logSprite; - } - - public static void clearAndReload() { - portalmaker = null; - cooldown = CustomOptionHolder.portalmakerCooldown.getFloat(); - usePortalCooldown = CustomOptionHolder.portalmakerUsePortalCooldown.getFloat(); - logOnlyHasColors = CustomOptionHolder.portalmakerLogOnlyColorType.getBool(); - logShowsTime = CustomOptionHolder.portalmakerLogHasTime.getBool(); - canPortalFromAnywhere = CustomOptionHolder.portalmakerCanPortalFromAnywhere.getBool(); - } - - - } - - public static class Mayor { - public static PlayerControl mayor; - public static Color color = new Color32(32, 77, 66, byte.MaxValue); - public static Minigame emergency = null; - public static Sprite emergencySprite = null; - public static int remoteMeetingsLeft = 1; - - public static bool canSeeVoteColors = false; - public static int tasksNeededToSeeVoteColors; - public static bool meetingButton = true; - public static int mayorChooseSingleVote; - - public static bool voteTwice = true; - - public static Sprite getMeetingSprite() - { - if (emergencySprite) return emergencySprite; - emergencySprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.EmergencyButton.png", 550f); - return emergencySprite; - } - - public static void clearAndReload() { - mayor = null; - emergency = null; - emergencySprite = null; - remoteMeetingsLeft = Mathf.RoundToInt(CustomOptionHolder.mayorMaxRemoteMeetings.getFloat()); - canSeeVoteColors = CustomOptionHolder.mayorCanSeeVoteColors.getBool(); - tasksNeededToSeeVoteColors = (int)CustomOptionHolder.mayorTasksNeededToSeeVoteColors.getFloat(); - meetingButton = CustomOptionHolder.mayorMeetingButton.getBool(); - mayorChooseSingleVote = CustomOptionHolder.mayorChooseSingleVote.getSelection(); - voteTwice = true; - } - } - - public static class Engineer { - public static PlayerControl engineer; - public static Color color = new Color32(0, 40, 245, byte.MaxValue); - private static Sprite buttonSprite; - - public static int remainingFixes = 1; - public static bool highlightForImpostors = true; - public static bool highlightForTeamJackal = true; - - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.RepairButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - engineer = null; - remainingFixes = Mathf.RoundToInt(CustomOptionHolder.engineerNumberOfFixes.getFloat()); - highlightForImpostors = CustomOptionHolder.engineerHighlightForImpostors.getBool(); - highlightForTeamJackal = CustomOptionHolder.engineerHighlightForTeamJackal.getBool(); - } - } - - 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 = 30f; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CleanButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - janitor = null; - cooldown = CustomOptionHolder.janitorCooldown.getFloat(); - } - } - - public static class Sheriff { - public static PlayerControl sheriff; - public static Color color = new Color32(248, 205, 70, byte.MaxValue); - - public static float cooldown = 30f; - public static bool canKillNeutrals = false; - public static bool spyCanDieToSheriff = false; - - public static PlayerControl currentTarget; - - public static PlayerControl formerDeputy; // Needed for keeping handcuffs + shifting - public static PlayerControl formerSheriff; // When deputy gets promoted... - - public static void replaceCurrentSheriff(PlayerControl deputy) - { - if (!formerSheriff) formerSheriff = sheriff; - sheriff = deputy; - currentTarget = null; - cooldown = CustomOptionHolder.sheriffCooldown.getFloat(); - } - - public static void clearAndReload() { - sheriff = null; - currentTarget = null; - formerDeputy = null; - formerSheriff = null; - cooldown = CustomOptionHolder.sheriffCooldown.getFloat(); - canKillNeutrals = CustomOptionHolder.sheriffCanKillNeutrals.getBool(); - spyCanDieToSheriff = CustomOptionHolder.spyCanDieToSheriff.getBool(); - } - } - - public static class Deputy - { - public static PlayerControl deputy; - public static Color color = Sheriff.color; - - public static PlayerControl currentTarget; - public static List handcuffedPlayers = new List(); - public static int promotesToSheriff; // No: 0, Immediately: 1, After Meeting: 2 - public static bool keepsHandcuffsOnPromotion; - public static float handcuffDuration; - public static float remainingHandcuffs; - public static float handcuffCooldown; - public static bool knowsSheriff; - public static Dictionary handcuffedKnows = new Dictionary(); - - private static Sprite buttonSprite; - private static Sprite handcuffedSprite; - - public static Sprite getButtonSprite() - { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DeputyHandcuffButton.png", 115f); - return buttonSprite; - } - - public static Sprite getHandcuffedButtonSprite() - { - if (handcuffedSprite) return handcuffedSprite; - handcuffedSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DeputyHandcuffed.png", 115f); - return handcuffedSprite; - } - - // Can be used to enable / disable the handcuff effect on the target's buttons - public static void setHandcuffedKnows(bool active = true, byte playerId = Byte.MaxValue) - { - if (playerId == Byte.MaxValue) - playerId = CachedPlayer.LocalPlayer.PlayerId; - - if (active && playerId == CachedPlayer.LocalPlayer.PlayerId) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareGhostInfo, Hazel.SendOption.Reliable, -1); - writer.Write(CachedPlayer.LocalPlayer.PlayerId); - writer.Write((byte)RPCProcedure.GhostInfoTypes.HandcuffNoticed); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - - if (active) { - handcuffedKnows.Add(playerId, handcuffDuration); - handcuffedPlayers.RemoveAll(x => x == playerId); - } - - if (playerId == CachedPlayer.LocalPlayer.PlayerId) { - HudManagerStartPatch.setAllButtonsHandcuffedStatus(active); - SoundEffectsManager.play("deputyHandcuff"); - } - - } - - public static void clearAndReload() - { - deputy = null; - currentTarget = null; - handcuffedPlayers = new List(); - handcuffedKnows = new Dictionary(); - HudManagerStartPatch.setAllButtonsHandcuffedStatus(false, true); - promotesToSheriff = CustomOptionHolder.deputyGetsPromoted.getSelection(); - remainingHandcuffs = CustomOptionHolder.deputyNumberOfHandcuffs.getFloat(); - handcuffCooldown = CustomOptionHolder.deputyHandcuffCooldown.getFloat(); - keepsHandcuffsOnPromotion = CustomOptionHolder.deputyKeepsHandcuffs.getBool(); - handcuffDuration = CustomOptionHolder.deputyHandcuffDuration.getFloat(); - knowsSheriff = CustomOptionHolder.deputyKnowsSheriff.getBool(); - } - } - - public static class Lighter { - public static PlayerControl lighter; - public static Color color = new Color32(238, 229, 190, byte.MaxValue); - - public static float lighterModeLightsOnVision = 2f; - public static float lighterModeLightsOffVision = 0.75f; - public static float flashlightWidth = 0.75f; - - public static void clearAndReload() { - lighter = null; - flashlightWidth = CustomOptionHolder.lighterFlashlightWidth.getFloat(); - lighterModeLightsOnVision = CustomOptionHolder.lighterModeLightsOnVision.getFloat(); - lighterModeLightsOffVision = CustomOptionHolder.lighterModeLightsOffVision.getFloat(); - } - } - - public static class Detective { - public static PlayerControl detective; - public static Color color = new Color32(45, 106, 165, byte.MaxValue); - - public static float footprintIntervall = 1f; - public static float footprintDuration = 1f; - public static bool anonymousFootprints = false; - public static float reportNameDuration = 0f; - public static float reportColorDuration = 20f; - public static float timer = 6.2f; - - public static void clearAndReload() { - detective = null; - anonymousFootprints = CustomOptionHolder.detectiveAnonymousFootprints.getBool(); - footprintIntervall = CustomOptionHolder.detectiveFootprintIntervall.getFloat(); - footprintDuration = CustomOptionHolder.detectiveFootprintDuration.getFloat(); - reportNameDuration = CustomOptionHolder.detectiveReportNameDuration.getFloat(); - reportColorDuration = CustomOptionHolder.detectiveReportColorDuration.getFloat(); - timer = 6.2f; - } - } - } - - public static class TimeMaster { - public static PlayerControl timeMaster; - public static Color color = new Color32(112, 142, 239, byte.MaxValue); - - public static bool reviveDuringRewind = false; - public static float rewindTime = 3f; - public static float shieldDuration = 3f; - public static float cooldown = 30f; - - public static bool shieldActive = false; - public static bool isRewinding = false; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TimeShieldButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - timeMaster = null; - isRewinding = false; - shieldActive = false; - rewindTime = CustomOptionHolder.timeMasterRewindTime.getFloat(); - shieldDuration = CustomOptionHolder.timeMasterShieldDuration.getFloat(); - cooldown = CustomOptionHolder.timeMasterCooldown.getFloat(); - } - } - - public static class Medic { - public static PlayerControl medic; - public static PlayerControl shielded; - public static PlayerControl futureShielded; - - public static Color color = new Color32(126, 251, 194, byte.MaxValue); - public static bool usedShield; - - public static int showShielded = 0; - public static bool showAttemptToShielded = false; - public static bool showAttemptToMedic = false; - public static bool setShieldAfterMeeting = false; - public static bool showShieldAfterMeeting = false; - public static bool meetingAfterShielding = false; - - public static Color shieldedColor = new Color32(0, 221, 255, byte.MaxValue); - public static PlayerControl currentTarget; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.ShieldButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - medic = null; - shielded = null; - futureShielded = null; - currentTarget = null; - usedShield = false; - showShielded = CustomOptionHolder.medicShowShielded.getSelection(); - showAttemptToShielded = CustomOptionHolder.medicShowAttemptToShielded.getBool(); - showAttemptToMedic = CustomOptionHolder.medicShowAttemptToMedic.getBool(); - setShieldAfterMeeting = CustomOptionHolder.medicSetOrShowShieldAfterMeeting.getSelection() == 2; - showShieldAfterMeeting = CustomOptionHolder.medicSetOrShowShieldAfterMeeting.getSelection() == 1; - meetingAfterShielding = false; - } - } - - public static class Swapper { - public static PlayerControl swapper; - public static Color color = new Color32(134, 55, 86, byte.MaxValue); - private static Sprite spriteCheck; - public static bool canCallEmergency = false; - public static bool canOnlySwapOthers = false; - public static int charges; - public static float rechargeTasksNumber; - public static float rechargedTasks; - - public static byte playerId1 = Byte.MaxValue; - public static byte playerId2 = Byte.MaxValue; - - public static Sprite getCheckSprite() { - if (spriteCheck) return spriteCheck; - spriteCheck = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SwapperCheck.png", 150f); - return spriteCheck; - } - - public static void clearAndReload() { - swapper = null; - playerId1 = Byte.MaxValue; - playerId2 = Byte.MaxValue; - canCallEmergency = CustomOptionHolder.swapperCanCallEmergency.getBool(); - canOnlySwapOthers = CustomOptionHolder.swapperCanOnlySwapOthers.getBool(); - charges = Mathf.RoundToInt(CustomOptionHolder.swapperSwapsNumber.getFloat()); - rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.swapperRechargeTasksNumber.getFloat()); - rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.swapperRechargeTasksNumber.getFloat()); - } - } - - public static class Lovers { - public static PlayerControl lover1; - public static PlayerControl lover2; - public static Color color = new Color32(232, 57, 185, byte.MaxValue); - - public static bool bothDie = true; - public static bool enableChat = 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 existing() { - return lover1 != null && lover2 != null && !lover1.Data.Disconnected && !lover2.Data.Disconnected; - } - - public static bool existingAndAlive() { - return existing() && !lover1.Data.IsDead && !lover2.Data.IsDead && !notAckedExiledIsLover; // ADD NOT ACKED IS LOVER - } - - public static PlayerControl otherLover(PlayerControl oneLover) { - if (!existingAndAlive()) return null; - if (oneLover == lover1) return lover2; - if (oneLover == lover2) return lover1; - return null; - } - - public static bool existingWithKiller() { - return existing() && (lover1 == Jackal.jackal || lover2 == Jackal.jackal - || lover1 == Sidekick.sidekick || lover2 == Sidekick.sidekick - || lover1.Data.Role.IsImpostor || lover2.Data.Role.IsImpostor); - } - - public static bool hasAliveKillingLover(this PlayerControl player) { - if (!Lovers.existingAndAlive() || !existingWithKiller()) - return false; - return (player != null && (player == lover1 || player == lover2)); - } - - public static void clearAndReload() { - lover1 = null; - lover2 = null; - notAckedExiledIsLover = false; - bothDie = CustomOptionHolder.modifierLoverBothDie.getBool(); - enableChat = CustomOptionHolder.modifierLoverEnableChat.getBool(); - } - - public static PlayerControl getPartner(this PlayerControl player) { - if (player == null) - return null; - if (lover1 == player) - return lover2; - if (lover2 == player) - return lover1; - return null; - } - } - - public static class Seer { - public static PlayerControl seer; - public static Color color = new Color32(97, 178, 108, byte.MaxValue); - public static List deadBodyPositions = new List(); - - public static float soulDuration = 15f; - public static bool limitSoulDuration = false; - public static int mode = 0; - - private static Sprite soulSprite; - public static Sprite getSoulSprite() { - if (soulSprite) return soulSprite; - soulSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Soul.png", 500f); - return soulSprite; - } - - public static void clearAndReload() { - seer = null; - deadBodyPositions = new List(); - limitSoulDuration = CustomOptionHolder.seerLimitSoulDuration.getBool(); - soulDuration = CustomOptionHolder.seerSoulDuration.getFloat(); - mode = CustomOptionHolder.seerMode.getSelection(); - } - } - - 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 = 30f; - public static float duration = 10f; - - public static PlayerControl currentTarget; - public static PlayerControl sampledTarget; - public static PlayerControl morphTarget; - public static float morphTimer = 0f; - - public static void resetMorph() { - morphTarget = null; - morphTimer = 0f; - if (morphling == null) return; - morphling.setDefaultLook(); - } - - public static void clearAndReload() { - resetMorph(); - morphling = null; - currentTarget = null; - sampledTarget = null; - morphTarget = null; - morphTimer = 0f; - cooldown = CustomOptionHolder.morphlingCooldown.getFloat(); - duration = CustomOptionHolder.morphlingDuration.getFloat(); - } - - public static Sprite getSampleSprite() { - if (sampleSprite) return sampleSprite; - sampleSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SampleButton.png", 115f); - return sampleSprite; - } - - public static Sprite getMorphSprite() { - if (morphSprite) return morphSprite; - morphSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.MorphButton.png", 115f); - return morphSprite; - } - } - - public static class Camouflager { - public static PlayerControl camouflager; - public static Color color = Palette.ImpostorRed; - - public static float cooldown = 30f; - public static float duration = 10f; - public static float camouflageTimer = 0f; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CamoButton.png", 115f); - return buttonSprite; - } - - public static void resetCamouflage() { - camouflageTimer = 0f; - foreach (PlayerControl p in CachedPlayer.AllPlayers) { - if (p == Ninja.ninja && Ninja.isInvisble) - continue; - p.setDefaultLook(); - } - } - - public static void clearAndReload() { - resetCamouflage(); - camouflager = null; - camouflageTimer = 0f; - cooldown = CustomOptionHolder.camouflagerCooldown.getFloat(); - duration = CustomOptionHolder.camouflagerDuration.getFloat(); - } - } - - public static class Hacker { - public static PlayerControl hacker; - public static Minigame vitals = null; - public static Minigame doorLog = null; - public static Color color = new Color32(117, 250, 76, byte.MaxValue); - - public static float cooldown = 30f; - public static float duration = 10f; - public static float toolsNumber = 5f; - public static bool onlyColorType = false; - public static float hackerTimer = 0f; - public static int rechargeTasksNumber = 2; - public static int rechargedTasks = 2; - public static int chargesVitals = 1; - public static int chargesAdminTable = 1; - public static bool cantMove = true; - - private static Sprite buttonSprite; - private static Sprite vitalsSprite; - private static Sprite logSprite; - private static Sprite adminSprite; - - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.HackerButton.png", 115f); - return buttonSprite; - } - - public static Sprite getVitalsSprite() { - if (vitalsSprite) return vitalsSprite; - vitalsSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.VitalsButton].Image; - return vitalsSprite; - } - - public static Sprite getLogSprite() { - if (logSprite) return logSprite; - logSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.DoorLogsButton].Image; - return logSprite; - } - - public static Sprite getAdminSprite() { - byte mapId = GameOptionsManager.Instance.currentNormalGameOptions.MapId; - UseButtonSettings button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.PolusAdminButton]; // Polus - if (mapId == 0 || mapId == 3) button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.AdminMapButton]; // Skeld || Dleks - else if (mapId == 1) button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.MIRAAdminButton]; // Mira HQ - else if (mapId == 4) button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.AirshipAdminButton]; // Airship - adminSprite = button.Image; - return adminSprite; - } - - public static void clearAndReload() { - hacker = null; - vitals = null; - doorLog = null; - hackerTimer = 0f; - adminSprite = null; - cooldown = CustomOptionHolder.hackerCooldown.getFloat(); - duration = CustomOptionHolder.hackerHackeringDuration.getFloat(); - onlyColorType = CustomOptionHolder.hackerOnlyColorType.getBool(); - toolsNumber = CustomOptionHolder.hackerToolsNumber.getFloat(); - rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.hackerRechargeTasksNumber.getFloat()); - rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.hackerRechargeTasksNumber.getFloat()); - chargesVitals = Mathf.RoundToInt(CustomOptionHolder.hackerToolsNumber.getFloat()) / 2; - chargesAdminTable = Mathf.RoundToInt(CustomOptionHolder.hackerToolsNumber.getFloat()) / 2; - cantMove = CustomOptionHolder.hackerNoMove.getBool(); - } - } - - public static class Tracker { - public static PlayerControl tracker; - public static Color color = new Color32(100, 58, 220, byte.MaxValue); - public static List localArrows = new List(); - - public static float updateIntervall = 5f; - public static bool resetTargetAfterMeeting = false; - public static bool canTrackCorpses = false; - public static float corpsesTrackingCooldown = 30f; - public static float corpsesTrackingDuration = 5f; - public static float corpsesTrackingTimer = 0f; - public static List deadBodyPositions = new List(); - - 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 trackCorpsesButtonSprite; - public static Sprite getTrackCorpsesButtonSprite() - { - if (trackCorpsesButtonSprite) return trackCorpsesButtonSprite; - trackCorpsesButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PathfindButton.png", 115f); - return trackCorpsesButtonSprite; - } - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TrackerButton.png", 115f); - return buttonSprite; - } - - public static void resetTracked() { - currentTarget = tracked = null; - usedTracker = false; - if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); - arrow = new Arrow(Color.blue); - if (arrow.arrow != null) arrow.arrow.SetActive(false); - } - - public static void clearAndReload() { - tracker = null; - resetTracked(); - timeUntilUpdate = 0f; - updateIntervall = CustomOptionHolder.trackerUpdateIntervall.getFloat(); - resetTargetAfterMeeting = CustomOptionHolder.trackerResetTargetAfterMeeting.getBool(); - if (localArrows != null) { - foreach (Arrow arrow in localArrows) - if (arrow?.arrow != null) - UnityEngine.Object.Destroy(arrow.arrow); - } - deadBodyPositions = new List(); - corpsesTrackingTimer = 0f; - corpsesTrackingCooldown = CustomOptionHolder.trackerCorpsesTrackingCooldown.getFloat(); - corpsesTrackingDuration = CustomOptionHolder.trackerCorpsesTrackingDuration.getFloat(); - canTrackCorpses = CustomOptionHolder.trackerCanTrackCorpses.getBool(); - } - } - - public static class Vampire { - public static PlayerControl vampire; - public static Color color = Palette.ImpostorRed; - - public static float delay = 10f; - public static float cooldown = 30f; - public static bool canKillNearGarlics = true; - 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("BetterOtherRoles.Resources.VampireButton.png", 115f); - return buttonSprite; - } - - private static Sprite garlicButtonSprite; - public static Sprite getGarlicButtonSprite() { - if (garlicButtonSprite) return garlicButtonSprite; - garlicButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.GarlicButton.png", 115f); - return garlicButtonSprite; - } - - public static void clearAndReload() { - vampire = null; - bitten = null; - targetNearGarlic = false; - localPlacedGarlic = false; - currentTarget = null; - garlicsActive = CustomOptionHolder.vampireSpawnRate.getSelection() > 0; - delay = CustomOptionHolder.vampireKillDelay.getFloat(); - cooldown = CustomOptionHolder.vampireCooldown.getFloat(); - canKillNearGarlics = CustomOptionHolder.vampireCanKillNearGarlics.getBool(); - } - } - - public static class Snitch { - public static PlayerControl snitch; - public static Color color = new Color32(184, 251, 79, byte.MaxValue); - public enum Mode { - Chat = 0, - Map = 1, - ChatAndMap = 2 - } - public enum Targets { - EvilPlayers = 0, - Killers = 1 - } - - public static Mode mode = Mode.Chat; - public static Targets targets = Targets.EvilPlayers; - public static int taskCountForReveal = 1; - - public static bool isRevealed = false; - public static Dictionary playerRoomMap = new Dictionary(); - public static TMPro.TextMeshPro text = null; - public static bool needsUpdate = true; - - public static void clearAndReload() { - taskCountForReveal = Mathf.RoundToInt(CustomOptionHolder.snitchLeftTasksForReveal.getFloat()); - snitch = null; - isRevealed = false; - playerRoomMap = new Dictionary(); - if (text != null) UnityEngine.Object.Destroy(text); - text = null; - needsUpdate = true; - mode = (Mode) CustomOptionHolder.snitchMode.getSelection(); - targets = (Targets) CustomOptionHolder.snitchTargets.getSelection(); - } - } - - public static class Jackal { - public static PlayerControl jackal; - public static Color color = new Color32(0, 180, 235, byte.MaxValue); - public static PlayerControl fakeSidekick; - public static PlayerControl currentTarget; - public static List formerJackals = new List(); - - public static float cooldown = 30f; - public static float createSidekickCooldown = 30f; - public static bool canUseVents = true; - public static bool canCreateSidekick = true; - public static Sprite buttonSprite; - public static bool jackalPromotedFromSidekickCanCreateSidekick = true; - public static bool canCreateSidekickFromImpostor = true; - public static bool hasImpostorVision = false; - public static bool wasTeamRed; - public static bool wasImpostor; - public static bool wasSpy; - - public static Sprite getSidekickButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SidekickButton.png", 115f); - return buttonSprite; - } - - public static void removeCurrentJackal() { - if (!formerJackals.Any(x => x.PlayerId == jackal.PlayerId)) formerJackals.Add(jackal); - jackal = null; - currentTarget = null; - fakeSidekick = null; - cooldown = CustomOptionHolder.jackalKillCooldown.getFloat(); - createSidekickCooldown = CustomOptionHolder.jackalCreateSidekickCooldown.getFloat(); - } - - public static void clearAndReload() { - jackal = null; - currentTarget = null; - fakeSidekick = null; - cooldown = CustomOptionHolder.jackalKillCooldown.getFloat(); - createSidekickCooldown = CustomOptionHolder.jackalCreateSidekickCooldown.getFloat(); - canUseVents = CustomOptionHolder.jackalCanUseVents.getBool(); - canCreateSidekick = CustomOptionHolder.jackalCanCreateSidekick.getBool(); - jackalPromotedFromSidekickCanCreateSidekick = CustomOptionHolder.jackalPromotedFromSidekickCanCreateSidekick.getBool(); - canCreateSidekickFromImpostor = CustomOptionHolder.jackalCanCreateSidekickFromImpostor.getBool(); - formerJackals.Clear(); - hasImpostorVision = CustomOptionHolder.jackalAndSidekickHaveImpostorVision.getBool(); - wasTeamRed = wasImpostor = wasSpy = false; - } - - } - - public static class Sidekick { - public static PlayerControl sidekick; - public static Color color = new Color32(0, 180, 235, byte.MaxValue); - - public static PlayerControl currentTarget; - - public static bool wasTeamRed; - public static bool wasImpostor; - public static bool wasSpy; - - public static float cooldown = 30f; - public static bool canUseVents = true; - public static bool canKill = true; - public static bool promotesToJackal = true; - public static bool hasImpostorVision = false; - - public static void clearAndReload() { - sidekick = null; - currentTarget = null; - cooldown = CustomOptionHolder.jackalKillCooldown.getFloat(); - canUseVents = CustomOptionHolder.sidekickCanUseVents.getBool(); - canKill = CustomOptionHolder.sidekickCanKill.getBool(); - promotesToJackal = CustomOptionHolder.sidekickPromotesToJackal.getBool(); - hasImpostorVision = CustomOptionHolder.jackalAndSidekickHaveImpostorVision.getBool(); - wasTeamRed = wasImpostor = wasSpy = false; - } - } - - public static class Eraser { - public static PlayerControl eraser; - public static Color color = Palette.ImpostorRed; - - public static List alreadyErased = new List(); - - public static List futureErased = new List(); - public static PlayerControl currentTarget; - public static float cooldown = 30f; - public static bool canEraseAnyone = false; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.EraserButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - eraser = null; - futureErased = new List(); - currentTarget = null; - cooldown = CustomOptionHolder.eraserCooldown.getFloat(); - canEraseAnyone = CustomOptionHolder.eraserCanEraseAnyone.getBool(); - alreadyErased = new List(); - } - } - - public static class Spy { - public static PlayerControl spy; - public static Color color = Palette.ImpostorRed; - - public static bool impostorsCanKillAnyone = true; - public static bool canEnterVents = false; - public static bool hasImpostorVision = false; - - public static void clearAndReload() { - spy = null; - impostorsCanKillAnyone = CustomOptionHolder.spyImpostorsCanKillAnyone.getBool(); - canEnterVents = CustomOptionHolder.spyCanEnterVents.getBool(); - hasImpostorVision = CustomOptionHolder.spyHasImpostorVision.getBool(); - } - } - - public static class Trickster { - public static PlayerControl trickster; - public static Color color = Palette.ImpostorRed; - public static float placeBoxCooldown = 30f; - public static float lightsOutCooldown = 30f; - public static float lightsOutDuration = 10f; - public static float lightsOutTimer = 0f; - - private static Sprite placeBoxButtonSprite; - private static Sprite lightOutButtonSprite; - private static Sprite tricksterVentButtonSprite; - - public static Sprite getPlaceBoxButtonSprite() { - if (placeBoxButtonSprite) return placeBoxButtonSprite; - placeBoxButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlaceJackInTheBoxButton.png", 115f); - return placeBoxButtonSprite; - } - - public static Sprite getLightsOutButtonSprite() { - if (lightOutButtonSprite) return lightOutButtonSprite; - lightOutButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.LightsOutButton.png", 115f); - return lightOutButtonSprite; - } - - public static Sprite getTricksterVentButtonSprite() { - if (tricksterVentButtonSprite) return tricksterVentButtonSprite; - tricksterVentButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TricksterVentButton.png", 115f); - return tricksterVentButtonSprite; - } - - public static void clearAndReload() { - trickster = null; - lightsOutTimer = 0f; - placeBoxCooldown = CustomOptionHolder.tricksterPlaceBoxCooldown.getFloat(); - lightsOutCooldown = CustomOptionHolder.tricksterLightsOutCooldown.getFloat(); - lightsOutDuration = CustomOptionHolder.tricksterLightsOutDuration.getFloat(); - JackInTheBox.UpdateStates(); // if the role is erased, we might have to update the state of the created objects - } - - } - - public static class Cleaner { - public static PlayerControl cleaner; - public static Color color = Palette.ImpostorRed; - - public static float cooldown = 30f; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CleanButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - cleaner = null; - cooldown = CustomOptionHolder.cleanerCooldown.getFloat(); - } - } - - public static class Warlock { - - public static PlayerControl warlock; - public static Color color = Palette.ImpostorRed; +namespace BetterOtherRoles; - public static PlayerControl currentTarget; - public static PlayerControl curseVictim; - public static PlayerControl curseVictimTarget; - - public static float cooldown = 30f; - public static float rootTime = 5f; - - private static Sprite curseButtonSprite; - private static Sprite curseKillButtonSprite; - - public static Sprite getCurseButtonSprite() { - if (curseButtonSprite) return curseButtonSprite; - curseButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CurseButton.png", 115f); - return curseButtonSprite; - } - - public static Sprite getCurseKillButtonSprite() { - if (curseKillButtonSprite) return curseKillButtonSprite; - curseKillButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CurseKillButton.png", 115f); - return curseKillButtonSprite; - } - - public static void clearAndReload() { - warlock = null; - currentTarget = null; - curseVictim = null; - curseVictimTarget = null; - cooldown = CustomOptionHolder.warlockCooldown.getFloat(); - rootTime = CustomOptionHolder.warlockRootTime.getFloat(); - } - - public static void resetCurse() { - HudManagerStartPatch.warlockCurseButton.Timer = HudManagerStartPatch.warlockCurseButton.MaxTimer; - HudManagerStartPatch.warlockCurseButton.Sprite = Warlock.getCurseButtonSprite(); - HudManagerStartPatch.warlockCurseButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; - currentTarget = null; - curseVictim = null; - curseVictimTarget = null; - } - } - - public static class SecurityGuard { - public static PlayerControl securityGuard; - public static Color color = new Color32(195, 178, 95, byte.MaxValue); - - public static float cooldown = 30f; - public static int remainingScrews = 7; - public static int totalScrews = 7; - public static int ventPrice = 1; - public static int camPrice = 2; - public static int placedCameras = 0; - public static float duration = 10f; - public static int maxCharges = 5; - public static int rechargeTasksNumber = 3; - public static int rechargedTasks = 3; - public static int charges = 1; - public static bool cantMove = true; - public static Vent ventTarget = null; - public static Minigame minigame = null; - - private static Sprite closeVentButtonSprite; - public static Sprite getCloseVentButtonSprite() { - if (closeVentButtonSprite) return closeVentButtonSprite; - closeVentButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CloseVentButton.png", 115f); - return closeVentButtonSprite; - } - - private static Sprite placeCameraButtonSprite; - public static Sprite getPlaceCameraButtonSprite() { - if (placeCameraButtonSprite) return placeCameraButtonSprite; - placeCameraButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlaceCameraButton.png", 115f); - return placeCameraButtonSprite; - } - - private static Sprite animatedVentSealedSprite; - private static float lastPPU; - public static Sprite getAnimatedVentSealedSprite() { - float ppu = 185f; - if (SubmergedCompatibility.IsSubmerged) ppu = 120f; - if (lastPPU != ppu) { - animatedVentSealedSprite = null; - lastPPU = ppu; - } - if (animatedVentSealedSprite) return animatedVentSealedSprite; - animatedVentSealedSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.AnimatedVentSealed.png", ppu); - return animatedVentSealedSprite; - } - - private static Sprite staticVentSealedSprite; - public static Sprite getStaticVentSealedSprite() { - if (staticVentSealedSprite) return staticVentSealedSprite; - staticVentSealedSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StaticVentSealed.png", 160f); - return staticVentSealedSprite; - } - - private static Sprite submergedCentralUpperVentSealedSprite; - public static Sprite getSubmergedCentralUpperSealedSprite() { - if (submergedCentralUpperVentSealedSprite) return submergedCentralUpperVentSealedSprite; - submergedCentralUpperVentSealedSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CentralUpperBlocked.png", 145f); - return submergedCentralUpperVentSealedSprite; - } - - private static Sprite submergedCentralLowerVentSealedSprite; - public static Sprite getSubmergedCentralLowerSealedSprite() { - if (submergedCentralLowerVentSealedSprite) return submergedCentralLowerVentSealedSprite; - submergedCentralLowerVentSealedSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CentralLowerBlocked.png", 145f); - return submergedCentralLowerVentSealedSprite; - } - - private static Sprite camSprite; - public static Sprite getCamSprite() { - if (camSprite) return camSprite; - camSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.CamsButton].Image; - return camSprite; - } - - private static Sprite logSprite; - public static Sprite getLogSprite() { - if (logSprite) return logSprite; - logSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.DoorLogsButton].Image; - return logSprite; - } - - public static void clearAndReload() { - securityGuard = null; - ventTarget = null; - minigame = null; - duration = CustomOptionHolder.securityGuardCamDuration.getFloat(); - maxCharges = Mathf.RoundToInt(CustomOptionHolder.securityGuardCamMaxCharges.getFloat()); - rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.securityGuardCamRechargeTasksNumber.getFloat()); - rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.securityGuardCamRechargeTasksNumber.getFloat()); - charges = Mathf.RoundToInt(CustomOptionHolder.securityGuardCamMaxCharges.getFloat()) /2; - placedCameras = 0; - cooldown = CustomOptionHolder.securityGuardCooldown.getFloat(); - totalScrews = remainingScrews = Mathf.RoundToInt(CustomOptionHolder.securityGuardTotalScrews.getFloat()); - camPrice = Mathf.RoundToInt(CustomOptionHolder.securityGuardCamPrice.getFloat()); - ventPrice = Mathf.RoundToInt(CustomOptionHolder.securityGuardVentPrice.getFloat()); - cantMove = CustomOptionHolder.securityGuardNoMove.getBool(); - } - } - - public static class Arsonist { - public static PlayerControl arsonist; - public static Color color = new Color32(238, 112, 46, byte.MaxValue); - - public static float cooldown = 30f; - public static float duration = 3f; - public static bool triggerArsonistWin = false; - - public static PlayerControl currentTarget; - public static PlayerControl douseTarget; - public static List dousedPlayers = new List(); - - private static Sprite douseSprite; - public static Sprite getDouseSprite() { - if (douseSprite) return douseSprite; - douseSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DouseButton.png", 115f); - return douseSprite; - } - - private static Sprite igniteSprite; - public static Sprite getIgniteSprite() { - if (igniteSprite) return igniteSprite; - igniteSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.IgniteButton.png", 115f); - return igniteSprite; - } - - public static bool dousedEveryoneAlive() { - return CachedPlayer.AllPlayers.All(x => { return x.PlayerControl == Arsonist.arsonist || x.Data.IsDead || x.Data.Disconnected || Arsonist.dousedPlayers.Any(y => y.PlayerId == x.PlayerId); }); - } - - public static void clearAndReload() { - arsonist = null; - currentTarget = null; - douseTarget = null; - triggerArsonistWin = false; - dousedPlayers = new List(); - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } - cooldown = CustomOptionHolder.arsonistCooldown.getFloat(); - duration = CustomOptionHolder.arsonistDuration.getFloat(); - } - } - - public static class Guesser { - public static PlayerControl niceGuesser; - public static PlayerControl evilGuesser; - public static Color color = new Color32(255, 255, 0, byte.MaxValue); - - public static int remainingShotsEvilGuesser = 2; - public static int remainingShotsNiceGuesser = 2; - - public static bool isGuesser (byte playerId) { - if ((niceGuesser != null && niceGuesser.PlayerId == playerId) || (evilGuesser != null && evilGuesser.PlayerId == playerId)) return true; - return false; - } - - public static void clear (byte playerId) { - if (niceGuesser != null && niceGuesser.PlayerId == playerId) niceGuesser = null; - else if (evilGuesser != null && evilGuesser.PlayerId == playerId) evilGuesser = null; - } - - public static int remainingShots(byte playerId, bool shoot = false) { - int remainingShots = remainingShotsEvilGuesser; - if (niceGuesser != null && niceGuesser.PlayerId == playerId) { - remainingShots = remainingShotsNiceGuesser; - if (shoot) remainingShotsNiceGuesser = Mathf.Max(0, remainingShotsNiceGuesser - 1); - } else if (shoot) { - remainingShotsEvilGuesser = Mathf.Max(0, remainingShotsEvilGuesser - 1); - } - return remainingShots; - } - - public static void clearAndReload() { - niceGuesser = null; - evilGuesser = null; - remainingShotsEvilGuesser = Mathf.RoundToInt(CustomOptionHolder.guesserNumberOfShots.getFloat()); - remainingShotsNiceGuesser = Mathf.RoundToInt(CustomOptionHolder.guesserNumberOfShots.getFloat()); - } - } - - public static class BountyHunter { - public static PlayerControl bountyHunter; - public static Color color = Palette.ImpostorRed; - - public static Arrow arrow; - public static float bountyDuration = 30f; - public static bool showArrow = true; - public static float bountyKillCooldown = 0f; - public static float punishmentTime = 15f; - public static float arrowUpdateIntervall = 10f; - - public static float arrowUpdateTimer = 0f; - public static float bountyUpdateTimer = 0f; - public static PlayerControl bounty; - public static TMPro.TextMeshPro cooldownText; - - public static void clearAndReload() { - arrow = new Arrow(color); - bountyHunter = null; - bounty = null; - arrowUpdateTimer = 0f; - bountyUpdateTimer = 0f; - if (arrow != null && arrow.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); - arrow = null; - if (cooldownText != null && cooldownText.gameObject != null) UnityEngine.Object.Destroy(cooldownText.gameObject); - cooldownText = null; - foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) { - if (p != null && p.gameObject != null) p.gameObject.SetActive(false); - } - - - bountyDuration = CustomOptionHolder.bountyHunterBountyDuration.getFloat(); - bountyKillCooldown = CustomOptionHolder.bountyHunterReducedCooldown.getFloat(); - punishmentTime = CustomOptionHolder.bountyHunterPunishmentTime.getFloat(); - showArrow = CustomOptionHolder.bountyHunterShowArrow.getBool(); - arrowUpdateIntervall = CustomOptionHolder.bountyHunterArrowUpdateIntervall.getFloat(); - } - } - - public static class Vulture { - public static PlayerControl vulture; - public static Color color = new Color32(139, 69, 19, byte.MaxValue); - public static List localArrows = new List(); - public static float cooldown = 30f; - public static int vultureNumberToWin = 4; - public static int eatenBodies = 0; - public static bool triggerVultureWin = false; - public static bool canUseVents = true; - public static bool showArrows = true; - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.VultureButton.png", 115f); - return buttonSprite; - } - - public static void clearAndReload() { - vulture = null; - vultureNumberToWin = Mathf.RoundToInt(CustomOptionHolder.vultureNumberToWin.getFloat()); - eatenBodies = 0; - cooldown = CustomOptionHolder.vultureCooldown.getFloat(); - triggerVultureWin = false; - canUseVents = CustomOptionHolder.vultureCanUseVents.getBool(); - showArrows = CustomOptionHolder.vultureShowArrows.getBool(); - if (localArrows != null) { - foreach (Arrow arrow in localArrows) - if (arrow?.arrow != null) - UnityEngine.Object.Destroy(arrow.arrow); - } - localArrows = new List(); - } - } - - - public static class Medium { - public static PlayerControl medium; - public static DeadPlayer target; - public static DeadPlayer soulTarget; - public static Color color = new Color32(98, 120, 115, byte.MaxValue); - public static List> deadBodies = new List>(); - public static List> futureDeadBodies = new List>(); - public static List souls = new List(); - public static DateTime meetingStartTime = DateTime.UtcNow; - - public static float cooldown = 30f; - public static float duration = 3f; - public static bool oneTimeUse = false; - public static float chanceAdditionalInfo = 0f; - - private static Sprite soulSprite; - - enum SpecialMediumInfo { - SheriffSuicide, - ThiefSuicide, - ActiveLoverDies, - PassiveLoverSuicide, - LawyerKilledByClient, - JackalKillsSidekick, - ImpostorTeamkill, - SubmergedO2, - WarlockSuicide, - BodyCleaned, - } - - public static Sprite getSoulSprite() { - if (soulSprite) return soulSprite; - soulSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Soul.png", 500f); - return soulSprite; - } - - private static Sprite question; - public static Sprite getQuestionSprite() { - if (question) return question; - question = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.MediumButton.png", 115f); - return question; - } - - public static void clearAndReload() { - medium = null; - target = null; - soulTarget = null; - deadBodies = new List>(); - futureDeadBodies = new List>(); - souls = new List(); - meetingStartTime = DateTime.UtcNow; - cooldown = CustomOptionHolder.mediumCooldown.getFloat(); - duration = CustomOptionHolder.mediumDuration.getFloat(); - oneTimeUse = CustomOptionHolder.mediumOneTimeUse.getBool(); - chanceAdditionalInfo = CustomOptionHolder.mediumChanceAdditionalInfo.getSelection() / 10f; - } - - public static string getInfo(PlayerControl target, PlayerControl killer) { - string msg = ""; - - List infos = new List(); - // collect fitting death info types. - // suicides: - if (killer == target) { - if (target == Sheriff.sheriff || target == Sheriff.formerSheriff) infos.Add(SpecialMediumInfo.SheriffSuicide); - if (target == Lovers.lover1 || target == Lovers.lover2) infos.Add(SpecialMediumInfo.PassiveLoverSuicide); - if (target == Thief.thief) infos.Add(SpecialMediumInfo.ThiefSuicide); - if (target == Warlock.warlock) infos.Add(SpecialMediumInfo.WarlockSuicide); - } else { - if (target == Lovers.lover1 || target == Lovers.lover2) infos.Add(SpecialMediumInfo.ActiveLoverDies); - if (target.Data.Role.IsImpostor && killer.Data.Role.IsImpostor && Thief.formerThief != killer) infos.Add(SpecialMediumInfo.ImpostorTeamkill); - } - if (target == Sidekick.sidekick && (killer == Jackal.jackal || Jackal.formerJackals.Any(x => x.PlayerId == killer.PlayerId))) infos.Add(SpecialMediumInfo.JackalKillsSidekick); - if (target == Lawyer.lawyer && killer == Lawyer.target) infos.Add(SpecialMediumInfo.LawyerKilledByClient); - if (Medium.target.wasCleaned) infos.Add(SpecialMediumInfo.BodyCleaned); - - if (infos.Count > 0) { - var selectedInfo = infos[Rnd.Next(infos.Count)]; - switch (selectedInfo) { - case SpecialMediumInfo.SheriffSuicide: - msg = "Yikes, that Sheriff shot backfired."; - break; - case SpecialMediumInfo.WarlockSuicide: - msg = "MAYBE I cursed the person next to me and killed myself. Oops."; - break; - case SpecialMediumInfo.ThiefSuicide: - msg = "I tried to steal the gun from their pocket, but they were just happy to see me."; - break; - case SpecialMediumInfo.ActiveLoverDies: - msg = "I wanted to get out of this toxic relationship anyways."; - break; - case SpecialMediumInfo.PassiveLoverSuicide: - msg = "The love of my life died, thus with a kiss I die."; - break; - case SpecialMediumInfo.LawyerKilledByClient: - msg = "My client killed me. Do I still get paid?"; - break; - case SpecialMediumInfo.JackalKillsSidekick: - msg = "First they sidekicked me, then they killed me. At least I don't need to do tasks anymore."; - break; - case SpecialMediumInfo.ImpostorTeamkill: - msg = "I guess they confused me for the Spy, is there even one?"; - break; - case SpecialMediumInfo.BodyCleaned: - msg = "Is my dead body some kind of art now or... aaand it's gone."; - break; - } - } else { - int randomNumber = Rnd.Next(4); - string typeOfColor = Helpers.isLighterColor(Medium.target.killerIfExisting.Data.DefaultOutfit.ColorId) ? "lighter" : "darker"; - float timeSinceDeath = ((float)(Medium.meetingStartTime - Medium.target.timeOfDeath).TotalMilliseconds); - - if (randomNumber == 0) msg = "If my role hasn't been saved, there's no " + RoleInfo.GetRolesString(Medium.target.player, false) + " in the game anymore."; - else if (randomNumber == 1) msg = "I'm not sure, but I guess a " + typeOfColor + " color killed me."; - else if (randomNumber == 2) msg = "If I counted correctly, I died " + Math.Round(timeSinceDeath / 1000) + "s before the next meeting started."; - else msg = "It seems like my killer was the " + RoleInfo.GetRolesString(Medium.target.killerIfExisting, false, false, true) + "."; - } - - if (Rnd.NextDouble() < chanceAdditionalInfo) { - int count = 0; - string condition = ""; - var alivePlayersList = PlayerControl.AllPlayerControls.ToArray().Where(pc => !pc.Data.IsDead); - switch (Rnd.Next(3)) { - case 0: - count = alivePlayersList.Where(pc => pc.Data.Role.IsImpostor || new List() { RoleInfo.jackal, RoleInfo.sidekick, RoleInfo.sheriff, RoleInfo.thief }.Contains(RoleInfo.getRoleInfoForPlayer(pc, false).FirstOrDefault())).Count(); - condition = "killer" + (count == 1 ? "" : "s"); - break; - case 1: - count = alivePlayersList.Where(Helpers.roleCanUseVents).Count(); - condition = "player" + (count == 1 ? "" : "s") + " who can use vents"; - break; - case 2: - count = alivePlayersList.Where(pc => Helpers.isNeutral(pc) && pc != Jackal.jackal && pc != Sidekick.sidekick && pc != Thief.thief).Count(); - condition = "player" + (count == 1 ? "" : "s") + " who " + (count == 1 ? "is" : "are") + " neutral but cannot kill"; - break; - case 3: - //count = alivePlayersList.Where(pc => - break; - } - msg += $"\nWhen you asked, {count} " + condition + (count == 1 ? " was" : " were") + " still alive"; - } - - return Medium.target.player.Data.PlayerName + "'s Soul:\n" + msg; - } - } - - public static class Lawyer { - public static PlayerControl lawyer; - public static PlayerControl target; - public static Color color = new Color32(134, 153, 25, byte.MaxValue); - public static Sprite targetSprite; - public static bool triggerProsecutorWin = false; - public static bool isProsecutor = false; - public static bool canCallEmergency = true; - - public static float vision = 1f; - public static bool lawyerKnowsRole = false; - public static bool targetCanBeJester = false; - public static bool targetWasGuessed = false; - - public static Sprite getTargetSprite() { - if (targetSprite) return targetSprite; - targetSprite = Helpers.loadSpriteFromResources("", 150f); - return targetSprite; - } - - public static void clearAndReload(bool clearTarget = true) { - lawyer = null; - if (clearTarget) { - target = null; - targetWasGuessed = false; - } - isProsecutor = false; - triggerProsecutorWin = false; - vision = CustomOptionHolder.lawyerVision.getFloat(); - lawyerKnowsRole = CustomOptionHolder.lawyerKnowsRole.getBool(); - targetCanBeJester = CustomOptionHolder.lawyerTargetCanBeJester.getBool(); - canCallEmergency = CustomOptionHolder.jesterCanCallEmergency.getBool(); - } - } - - public static class Pursuer { - public static PlayerControl pursuer; - public static PlayerControl target; - public static Color color = Lawyer.color; - public static List blankedList = new List(); - public static int blanks = 0; - public static Sprite blank; - public static bool notAckedExiled = false; - - public static float cooldown = 30f; - public static int blanksNumber = 5; - - public static Sprite getTargetSprite() { - if (blank) return blank; - blank = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PursuerButton.png", 115f); - return blank; - } - - public static void clearAndReload() { - pursuer = null; - target = null; - blankedList = new List(); - blanks = 0; - notAckedExiled = false; - - cooldown = CustomOptionHolder.pursuerCooldown.getFloat(); - blanksNumber = Mathf.RoundToInt(CustomOptionHolder.pursuerBlanksNumber.getFloat()); - } - } - - public static class Witch { - public static PlayerControl witch; - public static Color color = Palette.ImpostorRed; - - public static List futureSpelled = new List(); - public static PlayerControl currentTarget; - public static PlayerControl spellCastingTarget; - public static float cooldown = 30f; - public static float spellCastingDuration = 2f; - public static float cooldownAddition = 10f; - public static float currentCooldownAddition = 0f; - public static bool canSpellAnyone = false; - public static bool triggerBothCooldowns = true; - public static bool witchVoteSavesTargets = true; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SpellButton.png", 115f); - return buttonSprite; - } - - private static Sprite spelledOverlaySprite; - public static Sprite getSpelledOverlaySprite() { - if (spelledOverlaySprite) return spelledOverlaySprite; - spelledOverlaySprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SpellButtonMeeting.png", 225f); - return spelledOverlaySprite; - } - - - public static void clearAndReload() { - witch = null; - futureSpelled = new List(); - currentTarget = spellCastingTarget = null; - cooldown = CustomOptionHolder.witchCooldown.getFloat(); - cooldownAddition = CustomOptionHolder.witchAdditionalCooldown.getFloat(); - currentCooldownAddition = 0f; - canSpellAnyone = CustomOptionHolder.witchCanSpellAnyone.getBool(); - spellCastingDuration = CustomOptionHolder.witchSpellCastingDuration.getFloat(); - triggerBothCooldowns = CustomOptionHolder.witchTriggerBothCooldowns.getBool(); - witchVoteSavesTargets = CustomOptionHolder.witchVoteSavesTargets.getBool(); - } - } - - public static class Ninja { - public static PlayerControl ninja; - public static Color color = Palette.ImpostorRed; - - public static PlayerControl ninjaMarked; - public static PlayerControl currentTarget; - public static float cooldown = 30f; - public static float traceTime = 1f; - public static bool knowsTargetLocation = false; - public static float invisibleDuration = 5f; - - public static float invisibleTimer = 0f; - public static bool isInvisble = false; - private static Sprite markButtonSprite; - private static Sprite killButtonSprite; - public static Arrow arrow = new Arrow(Color.black); - public static Sprite getMarkButtonSprite() { - if (markButtonSprite) return markButtonSprite; - markButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.NinjaMarkButton.png", 115f); - return markButtonSprite; - } - - public static Sprite getKillButtonSprite() { - if (killButtonSprite) return killButtonSprite; - killButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.NinjaAssassinateButton.png", 115f); - return killButtonSprite; - } - - public static void clearAndReload() { - ninja = null; - currentTarget = ninjaMarked = null; - cooldown = CustomOptionHolder.ninjaCooldown.getFloat(); - knowsTargetLocation = CustomOptionHolder.ninjaKnowsTargetLocation.getBool(); - traceTime = CustomOptionHolder.ninjaTraceTime.getFloat(); - invisibleDuration = CustomOptionHolder.ninjaInvisibleDuration.getFloat(); - invisibleTimer = 0f; - isInvisble = false; - if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); - arrow = new Arrow(Color.black); - if (arrow.arrow != null) arrow.arrow.SetActive(false); - } - } - - public static class Thief { - public static PlayerControl thief; - public static Color color = new Color32(71, 99, 45, Byte.MaxValue); - public static PlayerControl currentTarget; - public static PlayerControl formerThief; - - public static float cooldown = 30f; - - public static bool suicideFlag = false; // Used as a flag for suicide - - public static bool hasImpostorVision; - public static bool canUseVents; - public static bool canKillSheriff; - public static bool canStealWithGuess; - - public static void clearAndReload() { - thief = null; - suicideFlag = false; - currentTarget = null; - formerThief = null; - hasImpostorVision = CustomOptionHolder.thiefHasImpVision.getBool(); - cooldown = CustomOptionHolder.thiefCooldown.getFloat(); - canUseVents = CustomOptionHolder.thiefCanUseVents.getBool(); - canKillSheriff = CustomOptionHolder.thiefCanKillSheriff.getBool(); - canStealWithGuess = CustomOptionHolder.thiefCanStealWithGuess.getBool(); - } - - public static bool isFailedThiefKill(PlayerControl target, PlayerControl killer, RoleInfo targetRole) { - return killer == Thief.thief && !target.Data.Role.IsImpostor && !new List { RoleInfo.jackal, canKillSheriff ? RoleInfo.sheriff : null, RoleInfo.sidekick }.Contains(targetRole); - } - } - - public static class Trapper { - public static PlayerControl trapper; - public static Color color = new Color32(110, 57, 105, byte.MaxValue); - - public static float cooldown = 30f; - public static int maxCharges = 5; - public static int rechargeTasksNumber = 3; - public static int rechargedTasks = 3; - public static int charges = 1; - public static int trapCountToReveal = 2; - public static List playersOnMap = new List(); - public static bool anonymousMap = false; - public static int infoType = 0; // 0 = Role, 1 = Good/Evil, 2 = Name - public static float trapDuration = 5f; - - private static Sprite trapButtonSprite; - - public static Sprite getButtonSprite() { - if (trapButtonSprite) return trapButtonSprite; - trapButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Trapper_Place_Button.png", 115f); - return trapButtonSprite; - } - - public static void clearAndReload() { - trapper = null; - cooldown = CustomOptionHolder.trapperCooldown.getFloat(); - maxCharges = Mathf.RoundToInt(CustomOptionHolder.trapperMaxCharges.getFloat()); - rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.trapperRechargeTasksNumber.getFloat()); - rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.trapperRechargeTasksNumber.getFloat()); - charges = Mathf.RoundToInt(CustomOptionHolder.trapperMaxCharges.getFloat()) / 2; - trapCountToReveal = Mathf.RoundToInt(CustomOptionHolder.trapperTrapNeededTriggerToReveal.getFloat()); - playersOnMap = new List(); - anonymousMap = CustomOptionHolder.trapperAnonymousMap.getBool(); - infoType = CustomOptionHolder.trapperInfoType.getSelection(); - trapDuration = CustomOptionHolder.trapperTrapDuration.getFloat(); - } - } - - public static class Bomber { - public static PlayerControl bomber = null; - public static Color color = Palette.ImpostorRed; - - public static Bomb bomb = null; - public static bool isPlanted = false; - public static bool isActive = false; - public static float destructionTime = 20f; - public static float destructionRange = 2f; - public static float hearRange = 30f; - public static float defuseDuration = 3f; - public static float bombCooldown = 15f; - public static float bombActiveAfter = 3f; - - private static Sprite buttonSprite; - - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Bomb_Button_Plant.png", 115f); - return buttonSprite; - } - - public static void clearBomb(bool flag = true) { - if (bomb != null) { - UnityEngine.Object.Destroy(bomb.bomb); - UnityEngine.Object.Destroy(bomb.background); - bomb = null; - } - isPlanted = false; - isActive = false; - if (flag) - { - try - { - SoundEffectsManager.stop("bombFuseBurning"); - } - catch (Exception e) - { - BetterOtherRolesPlugin.Logger.LogWarning("Unable to stop bomb sound"); - } - } - } - - public static void clearAndReload() { - clearBomb(false); - bomber = null; - bomb = null; - isPlanted = false; - isActive = false; - destructionTime = CustomOptionHolder.bomberBombDestructionTime.getFloat(); - destructionRange = CustomOptionHolder.bomberBombDestructionRange.getFloat() / 10; - hearRange = CustomOptionHolder.bomberBombHearRange.getFloat() / 10; - defuseDuration = CustomOptionHolder.bomberDefuseDuration.getFloat(); - bombCooldown = CustomOptionHolder.bomberBombCooldown.getFloat(); - bombActiveAfter = CustomOptionHolder.bomberBombActiveAfter.getFloat(); - Bomb.clearBackgroundSprite(); - } - } - - public static class Fallen - { - public static PlayerControl Player; - public static readonly Color Color = new Color32(71, 99, 45, byte.MaxValue); - - public static void ClearAndReload() - { - Player = null; - } - } - - public static class Undertaker - { - public static PlayerControl Player; - public static readonly Color Color = Palette.ImpostorRed; - public static DeadBody DraggedBody; - public static DeadBody TargetBody; - public static bool CanDropBody; - - public static Sprite DragButtonSprite => - Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DragButton.png", 115f); - public static Sprite DropButtonSprite => Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DropButton.png", 115f); - - public static void ClearAndReload() - { - Player = null; - DraggedBody = null; - TargetBody = null; - } - - public static void RpcDropBody(Vector3 position) - { - if (Player == null) return; - var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.UndertakerDropBody, Hazel.SendOption.Reliable, -1); - writer.Write(position.x); - writer.Write(position.y); - writer.Write(position.z); - AmongUsClient.Instance.FinishRpcImmediately(writer); - DropBody(position); - } - - public static void DropBody(Vector3 position) - { - if (!DraggedBody) return; - DraggedBody.transform.position = position; - DraggedBody = null; - TargetBody = null; - } - - public static void RpcDragBody(byte playerId) - { - if (Player == null) return; - var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.UndertakerDragBody, Hazel.SendOption.Reliable, -1); - writer.Write(playerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - DragBody(playerId); - } - - public static void DragBody(byte playerId) - { - if (Player == null) return; - var body = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(b => b.ParentId == playerId); - if (body == null) return; - DraggedBody = body; - } - } +[HarmonyPatch] +public static class BetterOtherRoles +{ + public static readonly Random Rnd = new((int)DateTime.Now.Ticks); - public static class StickyBomber + public static void clearAndReloadRoles() { - public static PlayerControl Player; - public static Color Color = Palette.ImpostorRed; - - public static PlayerControl StuckPlayer; - public static float RemainingTime; - public static float RemainingDelay; - public static PlayerControl CurrentTarget; - public static PlayerControl CurrentTransferTarget; - - public static float BombCooldown; - public static float FirstDelay; - public static float OtherDelay; - public static float Duration; - public static bool CanReceiveBomb; - public static bool ShieldedPlayerCanReceiveBomb; - public static bool AllowKillButton; - public static bool TriggerBothCooldown; - public static bool ShowRemainingTime; - - public static void ClearAndReload() - { - Player = null; - StuckPlayer = null; - RemainingTime = 0f; - RemainingDelay = 0f; - CurrentTarget = null; - CurrentTransferTarget = null; - - BombCooldown = CustomOptionHolder.StickyBomberCooldown.getFloat(); - FirstDelay = CustomOptionHolder.StickyBomberFirstDelay.getFloat(); - OtherDelay = CustomOptionHolder.StickyBomberOtherDelay.getFloat(); - Duration = CustomOptionHolder.StickyBomberDuration.getFloat(); - CanReceiveBomb = CustomOptionHolder.StickyBomberCanReceiveBomb.getBool(); - ShieldedPlayerCanReceiveBomb = CustomOptionHolder.StickyBomberCanGiveBombToShielded.getBool(); - AllowKillButton = CustomOptionHolder.StickyBomberEnableKillButton.getBool(); - TriggerBothCooldown = CustomOptionHolder.StickyBomberTriggerAllCooldowns.getBool(); - ShowRemainingTime = CustomOptionHolder.StickyBomberShowTimer.getBool(); - } - - public static Sprite StickyButton => Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StickyBombButton.png", 115f); - public static Sprite StickyTransferButton => Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StickyBombTransferButton.png", 115f); - - public static void RpcGiveBomb(byte playerId) - { - var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.StickyBomberGiveBomb, Hazel.SendOption.Reliable, -1); - writer.Write(playerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - GiveBomb(playerId); - } - - public static void GiveBomb(byte playerId) - { - if (playerId == byte.MaxValue) - { - StuckPlayer = null; - if (Player != PlayerControl.LocalPlayer) return; - HudManagerStartPatch.stickyBomberButton.HasEffect = false; - HudManagerStartPatch.stickyBomberButton.Timer = HudManagerStartPatch.stickyBomberButton.MaxTimer; - return; - } - - var player = Helpers.playerById(playerId); - if (player == null) return; - RemainingDelay = StuckPlayer == null ? FirstDelay : OtherDelay; - if (StuckPlayer == null) - { - RemainingTime = Duration; - if (TriggerBothCooldown && Player == CachedPlayer.LocalPlayer.PlayerControl) - { - Player.killTimer = Duration + 1f; - } - } - StuckPlayer = player; - } - - public static IEnumerator CoCreateBomb() - { - var timer = 0f; - while (timer <= Duration) - { - timer += Time.deltaTime; - if (StuckPlayer && StuckPlayer.Data.IsDead) - { - System.Console.WriteLine($"Stuck player is dead"); - RpcGiveBomb(byte.MaxValue); - if (HudManagerStartPatch.stickyBomberButton != null) - { - HudManagerStartPatch.stickyBomberButton.HasEffect = false; - HudManagerStartPatch.stickyBomberButton.Timer = 0.5f; - } - - if (TriggerBothCooldown) - { - Player.killTimer = 0.5f; - } - break; - } - yield return new WaitForEndOfFrame(); - } - if (!Player || !StuckPlayer) yield break; - var killAttempt = Helpers.checkMurderAttemptAndKill(Player, StuckPlayer, showAnimation: false); - if (killAttempt == MurderAttemptResult.PerformKill) - { - var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareGhostInfo, Hazel.SendOption.Reliable, -1); - writer.Write(CachedPlayer.LocalPlayer.PlayerId); - writer.Write((byte)RPCProcedure.GhostInfoTypes.DeathReasonAndKiller); - writer.Write(StuckPlayer.PlayerId); - writer.Write((byte)DeadPlayer.CustomDeathReason.StickyBomb); - writer.Write(Player.PlayerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - GameHistory.overrideDeathReasonAndKiller(StuckPlayer, DeadPlayer.CustomDeathReason.StickyBomb, killer: StickyBomber.Player); - - } - RpcGiveBomb(byte.MaxValue); - } - } - - // Modifier - public static class Bait { - public static List bait = new List(); - public static Dictionary active = new Dictionary(); - public static Color color = new Color32(0, 247, 255, byte.MaxValue); - - public static float reportDelayMin = 0f; - public static float reportDelayMax = 0f; - public static bool showKillFlash = true; - - public static void clearAndReload() { - bait = new List(); - active = new Dictionary(); - reportDelayMin = CustomOptionHolder.modifierBaitReportDelayMin.getFloat(); - reportDelayMax = CustomOptionHolder.modifierBaitReportDelayMax.getFloat(); - if (reportDelayMin > reportDelayMax) reportDelayMin = reportDelayMax; - showKillFlash = CustomOptionHolder.modifierBaitShowKillFlash.getBool(); - } - } - - public static class Bloody { - public static List bloody = new List(); - public static Dictionary active = new Dictionary(); - public static Dictionary bloodyKillerMap = new Dictionary(); - - public static float duration = 5f; - - public static void clearAndReload() { - bloody = new List(); - active = new Dictionary(); - bloodyKillerMap = new Dictionary(); - duration = CustomOptionHolder.modifierBloodyDuration.getFloat(); - } - } - - public static class AntiTeleport { - public static List antiTeleport = new List(); - public static Vector3 position; - - public static void clearAndReload() { - antiTeleport = new List(); - position = Vector3.zero; - } - - public static void setPosition() { - if (position == Vector3.zero) return; // Check if this has been set, otherwise first spawn on submerged will fail - if (antiTeleport.FindAll(x => x.PlayerId == CachedPlayer.LocalPlayer.PlayerId).Count > 0) { - CachedPlayer.LocalPlayer.NetTransform.RpcSnapTo(position); - if (SubmergedCompatibility.IsSubmerged) { - SubmergedCompatibility.ChangeFloor(position.y > -7); - } - } - } - } - - public static class Tiebreaker { - public static PlayerControl tiebreaker; - - public static bool isTiebreak = false; - - public static void clearAndReload() { - tiebreaker = null; - isTiebreak = false; - } - } - - public static class Sunglasses { - public static List sunglasses = new List(); - public static int vision = 1; - - public static void clearAndReload() { - sunglasses = new List(); - vision = CustomOptionHolder.modifierSunglassesVision.getSelection() + 1; - } - } - public static class Mini { - public static PlayerControl mini; - public static Color color = Color.yellow; - public const float defaultColliderRadius = 0.2233912f; - public const float defaultColliderOffset = 0.3636057f; - - public static float growingUpDuration = 400f; - public static bool isGrowingUpInMeeting = true; - public static DateTime timeOfGrowthStart = DateTime.UtcNow; - public static DateTime timeOfMeetingStart = DateTime.UtcNow; - public static float ageOnMeetingStart = 0f; - public static bool triggerMiniLose = false; - - public static void clearAndReload() { - mini = null; - triggerMiniLose = false; - growingUpDuration = CustomOptionHolder.modifierMiniGrowingUpDuration.getFloat(); - isGrowingUpInMeeting = CustomOptionHolder.modifierMiniGrowingUpInMeeting.getBool(); - timeOfGrowthStart = DateTime.UtcNow; - } - - public static float growingProgress() { - 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 Vip { - public static List vip = new List(); - public static bool showColor = true; - - public static void clearAndReload() { - vip = new List(); - showColor = CustomOptionHolder.modifierVipShowColor.getBool(); - } - } - - public static class Invert { - public static List invert = new List(); - public static int meetings = 3; - - public static void clearAndReload() { - invert = new List(); - meetings = (int) CustomOptionHolder.modifierInvertDuration.getFloat(); - } - } - - public static class Chameleon { - public static List chameleon = new List(); - public static float minVisibility = 0.2f; - public static float holdDuration = 1f; - public static float fadeDuration = 0.5f; - public static Dictionary lastMoved; - - public static void clearAndReload() { - chameleon = new List(); - lastMoved = new Dictionary(); - holdDuration = CustomOptionHolder.modifierChameleonHoldDuration.getFloat(); - fadeDuration = CustomOptionHolder.modifierChameleonFadeDuration.getFloat(); - minVisibility = CustomOptionHolder.modifierChameleonMinVisibility.getSelection() / 10f; - } - - public static float visibility(byte playerId) { - float visibility = 1f; - if (lastMoved != null && lastMoved.ContainsKey(playerId)) { - var tStill = Time.time - lastMoved[playerId]; - if (tStill > holdDuration) { - if (tStill - holdDuration > fadeDuration) visibility = minVisibility; - else visibility = (1 - (tStill - holdDuration) / fadeDuration) * (1 - minVisibility) + minVisibility; - } - } - if (PlayerControl.LocalPlayer.Data.IsDead && visibility < 0.1f) { // Ghosts can always see! - visibility = 0.1f; - } - return visibility; - } - - public static void update() { - foreach (var chameleonPlayer in chameleon) { - if (chameleonPlayer == Ninja.ninja && Ninja.isInvisble) continue; // Dont make Ninja visible... - // check movement by animation - PlayerPhysics playerPhysics = chameleonPlayer.MyPhysics; - var currentPhysicsAnim = playerPhysics.Animations.Animator.GetCurrentAnimation(); - if (currentPhysicsAnim != playerPhysics.Animations.group.IdleAnim) { - lastMoved[chameleonPlayer.PlayerId] = Time.time; - } - // calculate and set visibility - float visibility = Chameleon.visibility(chameleonPlayer.PlayerId); - float petVisibility = visibility; - if (chameleonPlayer.Data.IsDead) { - visibility = 0.5f; - petVisibility = 1f; - } - - try { // Sometimes renderers are missing for weird reasons. Try catch to avoid exceptions - chameleonPlayer.cosmetics.currentBodySprite.BodySprite.color = chameleonPlayer.cosmetics.currentBodySprite.BodySprite.color.SetAlpha(visibility); - if (DataManager.Settings.Accessibility.ColorBlindMode) chameleonPlayer.cosmetics.colorBlindText.color = chameleonPlayer.cosmetics.colorBlindText.color.SetAlpha(visibility); - chameleonPlayer.SetHatAndVisorAlpha(visibility); - chameleonPlayer.cosmetics.skin.layer.color = chameleonPlayer.cosmetics.skin.layer.color.SetAlpha(visibility); - chameleonPlayer.cosmetics.nameText.color = chameleonPlayer.cosmetics.nameText.color.SetAlpha(visibility); - chameleonPlayer.cosmetics.currentPet.rend.color = chameleonPlayer.cosmetics.currentPet.rend.color.SetAlpha(petVisibility); - chameleonPlayer.cosmetics.currentPet.shadowRend.color = chameleonPlayer.cosmetics.currentPet.shadowRend.color.SetAlpha(petVisibility); - } catch { } - } - - } - } - - public static class Shifter { - public static PlayerControl shifter; - - public static PlayerControl futureShift; - public static PlayerControl currentTarget; - - private static Sprite buttonSprite; - public static Sprite getButtonSprite() { - if (buttonSprite) return buttonSprite; - buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.ShiftButton.png", 115f); - return buttonSprite; - } - - public static void shiftRole (PlayerControl player1, PlayerControl player2, bool repeat = true) { - if (Mayor.mayor != null && Mayor.mayor == player2) { - if (repeat) shiftRole(player2, player1, false); - Mayor.mayor = player1; - } else if (Portalmaker.portalmaker != null && Portalmaker.portalmaker == player2) { - if (repeat) shiftRole(player2, player1, false); - Portalmaker.portalmaker = player1; - } else if (Engineer.engineer != null && Engineer.engineer == player2) { - if (repeat) shiftRole(player2, player1, false); - Engineer.engineer = player1; - } else if (Sheriff.sheriff != null && Sheriff.sheriff == player2) { - if (repeat) shiftRole(player2, player1, false); - if (Sheriff.formerDeputy != null && Sheriff.formerDeputy == Sheriff.sheriff) Sheriff.formerDeputy = player1; // Shifter also shifts info on promoted deputy (to get handcuffs) - Sheriff.sheriff = player1; - } else if (Deputy.deputy != null && Deputy.deputy == player2) { - if (repeat) shiftRole(player2, player1, false); - Deputy.deputy = player1; - } else if (Lighter.lighter != null && Lighter.lighter == player2) { - if (repeat) shiftRole(player2, player1, false); - Lighter.lighter = player1; - } else if (Detective.detective != null && Detective.detective == player2) { - if (repeat) shiftRole(player2, player1, false); - Detective.detective = player1; - } else if (TimeMaster.timeMaster != null && TimeMaster.timeMaster == player2) { - if (repeat) shiftRole(player2, player1, false); - TimeMaster.timeMaster = player1; - } else if (Medic.medic != null && Medic.medic == player2) { - if (repeat) shiftRole(player2, player1, false); - Medic.medic = player1; - } else if (Swapper.swapper != null && Swapper.swapper == player2) { - if (repeat) shiftRole(player2, player1, false); - Swapper.swapper = player1; - } else if (Seer.seer != null && Seer.seer == player2) { - if (repeat) shiftRole(player2, player1, false); - Seer.seer = player1; - } else if (Hacker.hacker != null && Hacker.hacker == player2) { - if (repeat) shiftRole(player2, player1, false); - Hacker.hacker = player1; - } else if (Tracker.tracker != null && Tracker.tracker == player2) { - if (repeat) shiftRole(player2, player1, false); - Tracker.tracker = player1; - } else if (Snitch.snitch != null && Snitch.snitch == player2) { - if (repeat) shiftRole(player2, player1, false); - Snitch.snitch = player1; - } else if (Spy.spy != null && Spy.spy == player2) { - if (repeat) shiftRole(player2, player1, false); - Spy.spy = player1; - } else if (SecurityGuard.securityGuard != null && SecurityGuard.securityGuard == player2) { - if (repeat) shiftRole(player2, player1, false); - SecurityGuard.securityGuard = player1; - } else if (Guesser.niceGuesser != null && Guesser.niceGuesser == player2) { - if (repeat) shiftRole(player2, player1, false); - Guesser.niceGuesser = player1; - } else if (Medium.medium != null && Medium.medium == player2) { - if (repeat) shiftRole(player2, player1, false); - Medium.medium = player1; - } else if (Pursuer.pursuer != null && Pursuer.pursuer == player2) { - if (repeat) shiftRole(player2, player1, false); - Pursuer.pursuer = player1; - } else if (Trapper.trapper != null && Trapper.trapper == player2) { - if (repeat) shiftRole(player2, player1, false); - Trapper.trapper = player1; - } - } - - public static void clearAndReload() { - shifter = null; - currentTarget = null; - futureShift = null; - } - } -} + Jester.clearAndReload(); + Mayor.clearAndReload(); + Portalmaker.clearAndReload(); + Engineer.clearAndReload(); + Sheriff.clearAndReload(); + Deputy.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(); + Hacker.clearAndReload(); + Tracker.clearAndReload(); + Vampire.clearAndReload(); + Snitch.clearAndReload(); + Jackal.clearAndReload(); + Sidekick.clearAndReload(); + Eraser.clearAndReload(); + Spy.clearAndReload(); + Trickster.clearAndReload(); + Cleaner.clearAndReload(); + Warlock.clearAndReload(); + SecurityGuard.clearAndReload(); + Arsonist.clearAndReload(); + BountyHunter.clearAndReload(); + Vulture.clearAndReload(); + Medium.clearAndReload(); + Lawyer.clearAndReload(); + Pursuer.clearAndReload(); + Witch.clearAndReload(); + Ninja.clearAndReload(); + Thief.clearAndReload(); + Trapper.clearAndReload(); + Bomber.clearAndReload(); + Fallen.ClearAndReload(); + Undertaker.ClearAndReload(); + StickyBomber.ClearAndReload(); + + // Modifier + Bait.clearAndReload(); + Bloody.clearAndReload(); + AntiTeleport.clearAndReload(); + Tiebreaker.clearAndReload(); + Sunglasses.clearAndReload(); + Mini.clearAndReload(); + Vip.clearAndReload(); + Invert.clearAndReload(); + Chameleon.clearAndReload(); + + // Gamemodes + HandleGuesser.clearAndReload(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/BetterOtherRoles.csproj b/BetterOtherRoles/BetterOtherRoles.csproj index d2dcba1..41717fb 100644 --- a/BetterOtherRoles/BetterOtherRoles.csproj +++ b/BetterOtherRoles/BetterOtherRoles.csproj @@ -1,7 +1,7 @@  net6.0 - 1.5.2 + 1.6.0 BetterOtherRoles EnoPM latest @@ -15,14 +15,18 @@ - - + + + + libs\AmongUsSpecimen.dll + libs\UniverseLib.IL2CPP.dll + libs\AmongUsSpecimen.dll diff --git a/BetterOtherRoles/Buttons.cs b/BetterOtherRoles/Buttons.cs index b49b24a..28bd336 100644 --- a/BetterOtherRoles/Buttons.cs +++ b/BetterOtherRoles/Buttons.cs @@ -10,7 +10,10 @@ using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles { @@ -89,12 +92,12 @@ static HudManagerStartPatch() private static void SetFirstCooldowns() { - vampireKillButton.Timer = CustomOptionHolder.vampireFirstCooldown.getFloat(); - ninjaButton.Timer = CustomOptionHolder.ninjaFirstCooldown.getFloat(); - witchSpellButton.Timer = CustomOptionHolder.witchFirstCooldown.getFloat(); - arsonistButton.Timer = CustomOptionHolder.arsonistFirstCooldown.getFloat(); - warlockCurseButton.Timer = CustomOptionHolder.warlockFirstCooldown.getFloat(); - stickyBomberButton.Timer = CustomOptionHolder.StickyBomberFirstCooldown.getFloat(); + vampireKillButton.Timer = CustomOptionHolder.VampireFirstCooldown.GetFloat(); + ninjaButton.Timer = CustomOptionHolder.NinjaFirstCooldown.GetFloat(); + witchSpellButton.Timer = CustomOptionHolder.WitchFirstCooldown.GetFloat(); + arsonistButton.Timer = CustomOptionHolder.ArsonistFirstCooldown.GetFloat(); + warlockCurseButton.Timer = CustomOptionHolder.WarlockFirstCooldown.GetFloat(); + stickyBomberButton.Timer = CustomOptionHolder.StickyBomberFirstCooldown.GetFloat(); } public static void setCustomButtonCooldowns() { @@ -147,10 +150,6 @@ public static void setCustomButtonCooldowns() { mayorMeetingButton.MaxTimer = GameManager.Instance.LogicOptions.GetEmergencyCooldown(); trapperButton.MaxTimer = Trapper.cooldown; bomberButton.MaxTimer = Bomber.bombCooldown; - hunterLighterButton.MaxTimer = Hunter.lightCooldown; - hunterAdminTableButton.MaxTimer = Hunter.AdminCooldown; - hunterArrowButton.MaxTimer = Hunter.ArrowCooldown; - huntedShieldButton.MaxTimer = Hunted.shieldCooldown; defuseButton.MaxTimer = 0f; defuseButton.Timer = 0f; stickyBomberButton.MaxTimer = StickyBomber.BombCooldown; @@ -170,9 +169,6 @@ public static void setCustomButtonCooldowns() { trackerTrackCorpsesButton.EffectDuration = Tracker.corpsesTrackingDuration; witchSpellButton.EffectDuration = Witch.spellCastingDuration; securityGuardCamButton.EffectDuration = SecurityGuard.duration; - hunterLighterButton.EffectDuration = Hunter.lightDuration; - hunterArrowButton.EffectDuration = Hunter.ArrowDuration; - huntedShieldButton.EffectDuration = Hunted.shieldDuration; defuseButton.EffectDuration = Bomber.defuseDuration; bomberButton.EffectDuration = Bomber.destructionTime + Bomber.bombActiveAfter; stickyBomberButton.EffectDuration = StickyBomber.Duration; @@ -1883,7 +1879,7 @@ public static void createButtonsPostfix(HudManager __instance) { () => { if (CachedPlayer.LocalPlayer.PlayerControl == null || !CachedPlayer.LocalPlayer.Data.IsDead || CachedPlayer.LocalPlayer.Data.Role.IsImpostor) return false; var (playerCompleted, playerTotal) = TasksHandler.taskInfo(CachedPlayer.LocalPlayer.Data); int numberOfLeftTasks = playerTotal - playerCompleted; - return numberOfLeftTasks <= 0 || !CustomOptionHolder.finishTasksBeforeHauntingOrZoomingOut.getBool(); + return numberOfLeftTasks <= 0 || !CustomOptionHolder.FinishTasksBeforeHauntingOrZoomingOut.GetBool(); }, () => { return true; }, () => { return; }, @@ -1893,142 +1889,6 @@ public static void createButtonsPostfix(HudManager __instance) { "ActionZoomOut" ); zoomOutButton.Timer = 0f; - - - hunterLighterButton = new CustomButton( - () => { - Hunter.lightActive.Add(CachedPlayer.LocalPlayer.PlayerId); - SoundEffectsManager.play("lighterLight"); - - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareTimer, Hazel.SendOption.Reliable, -1); - writer.Write(Hunter.lightPunish); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.shareTimer(Hunter.lightPunish); - }, - () => { return HideNSeek.isHunter() && !CachedPlayer.LocalPlayer.Data.IsDead; }, - () => { return true; }, - () => { - hunterLighterButton.Timer = 30f; - hunterLighterButton.isEffectActive = false; - hunterLighterButton.actionButton.graphic.color = Palette.EnabledColor; - }, - Hunter.getLightSprite(), - CustomButton.ButtonPositions.upperRowFarLeft, - __instance, - "ActionQuaternary", - true, - Hunter.lightDuration, - () => { - Hunter.lightActive.Remove(CachedPlayer.LocalPlayer.PlayerId); - hunterLighterButton.Timer = hunterLighterButton.MaxTimer; - SoundEffectsManager.play("lighterLight"); - } - ); - - hunterAdminTableButton = new CustomButton( - () => { - if (!MapBehaviour.Instance || !MapBehaviour.Instance.isActiveAndEnabled) { - HudManager __instance = FastDestroyableSingleton.Instance; - __instance.InitMap(); - MapBehaviour.Instance.ShowCountOverlay(allowedToMove: true, showLivePlayerPosition: true, includeDeadBodies: false); - } - - CachedPlayer.LocalPlayer.NetTransform.Halt(); // Stop current movement - - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareTimer, Hazel.SendOption.Reliable, -1); - writer.Write(Hunter.AdminPunish); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.shareTimer(Hunter.AdminPunish); - }, - () => { return HideNSeek.isHunter() && !CachedPlayer.LocalPlayer.Data.IsDead; }, - () => { return true; }, - () => { - hunterAdminTableButton.Timer = hunterAdminTableButton.MaxTimer; - hunterAdminTableButton.isEffectActive = false; - hunterAdminTableButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; - }, - Hacker.getAdminSprite(), - CustomButton.ButtonPositions.lowerRowCenter, - __instance, - "HunterAdmin", - true, - Hunter.AdminDuration, - () => { - hunterAdminTableButton.Timer = hunterAdminTableButton.MaxTimer; - if (MapBehaviour.Instance && MapBehaviour.Instance.isActiveAndEnabled) MapBehaviour.Instance.Close(); - }, - false, - "ADMIN" - ); - - hunterArrowButton = new CustomButton( - () => { - Hunter.arrowActive = true; - SoundEffectsManager.play("trackerTrackPlayer"); - - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareTimer, Hazel.SendOption.Reliable, -1); - writer.Write(Hunter.ArrowPunish); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.shareTimer(Hunter.ArrowPunish); - }, - () => { return HideNSeek.isHunter() && !CachedPlayer.LocalPlayer.Data.IsDead; }, - () => { return true; }, - () => { - hunterArrowButton.Timer = 30f; - hunterArrowButton.isEffectActive = false; - hunterArrowButton.actionButton.graphic.color = Palette.EnabledColor; - }, - Hunter.getArrowSprite(), - CustomButton.ButtonPositions.upperRowLeft, - __instance, - "HunterArrow", - true, - Hunter.ArrowDuration, - () => { - Hunter.arrowActive = false; - hunterArrowButton.Timer = hunterArrowButton.MaxTimer; - SoundEffectsManager.play("trackerTrackPlayer"); - } - ); - - huntedShieldButton = new CustomButton( - () => { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.HuntedShield, Hazel.SendOption.Reliable, -1); - writer.Write(CachedPlayer.LocalPlayer.PlayerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.huntedShield(CachedPlayer.LocalPlayer.PlayerId); - SoundEffectsManager.play("timemasterShield"); - - Hunted.shieldCount--; - }, - () => { return HideNSeek.isHunted() && !CachedPlayer.LocalPlayer.Data.IsDead; }, - () => { - if (huntedShieldCountText != null) huntedShieldCountText.text = $"{Hunted.shieldCount}"; - return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Hunted.shieldCount > 0; - }, - () => { - huntedShieldButton.Timer = huntedShieldButton.MaxTimer; - huntedShieldButton.isEffectActive = false; - huntedShieldButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; - }, - TimeMaster.getButtonSprite(), - CustomButton.ButtonPositions.lowerRowRight, - __instance, - "ActionQuaternary", - true, - Hunted.shieldDuration, - () => { - huntedShieldButton.Timer = huntedShieldButton.MaxTimer; - SoundEffectsManager.stop("timemasterShield"); - - } - ); - - huntedShieldCountText = UnityEngine.Object.Instantiate(huntedShieldButton.actionButton.cooldownTimerText, huntedShieldButton.actionButton.cooldownTimerText.transform.parent); - huntedShieldCountText.text = ""; - huntedShieldCountText.enableWordWrapping = false; - huntedShieldCountText.transform.localScale = Vector3.one * 0.5f; - huntedShieldCountText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); undertakerDragButton = new CustomButton( () => @@ -2107,7 +1967,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, "ActionQuaternary", true, - CustomOptionHolder.StickyBomberDuration.getFloat(), + CustomOptionHolder.StickyBomberDuration.GetFloat(), () => { stickyBomberButton.Timer = stickyBomberButton.MaxTimer; stickyBomberButton.isEffectActive = false; @@ -2130,7 +1990,7 @@ public static void createButtonsPostfix(HudManager __instance) { RPCProcedure.placeGarlic(buff); SoundEffectsManager.play("garlic"); }, - () => { return !Vampire.localPlacedGarlic && !CachedPlayer.LocalPlayer.Data.IsDead && Vampire.garlicsActive && !HideNSeek.isHideNSeekGM; }, + () => { return !Vampire.localPlacedGarlic && !CachedPlayer.LocalPlayer.Data.IsDead && Vampire.garlicsActive; }, () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && !Vampire.localPlacedGarlic; }, () => { }, Vampire.getGarlicButtonSprite(), diff --git a/BetterOtherRoles/CustomGameModes/GuesserGM.cs b/BetterOtherRoles/CustomGameModes/GuesserGM.cs index e5b5452..f6eb9cc 100644 --- a/BetterOtherRoles/CustomGameModes/GuesserGM.cs +++ b/BetterOtherRoles/CustomGameModes/GuesserGM.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using BetterOtherRoles.Options; using UnityEngine; namespace BetterOtherRoles.CustomGameModes { @@ -7,7 +8,7 @@ class GuesserGM { // Guesser Gamemode public static Color color = new Color32(255, 255, 0, byte.MaxValue); public PlayerControl guesser = null; - public int shots = Mathf.RoundToInt(CustomOptionHolder.guesserGamemodeNumberOfShots.getFloat()); + public int shots = Mathf.RoundToInt(CustomOptionHolder.GuesserModeNumberOfShots.GetFloat()); public GuesserGM(PlayerControl player) { guesser = player; guessers.Add(this); @@ -25,7 +26,7 @@ public static void clear(byte playerId) { var g = guessers.FindLast(x => x.guesser.PlayerId == playerId); if (g == null) return; g.guesser = null; - g.shots = Mathf.RoundToInt(CustomOptionHolder.guesserGamemodeNumberOfShots.getFloat()); + g.shots = Mathf.RoundToInt(CustomOptionHolder.GuesserModeNumberOfShots.GetFloat()); guessers.Remove(g); } diff --git a/BetterOtherRoles/CustomGameModes/HideNSeekGM.cs b/BetterOtherRoles/CustomGameModes/HideNSeekGM.cs deleted file mode 100644 index 3442d9f..0000000 --- a/BetterOtherRoles/CustomGameModes/HideNSeekGM.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using BetterOtherRoles.Objects; -using BetterOtherRoles.Players; -using UnityEngine; - -namespace BetterOtherRoles.CustomGameModes { - public static class HideNSeek { // HideNSeek Gamemode - public static bool isHideNSeekGM = false; - public static TMPro.TMP_Text timerText = null; - public static Vent polusVent = null; - public static bool isWaitingTimer = true; - public static DateTime startTime = DateTime.UtcNow; - - public static float timer = 300f; - public static float hunterVision = 0.5f; - public static float huntedVision = 2f; - public static bool taskWinPossible = false; - public static float taskPunish = 10f; - public static int impNumber = 2; - public static bool canSabotage = false; - public static float killCooldown = 10f; - public static float hunterWaitingTime = 15f; - public static bool isHunter() { - return isHideNSeekGM && CachedPlayer.LocalPlayer != null && CachedPlayer.LocalPlayer.Data.Role.IsImpostor; - } - - public static List getHunters() { - List hunters = new List(CachedPlayer.AllPlayers); - hunters.RemoveAll(x => !x.Data.Role.IsImpostor); - return hunters; - } - - public static bool isHunted() { - return isHideNSeekGM && CachedPlayer.LocalPlayer != null && !CachedPlayer.LocalPlayer.Data.Role.IsImpostor; - } - - public static void clearAndReload() { - isHideNSeekGM = TORMapOptions.gameMode == CustomGamemodes.HideNSeek; - if (timerText != null) UnityEngine.Object.Destroy(timerText); - timerText = null; - if (polusVent != null) UnityEngine.Object.Destroy(polusVent); - polusVent = null; - isWaitingTimer = true; - startTime = DateTime.UtcNow; - - timer = CustomOptionHolder.hideNSeekTimer.getFloat() * 60; - hunterVision = CustomOptionHolder.hideNSeekHunterVision.getFloat(); - huntedVision = CustomOptionHolder.hideNSeekHuntedVision.getFloat(); - taskWinPossible = CustomOptionHolder.hideNSeekTaskWin.getBool(); - taskPunish = CustomOptionHolder.hideNSeekTaskPunish.getFloat(); - impNumber = Mathf.RoundToInt(CustomOptionHolder.hideNSeekHunterCount.getFloat()); - canSabotage = CustomOptionHolder.hideNSeekCanSabotage.getBool(); - killCooldown = CustomOptionHolder.hideNSeekKillCooldown.getFloat(); - hunterWaitingTime = CustomOptionHolder.hideNSeekHunterWaiting.getFloat(); - - Hunter.clearAndReload(); - Hunted.clearAndReload(); - } - } - - public static class Hunter { - public static List localArrows = new List(); - public static List lightActive = new List(); - public static bool arrowActive = false; - public static Dictionary playerKillCountMap = new Dictionary(); - - public static float lightCooldown = 30f; - public static float lightDuration = 5f; - public static float lightVision = 2f; - public static float lightPunish = 5f; - public static float AdminCooldown = 30f; - public static float AdminDuration = 5f; - public static float AdminPunish = 5f; - public static float ArrowCooldown = 30f; - public static float ArrowDuration = 5f; - public static float ArrowPunish = 5f; - private static Sprite buttonSpriteLight; - private static Sprite buttonSpriteArrow; - - public static bool isLightActive (byte playerId) { - return lightActive.Contains(playerId); - } - - public static Sprite getArrowSprite() { - if (buttonSpriteArrow) return buttonSpriteArrow; - buttonSpriteArrow = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.HideNSeekArrowButton.png", 115f); - return buttonSpriteArrow; - } - - public static Sprite getLightSprite() { - if (buttonSpriteLight) return buttonSpriteLight; - buttonSpriteLight = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.LighterButton.png", 115f); - return buttonSpriteLight; - } - - public static void clearAndReload() { - if (localArrows != null) { - foreach (Arrow arrow in localArrows) - if (arrow?.arrow != null) - UnityEngine.Object.Destroy(arrow.arrow); - } - localArrows = new List(); - lightActive = new List(); - arrowActive = false; - - lightCooldown = CustomOptionHolder.hunterLightCooldown.getFloat(); - lightDuration = CustomOptionHolder.hunterLightDuration.getFloat(); - lightVision = CustomOptionHolder.hunterLightVision.getFloat(); - lightPunish = CustomOptionHolder.hunterLightPunish.getFloat(); - AdminCooldown = CustomOptionHolder.hunterAdminCooldown.getFloat(); - AdminDuration = CustomOptionHolder.hunterAdminDuration.getFloat(); - AdminPunish = CustomOptionHolder.hunterAdminPunish.getFloat(); - ArrowCooldown = CustomOptionHolder.hunterArrowCooldown.getFloat(); - ArrowDuration = CustomOptionHolder.hunterArrowDuration.getFloat(); - ArrowPunish = CustomOptionHolder.hunterArrowPunish.getFloat(); - } - } - - public static class Hunted { - public static List timeshieldActive = new List(); - public static int shieldCount = 3; - - public static float shieldCooldown = 30f; - public static float shieldDuration = 5f; - public static float shieldRewindTime = 3f; - public static bool taskPunish = false; - public static void clearAndReload() { - timeshieldActive = new List(); - taskPunish = false; - - shieldCount = Mathf.RoundToInt(CustomOptionHolder.huntedShieldNumber.getFloat()); - shieldCooldown = CustomOptionHolder.huntedShieldCooldown.getFloat(); - shieldDuration = CustomOptionHolder.huntedShieldDuration.getFloat(); - shieldRewindTime = CustomOptionHolder.huntedShieldRewindTime.getFloat(); - } - } -} \ No newline at end of file diff --git a/BetterOtherRoles/CustomOptionHolder.cs b/BetterOtherRoles/CustomOptionHolder.cs deleted file mode 100644 index 14a24a5..0000000 --- a/BetterOtherRoles/CustomOptionHolder.cs +++ /dev/null @@ -1,822 +0,0 @@ -using System.Collections.Generic; -using BetterOtherRoles.Modules; -using BetterOtherRoles.UI; -using UnityEngine; -using static BetterOtherRoles.BetterOtherRoles; -using Types = BetterOtherRoles.Modules.CustomOption.CustomOptionType; - -namespace BetterOtherRoles { - public class CustomOptionHolder { - public static string[] rates = new string[]{"0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"}; - public static string[] ratesModifier = new string[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; - public static string[] presets = new string[]{"Preset 1", "Preset 2", "Random Preset Skeld", "Random Preset Mira HQ", "Random Preset Polus", "Random Preset Airship", "Random Preset Submerged" }; - - public static CustomOption presetSelection; - public static CustomOption activateRoles; - public static CustomOption crewmateRolesCountMin; - public static CustomOption crewmateRolesCountMax; - public static CustomOption crewmateRolesFill; - public static CustomOption neutralRolesCountMin; - public static CustomOption neutralRolesCountMax; - public static CustomOption impostorRolesCountMin; - public static CustomOption impostorRolesCountMax; - public static CustomOption modifiersCountMin; - public static CustomOption modifiersCountMax; - - public static CustomOption EnableBetterPolus; - public static CustomOption PolusReactorCountdown; - - public static CustomOption EnableBetterSkeld; - public static CustomOption BetterSkeldEnableAdmin; - public static CustomOption BetterSkeldEnableVitals; - - public static CustomOption enableCodenameHorsemode; - public static CustomOption enableCodenameDisableHorses; - - public static CustomOption mafiaSpawnRate; - public static CustomOption janitorCooldown; - - public static CustomOption morphlingSpawnRate; - public static CustomOption morphlingCooldown; - public static CustomOption morphlingDuration; - - public static CustomOption camouflagerSpawnRate; - public static CustomOption camouflagerCooldown; - public static CustomOption camouflagerDuration; - - public static CustomOption vampireSpawnRate; - public static CustomOption vampireKillDelay; - public static CustomOption vampireCooldown; - public static CustomOption vampireCanKillNearGarlics; - public static CustomOption vampireFirstCooldown; - - public static CustomOption eraserSpawnRate; - public static CustomOption eraserCooldown; - public static CustomOption eraserCanEraseAnyone; - public static CustomOption guesserSpawnRate; - public static CustomOption guesserIsImpGuesserRate; - public static CustomOption guesserNumberOfShots; - public static CustomOption guesserHasMultipleShotsPerMeeting; - public static CustomOption guesserKillsThroughShield; - public static CustomOption guesserEvilCanKillSpy; - public static CustomOption guesserSpawnBothRate; - public static CustomOption guesserCantGuessSnitchIfTaksDone; - - public static CustomOption jesterSpawnRate; - public static CustomOption jesterCanCallEmergency; - public static CustomOption jesterHasImpostorVision; - - public static CustomOption arsonistSpawnRate; - public static CustomOption arsonistCooldown; - public static CustomOption arsonistFirstCooldown; - public static CustomOption arsonistDuration; - - public static CustomOption jackalSpawnRate; - public static CustomOption jackalKillCooldown; - public static CustomOption jackalCreateSidekickCooldown; - public static CustomOption jackalCanUseVents; - public static CustomOption jackalCanCreateSidekick; - public static CustomOption sidekickPromotesToJackal; - public static CustomOption sidekickCanKill; - public static CustomOption sidekickCanUseVents; - public static CustomOption jackalPromotedFromSidekickCanCreateSidekick; - public static CustomOption jackalCanCreateSidekickFromImpostor; - public static CustomOption jackalAndSidekickHaveImpostorVision; - - public static CustomOption bountyHunterSpawnRate; - public static CustomOption bountyHunterBountyDuration; - public static CustomOption bountyHunterReducedCooldown; - public static CustomOption bountyHunterPunishmentTime; - public static CustomOption bountyHunterShowArrow; - public static CustomOption bountyHunterArrowUpdateIntervall; - - public static CustomOption witchSpawnRate; - public static CustomOption witchCooldown; - public static CustomOption witchFirstCooldown; - public static CustomOption witchAdditionalCooldown; - public static CustomOption witchCanSpellAnyone; - public static CustomOption witchSpellCastingDuration; - public static CustomOption witchTriggerBothCooldowns; - public static CustomOption witchVoteSavesTargets; - - public static CustomOption ninjaSpawnRate; - public static CustomOption ninjaCooldown; - public static CustomOption ninjaFirstCooldown; - public static CustomOption ninjaKnowsTargetLocation; - public static CustomOption ninjaTraceTime; - public static CustomOption ninjaTraceColorTime; - public static CustomOption ninjaInvisibleDuration; - - public static CustomOption mayorSpawnRate; - public static CustomOption mayorCanSeeVoteColors; - public static CustomOption mayorTasksNeededToSeeVoteColors; - public static CustomOption mayorMeetingButton; - public static CustomOption mayorMaxRemoteMeetings; - public static CustomOption mayorChooseSingleVote; - - public static CustomOption portalmakerSpawnRate; - public static CustomOption portalmakerCooldown; - public static CustomOption portalmakerUsePortalCooldown; - public static CustomOption portalmakerLogOnlyColorType; - public static CustomOption portalmakerLogHasTime; - public static CustomOption portalmakerCanPortalFromAnywhere; - - public static CustomOption engineerSpawnRate; - public static CustomOption engineerNumberOfFixes; - public static CustomOption engineerHighlightForImpostors; - public static CustomOption engineerHighlightForTeamJackal; - - public static CustomOption sheriffSpawnRate; - public static CustomOption sheriffCooldown; - public static CustomOption sheriffCanKillNeutrals; - public static CustomOption deputySpawnRate; - - public static CustomOption deputyNumberOfHandcuffs; - public static CustomOption deputyHandcuffCooldown; - public static CustomOption deputyGetsPromoted; - public static CustomOption deputyKeepsHandcuffs; - public static CustomOption deputyHandcuffDuration; - public static CustomOption deputyKnowsSheriff; - - public static CustomOption lighterSpawnRate; - public static CustomOption lighterModeLightsOnVision; - public static CustomOption lighterModeLightsOffVision; - public static CustomOption lighterFlashlightWidth; - - public static CustomOption detectiveSpawnRate; - public static CustomOption detectiveAnonymousFootprints; - public static CustomOption detectiveFootprintIntervall; - public static CustomOption detectiveFootprintDuration; - public static CustomOption detectiveReportNameDuration; - public static CustomOption detectiveReportColorDuration; - - public static CustomOption timeMasterSpawnRate; - public static CustomOption timeMasterCooldown; - public static CustomOption timeMasterRewindTime; - public static CustomOption timeMasterShieldDuration; - - public static CustomOption medicSpawnRate; - public static CustomOption medicShowShielded; - public static CustomOption medicShowAttemptToShielded; - public static CustomOption medicSetOrShowShieldAfterMeeting; - public static CustomOption medicShowAttemptToMedic; - public static CustomOption medicSetShieldAfterMeeting; - - public static CustomOption swapperSpawnRate; - public static CustomOption swapperCanCallEmergency; - public static CustomOption swapperCanOnlySwapOthers; - public static CustomOption swapperSwapsNumber; - public static CustomOption swapperRechargeTasksNumber; - - public static CustomOption seerSpawnRate; - public static CustomOption seerMode; - public static CustomOption seerSoulDuration; - public static CustomOption seerLimitSoulDuration; - - public static CustomOption hackerSpawnRate; - public static CustomOption hackerCooldown; - public static CustomOption hackerHackeringDuration; - public static CustomOption hackerOnlyColorType; - public static CustomOption hackerToolsNumber; - public static CustomOption hackerRechargeTasksNumber; - public static CustomOption hackerNoMove; - - public static CustomOption trackerSpawnRate; - public static CustomOption trackerUpdateIntervall; - public static CustomOption trackerResetTargetAfterMeeting; - public static CustomOption trackerCanTrackCorpses; - public static CustomOption trackerCorpsesTrackingCooldown; - public static CustomOption trackerCorpsesTrackingDuration; - - public static CustomOption snitchSpawnRate; - public static CustomOption snitchLeftTasksForReveal; - public static CustomOption snitchMode; - public static CustomOption snitchTargets; - - public static CustomOption spySpawnRate; - public static CustomOption spyCanDieToSheriff; - public static CustomOption spyImpostorsCanKillAnyone; - public static CustomOption spyCanEnterVents; - public static CustomOption spyHasImpostorVision; - - public static CustomOption tricksterSpawnRate; - public static CustomOption tricksterPlaceBoxCooldown; - public static CustomOption tricksterLightsOutCooldown; - public static CustomOption tricksterLightsOutDuration; - - public static CustomOption cleanerSpawnRate; - public static CustomOption cleanerCooldown; - - public static CustomOption warlockSpawnRate; - public static CustomOption warlockCooldown; - public static CustomOption warlockFirstCooldown; - public static CustomOption warlockRootTime; - - public static CustomOption securityGuardSpawnRate; - public static CustomOption securityGuardCooldown; - public static CustomOption securityGuardTotalScrews; - public static CustomOption securityGuardCamPrice; - public static CustomOption securityGuardVentPrice; - public static CustomOption securityGuardCamDuration; - public static CustomOption securityGuardCamMaxCharges; - public static CustomOption securityGuardCamRechargeTasksNumber; - public static CustomOption securityGuardNoMove; - - public static CustomOption vultureSpawnRate; - public static CustomOption vultureCooldown; - public static CustomOption vultureNumberToWin; - public static CustomOption vultureCanUseVents; - public static CustomOption vultureShowArrows; - - public static CustomOption mediumSpawnRate; - public static CustomOption mediumCooldown; - public static CustomOption mediumDuration; - public static CustomOption mediumOneTimeUse; - public static CustomOption mediumChanceAdditionalInfo; - - public static CustomOption lawyerSpawnRate; - public static CustomOption lawyerIsProsecutorChance; - public static CustomOption lawyerTargetCanBeJester; - public static CustomOption lawyerVision; - public static CustomOption lawyerKnowsRole; - public static CustomOption lawyerCanCallEmergency; - public static CustomOption pursuerCooldown; - public static CustomOption pursuerBlanksNumber; - - public static CustomOption thiefSpawnRate; - public static CustomOption thiefCooldown; - public static CustomOption thiefHasImpVision; - public static CustomOption thiefCanUseVents; - public static CustomOption thiefCanKillSheriff; - public static CustomOption thiefCanStealWithGuess; - public static CustomOption StolenPlayerKeepsHisTeam; - - - public static CustomOption trapperSpawnRate; - public static CustomOption trapperCooldown; - public static CustomOption trapperMaxCharges; - public static CustomOption trapperRechargeTasksNumber; - public static CustomOption trapperTrapNeededTriggerToReveal; - public static CustomOption trapperAnonymousMap; - public static CustomOption trapperInfoType; - public static CustomOption trapperTrapDuration; - - public static CustomOption bomberSpawnRate; - public static CustomOption bomberBombDestructionTime; - public static CustomOption bomberBombDestructionRange; - public static CustomOption bomberBombHearRange; - public static CustomOption bomberDefuseDuration; - public static CustomOption bomberBombCooldown; - public static CustomOption bomberBombActiveAfter; - - public static CustomOption UndertakerSpawnRate; - public static CustomOption UndertakerSpeedModifier; - public static CustomOption UndertakerDisableVent; - - public static CustomOption StickyBomberSpawnRate; - public static CustomOption StickyBomberCooldown; - public static CustomOption StickyBomberFirstCooldown; - public static CustomOption StickyBomberFirstDelay; - public static CustomOption StickyBomberOtherDelay; - public static CustomOption StickyBomberDuration; - public static CustomOption StickyBomberCanReceiveBomb; - public static CustomOption StickyBomberCanGiveBombToShielded; - public static CustomOption StickyBomberEnableKillButton; - public static CustomOption StickyBomberTriggerAllCooldowns; - public static CustomOption StickyBomberShowTimer; - - public static CustomOption modifiersAreHidden; - - public static CustomOption modifierBait; - public static CustomOption modifierBaitQuantity; - public static CustomOption modifierBaitReportDelayMin; - public static CustomOption modifierBaitReportDelayMax; - public static CustomOption modifierBaitShowKillFlash; - - public static CustomOption modifierLover; - public static CustomOption modifierLoverImpLoverRate; - public static CustomOption modifierLoverBothDie; - public static CustomOption modifierLoverEnableChat; - - public static CustomOption modifierBloody; - public static CustomOption modifierBloodyQuantity; - public static CustomOption modifierBloodyDuration; - - public static CustomOption modifierAntiTeleport; - public static CustomOption modifierAntiTeleportQuantity; - - public static CustomOption modifierTieBreaker; - - public static CustomOption modifierSunglasses; - public static CustomOption modifierSunglassesQuantity; - public static CustomOption modifierSunglassesVision; - - public static CustomOption modifierMini; - public static CustomOption modifierMiniGrowingUpDuration; - public static CustomOption modifierMiniGrowingUpInMeeting; - - public static CustomOption modifierVip; - public static CustomOption modifierVipQuantity; - public static CustomOption modifierVipShowColor; - - public static CustomOption modifierInvert; - public static CustomOption modifierInvertQuantity; - public static CustomOption modifierInvertDuration; - - public static CustomOption modifierChameleon; - public static CustomOption modifierChameleonQuantity; - public static CustomOption modifierChameleonHoldDuration; - public static CustomOption modifierChameleonFadeDuration; - public static CustomOption modifierChameleonMinVisibility; - - public static CustomOption modifierShifter; - - public static CustomOption RandomizePlayersInMeeting; - public static CustomOption RandomizeWireTaskPositions; - public static CustomOption RandomizeUploadTaskPosition; - - public static CustomOption maxNumberOfMeetings; - public static CustomOption blockSkippingInEmergencyMeetings; - public static CustomOption noVoteIsSelfVote; - public static CustomOption hidePlayerNames; - public static CustomOption allowParallelMedBayScans; - public static CustomOption RandomizePositionDuringScan; - public static CustomOption shieldFirstKill; - public static CustomOption ExpireFirstKillShield; - public static CustomOption FirstKillShieldDuration; - public static CustomOption finishTasksBeforeHauntingOrZoomingOut; - public static CustomOption camsNightVision; - public static CustomOption camsNoNightVisionIfImpVision; - - public static CustomOption dynamicMap; - public static CustomOption dynamicMapEnableSkeld; - public static CustomOption dynamicMapEnableMira; - public static CustomOption dynamicMapEnablePolus; - public static CustomOption dynamicMapEnableAirShip; - public static CustomOption dynamicMapEnableSubmerged; - public static CustomOption dynamicMapSeparateSettings; - - //Guesser Gamemode - public static CustomOption guesserGamemodeCrewNumber; - public static CustomOption guesserGamemodeNeutralNumber; - public static CustomOption guesserGamemodeImpNumber; - public static CustomOption guesserForceJackalGuesser; - public static CustomOption guesserForceThiefGuesser; - public static CustomOption guesserGamemodeHaveModifier; - public static CustomOption guesserGamemodeNumberOfShots; - public static CustomOption guesserGamemodeHasMultipleShotsPerMeeting; - public static CustomOption guesserGamemodeKillsThroughShield; - public static CustomOption guesserGamemodeEvilCanKillSpy; - public static CustomOption guesserGamemodeCantGuessSnitchIfTaksDone; - - // Hide N Seek Gamemode - public static CustomOption hideNSeekHunterCount; - public static CustomOption hideNSeekKillCooldown; - public static CustomOption hideNSeekHunterVision; - public static CustomOption hideNSeekHuntedVision; - public static CustomOption hideNSeekTimer; - public static CustomOption hideNSeekCommonTasks; - public static CustomOption hideNSeekShortTasks; - public static CustomOption hideNSeekLongTasks; - public static CustomOption hideNSeekTaskWin; - public static CustomOption hideNSeekTaskPunish; - public static CustomOption hideNSeekCanSabotage; - public static CustomOption hideNSeekMap; - public static CustomOption hideNSeekHunterWaiting; - - public static CustomOption hunterLightCooldown; - public static CustomOption hunterLightDuration; - public static CustomOption hunterLightVision; - public static CustomOption hunterLightPunish; - public static CustomOption hunterAdminCooldown; - public static CustomOption hunterAdminDuration; - public static CustomOption hunterAdminPunish; - public static CustomOption hunterArrowCooldown; - public static CustomOption hunterArrowDuration; - public static CustomOption hunterArrowPunish; - - public static CustomOption huntedShieldCooldown; - public static CustomOption huntedShieldDuration; - public static CustomOption huntedShieldRewindTime; - public static CustomOption huntedShieldNumber; - - internal static Dictionary blockedRolePairings = new Dictionary(); - - public static string cs(Color c, string s) { - return string.Format("{4}", ToByte(c.r), ToByte(c.g), ToByte(c.b), ToByte(c.a), s); - } - - private static byte ToByte(float f) { - f = Mathf.Clamp01(f); - return (byte)(f * 255); - } - - public static void Load() { - - CustomOption.vanillaSettings = BetterOtherRolesPlugin.Instance.Config.Bind("Preset0", "VanillaOptions", ""); - - // Role Options - presetSelection = CustomOption.Create(0, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Preset"), presets, null, true); - activateRoles = CustomOption.Create(1, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Enable Mod Roles And Block Vanilla Roles"), true, null, true); - - if (Utilities.EventUtility.canBeEnabled) enableCodenameHorsemode = CustomOption.Create(10423, Types.General, cs(Color.green, "Enable Codename Horsemode"), true, null, true); - if (Utilities.EventUtility.canBeEnabled) enableCodenameDisableHorses = CustomOption.Create(10424, Types.General, cs(Color.green, "Disable Horses"), false, enableCodenameHorsemode, false); - - // Using new id's for the options to not break compatibilty with older versions - crewmateRolesCountMin = CustomOption.Create(300, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Crewmate Roles"), 15f, 0f, 15f, 1f, null, true); - crewmateRolesCountMax = CustomOption.Create(301, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Crewmate Roles"), 15f, 0f, 15f, 1f); - crewmateRolesFill = CustomOption.Create(308, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Fill Crewmate Roles\n(Ignores Min/Max)"), false); - neutralRolesCountMin = CustomOption.Create(302, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Neutral Roles"), 15f, 0f, 15f, 1f, isHeader: true); - neutralRolesCountMax = CustomOption.Create(303, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Neutral Roles"), 15f, 0f, 15f, 1f); - impostorRolesCountMin = CustomOption.Create(304, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Impostor Roles"), 15f, 0f, 15f, 1f, isHeader: true); - impostorRolesCountMax = CustomOption.Create(305, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Impostor Roles"), 15f, 0f, 15f, 1f); - modifiersCountMin = CustomOption.Create(306, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Modifiers"), 15f, 0f, 15f, 1f, isHeader: true); - modifiersCountMax = CustomOption.Create(307, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Modifiers"), 15f, 0f, 15f, 1f); - - EnableBetterPolus = CustomOption.Create(5001, Types.General, "Better Polus", false, isHeader: true); - PolusReactorCountdown = CustomOption.Create(5002, Types.General, "Polus Reactor Cooldown", 40f, 10f, 120f, 2.5f, isHeader: true, suffix: "s"); - - EnableBetterSkeld = CustomOption.Create(5017, Types.General, "Better Skeld", false, isHeader: true); - BetterSkeldEnableAdmin = CustomOption.Create(5018, Types.General, "Enable Admin Table", false, EnableBetterSkeld); - BetterSkeldEnableVitals = CustomOption.Create(5019, Types.General, "Enable Vitals", false, EnableBetterSkeld); - - mafiaSpawnRate = CustomOption.Create(18, Types.Impostor, cs(Janitor.color, "Mafia"), rates, null, true); - janitorCooldown = CustomOption.Create(19, Types.Impostor, "Janitor Cooldown", 30f, 10f, 60f, 2.5f, mafiaSpawnRate, suffix: "s"); - - morphlingSpawnRate = CustomOption.Create(20, Types.Impostor, cs(Morphling.color, "Morphling"), rates, null, true); - morphlingCooldown = CustomOption.Create(21, Types.Impostor, "Morphling Cooldown", 30f, 10f, 60f, 2.5f, morphlingSpawnRate, suffix: "s"); - morphlingDuration = CustomOption.Create(22, Types.Impostor, "Morph Duration", 10f, 1f, 20f, 0.5f, morphlingSpawnRate, suffix: "s"); - - camouflagerSpawnRate = CustomOption.Create(30, Types.Impostor, cs(Camouflager.color, "Camouflager"), rates, null, true); - camouflagerCooldown = CustomOption.Create(31, Types.Impostor, "Camouflager Cooldown", 30f, 10f, 60f, 2.5f, camouflagerSpawnRate, suffix: "s"); - camouflagerDuration = CustomOption.Create(32, Types.Impostor, "Camo Duration", 10f, 1f, 20f, 0.5f, camouflagerSpawnRate, suffix: "s"); - - vampireSpawnRate = CustomOption.Create(40, Types.Impostor, cs(Vampire.color, "Vampire"), rates, null, true); - vampireKillDelay = CustomOption.Create(41, Types.Impostor, "Vampire Kill Delay", 10f, 1f, 20f, 1f, vampireSpawnRate, suffix: "s"); - vampireCooldown = CustomOption.Create(42, Types.Impostor, "Vampire Cooldown", 30f, 10f, 60f, 2.5f, vampireSpawnRate, suffix: "s"); - vampireCanKillNearGarlics = CustomOption.Create(43, Types.Impostor, "Vampire Can Kill Near Garlics", true, vampireSpawnRate); - vampireFirstCooldown = CustomOption.Create(5012, Types.Impostor, "Vampire first Cooldown", 15f, 10f, 60f, 2.5f, vampireSpawnRate, suffix: "s"); - - eraserSpawnRate = CustomOption.Create(230, Types.Impostor, cs(Eraser.color, "Eraser"), rates, null, true); - eraserCooldown = CustomOption.Create(231, Types.Impostor, "Eraser Cooldown", 30f, 10f, 120f, 5f, eraserSpawnRate, suffix: "s"); - eraserCanEraseAnyone = CustomOption.Create(232, Types.Impostor, "Eraser Can Erase Anyone", false, eraserSpawnRate, suffix: "s"); - - tricksterSpawnRate = CustomOption.Create(250, Types.Impostor, cs(Trickster.color, "Trickster"), rates, null, true); - tricksterPlaceBoxCooldown = CustomOption.Create(251, Types.Impostor, "Trickster Box Cooldown", 10f, 2.5f, 30f, 2.5f, tricksterSpawnRate, suffix: "s"); - tricksterLightsOutCooldown = CustomOption.Create(252, Types.Impostor, "Trickster Lights Out Cooldown", 30f, 10f, 60f, 5f, tricksterSpawnRate, suffix: "s"); - tricksterLightsOutDuration = CustomOption.Create(253, Types.Impostor, "Trickster Lights Out Duration", 15f, 5f, 60f, 2.5f, tricksterSpawnRate, suffix: "s"); - - cleanerSpawnRate = CustomOption.Create(260, Types.Impostor, cs(Cleaner.color, "Cleaner"), rates, null, true); - cleanerCooldown = CustomOption.Create(261, Types.Impostor, "Cleaner Cooldown", 30f, 10f, 60f, 2.5f, cleanerSpawnRate, suffix: "s"); - - warlockSpawnRate = CustomOption.Create(270, Types.Impostor, cs(Cleaner.color, "Warlock"), rates, null, true); - warlockCooldown = CustomOption.Create(271, Types.Impostor, "Warlock Cooldown", 30f, 10f, 60f, 2.5f, warlockSpawnRate, suffix: "s"); - warlockRootTime = CustomOption.Create(272, Types.Impostor, "Warlock Root Time", 5f, 0f, 15f, 1f, warlockSpawnRate, suffix: "s"); - warlockFirstCooldown = CustomOption.Create(5016, Types.Impostor, "Warlock First Cooldown", 15f, 10f, 60f, 2.5f, warlockSpawnRate, suffix: "s"); - - bountyHunterSpawnRate = CustomOption.Create(320, Types.Impostor, cs(BountyHunter.color, "Bounty Hunter"), rates, null, true); - bountyHunterBountyDuration = CustomOption.Create(321, Types.Impostor, "Duration After Which Bounty Changes", 60f, 10f, 180f, 10f, bountyHunterSpawnRate, suffix: "s"); - bountyHunterReducedCooldown = CustomOption.Create(322, Types.Impostor, "Cooldown After Killing Bounty", 2.5f, 0f, 30f, 2.5f, bountyHunterSpawnRate, suffix: "s"); - bountyHunterPunishmentTime = CustomOption.Create(323, Types.Impostor, "Additional Cooldown After Killing Others", 20f, 0f, 60f, 2.5f, bountyHunterSpawnRate, suffix: "s"); - bountyHunterShowArrow = CustomOption.Create(324, Types.Impostor, "Show Arrow Pointing Towards The Bounty", true, bountyHunterSpawnRate); - bountyHunterArrowUpdateIntervall = CustomOption.Create(325, Types.Impostor, "Arrow Update Intervall", 15f, 2.5f, 60f, 2.5f, bountyHunterShowArrow, suffix: "s"); - - witchSpawnRate = CustomOption.Create(370, Types.Impostor, cs(Witch.color, "Witch"), rates, null, true); - witchCooldown = CustomOption.Create(371, Types.Impostor, "Witch Spell Casting Cooldown", 30f, 10f, 120f, 5f, witchSpawnRate, suffix: "s"); - witchAdditionalCooldown = CustomOption.Create(372, Types.Impostor, "Witch Additional Cooldown", 10f, 0f, 60f, 5f, witchSpawnRate, suffix: "s"); - witchCanSpellAnyone = CustomOption.Create(373, Types.Impostor, "Witch Can Spell Anyone", false, witchSpawnRate); - witchSpellCastingDuration = CustomOption.Create(374, Types.Impostor, "Spell Casting Duration", 1f, 0f, 10f, 1f, witchSpawnRate, suffix: "s"); - witchTriggerBothCooldowns = CustomOption.Create(375, Types.Impostor, "Trigger Both Cooldowns", true, witchSpawnRate); - witchVoteSavesTargets = CustomOption.Create(376, Types.Impostor, "Voting The Witch Saves All The Targets", true, witchSpawnRate); - witchFirstCooldown = CustomOption.Create(5014, Types.Impostor, "Witch First Spell Casting Cooldown", 15f, 10f, 120f, 5f, witchSpawnRate, suffix: "s"); - - ninjaSpawnRate = CustomOption.Create(380, Types.Impostor, cs(Ninja.color, "Ninja"), rates, null, true); - ninjaCooldown = CustomOption.Create(381, Types.Impostor, "Ninja Mark Cooldown", 30f, 10f, 120f, 5f, ninjaSpawnRate, suffix: "s"); - ninjaKnowsTargetLocation = CustomOption.Create(382, Types.Impostor, "Ninja Knows Location Of Target", true, ninjaSpawnRate); - ninjaTraceTime = CustomOption.Create(383, Types.Impostor, "Trace Duration", 5f, 1f, 20f, 0.5f, ninjaSpawnRate, suffix: "s"); - ninjaTraceColorTime = CustomOption.Create(384, Types.Impostor, "Time Till Trace Color Has Faded", 2f, 0f, 20f, 0.5f, ninjaSpawnRate, suffix: "s"); - ninjaInvisibleDuration = CustomOption.Create(385, Types.Impostor, "Time The Ninja Is Invisible", 3f, 0f, 20f, 1f, ninjaSpawnRate, suffix: "s"); - ninjaFirstCooldown = CustomOption.Create(5013, Types.Impostor, "Ninja First Mark Cooldown", 15f, 10f, 120f, 5f, ninjaSpawnRate, suffix: "s"); - - bomberSpawnRate = CustomOption.Create(460, Types.Impostor, cs(Bomber.color, "Bomber"), rates, null, true); - bomberBombDestructionTime = CustomOption.Create(461, Types.Impostor, "Bomb Destruction Time", 20f, 2.5f, 120f, 2.5f, bomberSpawnRate, suffix: "s"); - bomberBombDestructionRange = CustomOption.Create(462, Types.Impostor, "Bomb Destruction Range", 50f, 5f, 150f, 5f, bomberSpawnRate, suffix: "µ"); - bomberBombHearRange = CustomOption.Create(463, Types.Impostor, "Bomb Hear Range", 60f, 5f, 150f, 5f, bomberSpawnRate, suffix: "µ"); - bomberDefuseDuration = CustomOption.Create(464, Types.Impostor, "Bomb Defuse Duration", 3f, 0.5f, 30f, 0.5f, bomberSpawnRate, suffix: "s"); - bomberBombCooldown = CustomOption.Create(465, Types.Impostor, "Bomb Cooldown", 15f, 2.5f, 30f, 2.5f, bomberSpawnRate, suffix: "s"); - bomberBombActiveAfter = CustomOption.Create(466, Types.Impostor, "Bomb Is Active After", 3f, 0.5f, 15f, 0.5f, bomberSpawnRate, suffix: "s"); - - UndertakerSpawnRate = CustomOption.Create(5009, Types.Impostor, cs(Undertaker.Color, "Undertaker"), rates, null, true); - UndertakerSpeedModifier = CustomOption.Create(5010, Types.Impostor, - "Speed modifier while dragging", 0f, -100f, 100f, 5f, UndertakerSpawnRate, suffix: "%"); - UndertakerDisableVent = CustomOption.Create(5011, Types.Impostor, "Disable vent while dragging", true, UndertakerSpawnRate); - - StickyBomberSpawnRate = CustomOption.Create(5021, Types.Impostor, cs(StickyBomber.Color, "Sticky Bomber"), rates, null, true); - StickyBomberCooldown = CustomOption.Create(5022, Types.Impostor, "Sticky Bomb Cooldown", 15f, 2.5f, 30f, 2.5f, StickyBomberSpawnRate, suffix: "s"); - StickyBomberFirstCooldown = CustomOption.Create(5031, Types.Impostor, "Sticky Bomb First Cooldown", 15f, 2.5f, 30f, 2.5f, StickyBomberSpawnRate, suffix: "s"); - StickyBomberFirstDelay = CustomOption.Create(5023, Types.Impostor, "Sticky Bomb First Delay", 5f, 0f, 20f, 1f, StickyBomberSpawnRate, suffix: "s"); - StickyBomberOtherDelay = CustomOption.Create(5024, Types.Impostor, "Sticky Bomb Other Delay", 5f, 0f, 20f, 1f, StickyBomberSpawnRate, suffix: "s"); - StickyBomberDuration = CustomOption.Create(5025, Types.Impostor, "Sticky Bomb Timer", 30f, 5f, 60f, 2.5f, StickyBomberSpawnRate, suffix: "s"); - StickyBomberShowTimer = CustomOption.Create(5030, Types.Impostor, "Display Remaining Time", true, StickyBomberSpawnRate); - StickyBomberCanReceiveBomb = CustomOption.Create(5026, Types.Impostor, "Sticky Bomber Can Receive His Own Bomb", false, StickyBomberSpawnRate); - StickyBomberCanGiveBombToShielded = CustomOption.Create(5027, Types.Impostor, "Shielded Players Can Receive Bomb", false, StickyBomberSpawnRate); - StickyBomberEnableKillButton = CustomOption.Create(5028, Types.Impostor, "Has Kill Button", false, StickyBomberSpawnRate); - StickyBomberTriggerAllCooldowns = CustomOption.Create(5029, Types.Impostor, "Trigger Both Cooldown", false, StickyBomberEnableKillButton); - - guesserSpawnRate = CustomOption.Create(310, Types.Neutral, cs(Guesser.color, "Guesser"), rates, null, true); - guesserIsImpGuesserRate = CustomOption.Create(311, Types.Neutral, "Chance That The Guesser Is An Impostor", rates, guesserSpawnRate); - guesserNumberOfShots = CustomOption.Create(312, Types.Neutral, "Guesser Number Of Shots", 2f, 1f, 15f, 1f, guesserSpawnRate); - guesserHasMultipleShotsPerMeeting = CustomOption.Create(313, Types.Neutral, "Guesser Can Shoot Multiple Times Per Meeting", false, guesserSpawnRate); - guesserKillsThroughShield = CustomOption.Create(315, Types.Neutral, "Guesses Ignore The Medic Shield", true, guesserSpawnRate); - guesserEvilCanKillSpy = CustomOption.Create(316, Types.Neutral, "Evil Guesser Can Guess The Spy", true, guesserSpawnRate); - guesserSpawnBothRate = CustomOption.Create(317, Types.Neutral, "Both Guesser Spawn Rate", rates, guesserSpawnRate); - guesserCantGuessSnitchIfTaksDone = CustomOption.Create(318, Types.Neutral, "Guesser Can't Guess Snitch When Tasks Completed", true, guesserSpawnRate); - - jesterSpawnRate = CustomOption.Create(60, Types.Neutral, cs(Jester.color, "Jester"), rates, null, true); - jesterCanCallEmergency = CustomOption.Create(61, Types.Neutral, "Jester Can Call Emergency Meeting", true, jesterSpawnRate); - jesterHasImpostorVision = CustomOption.Create(62, Types.Neutral, "Jester Has Impostor Vision", false, jesterSpawnRate); - - arsonistSpawnRate = CustomOption.Create(290, Types.Neutral, cs(Arsonist.color, "Arsonist"), rates, null, true); - arsonistCooldown = CustomOption.Create(291, Types.Neutral, "Arsonist Cooldown", 12.5f, 2.5f, 60f, 2.5f, arsonistSpawnRate, suffix: "s"); - arsonistDuration = CustomOption.Create(292, Types.Neutral, "Arsonist Douse Duration", 3f, 1f, 10f, 1f, arsonistSpawnRate, suffix: "s"); - arsonistFirstCooldown = CustomOption.Create(5015, Types.Neutral, "Arsonist First Cooldown", 12.5f, 2.5f, 60f, 2.5f, arsonistSpawnRate, suffix: "s"); - - jackalSpawnRate = CustomOption.Create(220, Types.Neutral, cs(Jackal.color, "Jackal"), rates, null, true); - jackalKillCooldown = CustomOption.Create(221, Types.Neutral, "Jackal/Sidekick Kill Cooldown", 30f, 10f, 60f, 2.5f, jackalSpawnRate, suffix: "s"); - jackalCreateSidekickCooldown = CustomOption.Create(222, Types.Neutral, "Jackal Create Sidekick Cooldown", 30f, 10f, 60f, 2.5f, jackalSpawnRate); - jackalCanUseVents = CustomOption.Create(223, Types.Neutral, "Jackal Can Use Vents", true, jackalSpawnRate); - jackalCanCreateSidekick = CustomOption.Create(224, Types.Neutral, "Jackal Can Create A Sidekick", false, jackalSpawnRate); - sidekickPromotesToJackal = CustomOption.Create(225, Types.Neutral, "Sidekick Gets Promoted To Jackal On Jackal Death", false, jackalCanCreateSidekick); - sidekickCanKill = CustomOption.Create(226, Types.Neutral, "Sidekick Can Kill", false, jackalCanCreateSidekick); - sidekickCanUseVents = CustomOption.Create(227, Types.Neutral, "Sidekick Can Use Vents", true, jackalCanCreateSidekick); - jackalPromotedFromSidekickCanCreateSidekick = CustomOption.Create(228, Types.Neutral, "Jackals Promoted From Sidekick Can Create A Sidekick", true, sidekickPromotesToJackal); - jackalCanCreateSidekickFromImpostor = CustomOption.Create(229, Types.Neutral, "Jackals Can Make An Impostor To His Sidekick", true, jackalCanCreateSidekick); - jackalAndSidekickHaveImpostorVision = CustomOption.Create(430, Types.Neutral, "Jackal And Sidekick Have Impostor Vision", false, jackalSpawnRate); - - vultureSpawnRate = CustomOption.Create(340, Types.Neutral, cs(Vulture.color, "Vulture"), rates, null, true); - vultureCooldown = CustomOption.Create(341, Types.Neutral, "Vulture Cooldown", 15f, 10f, 60f, 2.5f, vultureSpawnRate, suffix: "s"); - vultureNumberToWin = CustomOption.Create(342, Types.Neutral, "Number Of Corpses Needed To Be Eaten", 4f, 1f, 10f, 1f, vultureSpawnRate); - vultureCanUseVents = CustomOption.Create(343, Types.Neutral, "Vulture Can Use Vents", true, vultureSpawnRate); - vultureShowArrows = CustomOption.Create(344, Types.Neutral, "Show Arrows Pointing Towards The Corpses", true, vultureSpawnRate); - - lawyerSpawnRate = CustomOption.Create(350, Types.Neutral, cs(Lawyer.color, "Lawyer"), rates, null, true); - lawyerIsProsecutorChance = CustomOption.Create(358, Types.Neutral, "Chance That The Lawyer Is Prosecutor", rates, lawyerSpawnRate); - lawyerVision = CustomOption.Create(354, Types.Neutral, "Vision", 1f, 0.25f, 3f, 0.25f, lawyerSpawnRate, suffix: "µ"); - lawyerKnowsRole = CustomOption.Create(355, Types.Neutral, "Lawyer/Prosecutor Knows Target Role", false, lawyerSpawnRate); - lawyerCanCallEmergency = CustomOption.Create(352, Types.Neutral, "Lawyer/Prosecutor Can Call Emergency Meeting", true, lawyerSpawnRate); - lawyerTargetCanBeJester = CustomOption.Create(351, Types.Neutral, "Lawyer Target Can Be The Jester", false, lawyerSpawnRate); - pursuerCooldown = CustomOption.Create(356, Types.Neutral, "Pursuer Blank Cooldown", 30f, 5f, 60f, 2.5f, lawyerSpawnRate, suffix: "s"); - pursuerBlanksNumber = CustomOption.Create(357, Types.Neutral, "Pursuer Number Of Blanks", 5f, 1f, 20f, 1f, lawyerSpawnRate); - - mayorSpawnRate = CustomOption.Create(80, Types.Crewmate, cs(Mayor.color, "Mayor"), rates, null, true); - mayorCanSeeVoteColors = CustomOption.Create(81, Types.Crewmate, "Mayor Can See Vote Colors", false, mayorSpawnRate); - mayorTasksNeededToSeeVoteColors = CustomOption.Create(82, Types.Crewmate, "Completed Tasks Needed To See Vote Colors", 5f, 0f, 20f, 1f, mayorCanSeeVoteColors); - mayorMeetingButton = CustomOption.Create(83, Types.Crewmate, "Mobile Emergency Button", true, mayorSpawnRate); - mayorMaxRemoteMeetings = CustomOption.Create(84, Types.Crewmate, "Number Of Remote Meetings", 1f, 1f, 5f, 1f, mayorMeetingButton); - mayorChooseSingleVote = CustomOption.Create(85, Types.Crewmate, "Mayor Can Choose Single Vote", new string[] { "Off", "On (Before Voting)", "On (Until Meeting Ends)" }, mayorSpawnRate); - - engineerSpawnRate = CustomOption.Create(90, Types.Crewmate, cs(Engineer.color, "Engineer"), rates, null, true); - engineerNumberOfFixes = CustomOption.Create(91, Types.Crewmate, "Number Of Sabotage Fixes", 1f, 1f, 3f, 1f, engineerSpawnRate); - engineerHighlightForImpostors = CustomOption.Create(92, Types.Crewmate, "Impostors See Vents Highlighted", true, engineerSpawnRate); - engineerHighlightForTeamJackal = CustomOption.Create(93, Types.Crewmate, "Jackal and Sidekick See Vents Highlighted ", true, engineerSpawnRate); - - sheriffSpawnRate = CustomOption.Create(100, Types.Crewmate, cs(Sheriff.color, "Sheriff"), rates, null, true); - sheriffCooldown = CustomOption.Create(101, Types.Crewmate, "Sheriff Cooldown", 30f, 10f, 60f, 2.5f, sheriffSpawnRate, suffix: "s"); - sheriffCanKillNeutrals = CustomOption.Create(102, Types.Crewmate, "Sheriff Can Kill Neutrals", false, sheriffSpawnRate); - deputySpawnRate = CustomOption.Create(103, Types.Crewmate, "Sheriff Has A Deputy", rates, sheriffSpawnRate); - deputyNumberOfHandcuffs = CustomOption.Create(104, Types.Crewmate, "Deputy Number Of Handcuffs", 3f, 1f, 10f, 1f, deputySpawnRate); - deputyHandcuffCooldown = CustomOption.Create(105, Types.Crewmate, "Handcuff Cooldown", 30f, 10f, 60f, 2.5f, deputySpawnRate, suffix: "s"); - deputyHandcuffDuration = CustomOption.Create(106, Types.Crewmate, "Handcuff Duration", 15f, 5f, 60f, 2.5f, deputySpawnRate, suffix: "s"); - deputyKnowsSheriff = CustomOption.Create(107, Types.Crewmate, "Sheriff And Deputy Know Each Other ", true, deputySpawnRate); - deputyGetsPromoted = CustomOption.Create(108, Types.Crewmate, "Deputy Gets Promoted To Sheriff", new string[] { "Off", "On (Immediately)", "On (After Meeting)" }, deputySpawnRate); - deputyKeepsHandcuffs = CustomOption.Create(109, Types.Crewmate, "Deputy Keeps Handcuffs When Promoted", true, deputyGetsPromoted); - - lighterSpawnRate = CustomOption.Create(110, Types.Crewmate, cs(Lighter.color, "Lighter"), rates, null, true); - lighterModeLightsOnVision = CustomOption.Create(111, Types.Crewmate, "Vision On Lights On", 1.5f, 0.25f, 5f, 0.25f, lighterSpawnRate, suffix: "µ"); - lighterModeLightsOffVision = CustomOption.Create(112, Types.Crewmate, "Vision On Lights Off", 0.5f, 0.25f, 5f, 0.25f, lighterSpawnRate, suffix: "%"); - lighterFlashlightWidth = CustomOption.Create(113, Types.Crewmate, "Flashlight Width", 0.3f, 0.1f, 1f, 0.1f, lighterSpawnRate, suffix: "µ"); - - detectiveSpawnRate = CustomOption.Create(120, Types.Crewmate, cs(Detective.color, "Detective"), rates, null, true); - detectiveAnonymousFootprints = CustomOption.Create(121, Types.Crewmate, "Anonymous Footprints", false, detectiveSpawnRate); - detectiveFootprintIntervall = CustomOption.Create(122, Types.Crewmate, "Footprint Intervall", 0.5f, 0.25f, 10f, 0.25f, detectiveSpawnRate, suffix: "s"); - detectiveFootprintDuration = CustomOption.Create(123, Types.Crewmate, "Footprint Duration", 5f, 0.25f, 10f, 0.25f, detectiveSpawnRate, suffix: "s"); - detectiveReportNameDuration = CustomOption.Create(124, Types.Crewmate, "Time Where Detective Reports Will Have Name", 0, 0, 60, 2.5f, detectiveSpawnRate, suffix: "s"); - detectiveReportColorDuration = CustomOption.Create(125, Types.Crewmate, "Time Where Detective Reports Will Have Color Type", 20, 0, 120, 2.5f, detectiveSpawnRate, suffix: "s"); - - timeMasterSpawnRate = CustomOption.Create(130, Types.Crewmate, cs(TimeMaster.color, "Time Master"), rates, null, true); - timeMasterCooldown = CustomOption.Create(131, Types.Crewmate, "Time Master Cooldown", 30f, 10f, 120f, 2.5f, timeMasterSpawnRate, suffix: "s"); - timeMasterRewindTime = CustomOption.Create(132, Types.Crewmate, "Rewind Time", 3f, 1f, 10f, 1f, timeMasterSpawnRate, suffix: "s"); - timeMasterShieldDuration = CustomOption.Create(133, Types.Crewmate, "Time Master Shield Duration", 3f, 1f, 20f, 1f, timeMasterSpawnRate, suffix: "s"); - - medicSpawnRate = CustomOption.Create(140, Types.Crewmate, cs(Medic.color, "Medic"), rates, null, true); - medicShowShielded = CustomOption.Create(143, Types.Crewmate, "Show Shielded Player", new string[] {"Everyone", "Shielded + Medic", "Medic"}, medicSpawnRate); - medicShowAttemptToShielded = CustomOption.Create(144, Types.Crewmate, "Shielded Player Sees Murder Attempt", false, medicSpawnRate); - medicSetOrShowShieldAfterMeeting = CustomOption.Create(145, Types.Crewmate, "Shield Will Be Activated", new string[] { "Instantly", "Instantly, Visible\nAfter Meeting", "After Meeting" }, medicSpawnRate); - medicShowAttemptToMedic = CustomOption.Create(146, Types.Crewmate, "Medic Sees Murder Attempt On Shielded Player", false, medicSpawnRate); - - swapperSpawnRate = CustomOption.Create(150, Types.Crewmate, cs(Swapper.color, "Swapper"), rates, null, true); - swapperCanCallEmergency = CustomOption.Create(151, Types.Crewmate, "Swapper Can Call Emergency Meeting", false, swapperSpawnRate); - swapperCanOnlySwapOthers = CustomOption.Create(152, Types.Crewmate, "Swapper Can Only Swap Others", false, swapperSpawnRate); - - swapperSwapsNumber = CustomOption.Create(153, Types.Crewmate, "Initial Swap Charges", 1f, 0f, 5f, 1f, swapperSpawnRate); - swapperRechargeTasksNumber = CustomOption.Create(154, Types.Crewmate, "Number Of Tasks Needed For Recharging", 2f, 1f, 10f, 1f, swapperSpawnRate); - - - seerSpawnRate = CustomOption.Create(160, Types.Crewmate, cs(Seer.color, "Seer"), rates, null, true); - seerMode = CustomOption.Create(161, Types.Crewmate, "Seer Mode", new string[]{ "Show Death Flash + Souls", "Show Death Flash", "Show Souls"}, seerSpawnRate); - seerLimitSoulDuration = CustomOption.Create(163, Types.Crewmate, "Seer Limit Soul Duration", false, seerSpawnRate); - seerSoulDuration = CustomOption.Create(162, Types.Crewmate, "Seer Soul Duration", 15f, 0f, 120f, 5f, seerLimitSoulDuration, suffix: "s"); - - hackerSpawnRate = CustomOption.Create(170, Types.Crewmate, cs(Hacker.color, "Hacker"), rates, null, true); - hackerCooldown = CustomOption.Create(171, Types.Crewmate, "Hacker Cooldown", 30f, 5f, 60f, 5f, hackerSpawnRate, suffix: "s"); - hackerHackeringDuration = CustomOption.Create(172, Types.Crewmate, "Hacker Duration", 10f, 2.5f, 60f, 2.5f, hackerSpawnRate, suffix: "s"); - hackerOnlyColorType = CustomOption.Create(173, Types.Crewmate, "Hacker Only Sees Color Type", false, hackerSpawnRate); - hackerToolsNumber = CustomOption.Create(174, Types.Crewmate, "Max Mobile Gadget Charges", 5f, 1f, 30f, 1f, hackerSpawnRate); - hackerRechargeTasksNumber = CustomOption.Create(175, Types.Crewmate, "Number Of Tasks Needed For Recharging", 2f, 1f, 5f, 1f, hackerSpawnRate); - hackerNoMove = CustomOption.Create(176, Types.Crewmate, "Cant Move During Mobile Gadget Duration", true, hackerSpawnRate); - - trackerSpawnRate = CustomOption.Create(200, Types.Crewmate, cs(Tracker.color, "Tracker"), rates, null, true); - trackerUpdateIntervall = CustomOption.Create(201, Types.Crewmate, "Tracker Update Intervall", 5f, 1f, 30f, 1f, trackerSpawnRate, suffix: "s"); - trackerResetTargetAfterMeeting = CustomOption.Create(202, Types.Crewmate, "Tracker Reset Target After Meeting", false, trackerSpawnRate); - trackerCanTrackCorpses = CustomOption.Create(203, Types.Crewmate, "Tracker Can Track Corpses", true, trackerSpawnRate); - trackerCorpsesTrackingCooldown = CustomOption.Create(204, Types.Crewmate, "Corpses Tracking Cooldown", 30f, 5f, 120f, 5f, trackerCanTrackCorpses, suffix: "s"); - trackerCorpsesTrackingDuration = CustomOption.Create(205, Types.Crewmate, "Corpses Tracking Duration", 5f, 2.5f, 30f, 2.5f, trackerCanTrackCorpses, suffix: "s"); - - snitchSpawnRate = CustomOption.Create(210, Types.Crewmate, cs(Snitch.color, "Snitch"), rates, null, true); - snitchLeftTasksForReveal = CustomOption.Create(219, Types.Crewmate, "Task Count Where The Snitch Will Be Revealed", 5f, 0f, 25f, 1f, snitchSpawnRate); - snitchMode = CustomOption.Create(211, Types.Crewmate, "Information Mode", new string[] { "Chat", "Map", "Chat & Map" }, snitchSpawnRate); - snitchTargets = CustomOption.Create(212, Types.Crewmate, "Targets", new string[] { "All Evil Players", "Killing Players" }, snitchSpawnRate); - - spySpawnRate = CustomOption.Create(240, Types.Crewmate, cs(Spy.color, "Spy"), rates, null, true); - spyCanDieToSheriff = CustomOption.Create(241, Types.Crewmate, "Spy Can Die To Sheriff", false, spySpawnRate); - spyImpostorsCanKillAnyone = CustomOption.Create(242, Types.Crewmate, "Impostors Can Kill Anyone If There Is A Spy", true, spySpawnRate); - spyCanEnterVents = CustomOption.Create(243, Types.Crewmate, "Spy Can Enter Vents", false, spySpawnRate); - spyHasImpostorVision = CustomOption.Create(244, Types.Crewmate, "Spy Has Impostor Vision", false, spySpawnRate); - - portalmakerSpawnRate = CustomOption.Create(390, Types.Crewmate, cs(Portalmaker.color, "Portalmaker"), rates, null, true); - portalmakerCooldown = CustomOption.Create(391, Types.Crewmate, "Portalmaker Cooldown", 30f, 10f, 60f, 2.5f, portalmakerSpawnRate, suffix: "s"); - portalmakerUsePortalCooldown = CustomOption.Create(392, Types.Crewmate, "Use Portal Cooldown", 30f, 10f, 60f, 2.5f, portalmakerSpawnRate, suffix: "s"); - portalmakerLogOnlyColorType = CustomOption.Create(393, Types.Crewmate, "Portalmaker Log Only Shows Color Type", true, portalmakerSpawnRate); - portalmakerLogHasTime = CustomOption.Create(394, Types.Crewmate, "Log Shows Time", true, portalmakerSpawnRate); - portalmakerCanPortalFromAnywhere = CustomOption.Create(395, Types.Crewmate, "Can Port To Portal From Everywhere", true, portalmakerSpawnRate); - - securityGuardSpawnRate = CustomOption.Create(280, Types.Crewmate, cs(SecurityGuard.color, "Security Guard"), rates, null, true); - securityGuardCooldown = CustomOption.Create(281, Types.Crewmate, "Security Guard Cooldown", 30f, 10f, 60f, 2.5f, securityGuardSpawnRate, suffix: "s"); - securityGuardTotalScrews = CustomOption.Create(282, Types.Crewmate, "Security Guard Number Of Screws", 7f, 1f, 15f, 1f, securityGuardSpawnRate); - securityGuardCamPrice = CustomOption.Create(283, Types.Crewmate, "Number Of Screws Per Cam", 2f, 1f, 15f, 1f, securityGuardSpawnRate); - securityGuardVentPrice = CustomOption.Create(284, Types.Crewmate, "Number Of Screws Per Vent", 1f, 1f, 15f, 1f, securityGuardSpawnRate); - securityGuardCamDuration = CustomOption.Create(285, Types.Crewmate, "Security Guard Duration", 10f, 2.5f, 60f, 2.5f, securityGuardSpawnRate, suffix: "s"); - securityGuardCamMaxCharges = CustomOption.Create(286, Types.Crewmate, "Gadged Max Charges", 5f, 1f, 30f, 1f, securityGuardSpawnRate); - securityGuardCamRechargeTasksNumber = CustomOption.Create(287, Types.Crewmate, "Number Of Tasks Needed For Recharging", 3f, 1f, 10f, 1f, securityGuardSpawnRate); - securityGuardNoMove = CustomOption.Create(288, Types.Crewmate, "Cant Move During Cam Duration", true, securityGuardSpawnRate); - - mediumSpawnRate = CustomOption.Create(360, Types.Crewmate, cs(Medium.color, "Medium"), rates, null, true); - mediumCooldown = CustomOption.Create(361, Types.Crewmate, "Medium Questioning Cooldown", 30f, 5f, 120f, 5f, mediumSpawnRate, suffix: "s"); - mediumDuration = CustomOption.Create(362, Types.Crewmate, "Medium Questioning Duration", 3f, 0f, 15f, 1f, mediumSpawnRate, suffix: "s"); - mediumOneTimeUse = CustomOption.Create(363, Types.Crewmate, "Each Soul Can Only Be Questioned Once", false, mediumSpawnRate); - mediumChanceAdditionalInfo = CustomOption.Create(364, Types.Crewmate, "Chance That The Answer Contains \n Additional Information", rates, mediumSpawnRate); - - thiefSpawnRate = CustomOption.Create(400, Types.Neutral, cs(Thief.color, "Thief"), rates, null, true); - thiefCooldown = CustomOption.Create(401, Types.Neutral, "Thief Cooldown", 30f, 5f, 120f, 5f, thiefSpawnRate, suffix: "s"); - thiefCanKillSheriff = CustomOption.Create(402, Types.Neutral, "Thief Can Kill Sheriff", true, thiefSpawnRate); - thiefHasImpVision = CustomOption.Create(403, Types.Neutral, "Thief Has Impostor Vision", true, thiefSpawnRate); - thiefCanUseVents = CustomOption.Create(404, Types.Neutral, "Thief Can Use Vents", true, thiefSpawnRate); - thiefCanStealWithGuess = CustomOption.Create(405, Types.Neutral, "Thief Can Guess To Steal A Role (If Guesser)", false, thiefSpawnRate); - StolenPlayerKeepsHisTeam = CustomOption.Create(5008, Types.Neutral, "The stolen player keeps his team", false, thiefSpawnRate); - - trapperSpawnRate = CustomOption.Create(410, Types.Crewmate, cs(Trapper.color, "Trapper"), rates, null, true); - trapperCooldown = CustomOption.Create(420, Types.Crewmate, "Trapper Cooldown", 30f, 5f, 120f, 5f, trapperSpawnRate, suffix: "s"); - trapperMaxCharges = CustomOption.Create(440, Types.Crewmate, "Max Traps Charges", 5f, 1f, 15f, 1f, trapperSpawnRate); - trapperRechargeTasksNumber = CustomOption.Create(450, Types.Crewmate, "Number Of Tasks Needed For Recharging", 2f, 1f, 15f, 1f, trapperSpawnRate); - trapperTrapNeededTriggerToReveal = CustomOption.Create(451, Types.Crewmate, "Trap Needed Trigger To Reveal", 3f, 2f, 10f, 1f, trapperSpawnRate); - trapperAnonymousMap = CustomOption.Create(452, Types.Crewmate, "Show Anonymous Map", false, trapperSpawnRate); - trapperInfoType = CustomOption.Create(453, Types.Crewmate, "Trap Information Type", new string[] { "Role", "Good/Evil Role", "Name" }, trapperSpawnRate); - trapperTrapDuration = CustomOption.Create(454, Types.Crewmate, "Time before trap is active", 5f, 1f, 15f, 1f, trapperSpawnRate, suffix: "s"); - - // Modifier (1000 - 1999) - modifiersAreHidden = CustomOption.Create(1009, Types.Modifier, cs(Color.yellow, "Hide After Death Modifiers"), true, null, true); - - modifierBloody = CustomOption.Create(1000, Types.Modifier, cs(Color.yellow, "Bloody"), rates, null, true); - modifierBloodyQuantity = CustomOption.Create(1001, Types.Modifier, cs(Color.yellow, "Bloody Quantity"), ratesModifier, modifierBloody); - modifierBloodyDuration = CustomOption.Create(1002, Types.Modifier, "Trail Duration", 10f, 3f, 60f, 1f, modifierBloody, suffix: "s"); - - modifierAntiTeleport = CustomOption.Create(1010, Types.Modifier, cs(Color.yellow, "Anti Teleport"), rates, null, true); - modifierAntiTeleportQuantity = CustomOption.Create(1011, Types.Modifier, cs(Color.yellow, "Anti Teleport Quantity"), ratesModifier, modifierAntiTeleport); - - modifierTieBreaker = CustomOption.Create(1020, Types.Modifier, cs(Color.yellow, "Tie Breaker"), rates, null, true); - - modifierBait = CustomOption.Create(1030, Types.Modifier, cs(Color.yellow, "Bait"), rates, null, true); - modifierBaitQuantity = CustomOption.Create(1031, Types.Modifier, cs(Color.yellow, "Bait Quantity"), ratesModifier, modifierBait); - modifierBaitReportDelayMin = CustomOption.Create(1032, Types.Modifier, "Bait Report Delay Min", 0f, 0f, 10f, 1f, modifierBait, suffix: "s"); - modifierBaitReportDelayMax = CustomOption.Create(1033, Types.Modifier, "Bait Report Delay Max", 0f, 0f, 10f, 1f, modifierBait, suffix: "s"); - modifierBaitShowKillFlash = CustomOption.Create(1034, Types.Modifier, "Warn The Killer With A Flash", true, modifierBait); - - modifierLover = CustomOption.Create(1040, Types.Modifier, cs(Color.yellow, "Lovers"), rates, null, true); - modifierLoverImpLoverRate = CustomOption.Create(1041, Types.Modifier, "Chance That One Lover Is Impostor", rates, modifierLover); - modifierLoverBothDie = CustomOption.Create(1042, Types.Modifier, "Both Lovers Die", true, modifierLover); - modifierLoverEnableChat = CustomOption.Create(1043, Types.Modifier, "Enable Lover Chat", true, modifierLover); - - modifierSunglasses = CustomOption.Create(1050, Types.Modifier, cs(Color.yellow, "Sunglasses"), rates, null, true); - modifierSunglassesQuantity = CustomOption.Create(1051, Types.Modifier, cs(Color.yellow, "Sunglasses Quantity"), ratesModifier, modifierSunglasses); - modifierSunglassesVision = CustomOption.Create(1052, Types.Modifier, "Vision With Sunglasses", new string[] { "-10%", "-20%", "-30%", "-40%", "-50%" }, modifierSunglasses); - - modifierMini = CustomOption.Create(1061, Types.Modifier, cs(Color.yellow, "Mini"), rates, null, true); - modifierMiniGrowingUpDuration = CustomOption.Create(1062, Types.Modifier, "Mini Growing Up Duration", 400f, 100f, 1500f, 100f, modifierMini, suffix: "s"); - modifierMiniGrowingUpInMeeting = CustomOption.Create(1063, Types.Modifier, "Mini Grows Up In Meeting", true, modifierMini); - - modifierVip = CustomOption.Create(1070, Types.Modifier, cs(Color.yellow, "VIP"), rates, null, true); - modifierVipQuantity = CustomOption.Create(1071, Types.Modifier, cs(Color.yellow, "VIP Quantity"), ratesModifier, modifierVip); - modifierVipShowColor = CustomOption.Create(1072, Types.Modifier, "Show Team Color", true, modifierVip); - - modifierInvert = CustomOption.Create(1080, Types.Modifier, cs(Color.yellow, "Invert"), rates, null, true); - modifierInvertQuantity = CustomOption.Create(1081, Types.Modifier, cs(Color.yellow, "Modifier Quantity"), ratesModifier, modifierInvert); - modifierInvertDuration = CustomOption.Create(1082, Types.Modifier, "Number Of Meetings Inverted", 3f, 1f, 15f, 1f, modifierInvert); - - modifierChameleon = CustomOption.Create(1090, Types.Modifier, cs(Color.yellow, "Chameleon"), rates, null, true); - modifierChameleonQuantity = CustomOption.Create(1091, Types.Modifier, cs(Color.yellow, "Chameleon Quantity"), ratesModifier, modifierChameleon); - modifierChameleonHoldDuration = CustomOption.Create(1092, Types.Modifier, "Time Until Fading Starts", 3f, 1f, 10f, 0.5f, modifierChameleon, suffix: "s"); - modifierChameleonFadeDuration = CustomOption.Create(1093, Types.Modifier, "Fade Duration", 1f, 0.25f, 10f, 0.25f, modifierChameleon, suffix: "s"); - modifierChameleonMinVisibility = CustomOption.Create(1094, Types.Modifier, "Minimum Visibility", new string[] { "0%", "10%", "20%", "30%", "40%", "50%" }, modifierChameleon); - - modifierShifter = CustomOption.Create(1100, Types.Modifier, cs(Color.yellow, "Shifter"), rates, null, true); - - // Guesser Gamemode (2000 - 2999) - guesserGamemodeCrewNumber = CustomOption.Create(2001, Types.Guesser, cs(Guesser.color, "Number of Crew Guessers"), 15f, 1f, 15f, 1f, null, true); - guesserGamemodeNeutralNumber = CustomOption.Create(2002, Types.Guesser, cs(Guesser.color, "Number of Neutral Guessers"), 15f, 1f, 15f, 1f, null, true); - guesserGamemodeImpNumber = CustomOption.Create(2003, Types.Guesser, cs(Guesser.color, "Number of Impostor Guessers"), 15f, 1f, 15f, 1f, null, true); - guesserForceJackalGuesser = CustomOption.Create(2007, Types.Guesser, "Force Jackal Guesser", false, null, true); - guesserForceThiefGuesser = CustomOption.Create(2011, Types.Guesser, "Force Thief Guesser", false, null, true); - guesserGamemodeHaveModifier = CustomOption.Create(2004, Types.Guesser, "Guessers Can Have A Modifier", true, null); - guesserGamemodeNumberOfShots = CustomOption.Create(2005, Types.Guesser, "Guesser Number Of Shots", 3f, 1f, 15f, 1f, null); - guesserGamemodeHasMultipleShotsPerMeeting = CustomOption.Create(2006, Types.Guesser, "Guesser Can Shoot Multiple Times Per Meeting", false, null); - guesserGamemodeKillsThroughShield = CustomOption.Create(2008, Types.Guesser, "Guesses Ignore The Medic Shield", true, null); - guesserGamemodeEvilCanKillSpy = CustomOption.Create(2009, Types.Guesser, "Evil Guesser Can Guess The Spy", true, null); - guesserGamemodeCantGuessSnitchIfTaksDone = CustomOption.Create(2010, Types.Guesser, "Guesser Can't Guess Snitch When Tasks Completed", true, null); - - // Hide N Seek Gamemode (3000 - 3999) - hideNSeekMap = CustomOption.Create(3020, Types.HideNSeekMain, cs(Color.yellow, "Map"), new string[] { "The Skeld", "Mira", "Polus", "Airship", "Submerged" }, null, true); - hideNSeekHunterCount = CustomOption.Create(3000, Types.HideNSeekMain, cs(Color.yellow, "Number Of Hunters"), 1f, 1f, 3f, 1f); - hideNSeekKillCooldown = CustomOption.Create(3021, Types.HideNSeekMain, cs(Color.yellow, "Kill Cooldown"), 10f, 2.5f, 60f, 2.5f, suffix: "s"); - hideNSeekHunterVision = CustomOption.Create(3001, Types.HideNSeekMain, cs(Color.yellow, "Hunter Vision"), 0.5f, 0.25f, 2f, 0.25f, suffix: "µ"); - hideNSeekHuntedVision = CustomOption.Create(3002, Types.HideNSeekMain, cs(Color.yellow, "Hunted Vision"), 2f, 0.25f, 5f, 0.25f); - hideNSeekCommonTasks = CustomOption.Create(3023, Types.HideNSeekMain, cs(Color.yellow, "Common Tasks"), 1f, 0f, 4f, 1f); - hideNSeekShortTasks = CustomOption.Create(3024, Types.HideNSeekMain, cs(Color.yellow, "Short Tasks"), 3f, 1f, 23f, 1f); - hideNSeekLongTasks = CustomOption.Create(3025, Types.HideNSeekMain, cs(Color.yellow, "Long Tasks"), 3f, 0f, 15f, 1f); - hideNSeekTimer = CustomOption.Create(3003, Types.HideNSeekMain, cs(Color.yellow, "Timer In Min"), 5f, 1f, 30f, 1f); - hideNSeekTaskWin = CustomOption.Create(3004, Types.HideNSeekMain, cs(Color.yellow, "Task Win Is Possible"), false); - hideNSeekTaskPunish = CustomOption.Create(3017, Types.HideNSeekMain, cs(Color.yellow, "Finish Tasks Punishment"), 10f, 0f, 30f, 1f, suffix: "s"); - hideNSeekCanSabotage = CustomOption.Create(3019, Types.HideNSeekMain, cs(Color.yellow, "Enable Sabotages"), false); - hideNSeekHunterWaiting = CustomOption.Create(3022, Types.HideNSeekMain, cs(Color.yellow, "Time The Hunter Needs To Wait"), 15f, 2.5f, 60f, 2.5f); - - hunterLightCooldown = CustomOption.Create(3005, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Cooldown"), 30f, 5f, 60f, 1f, null, true, suffix: "s"); - hunterLightDuration = CustomOption.Create(3006, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Duration"), 5f, 1f, 60f, 1f, suffix: "s"); - hunterLightVision = CustomOption.Create(3007, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Vision"), 3f, 1f, 5f, 0.25f, suffix: "%"); - hunterLightPunish = CustomOption.Create(3008, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Punishment"), 5f, 0f, 30f, 1f, suffix: "s"); - hunterAdminCooldown = CustomOption.Create(3009, Types.HideNSeekRoles, cs(Color.red, "Hunter Admin Cooldown"), 30f, 5f, 60f, 1f, suffix: "s"); - hunterAdminDuration = CustomOption.Create(3010, Types.HideNSeekRoles, cs(Color.red, "Hunter Admin Duration"), 5f, 1f, 60f, 1f, suffix: "s"); - hunterAdminPunish = CustomOption.Create(3011, Types.HideNSeekRoles, cs(Color.red, "Hunter Admin Punishment"), 5f, 0f, 30f, 1f, suffix: "s"); - hunterArrowCooldown = CustomOption.Create(3012, Types.HideNSeekRoles, cs(Color.red, "Hunter Arrow Cooldown"), 30f, 5f, 60f, 1f, suffix: "s"); - hunterArrowDuration = CustomOption.Create(3013, Types.HideNSeekRoles, cs(Color.red, "Hunter Arrow Duration"), 5f, 0f, 60f, 1f, suffix: "s"); - hunterArrowPunish = CustomOption.Create(3014, Types.HideNSeekRoles, cs(Color.red, "Hunter Arrow Punishment"), 5f, 0f, 30f, 1f, suffix: "s"); - - huntedShieldCooldown = CustomOption.Create(3015, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Cooldown"), 30f, 5f, 60f, 1f, null, true, suffix: "s"); - huntedShieldDuration = CustomOption.Create(3016, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Duration"), 5f, 1f, 60f, 1f, suffix: "s"); - huntedShieldRewindTime = CustomOption.Create(3018, Types.HideNSeekRoles, cs(Color.gray, "Hunted Rewind Time"), 3f, 1f, 10f, 1f, suffix: "s"); - huntedShieldNumber = CustomOption.Create(3026, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Number"), 3f, 1f, 15f, 1f); - - // Other options - RandomizePlayersInMeeting = CustomOption.Create(5020, Types.General, "Randomize Players Order In Meetings", false, isHeader: true); - RandomizeWireTaskPositions = CustomOption.Create(5006, Types.General, "Randomize Wire Tasks Positions", false, isHeader: true); - RandomizeUploadTaskPosition = CustomOption.Create(5007, Types.General, "Randomize Upload Task Positions", false); - - maxNumberOfMeetings = CustomOption.Create(3, Types.General, "Number Of Meetings (excluding Mayor meeting)", 10, 0, 15, 1, null, true); - blockSkippingInEmergencyMeetings = CustomOption.Create(4, Types.General, "Block Skipping In Emergency Meetings", false); - noVoteIsSelfVote = CustomOption.Create(5, Types.General, "No Vote Is Self Vote", false, blockSkippingInEmergencyMeetings); - hidePlayerNames = CustomOption.Create(6, Types.General, "Hide Player Names", false, isHeader: true); - allowParallelMedBayScans = CustomOption.Create(7, Types.General, "Allow Parallel MedBay Scans", false, isHeader: true); - RandomizePositionDuringScan = CustomOption.Create(5003, Types.General, "Randomize Position During MedBay Scans", false); - shieldFirstKill = CustomOption.Create(8, Types.General, "Shield Last Game First Kill", false, isHeader: true); - ExpireFirstKillShield = CustomOption.Create(5004, Types.General, "Expire shield with duration", false, shieldFirstKill); - FirstKillShieldDuration = CustomOption.Create(5005, Types.General, "Shield duration", 80f, 10f, 300f, 5f, ExpireFirstKillShield, suffix: "s"); - finishTasksBeforeHauntingOrZoomingOut = CustomOption.Create(9, Types.General, "Finish Tasks Before Haunting Or Zooming Out", true, isHeader: true); - camsNightVision = CustomOption.Create(11, Types.General, "Cams Switch To Night Vision If Lights Are Off", false, null, true); - camsNoNightVisionIfImpVision = CustomOption.Create(12, Types.General, "Impostor Vision Ignores Night Vision Cams", false, camsNightVision, false); - - - dynamicMap = CustomOption.Create(500, Types.General, "Play On A Random Map", false, null, true); - dynamicMapEnableSkeld = CustomOption.Create(501, Types.General, "Skeld", 0f, 0f, 100f, 1f, dynamicMap, suffix: "%"); - dynamicMapEnableMira = CustomOption.Create(502, Types.General, "Mira", 0f, 0f, 100f, 1f, dynamicMap, suffix: "%"); - dynamicMapEnablePolus = CustomOption.Create(503, Types.General, "Polus", 0f, 0f, 100f, 1f, dynamicMap, suffix: "%"); - dynamicMapEnableAirShip = CustomOption.Create(504, Types.General, "Airship", 0f, 0f, 100f, 1f, dynamicMap, suffix: "%"); - dynamicMapEnableSubmerged = CustomOption.Create(505, Types.General, "Submerged", 0f, 0f, 100f, 1f, dynamicMap, suffix: "%"); - dynamicMapSeparateSettings = CustomOption.Create(509, Types.General, "Use Random Map Setting Presets", false, dynamicMap); - - blockedRolePairings.Add((byte)RoleId.Vampire, new [] { (byte)RoleId.Warlock}); - blockedRolePairings.Add((byte)RoleId.Warlock, new [] { (byte)RoleId.Vampire}); - blockedRolePairings.Add((byte)RoleId.Spy, new [] { (byte)RoleId.Mini}); - blockedRolePairings.Add((byte)RoleId.Mini, new [] { (byte)RoleId.Spy}); - blockedRolePairings.Add((byte)RoleId.Vulture, new [] { (byte)RoleId.Cleaner}); - blockedRolePairings.Add((byte)RoleId.Cleaner, new [] { (byte)RoleId.Vulture}); - } - } -} diff --git a/BetterOtherRoles/Eno/PluginUpdater.cs b/BetterOtherRoles/Eno/PluginUpdater.cs deleted file mode 100644 index 4670046..0000000 --- a/BetterOtherRoles/Eno/PluginUpdater.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; -using BepInEx; -using BepInEx.Unity.IL2CPP.Utils; -using BetterOtherRoles.UI; -using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.SceneManagement; - -namespace BetterOtherRoles.Eno; - -public class PluginUpdater : MonoBehaviour -{ - public const string RepositoryOwner = "EnoPM"; - public const string RepositoryName = "BetterOtherRoles"; - public static PluginUpdater Instance { get; private set; } - - public PluginUpdater(IntPtr ptr) : base(ptr) { } - - private bool _busy; - public List Releases; - - public void Awake() - { - if (Instance) Destroy(Instance); - Instance = this; - foreach (var file in Directory.GetFiles(Path.Combine(Paths.PluginPath, "BetterOtherRoles"), "*.old")) - { - File.Delete(file); - } - } - - private void Update() - { - if (Rewired.ReInput.players?.GetPlayer(0)?.GetButtonDown("ActionToggleUpdater") == true) - { - UIManager.UpdatePluginPanel?.Toggle(); - } - } - - private void Start() - { - if (_busy) return; - this.StartCoroutine(CoCheckForUpdate()); - } - - [HideFromIl2Cpp] - private void SetLoadingText(string text) - { - UIManager.UpdatePluginPanel?.SetProgressInfosText(text); - } - - [HideFromIl2Cpp] - private void SetLoadingProgression(float progression) - { - UIManager.UpdatePluginPanel?.SetDownloadProgression(progression); - } - - [HideFromIl2Cpp] - private void SetLoadingActive(bool active) - { - UIManager.UpdatePluginPanel?.SetProgressBarActive(active); - } - - [HideFromIl2Cpp] - private void SetLoadingError(string error) - { - UIManager.UpdatePluginPanel?.SetProgressInfosText(Helpers.cs(Color.red, error)); - BetterOtherRolesPlugin.Logger.LogError(error); - } - - [HideFromIl2Cpp] - public void StartDownloadRelease(GithubRelease release) - { - if (_busy) return; - this.StartCoroutine(CoDownloadRelease(release)); - } - - [HideFromIl2Cpp] - private IEnumerator CoCheckForUpdate() - { - _busy = true; - SetLoadingText("Checking for updates"); - var www = new UnityWebRequest(); - www.SetMethod(UnityWebRequest.UnityWebRequestMethod.Get); - www.SetUrl($"https://api.github.com/repos/{RepositoryOwner}/{RepositoryName}/releases"); - www.downloadHandler = new DownloadHandlerBuffer(); - var operation = www.SendWebRequest(); - - while (!operation.isDone) - { - yield return new WaitForEndOfFrame(); - } - - if (www.isNetworkError || www.isHttpError) - { - SetLoadingError(www.error); - yield break; - } - - Releases = JsonSerializer.Deserialize>(www.downloadHandler.text); - www.downloadHandler.Dispose(); - www.Dispose(); - Releases.Sort(SortReleases); - var latestRelease = Releases.FirstOrDefault(); - if (latestRelease != null && latestRelease.Version != BetterOtherRolesPlugin.Version) - { - UIManager.UpdatePluginPanel?.RefreshDropdown(latestRelease); - UIManager.UpdatePluginPanel?.SetActive(true); - } - else - { - UIManager.UpdatePluginPanel?.RefreshDropdown(); - } - - _busy = false; - } - - [HideFromIl2Cpp] - private IEnumerator CoDownloadRelease(GithubRelease release) - { - _busy = true; - var asset = release.Assets.Find(FilterPluginAsset); - var www = new UnityWebRequest(); - www.SetMethod(UnityWebRequest.UnityWebRequestMethod.Get); - www.SetUrl(asset.DownloadUrl); - www.downloadHandler = new DownloadHandlerBuffer(); - var operation = www.SendWebRequest(); - - SetLoadingText($"Downloading {BetterOtherRolesPlugin.Name} {release.Tag}..."); - SetLoadingActive(true); - SetLoadingProgression(0f); - - while (!operation.isDone) - { - SetLoadingProgression(www.downloadProgress); - yield return new WaitForEndOfFrame(); - } - - SetLoadingProgression(1f); - - if (www.isNetworkError || www.isHttpError) - { - SetLoadingError(www.error); - yield break; - } - - SetLoadingText($"Installing {BetterOtherRolesPlugin.Name} {release.Tag}..."); - - var filePath = Path.Combine(Paths.PluginPath, "BetterOtherRoles", asset.Name); - - if (File.Exists(filePath + ".old")) File.Delete(filePath + "old"); - if (File.Exists(filePath)) File.Move(filePath, filePath + ".old"); - - var persistTask = File.WriteAllBytesAsync(filePath, www.downloadHandler.data); - var hasError = false; - while (!persistTask.IsCompleted) - { - if (persistTask.Exception != null) - { - hasError = true; - SetLoadingError(persistTask.Exception.Message); - break; - } - yield return new WaitForEndOfFrame(); - } - - www.downloadHandler.Dispose(); - www.Dispose(); - - if (!hasError) - { - SetLoadingText(Helpers.cs(Color.green, "Installation completed! Please restart your game to apply the update")); - } - // SetLoadingActive(false); - _busy = false; - } - - [HideFromIl2Cpp] - private static bool FilterLatestRelease(GithubRelease release) - { - return release.IsNewer(BetterOtherRolesPlugin.Version) && release.Assets.Any(FilterPluginAsset); - } - - [HideFromIl2Cpp] - private static bool FilterPluginAsset(GithubAsset asset) - { - return asset.Name == "BetterOtherRoles.dll"; - } - - [HideFromIl2Cpp] - private static int SortReleases(GithubRelease a, GithubRelease b) - { - if (a.IsNewer(b.Version)) return -1; - if (b.IsNewer(a.Version)) return 1; - return 0; - } -} - -public class GithubRelease -{ - [JsonPropertyName("id")] - public int Id { get; set; } - - [JsonPropertyName("tag_name")] - public string Tag { get; set; } - - [JsonPropertyName("name")] - public string Name { get; set; } - - [JsonPropertyName("draft")] - public bool Draft { get; set; } - - [JsonPropertyName("prerelease")] - public bool Prerelease { get; set; } - - [JsonPropertyName("created_at")] - public string CreatedAt { get; set; } - - [JsonPropertyName("published_at")] - public string PublishedAt { get; set; } - - [JsonPropertyName("body")] - public string Description { get; set; } - - [JsonPropertyName("assets")] - public List Assets { get; set; } - - public Version Version => Version.Parse(Tag.Replace("v", string.Empty)); - - public bool IsNewer(Version version) - { - return Version > version; - } -} - -public class GithubAsset -{ - [JsonPropertyName("url")] - public string Url { get; set; } - - [JsonPropertyName("id")] - public int Id { get; set; } - - [JsonPropertyName("name")] - public string Name { get; set; } - - [JsonPropertyName("size")] - public int Size { get; set; } - - [JsonPropertyName("browser_download_url")] - public string DownloadUrl { get; set; } -} \ No newline at end of file diff --git a/BetterOtherRoles/Eno/VersionHandshake.cs b/BetterOtherRoles/Eno/VersionHandshake.cs deleted file mode 100644 index 4930006..0000000 --- a/BetterOtherRoles/Eno/VersionHandshake.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using BetterOtherRoles.Modules; -using BetterOtherRoles.Patches; -using BetterOtherRoles.Players; -using Hazel; - -namespace BetterOtherRoles.Eno; - -public class VersionHandshake -{ - public static VersionHandshake Instance - { - get - { - if (_instance == null) - { - GenerateLocalVersion(); - } - - return _instance; - } - - private set => _instance = value; - } - private static VersionHandshake _instance { get; set; } - private static readonly Dictionary AllVersions = new(); - - public Version Version { get; private set; } - public int ClientId { get; private set; } - public Guid Guid { get; private set; } - public Dictionary Flags { get; private set; } - - public static VersionHandshake Find(int clientId) - { - if (Instance.ClientId == clientId) return Instance; - return AllVersions.TryGetValue(clientId, out var value) ? value : null; - } - - public static bool Has(int clientId) - { - return Instance.ClientId == clientId || AllVersions.ContainsKey(clientId); - } - - public static void Clear() - { - Instance = null; - AllVersions.Clear(); - } - - public static void HandleRpcHandshake(MessageReader reader) - { - try - { - var major = reader.ReadByte(); - var minor = reader.ReadByte(); - var build = reader.ReadByte(); - var timer = reader.ReadSingle(); - var clientId = reader.ReadPackedInt32(); - var guid = Guid.Parse(reader.ReadString()); - var flags = JsonSerializer.Deserialize>(reader.ReadString()); - if (!AmongUsClient.Instance.AmHost && timer > 0f) - { - GameStartManagerPatch.timer = timer; - } - - var handshake = new VersionHandshake - { - Version = new Version(major, minor, build), - ClientId = clientId, - Guid = guid, - Flags = flags, - }; - - AllVersions[handshake.ClientId] = handshake; - } - catch (Exception e) - { - BetterOtherRolesPlugin.Logger.LogWarning($"Legacy version handshake cannot be parsed, error: {e.ToString()}"); - } - } - - public static void GenerateLocalVersion() - { - Instance = new VersionHandshake - { - Version = BetterOtherRolesPlugin.Version, - ClientId = AmongUsClient.Instance.ClientId, - Guid = DevConfig.CurrentGuid, - Flags = DevConfig.Flags, - }; - } - - public void Share() - { - var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.VersionHandshake, Hazel.SendOption.Reliable, -1); - writer.Write((byte)Version.Major); - writer.Write((byte)Version.Minor); - writer.Write((byte)Version.Build); - writer.Write(AmongUsClient.Instance.AmHost ? GameStartManagerPatch.timer : -1f); - writer.WritePacked(AmongUsClient.Instance.ClientId); - writer.Write(Guid.ToString()); - writer.Write(JsonSerializer.Serialize(Flags)); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - - public bool GuidMatch() - { - return Flags.ContainsKey("NO_GUID_CHECK") || Instance.Flags.ContainsKey("NO_GUID_CHECK") || Guid.Equals(Instance.Guid); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/Helpers.cs b/BetterOtherRoles/Helpers.cs index 98fd421..3a677c2 100644 --- a/BetterOtherRoles/Helpers.cs +++ b/BetterOtherRoles/Helpers.cs @@ -15,6 +15,8 @@ using System.Net; using BetterOtherRoles.CustomGameModes; using AmongUs.GameOptions; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Roles; using Innersloth.Assets; namespace BetterOtherRoles { @@ -28,7 +30,6 @@ public enum MurderAttemptResult { public enum CustomGamemodes { Classic, Guesser, - HideNSeek } public static class Helpers { @@ -444,12 +445,7 @@ public static MurderAttemptResult checkMuderAttempt(PlayerControl killer, Player } // Block hunted with time shield kill - else if (!ignoreShield && Hunted.timeshieldActive.Contains(target.PlayerId)) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.HuntedRewindTime, Hazel.SendOption.Reliable, -1); - writer.Write(target.PlayerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.huntedRewindTime(target.PlayerId); - + else if (!ignoreShield) { return MurderAttemptResult.SuppressKill; } diff --git a/BetterOtherRoles/Main.cs b/BetterOtherRoles/Main.cs index 5a9466d..61d060c 100644 --- a/BetterOtherRoles/Main.cs +++ b/BetterOtherRoles/Main.cs @@ -18,7 +18,10 @@ using BetterOtherRoles.Utilities; using Il2CppSystem.Security.Cryptography; using Il2CppSystem.Text; -using AmongUs.Data; +using AmongUsSpecimen; +using AmongUsSpecimen.Cosmetics; +using AmongUsSpecimen.Updater; +using AmongUsSpecimen.VersionCheck; using BetterOtherRoles.Modules.CustomHats; using BetterOtherRoles.UI; using BetterOtherRoles.Utilities.Attributes; @@ -26,13 +29,17 @@ namespace BetterOtherRoles { [BepInPlugin(Id, Name, VersionString)] + [BepInDependency(Specimen.Guid)] [BepInDependency(SubmergedCompatibility.SUBMERGED_GUID, BepInDependency.DependencyFlags.SoftDependency)] + [ModUpdater("EnoPM/BetterOtherRoles", VersionString, "BetterOtherRoles.dll", "BetterOtherRoles")] + [VersionHandshake(Name, VersionString)] + [CustomCosmetics("EnoPM/BetterOtherHats", "CustomHats.json")] [BepInProcess("Among Us.exe")] public class BetterOtherRolesPlugin : BasePlugin { public const string Name = "Better Other Roles"; public const string Id = "betterohterroles.eno.pm"; - public const string VersionString = "1.5.2"; + public const string VersionString = "1.6.0"; public static Version Version = Version.Parse(VersionString); internal static BepInEx.Logging.ManualLogSource Logger; @@ -71,7 +78,6 @@ public override void Load() { DebugMode = Config.Bind("Custom", "Enable Debug Mode", "false"); Harmony.PatchAll(); - CustomOptionHolder.Load(); CustomColors.Load(); CustomHatManager.LoadHats(); if (BepInExUpdater.UpdateRequired) diff --git a/BetterOtherRoles/MapOptions.cs b/BetterOtherRoles/MapOptions.cs index 3f1276b..76023c7 100644 --- a/BetterOtherRoles/MapOptions.cs +++ b/BetterOtherRoles/MapOptions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using BetterOtherRoles.Options; using BetterOtherRoles.UI; using UnityEngine; @@ -24,9 +25,7 @@ public static CustomGamemodes gameMode get => _gameMode; set { - var oldValue = _gameMode; _gameMode = value; - UIManager.CustomOptionsPanel?.CheckForUpdate(oldValue, _gameMode); } } private static CustomGamemodes _gameMode = CustomGamemodes.Classic; @@ -43,11 +42,11 @@ public static void clearAndReloadMapOptions() { ventsToSeal = new List(); playerIcons = new Dictionary(); ; - maxNumberOfMeetings = Mathf.RoundToInt(CustomOptionHolder.maxNumberOfMeetings.getSelection()); - blockSkippingInEmergencyMeetings = CustomOptionHolder.blockSkippingInEmergencyMeetings.getBool(); - noVoteIsSelfVote = CustomOptionHolder.noVoteIsSelfVote.getBool(); - hidePlayerNames = CustomOptionHolder.hidePlayerNames.getBool(); - allowParallelMedBayScans = CustomOptionHolder.allowParallelMedBayScans.getBool(); + maxNumberOfMeetings = Mathf.RoundToInt(CustomOptionHolder.MaxNumberOfMeetings.GetInt()); + blockSkippingInEmergencyMeetings = CustomOptionHolder.BlockSkippingInEmergencyMeetings.GetBool(); + noVoteIsSelfVote = CustomOptionHolder.NoVoteIsSelfVote.GetBool(); + hidePlayerNames = CustomOptionHolder.HidePlayerNames.GetBool(); + allowParallelMedBayScans = CustomOptionHolder.AllowParallelMedBayScans.GetBool(); } public static void reloadPluginOptions() { diff --git a/BetterOtherRoles/Modifiers/AntiTeleport.cs b/BetterOtherRoles/Modifiers/AntiTeleport.cs new file mode 100644 index 0000000..d09319d --- /dev/null +++ b/BetterOtherRoles/Modifiers/AntiTeleport.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using BetterOtherRoles.Players; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class AntiTeleport +{ + public static List antiTeleport = new List(); + public static Vector3 position; + + public static void clearAndReload() + { + antiTeleport = new List(); + position = Vector3.zero; + } + + public static void setPosition() + { + if (position == Vector3.zero) + return; // Check if this has been set, otherwise first spawn on submerged will fail + if (antiTeleport.FindAll(x => x.PlayerId == CachedPlayer.LocalPlayer.PlayerId).Count > 0) + { + CachedPlayer.LocalPlayer.NetTransform.RpcSnapTo(position); + if (SubmergedCompatibility.IsSubmerged) + { + SubmergedCompatibility.ChangeFloor(position.y > -7); + } + } + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Bait.cs b/BetterOtherRoles/Modifiers/Bait.cs new file mode 100644 index 0000000..1fecc97 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Bait.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class Bait +{ + public static List bait = new List(); + public static Dictionary active = new Dictionary(); + public static Color color = new Color32(0, 247, 255, byte.MaxValue); + + public static float reportDelayMin = 0f; + public static float reportDelayMax = 0f; + public static bool showKillFlash = true; + + public static void clearAndReload() + { + bait = new List(); + active = new Dictionary(); + reportDelayMin = CustomOptionHolder.ModifierBaitReportDelayMin.GetFloat(); + reportDelayMax = CustomOptionHolder.ModifierBaitReportDelayMax.GetFloat(); + if (reportDelayMin > reportDelayMax) reportDelayMin = reportDelayMax; + showKillFlash = CustomOptionHolder.ModifierBaitShowKillFlash.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Bloody.cs b/BetterOtherRoles/Modifiers/Bloody.cs new file mode 100644 index 0000000..682cbf2 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Bloody.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; + +namespace BetterOtherRoles.Modifiers; + +public static class Bloody +{ + public static List bloody = new List(); + public static Dictionary active = new Dictionary(); + public static Dictionary bloodyKillerMap = new Dictionary(); + + public static float duration = 5f; + + public static void clearAndReload() + { + bloody = new List(); + active = new Dictionary(); + bloodyKillerMap = new Dictionary(); + duration = CustomOptionHolder.ModifierBloodyDuration.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Chameleon.cs b/BetterOtherRoles/Modifiers/Chameleon.cs new file mode 100644 index 0000000..163c8e8 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Chameleon.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using AmongUs.Data; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class Chameleon +{ + public static List chameleon = new List(); + public static float minVisibility = 0.2f; + public static float holdDuration = 1f; + public static float fadeDuration = 0.5f; + public static Dictionary lastMoved; + + public static void clearAndReload() + { + chameleon = []; + lastMoved = new Dictionary(); + holdDuration = CustomOptionHolder.ModifierChameleonHoldDuration.GetFloat(); + fadeDuration = CustomOptionHolder.ModifierChameleonFadeDuration.GetFloat(); + minVisibility = CustomOptionHolder.ModifierChameleonMinVisibility.GetFloat() / 100f; + } + + public static float visibility(byte playerId) + { + float visibility = 1f; + if (lastMoved != null && lastMoved.ContainsKey(playerId)) + { + var tStill = Time.time - lastMoved[playerId]; + if (tStill > holdDuration) + { + if (tStill - holdDuration > fadeDuration) visibility = minVisibility; + else + visibility = (1 - (tStill - holdDuration) / fadeDuration) * (1 - minVisibility) + minVisibility; + } + } + + if (PlayerControl.LocalPlayer.Data.IsDead && visibility < 0.1f) + { + // Ghosts can always see! + visibility = 0.1f; + } + + return visibility; + } + + public static void update() + { + foreach (var chameleonPlayer in chameleon) + { + if (chameleonPlayer == Ninja.ninja && Ninja.isInvisble) continue; // Dont make Ninja visible... + // check movement by animation + PlayerPhysics playerPhysics = chameleonPlayer.MyPhysics; + var currentPhysicsAnim = playerPhysics.Animations.Animator.GetCurrentAnimation(); + if (currentPhysicsAnim != playerPhysics.Animations.group.IdleAnim) + { + lastMoved[chameleonPlayer.PlayerId] = Time.time; + } + + // calculate and set visibility + float visibility = Chameleon.visibility(chameleonPlayer.PlayerId); + float petVisibility = visibility; + if (chameleonPlayer.Data.IsDead) + { + visibility = 0.5f; + petVisibility = 1f; + } + + try + { + // Sometimes renderers are missing for weird reasons. Try catch to avoid exceptions + chameleonPlayer.cosmetics.currentBodySprite.BodySprite.color = + chameleonPlayer.cosmetics.currentBodySprite.BodySprite.color.SetAlpha(visibility); + if (DataManager.Settings.Accessibility.ColorBlindMode) + chameleonPlayer.cosmetics.colorBlindText.color = + chameleonPlayer.cosmetics.colorBlindText.color.SetAlpha(visibility); + chameleonPlayer.SetHatAndVisorAlpha(visibility); + chameleonPlayer.cosmetics.skin.layer.color = + chameleonPlayer.cosmetics.skin.layer.color.SetAlpha(visibility); + chameleonPlayer.cosmetics.nameText.color = + chameleonPlayer.cosmetics.nameText.color.SetAlpha(visibility); + foreach (var rend in chameleonPlayer.cosmetics.currentPet.renderers) + rend.color = rend.color.SetAlpha(petVisibility); + foreach (var shadowRend in chameleonPlayer.cosmetics.currentPet.shadows) + shadowRend.color = shadowRend.color.SetAlpha(petVisibility); + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Invert.cs b/BetterOtherRoles/Modifiers/Invert.cs new file mode 100644 index 0000000..201a86e --- /dev/null +++ b/BetterOtherRoles/Modifiers/Invert.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; + +namespace BetterOtherRoles.Modifiers; + +public static class Invert +{ + public static List invert = new List(); + public static int meetings = 3; + + public static void clearAndReload() + { + invert = []; + meetings = CustomOptionHolder.ModifierInvertDuration.GetInt(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Lovers.cs b/BetterOtherRoles/Modifiers/Lovers.cs new file mode 100644 index 0000000..d6fedd7 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Lovers.cs @@ -0,0 +1,73 @@ +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class Lovers +{ + public static PlayerControl lover1; + public static PlayerControl lover2; + public static Color color = new Color32(232, 57, 185, byte.MaxValue); + + public static bool bothDie = true; + + public static bool enableChat = 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 existing() + { + return lover1 != null && lover2 != null && !lover1.Data.Disconnected && !lover2.Data.Disconnected; + } + + public static bool existingAndAlive() + { + return existing() && !lover1.Data.IsDead && !lover2.Data.IsDead && + !notAckedExiledIsLover; // ADD NOT ACKED IS LOVER + } + + public static PlayerControl otherLover(PlayerControl oneLover) + { + if (!existingAndAlive()) return null; + if (oneLover == lover1) return lover2; + if (oneLover == lover2) return lover1; + return null; + } + + public static bool existingWithKiller() + { + return existing() && (lover1 == Jackal.jackal || lover2 == Jackal.jackal + || lover1 == Sidekick.sidekick || lover2 == Sidekick.sidekick + || lover1.Data.Role.IsImpostor || + lover2.Data.Role.IsImpostor); + } + + public static bool hasAliveKillingLover(this PlayerControl player) + { + if (!Lovers.existingAndAlive() || !existingWithKiller()) + return false; + return (player != null && (player == lover1 || player == lover2)); + } + + public static void clearAndReload() + { + lover1 = null; + lover2 = null; + notAckedExiledIsLover = false; + bothDie = CustomOptionHolder.ModifierLoverBothDie.GetBool(); + enableChat = CustomOptionHolder.ModifierLoverEnableChat.GetBool(); + } + + public static PlayerControl getPartner(this PlayerControl player) + { + if (player == null) + return null; + if (lover1 == player) + return lover2; + if (lover2 == player) + return lover1; + return null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Mini.cs b/BetterOtherRoles/Modifiers/Mini.cs new file mode 100644 index 0000000..1e18e98 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Mini.cs @@ -0,0 +1,40 @@ +using System; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class Mini +{ + public static PlayerControl mini; + public static Color color = Color.yellow; + public const float defaultColliderRadius = 0.2233912f; + public const float defaultColliderOffset = 0.3636057f; + + public static float growingUpDuration = 400f; + public static bool isGrowingUpInMeeting = true; + public static DateTime timeOfGrowthStart = DateTime.UtcNow; + public static DateTime timeOfMeetingStart = DateTime.UtcNow; + public static float ageOnMeetingStart = 0f; + public static bool triggerMiniLose = false; + + public static void clearAndReload() + { + mini = null; + triggerMiniLose = false; + growingUpDuration = CustomOptionHolder.ModifierMiniGrowingUpDuration.GetFloat(); + isGrowingUpInMeeting = CustomOptionHolder.ModifierMiniGrowingUpInMeeting.GetBool(); + timeOfGrowthStart = DateTime.UtcNow; + } + + public static float growingProgress() + { + 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/BetterOtherRoles/Modifiers/Shifter.cs b/BetterOtherRoles/Modifiers/Shifter.cs new file mode 100644 index 0000000..b65a01c --- /dev/null +++ b/BetterOtherRoles/Modifiers/Shifter.cs @@ -0,0 +1,134 @@ +using BetterOtherRoles.Roles; +using UnityEngine; + +namespace BetterOtherRoles.Modifiers; + +public static class Shifter +{ + public static PlayerControl shifter; + + public static PlayerControl futureShift; + public static PlayerControl currentTarget; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.ShiftButton.png", 115f); + return buttonSprite; + } + + public static void shiftRole(PlayerControl player1, PlayerControl player2, bool repeat = true) + { + if (Mayor.mayor != null && Mayor.mayor == player2) + { + if (repeat) shiftRole(player2, player1, false); + Mayor.mayor = player1; + } + else if (Portalmaker.portalmaker != null && Portalmaker.portalmaker == player2) + { + if (repeat) shiftRole(player2, player1, false); + Portalmaker.portalmaker = player1; + } + else if (Engineer.engineer != null && Engineer.engineer == player2) + { + if (repeat) shiftRole(player2, player1, false); + Engineer.engineer = player1; + } + else if (Sheriff.sheriff != null && Sheriff.sheriff == player2) + { + if (repeat) shiftRole(player2, player1, false); + if (Sheriff.formerDeputy != null && Sheriff.formerDeputy == Sheriff.sheriff) + Sheriff.formerDeputy = player1; // Shifter also shifts info on promoted deputy (to get handcuffs) + Sheriff.sheriff = player1; + } + else if (Deputy.deputy != null && Deputy.deputy == player2) + { + if (repeat) shiftRole(player2, player1, false); + Deputy.deputy = player1; + } + else if (Lighter.lighter != null && Lighter.lighter == player2) + { + if (repeat) shiftRole(player2, player1, false); + Lighter.lighter = player1; + } + else if (Detective.detective != null && Detective.detective == player2) + { + if (repeat) shiftRole(player2, player1, false); + Detective.detective = player1; + } + else if (TimeMaster.timeMaster != null && TimeMaster.timeMaster == player2) + { + if (repeat) shiftRole(player2, player1, false); + TimeMaster.timeMaster = player1; + } + else if (Medic.medic != null && Medic.medic == player2) + { + if (repeat) shiftRole(player2, player1, false); + Medic.medic = player1; + } + else if (Swapper.swapper != null && Swapper.swapper == player2) + { + if (repeat) shiftRole(player2, player1, false); + Swapper.swapper = player1; + } + else if (Seer.seer != null && Seer.seer == player2) + { + if (repeat) shiftRole(player2, player1, false); + Seer.seer = player1; + } + else if (Hacker.hacker != null && Hacker.hacker == player2) + { + if (repeat) shiftRole(player2, player1, false); + Hacker.hacker = player1; + } + else if (Tracker.tracker != null && Tracker.tracker == player2) + { + if (repeat) shiftRole(player2, player1, false); + Tracker.tracker = player1; + } + else if (Snitch.snitch != null && Snitch.snitch == player2) + { + if (repeat) shiftRole(player2, player1, false); + Snitch.snitch = player1; + } + else if (Spy.spy != null && Spy.spy == player2) + { + if (repeat) shiftRole(player2, player1, false); + Spy.spy = player1; + } + else if (SecurityGuard.securityGuard != null && SecurityGuard.securityGuard == player2) + { + if (repeat) shiftRole(player2, player1, false); + SecurityGuard.securityGuard = player1; + } + else if (Guesser.niceGuesser != null && Guesser.niceGuesser == player2) + { + if (repeat) shiftRole(player2, player1, false); + Guesser.niceGuesser = player1; + } + else if (Medium.medium != null && Medium.medium == player2) + { + if (repeat) shiftRole(player2, player1, false); + Medium.medium = player1; + } + else if (Pursuer.pursuer != null && Pursuer.pursuer == player2) + { + if (repeat) shiftRole(player2, player1, false); + Pursuer.pursuer = player1; + } + else if (Trapper.trapper != null && Trapper.trapper == player2) + { + if (repeat) shiftRole(player2, player1, false); + Trapper.trapper = player1; + } + } + + public static void clearAndReload() + { + shifter = null; + currentTarget = null; + futureShift = null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Sunglasses.cs b/BetterOtherRoles/Modifiers/Sunglasses.cs new file mode 100644 index 0000000..6be70fb --- /dev/null +++ b/BetterOtherRoles/Modifiers/Sunglasses.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; + +namespace BetterOtherRoles.Modifiers; + +public static class Sunglasses +{ + public static List sunglasses = new List(); + public static int vision = 1; + + public static void clearAndReload() + { + sunglasses = []; + vision = CustomOptionHolder.ModifierSunglassesVision.CurrentSelection + 1; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Tiebreaker.cs b/BetterOtherRoles/Modifiers/Tiebreaker.cs new file mode 100644 index 0000000..6bc5b5d --- /dev/null +++ b/BetterOtherRoles/Modifiers/Tiebreaker.cs @@ -0,0 +1,14 @@ +namespace BetterOtherRoles.Modifiers; + +public static class Tiebreaker +{ + public static PlayerControl tiebreaker; + + public static bool isTiebreak = false; + + public static void clearAndReload() + { + tiebreaker = null; + isTiebreak = false; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modifiers/Vip.cs b/BetterOtherRoles/Modifiers/Vip.cs new file mode 100644 index 0000000..4e11935 --- /dev/null +++ b/BetterOtherRoles/Modifiers/Vip.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; + +namespace BetterOtherRoles.Modifiers; + +public static class Vip +{ + public static List vip = new List(); + public static bool showColor = true; + + public static void clearAndReload() + { + vip = new List(); + showColor = CustomOptionHolder.ModifierVipShowColor.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Modules/BepInExUpdater.cs b/BetterOtherRoles/Modules/BepInExUpdater.cs index b274f54..89dfd32 100644 --- a/BetterOtherRoles/Modules/BepInExUpdater.cs +++ b/BetterOtherRoles/Modules/BepInExUpdater.cs @@ -21,7 +21,8 @@ public class BepInExUpdater : MonoBehaviour { public const string RequiredBepInExVersion = "6.0.0-be.674+82077ec7c91c97f0e5f8ada5d178fd7ece6c0099"; public const string BepInExDownloadURL = "https://builds.bepinex.dev/projects/bepinex_be/674/BepInEx-Unity.IL2CPP-win-x86-6.0.0-be.674%2B82077ec.zip"; - public static bool UpdateRequired => Paths.BepInExVersion.ToString() != RequiredBepInExVersion; + public static bool UpdateRequired => false; + //public static bool UpdateRequired => Paths.BepInExVersion.ToString() != RequiredBepInExVersion; public void Awake() { diff --git a/BetterOtherRoles/Modules/BetterPolus.cs b/BetterOtherRoles/Modules/BetterPolus.cs index 4324dae..5147e15 100644 --- a/BetterOtherRoles/Modules/BetterPolus.cs +++ b/BetterOtherRoles/Modules/BetterPolus.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using AmongUsSpecimen.ModOptions; +using BetterOtherRoles.Options; using BetterOtherRoles.Utilities.Attributes; using UnityEngine; @@ -8,8 +10,8 @@ namespace BetterOtherRoles.Modules; [Autoload] public static class BetterPolus { - public static CustomOption Enabled => CustomOptionHolder.EnableBetterPolus; - public static CustomOption ReactorCountdown = CustomOptionHolder.PolusReactorCountdown; + public static ModBoolOption Enabled => CustomOptionHolder.EnableBetterPolus; + public static ModFloatOption ReactorCountdown = CustomOptionHolder.PolusReactorCountdown; private static readonly Dictionary Objects = new(); private static readonly Dictionary Consoles = new(); @@ -65,7 +67,7 @@ public static void Start() { Clear(); if (!ShipStatus.Instance) return; - if (Enabled.getBool()) + if (Enabled.GetBool()) { if (IsAdjustmentsDone) return; ApplyChanges(ShipStatus.Instance); @@ -79,7 +81,7 @@ public static void Start() public static void ApplyChanges(ShipStatus shipStatus) { - if (!Enabled.getBool() || shipStatus.Type != ShipStatus.MapType.Pb || IsAdjustmentsDone) return; + if (!Enabled.GetBool() || shipStatus.Type != ShipStatus.MapType.Pb || IsAdjustmentsDone) return; FindPolusObjects(); AdjustPolus(); IsAdjustmentsDone = true; diff --git a/BetterOtherRoles/Modules/BetterSkeld.cs b/BetterOtherRoles/Modules/BetterSkeld.cs index 28006ea..5d199fd 100644 --- a/BetterOtherRoles/Modules/BetterSkeld.cs +++ b/BetterOtherRoles/Modules/BetterSkeld.cs @@ -1,8 +1,8 @@ using System; using System.Collections; using System.Linq; -using System.Threading; using BepInEx.Unity.IL2CPP.Utils; +using BetterOtherRoles.Options; using BetterOtherRoles.Utilities.Attributes; using UnityEngine; using UnityEngine.AddressableAssets; @@ -12,9 +12,9 @@ namespace BetterOtherRoles.Modules; [Autoload] public static class BetterSkeld { - private static bool Enabled => CustomOptionHolder.EnableBetterSkeld.getBool(); - private static bool EnableAdmin => CustomOptionHolder.BetterSkeldEnableAdmin.getBool(); - private static bool EnableVitals => CustomOptionHolder.BetterSkeldEnableVitals.getBool(); + private static bool Enabled => CustomOptionHolder.EnableBetterSkeld.GetBool(); + private static bool EnableAdmin => CustomOptionHolder.BetterSkeldEnableAdmin.GetBool(); + private static bool EnableVitals => CustomOptionHolder.BetterSkeldEnableVitals.GetBool(); static BetterSkeld() { diff --git a/BetterOtherRoles/Modules/ChatCommands.cs b/BetterOtherRoles/Modules/ChatCommands.cs index 5cc5765..cfbd8dd 100644 --- a/BetterOtherRoles/Modules/ChatCommands.cs +++ b/BetterOtherRoles/Modules/ChatCommands.cs @@ -1,9 +1,8 @@ -using System; using HarmonyLib; using System.Linq; -using BetterOtherRoles.Eno; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Players; -using BetterOtherRoles.UI; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; namespace BetterOtherRoles.Modules { @@ -20,7 +19,6 @@ public static void Postfix(HudManager __instance) { { __instance.Chat.SetVisible(true); } - UIManager.VersionHandshakePanel?.UpdateChecks(); } } diff --git a/BetterOtherRoles/Modules/CustomOptions.cs b/BetterOtherRoles/Modules/CustomOptions.cs deleted file mode 100644 index 0c4fc7f..0000000 --- a/BetterOtherRoles/Modules/CustomOptions.cs +++ /dev/null @@ -1,1562 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using AmongUs.GameOptions; -using BepInEx.Configuration; -using BetterOtherRoles.Players; -using BetterOtherRoles.UI; -using BetterOtherRoles.Utilities; -using HarmonyLib; -using Hazel; -using UnityEngine; -using static BetterOtherRoles.BetterOtherRoles; -using static BetterOtherRoles.Modules.CustomOption; - -namespace BetterOtherRoles.Modules; - -public class CustomOption -{ - public enum CustomOptionType - { - General, - Impostor, - Neutral, - Crewmate, - Modifier, - Guesser, - HideNSeekMain, - HideNSeekRoles - } - - public enum ValueType - { - Float, - String, - Boolean - } - - public static List options = new List(); - public static int preset = 0; - public static ConfigEntry vanillaSettings; - - public int id; - public string name; - public System.Object[] selections; - - public int defaultSelection; - public ConfigEntry entry; - public int selection; - public OptionBehaviour optionBehaviour; - public CustomOption parent; - public bool isHeader; - public CustomOptionType type; - public string suffix; - public ValueType valueType; - - public string DisplayValue - { - get - { - if (valueType == ValueType.Boolean) - { - return selection > 0 ? Helpers.cs(Color.green, "yes") : Helpers.cs(Color.red, "no"); - } - - return $"{selections[selection]}{suffix}"; - } - } - - public string DisplayUIValue - { - get - { - if (valueType == ValueType.Boolean) - { - return selection > 0 ? Helpers.cs(Color.green, "✔") : Helpers.cs(Color.red, "✖"); - } - - return $"{selections[selection]}{suffix}"; - } - } - - public delegate void UpdateEvent(); - - public event UpdateEvent OnChange; - - // Option creation - - public CustomOption(int id, CustomOptionType type, string name, System.Object[] selections, - System.Object defaultValue, CustomOption parent, bool isHeader, string suffix, ValueType valueType) - { - this.id = id; - this.name = parent == null ? name : "- " + name; - this.selections = selections; - int index = Array.IndexOf(selections, defaultValue); - this.defaultSelection = index >= 0 ? index : 0; - this.parent = parent; - this.isHeader = isHeader; - this.type = type; - selection = 0; - this.suffix = suffix; - this.valueType = valueType; - if (id != 0) - { - entry = BetterOtherRolesPlugin.Instance.Config.Bind($"Preset{preset}", id.ToString(), defaultSelection); - selection = Mathf.Clamp(entry.Value, 0, selections.Length - 1); - } - - options.Add(this); - } - - public static CustomOption Create(int id, CustomOptionType type, string name, string[] selections, - CustomOption parent = null, bool isHeader = false, string suffix = "") - { - return new CustomOption(id, type, name, selections, "", parent, isHeader, suffix, ValueType.String); - } - - public static CustomOption Create(int id, CustomOptionType type, string name, float defaultValue, float min, - float max, float step, CustomOption parent = null, bool isHeader = false, string suffix = "") - { - List selections = new(); - for (float s = min; s <= max; s += step) - selections.Add(s); - return new CustomOption(id, type, name, selections.ToArray(), defaultValue, parent, isHeader, suffix, - ValueType.Float); - } - - public static CustomOption Create(int id, CustomOptionType type, string name, bool defaultValue, - CustomOption parent = null, bool isHeader = false, string suffix = "") - { - return new CustomOption(id, type, name, new string[] { "Off", "On" }, defaultValue ? "On" : "Off", parent, - isHeader, suffix, ValueType.Boolean); - } - - // Static behaviour - - public static void switchPreset(int newPreset) - { - saveVanillaOptions(); - CustomOption.preset = newPreset; - vanillaSettings = BetterOtherRolesPlugin.Instance.Config.Bind($"Preset{preset}", "GameOptions", ""); - loadVanillaOptions(); - foreach (CustomOption option in CustomOption.options) - { - if (option.id == 0) continue; - - option.entry = - BetterOtherRolesPlugin.Instance.Config.Bind($"Preset{preset}", option.id.ToString(), - option.defaultSelection); - option.selection = Mathf.Clamp(option.entry.Value, 0, option.selections.Length - 1); - if (option.optionBehaviour != null && option.optionBehaviour is StringOption stringOption) - { - stringOption.oldValue = stringOption.Value = option.selection; - stringOption.ValueText.text = option.DisplayValue; - } - } - } - - public static void saveVanillaOptions() - { - vanillaSettings.Value = - Convert.ToBase64String( - GameOptionsManager.Instance.gameOptionsFactory.ToBytes(GameManager.Instance.LogicOptions - .currentGameOptions)); - } - - public static void loadVanillaOptions() - { - string optionsString = vanillaSettings.Value; - if (optionsString == "") return; - GameOptionsManager.Instance.GameHostOptions = - GameOptionsManager.Instance.gameOptionsFactory.FromBytes(Convert.FromBase64String(optionsString)); - GameOptionsManager.Instance.CurrentGameOptions = GameOptionsManager.Instance.GameHostOptions; - GameManager.Instance.LogicOptions.SetGameOptions(GameOptionsManager.Instance.CurrentGameOptions); - GameManager.Instance.LogicOptions.SyncOptions(); - } - - public static void ShareOptionChange(uint optionId) - { - var option = options.FirstOrDefault(x => x.id == optionId); - if (option == null) return; - var writer = AmongUsClient.Instance!.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, - (byte)CustomRPC.ShareOptions, SendOption.Reliable, -1); - writer.Write((byte)1); - writer.WritePacked((uint)option.id); - writer.WritePacked(Convert.ToUInt32(option.selection)); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - - public static void ShareOptionSelections() - { - if (CachedPlayer.AllPlayers.Count <= 1 || - AmongUsClient.Instance!.AmHost == false && CachedPlayer.LocalPlayer.PlayerControl == null) return; - var optionsList = new List(CustomOption.options); - while (optionsList.Any()) - { - byte amount = (byte)Math.Min(optionsList.Count, 200); // takes less than 3 bytes per option on average - var writer = AmongUsClient.Instance!.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, - (byte)CustomRPC.ShareOptions, SendOption.Reliable, -1); - writer.Write(amount); - for (int i = 0; i < amount; i++) - { - var option = optionsList[0]; - optionsList.RemoveAt(0); - writer.WritePacked((uint)option.id); - writer.WritePacked(Convert.ToUInt32(option.selection)); - } - - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - } - - // Getter - - public int getSelection() - { - return selection; - } - - public bool getBool() - { - return selection > 0; - } - - public float getFloat() - { - return (float)selections[selection]; - } - - public int getQuantity() - { - return selection + 1; - } - - // Option changes - - public void updateSelection(int newSelection) - { - selection = Mathf.Clamp((newSelection + selections.Length) % selections.Length, 0, selections.Length - 1); - if (optionBehaviour != null) - { - if (optionBehaviour is StringOption stringOption) - { - stringOption.oldValue = stringOption.Value = selection; - stringOption.ValueText.text = DisplayValue; - } - else if (optionBehaviour is ToggleOption toggleOption) - { - toggleOption.oldValue = toggleOption.CheckMark.enabled = getBool(); - } - - - if (AmongUsClient.Instance && AmongUsClient.Instance.AmHost && CachedPlayer.LocalPlayer.PlayerControl) - { - if (id == 0 && selection != preset) - { - switchPreset(selection); // Switch presets - ShareOptionSelections(); - } - else if (entry != null) - { - entry.Value = selection; // Save selection to config - ShareOptionChange((uint)id); // Share single selection - } - } - } - else if (id == 0 && AmongUsClient.Instance?.AmHost == true && PlayerControl.LocalPlayer) - { - // Share the preset switch for random maps, even if the menu isnt open! - switchPreset(selection); - ShareOptionSelections(); // Share all selections - } - - OnChange?.Invoke(); - } - - public static byte[] serializeOptions() - { - using (MemoryStream memoryStream = new MemoryStream()) - { - using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) - { - int lastId = -1; - foreach (var option in CustomOption.options.OrderBy(x => x.id)) - { - if (option.id == 0) continue; - bool consecutive = lastId + 1 == option.id; - lastId = option.id; - - binaryWriter.Write((byte)(option.selection + (consecutive ? 128 : 0))); - if (!consecutive) binaryWriter.Write((ushort)option.id); - } - - binaryWriter.Flush(); - memoryStream.Position = 0L; - return memoryStream.ToArray(); - } - } - } - - public static void deserializeOptions(byte[] inputValues) - { - BinaryReader reader = new BinaryReader(new MemoryStream(inputValues)); - int lastId = -1; - while (reader.BaseStream.Position < inputValues.Length) - { - try - { - int selection = reader.ReadByte(); - int id = -1; - bool consecutive = selection >= 128; - if (consecutive) - { - selection -= 128; - id = lastId + 1; - } - else - { - id = reader.ReadUInt16(); - } - - if (id == 0) continue; - lastId = id; - CustomOption option = CustomOption.options.First(option => option.id == id); - option.updateSelection(selection); - } - catch (Exception e) - { - BetterOtherRolesPlugin.Logger.LogWarning( - $"{e}: while deserializing - tried to paste invalid settings!"); - } - } - } - - // Copy to or paste from clipboard (as string) - public static void copyToClipboard() - { - GUIUtility.systemCopyBuffer = - $"{BetterOtherRolesPlugin.VersionString}!{Convert.ToBase64String(serializeOptions())}!{vanillaSettings.Value}"; - } - - public static bool pasteFromClipboard() - { - string allSettings = GUIUtility.systemCopyBuffer; - try - { - var settingsSplit = allSettings.Split("!"); - string versionInfo = settingsSplit[0]; - string torSettings = settingsSplit[1]; - string vanillaSettingsSub = settingsSplit[2]; - deserializeOptions(Convert.FromBase64String(torSettings)); - - vanillaSettings.Value = vanillaSettingsSub; - loadVanillaOptions(); - return true; - } - catch (Exception e) - { - BetterOtherRolesPlugin.Logger.LogWarning($"{e}: tried to paste invalid settings!"); - SoundEffectsManager.Load(); - SoundEffectsManager.play("fail"); - return false; - } - } -} - -[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Start))] -class GameOptionsMenuStartPatch -{ - public static void Postfix(GameOptionsMenu __instance) - { - switch (TORMapOptions.gameMode) - { - case CustomGamemodes.Classic: - createClassicTabs(__instance); - break; - case CustomGamemodes.Guesser: - createGuesserTabs(__instance); - break; - case CustomGamemodes.HideNSeek: - createHideNSeekTabs(__instance); - break; - } - - // create copy to clipboard and paste from clipboard buttons. - var template = GameObject.Find("CloseButton"); - var copyButton = GameObject.Instantiate(template, template.transform.parent); - copyButton.transform.localPosition += Vector3.down * 0.8f; - var copyButtonPassive = copyButton.GetComponent(); - var copyButtonRenderer = copyButton.GetComponent(); - copyButtonRenderer.sprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CopyButton.png", 175f); - copyButtonPassive.OnClick.RemoveAllListeners(); - copyButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); - copyButtonPassive.OnClick.AddListener((System.Action)(() => - { - copyToClipboard(); - copyButtonRenderer.color = Color.green; - __instance.StartCoroutine(Effects.Lerp(1f, new System.Action((p) => - { - if (p > 0.95) - copyButtonRenderer.color = Color.white; - }))); - })); - var pasteButton = GameObject.Instantiate(template, template.transform.parent); - pasteButton.transform.localPosition += Vector3.down * 1.6f; - var pasteButtonPassive = pasteButton.GetComponent(); - var pasteButtonRenderer = pasteButton.GetComponent(); - pasteButtonRenderer.sprite = - Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PasteButton.png", 175f); - pasteButtonPassive.OnClick.RemoveAllListeners(); - pasteButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); - pasteButtonPassive.OnClick.AddListener((System.Action)(() => - { - pasteButtonRenderer.color = Color.yellow; - bool success = pasteFromClipboard(); - pasteButtonRenderer.color = success ? Color.green : Color.red; - __instance.StartCoroutine(Effects.Lerp(1f, new System.Action((p) => - { - if (p > 0.95) - pasteButtonRenderer.color = Color.white; - }))); - })); - } - - private static void createClassicTabs(GameOptionsMenu __instance) - { - bool isReturn = setNames( - new Dictionary() - { - ["TORSettings"] = "Mods Settings", - ["ImpostorSettings"] = "Impostor Roles Settings", - ["NeutralSettings"] = "Neutral Roles Settings", - ["CrewmateSettings"] = "Crewmate Roles Settings", - ["ModifierSettings"] = "Modifier Settings" - }); - - if (isReturn) return; - - // Setup TOR tab - var template = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - var boolTemplate = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - if (template == null || boolTemplate == null) return; - var gameSettings = GameObject.Find("Game Settings"); - var gameSettingMenu = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - - var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var torMenu = getMenu(torSettings, "TORSettings"); - - var impostorSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var impostorMenu = getMenu(impostorSettings, "ImpostorSettings"); - - var neutralSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var neutralMenu = getMenu(neutralSettings, "NeutralSettings"); - - var crewmateSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var crewmateMenu = getMenu(crewmateSettings, "CrewmateSettings"); - - var modifierSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var modifierMenu = getMenu(modifierSettings, "ModifierSettings"); - - var roleTab = GameObject.Find("RoleTab"); - var gameTab = GameObject.Find("GameTab"); - - var torTab = UnityEngine.Object.Instantiate(roleTab, roleTab.transform.parent); - var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "BetterOtherRoles.Resources.SettingsTab.png"); - - var impostorTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform); - var impostorTabHighlight = - getTabHighlight(impostorTab, "ImpostorTab", "BetterOtherRoles.Resources.TabIconImpostor.png"); - - var neutralTab = UnityEngine.Object.Instantiate(roleTab, impostorTab.transform); - var neutralTabHighlight = - getTabHighlight(neutralTab, "NeutralTab", "BetterOtherRoles.Resources.TabIconNeutral.png"); - - var crewmateTab = UnityEngine.Object.Instantiate(roleTab, neutralTab.transform); - var crewmateTabHighlight = - getTabHighlight(crewmateTab, "CrewmateTab", "BetterOtherRoles.Resources.TabIconCrewmate.png"); - - var modifierTab = UnityEngine.Object.Instantiate(roleTab, crewmateTab.transform); - var modifierTabHighlight = - getTabHighlight(modifierTab, "ModifierTab", "BetterOtherRoles.Resources.TabIconModifier.png"); - - // Position of Tab Icons - gameTab.transform.position += Vector3.left * 3f; - roleTab.transform.position += Vector3.left * 3f; - torTab.transform.position += Vector3.left * 2f; - impostorTab.transform.localPosition = Vector3.right * 1f; - neutralTab.transform.localPosition = Vector3.right * 1f; - crewmateTab.transform.localPosition = Vector3.right * 1f; - modifierTab.transform.localPosition = Vector3.right * 1f; - - var tabs = new GameObject[] { gameTab, roleTab, torTab, impostorTab, neutralTab, crewmateTab, modifierTab }; - var settingsHighlightMap = new Dictionary - { - [gameSettingMenu.RegularGameSettings] = gameSettingMenu.GameSettingsHightlight, - [gameSettingMenu.RolesSettings.gameObject] = gameSettingMenu.RolesSettingsHightlight, - [torSettings.gameObject] = torTabHighlight, - [impostorSettings.gameObject] = impostorTabHighlight, - [neutralSettings.gameObject] = neutralTabHighlight, - [crewmateSettings.gameObject] = crewmateTabHighlight, - [modifierSettings.gameObject] = modifierTabHighlight - }; - for (int i = 0; i < tabs.Length; i++) - { - var button = tabs[i].GetComponentInChildren(); - if (button == null) continue; - int copiedIndex = i; - button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); - button.OnClick.AddListener((System.Action)(() => { setListener(settingsHighlightMap, copiedIndex); })); - } - - destroyOptions(new List> - { - torMenu.GetComponentsInChildren().ToList(), - impostorMenu.GetComponentsInChildren().ToList(), - neutralMenu.GetComponentsInChildren().ToList(), - crewmateMenu.GetComponentsInChildren().ToList(), - modifierMenu.GetComponentsInChildren().ToList() - }); - - List torOptions = new List(); - List impostorOptions = new List(); - List neutralOptions = new List(); - List crewmateOptions = new List(); - List modifierOptions = new List(); - - - List menus = new List() - { - torMenu.transform, impostorMenu.transform, neutralMenu.transform, crewmateMenu.transform, - modifierMenu.transform - }; - List> optionBehaviours = new List>() - { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions }; - - for (int i = 0; i < CustomOption.options.Count; i++) - { - CustomOption option = CustomOption.options[i]; - if ((int)option.type > 4) continue; - if (option.optionBehaviour == null) - { - if (option.valueType == CustomOption.ValueType.Boolean) - { - var boolOption = UnityEngine.Object.Instantiate(boolTemplate, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(boolOption); - boolOption.OnValueChanged = new Action((_) => { }); - boolOption.TitleText.text = option.name; - boolOption.CheckMark.enabled = boolOption.oldValue = option.getBool(); - option.optionBehaviour = boolOption; - } - else - { - var stringOption = UnityEngine.Object.Instantiate(template, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(stringOption); - stringOption.OnValueChanged = new Action((o) => { }); - stringOption.TitleText.text = option.name; - stringOption.Value = stringOption.oldValue = option.selection; - stringOption.ValueText.text = option.DisplayValue; - option.optionBehaviour = stringOption; - } - } - - option.optionBehaviour.gameObject.SetActive(true); - } - - setOptions( - new List { torMenu, impostorMenu, neutralMenu, crewmateMenu, modifierMenu }, - new List> - { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions }, - new List { torSettings, impostorSettings, neutralSettings, crewmateSettings, modifierSettings } - ); - - adaptTaskCount(__instance); - } - - private static void createGuesserTabs(GameOptionsMenu __instance) - { - bool isReturn = setNames( - new Dictionary() - { - ["TORSettings"] = "Mod Settings", - ["GuesserSettings"] = "Guesser Mode Settings", - ["ImpostorSettings"] = "Impostor Roles Settings", - ["NeutralSettings"] = "Neutral Roles Settings", - ["CrewmateSettings"] = "Crewmate Roles Settings", - ["ModifierSettings"] = "Modifier Settings" - }); - - if (isReturn) return; - - // Setup TOR tab - var template = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - var boolTemplate = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - if (template == null || boolTemplate == null) return; - var gameSettings = GameObject.Find("Game Settings"); - var gameSettingMenu = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - - var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var torMenu = getMenu(torSettings, "TORSettings"); - - var guesserSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var guesserMenu = getMenu(guesserSettings, "GuesserSettings"); - - var impostorSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var impostorMenu = getMenu(impostorSettings, "ImpostorSettings"); - - var neutralSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var neutralMenu = getMenu(neutralSettings, "NeutralSettings"); - - var crewmateSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var crewmateMenu = getMenu(crewmateSettings, "CrewmateSettings"); - - var modifierSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var modifierMenu = getMenu(modifierSettings, "ModifierSettings"); - - var roleTab = GameObject.Find("RoleTab"); - var gameTab = GameObject.Find("GameTab"); - - var torTab = UnityEngine.Object.Instantiate(roleTab, gameTab.transform.parent); - var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "BetterOtherRoles.Resources.SettingsTab.png"); - - var guesserTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform); - var guesserTabHighlight = getTabHighlight(guesserTab, "GuesserTab", - "BetterOtherRoles.Resources.TabIconGuesserSettings.png"); - - var impostorTab = UnityEngine.Object.Instantiate(roleTab, guesserTab.transform); - var impostorTabHighlight = - getTabHighlight(impostorTab, "ImpostorTab", "BetterOtherRoles.Resources.TabIconImpostor.png"); - - var neutralTab = UnityEngine.Object.Instantiate(roleTab, impostorTab.transform); - var neutralTabHighlight = - getTabHighlight(neutralTab, "NeutralTab", "BetterOtherRoles.Resources.TabIconNeutral.png"); - - var crewmateTab = UnityEngine.Object.Instantiate(roleTab, neutralTab.transform); - var crewmateTabHighlight = - getTabHighlight(crewmateTab, "CrewmateTab", "BetterOtherRoles.Resources.TabIconCrewmate.png"); - - var modifierTab = UnityEngine.Object.Instantiate(roleTab, crewmateTab.transform); - var modifierTabHighlight = - getTabHighlight(modifierTab, "ModifierTab", "BetterOtherRoles.Resources.TabIconModifier.png"); - - roleTab.active = false; - // Position of Tab Icons - gameTab.transform.position += Vector3.left * 3f; - torTab.transform.position += Vector3.left * 3f; - guesserTab.transform.localPosition = Vector3.right * 1f; - impostorTab.transform.localPosition = Vector3.right * 1f; - neutralTab.transform.localPosition = Vector3.right * 1f; - crewmateTab.transform.localPosition = Vector3.right * 1f; - modifierTab.transform.localPosition = Vector3.right * 1f; - - var tabs = new GameObject[] { gameTab, torTab, impostorTab, neutralTab, crewmateTab, modifierTab, guesserTab }; - var settingsHighlightMap = new Dictionary - { - [gameSettingMenu.RegularGameSettings] = gameSettingMenu.GameSettingsHightlight, - [torSettings.gameObject] = torTabHighlight, - [impostorSettings.gameObject] = impostorTabHighlight, - [neutralSettings.gameObject] = neutralTabHighlight, - [crewmateSettings.gameObject] = crewmateTabHighlight, - [modifierSettings.gameObject] = modifierTabHighlight, - [guesserSettings.gameObject] = guesserTabHighlight - }; - for (int i = 0; i < tabs.Length; i++) - { - var button = tabs[i].GetComponentInChildren(); - if (button == null) continue; - int copiedIndex = i; - button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); - button.OnClick.AddListener((System.Action)(() => { setListener(settingsHighlightMap, copiedIndex); })); - } - - destroyOptions(new List> - { - torMenu.GetComponentsInChildren().ToList(), - guesserMenu.GetComponentsInChildren().ToList(), - impostorMenu.GetComponentsInChildren().ToList(), - neutralMenu.GetComponentsInChildren().ToList(), - crewmateMenu.GetComponentsInChildren().ToList(), - modifierMenu.GetComponentsInChildren().ToList() - }); - - List torOptions = new List(); - List guesserOptions = new List(); - List impostorOptions = new List(); - List neutralOptions = new List(); - List crewmateOptions = new List(); - List modifierOptions = new List(); - - - List menus = new List() - { - torMenu.transform, impostorMenu.transform, neutralMenu.transform, crewmateMenu.transform, - modifierMenu.transform, guesserMenu.transform - }; - List> optionBehaviours = new List>() - { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions, guesserOptions }; - List exludedIds = new List { 310, 311, 312, 313, 314, 315, 316, 317, 318 }; - - for (int i = 0; i < CustomOption.options.Count; i++) - { - CustomOption option = CustomOption.options[i]; - if (exludedIds.Contains(option.id)) continue; - if ((int)option.type > 5) continue; - if (option.optionBehaviour == null) - { - if (option.valueType == CustomOption.ValueType.Boolean) - { - var boolOption = UnityEngine.Object.Instantiate(boolTemplate, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(boolOption); - boolOption.OnValueChanged = new Action((_) => { }); - boolOption.TitleText.text = option.name; - boolOption.CheckMark.enabled = boolOption.oldValue = option.getBool(); - option.optionBehaviour = boolOption; - } - else - { - var stringOption = UnityEngine.Object.Instantiate(template, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(stringOption); - stringOption.OnValueChanged = new Action((o) => { }); - stringOption.TitleText.text = option.name; - stringOption.Value = stringOption.oldValue = option.selection; - stringOption.ValueText.text = option.DisplayValue; - option.optionBehaviour = stringOption; - } - } - - option.optionBehaviour.gameObject.SetActive(true); - } - - setOptions( - new List { torMenu, impostorMenu, neutralMenu, crewmateMenu, modifierMenu, guesserMenu }, - new List> - { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions, guesserOptions }, - new List - { torSettings, impostorSettings, neutralSettings, crewmateSettings, modifierSettings, guesserSettings } - ); - - adaptTaskCount(__instance); - } - - private static void createHideNSeekTabs(GameOptionsMenu __instance) - { - bool isReturn = setNames( - new Dictionary() - { - ["TORSettings"] = "Mod Settings", - ["HideNSeekSettings"] = "Hide 'N Seek Settings" - }); - - if (isReturn) return; - - // Setup TOR tab - var template = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - var boolTemplate = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - if (template == null || boolTemplate == null) return; - var gameSettings = GameObject.Find("Game Settings"); - var gameSettingMenu = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - - var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var torMenu = getMenu(torSettings, "TORSettings"); - - var hideNSeekSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent); - var hideNSeekMenu = getMenu(hideNSeekSettings, "HideNSeekSettings"); - - var roleTab = GameObject.Find("RoleTab"); - var gameTab = GameObject.Find("GameTab"); - - var torTab = UnityEngine.Object.Instantiate(roleTab, gameTab.transform.parent); - var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", - "BetterOtherRoles.Resources.TabIconHideNSeekSettings.png"); - - var hideNSeekTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform); - var hideNSeekTabHighlight = getTabHighlight(hideNSeekTab, "HideNSeekTab", - "BetterOtherRoles.Resources.TabIconHideNSeekRoles.png"); - - roleTab.active = false; - gameTab.active = false; - - // Position of Tab Icons - torTab.transform.position += Vector3.left * 3f; - hideNSeekTab.transform.position += Vector3.right * 1f; - - var tabs = new GameObject[] { torTab, hideNSeekTab }; - var settingsHighlightMap = new Dictionary - { - [torSettings.gameObject] = torTabHighlight, - [hideNSeekSettings.gameObject] = hideNSeekTabHighlight - }; - for (int i = 0; i < tabs.Length; i++) - { - var button = tabs[i].GetComponentInChildren(); - if (button == null) continue; - int copiedIndex = i; - button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent(); - button.OnClick.AddListener((System.Action)(() => { setListener(settingsHighlightMap, copiedIndex); })); - } - - destroyOptions(new List> - { - torMenu.GetComponentsInChildren().ToList(), - hideNSeekMenu.GetComponentsInChildren().ToList() - }); - - List torOptions = new List(); - List hideNSeekOptions = new List(); - - List menus = new List() { torMenu.transform, hideNSeekMenu.transform }; - List> optionBehaviours = new List>() - { torOptions, hideNSeekOptions }; - - for (int i = 0; i < CustomOption.options.Count; i++) - { - CustomOption option = CustomOption.options[i]; - if (option.type != CustomOptionType.HideNSeekMain && - option.type != CustomOptionType.HideNSeekRoles) continue; - if (option.optionBehaviour == null) - { - int index = (int)option.type - 6; - if (option.valueType == CustomOption.ValueType.Boolean) - { - var boolOption = UnityEngine.Object.Instantiate(boolTemplate, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(boolOption); - boolOption.OnValueChanged = new Action((_) => { }); - boolOption.TitleText.text = option.name; - boolOption.CheckMark.enabled = boolOption.oldValue = option.getBool(); - option.optionBehaviour = boolOption; - } - else - { - var stringOption = UnityEngine.Object.Instantiate(template, menus[(int)option.type]); - optionBehaviours[(int)option.type].Add(stringOption); - stringOption.OnValueChanged = new Action((o) => { }); - stringOption.TitleText.text = option.name; - stringOption.Value = stringOption.oldValue = option.selection; - stringOption.ValueText.text = option.DisplayValue; - option.optionBehaviour = stringOption; - } - } - - option.optionBehaviour.gameObject.SetActive(true); - } - - setOptions( - new List { torMenu, hideNSeekMenu }, - new List> { torOptions, hideNSeekOptions }, - new List { torSettings, hideNSeekSettings } - ); - - torSettings.gameObject.SetActive(true); - torTabHighlight.enabled = true; - gameSettingMenu.RegularGameSettings.SetActive(false); - gameSettingMenu.GameSettingsHightlight.enabled = false; - } - - - private static void setListener(Dictionary settingsHighlightMap, int index) - { - foreach (KeyValuePair entry in settingsHighlightMap) - { - entry.Key.SetActive(false); - entry.Value.enabled = false; - } - - settingsHighlightMap.ElementAt(index).Key.SetActive(true); - settingsHighlightMap.ElementAt(index).Value.enabled = true; - } - - private static void destroyOptions(List> optionBehavioursList) - { - foreach (List optionBehaviours in optionBehavioursList) - { - foreach (OptionBehaviour option in optionBehaviours) - UnityEngine.Object.Destroy(option.gameObject); - } - } - - private static bool setNames(Dictionary gameObjectNameDisplayNameMap) - { - foreach (KeyValuePair entry in gameObjectNameDisplayNameMap) - { - if (GameObject.Find(entry.Key) != null) - { - // Settings setup has already been performed, fixing the title of the tab and returning - GameObject.Find(entry.Key).transform.FindChild("GameGroup").FindChild("Text") - .GetComponent().SetText(entry.Value); - return true; - } - } - - return false; - } - - private static GameOptionsMenu getMenu(GameObject setting, string settingName) - { - var menu = setting.transform.FindChild("GameGroup").FindChild("SliderInner").GetComponent(); - setting.name = settingName; - - return menu; - } - - private static SpriteRenderer getTabHighlight(GameObject tab, string tabName, string tabSpritePath) - { - var tabHighlight = tab.transform.FindChild("Hat Button").FindChild("Tab Background") - .GetComponent(); - tab.transform.FindChild("Hat Button").FindChild("Icon").GetComponent().sprite = - Helpers.loadSpriteFromResources(tabSpritePath, 400f); - tab.name = "tabName"; - - return tabHighlight; - } - - private static void setOptions(List menus, List> options, - List settings) - { - if (!(menus.Count == options.Count && options.Count == settings.Count)) - { - BetterOtherRolesPlugin.Logger.LogError("List counts are not equal"); - return; - } - - for (int i = 0; i < menus.Count; i++) - { - menus[i].Children = options[i].ToArray(); - settings[i].gameObject.SetActive(false); - } - } - - private static void adaptTaskCount(GameOptionsMenu __instance) - { - // Adapt task count for main options - var commonTasksOption = - __instance.Children.FirstOrDefault(x => x.name == "NumCommonTasks").TryCast(); - if (commonTasksOption != null) commonTasksOption.ValidRange = new FloatRange(0f, 4f); - - var shortTasksOption = - __instance.Children.FirstOrDefault(x => x.name == "NumShortTasks").TryCast(); - if (shortTasksOption != null) shortTasksOption.ValidRange = new FloatRange(0f, 23f); - - var longTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumLongTasks").TryCast(); - if (longTasksOption != null) longTasksOption.ValidRange = new FloatRange(0f, 15f); - } -} - -[HarmonyPatch(typeof(StringOption), nameof(StringOption.OnEnable))] -public class StringOptionEnablePatch -{ - public static bool Prefix(StringOption __instance) - { - CustomOption option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == __instance); - if (option == null) return true; - - __instance.OnValueChanged = new Action((o) => { }); - __instance.TitleText.text = option.name; - __instance.Value = __instance.oldValue = option.selection; - __instance.ValueText.text = option.DisplayValue; - - return false; - } -} - -[HarmonyPatch(typeof(ToggleOption), nameof(ToggleOption.OnEnable))] -public static class ToggleOptionOnEnablePatch -{ - public static bool Prefix(ToggleOption __instance) - { - return CustomOptionEnable(__instance); - } - - private static bool CustomOptionEnable(ToggleOption boolOption) - { - - var option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == boolOption); - if (option == null) return true; - boolOption.OnValueChanged = new Action(_ => { }); - boolOption.TitleText.text = option.name; - boolOption.CheckMark.enabled = boolOption.oldValue = option.getBool(); - - return false; - } -} - -[HarmonyPatch(typeof(StringOption), nameof(StringOption.Increase))] -public class StringOptionIncreasePatch -{ - public static bool Prefix(StringOption __instance) - { - CustomOption option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == __instance); - if (option == null) return true; - option.updateSelection(option.selection + 1); - return false; - } -} - -[HarmonyPatch(typeof(StringOption), nameof(StringOption.Decrease))] -public class StringOptionDecreasePatch -{ - public static bool Prefix(StringOption __instance) - { - CustomOption option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == __instance); - if (option == null) return true; - option.updateSelection(option.selection - 1); - return false; - } -} - -[HarmonyPatch(typeof(ToggleOption), nameof(ToggleOption.Toggle))] -public static class ToggleOptionTogglePatch -{ - public static bool Prefix(ToggleOption __instance) - { - return CustomOptionToggle(__instance); - } - - private static bool CustomOptionToggle(ToggleOption boolOption) - { - var option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == boolOption); - if (option == null) return true; - option.updateSelection(option.selection + 1); - return false; - } -} - -[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSyncSettings))] -public class RpcSyncSettingsPatch -{ - public static void Postfix() - { - CustomOption.ShareOptionSelections(); - CustomOption.saveVanillaOptions(); - } -} - -[HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.CoSpawnPlayer))] -public class AmongUsClientOnPlayerJoinedPatch -{ - public static void Postfix() - { - if (PlayerControl.LocalPlayer != null && AmongUsClient.Instance.AmHost) - { - CustomOption.ShareOptionSelections(); - } - } -} - -[HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Update))] -class GameOptionsMenuUpdatePatch -{ - private static float timer = 1f; - - public static void Postfix(GameOptionsMenu __instance) - { - // Return Menu Update if in normal among us settings - var gameSettingMenu = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(); - if (gameSettingMenu.RegularGameSettings.active || gameSettingMenu.RolesSettings.gameObject.active) return; - - __instance.GetComponentInParent().ContentYBounds.max = -0.5F + __instance.Children.Length * 0.55F; - timer += Time.deltaTime; - if (timer < 0.1f) return; - timer = 0f; - - float offset = 2.75f; - foreach (CustomOption option in CustomOption.options) - { - if (GameObject.Find("TORSettings") && option.type != CustomOption.CustomOptionType.General && - option.type != CustomOptionType.HideNSeekMain) - continue; - if (GameObject.Find("ImpostorSettings") && option.type != CustomOption.CustomOptionType.Impostor) - continue; - if (GameObject.Find("NeutralSettings") && option.type != CustomOption.CustomOptionType.Neutral) - continue; - if (GameObject.Find("CrewmateSettings") && option.type != CustomOption.CustomOptionType.Crewmate) - continue; - if (GameObject.Find("ModifierSettings") && option.type != CustomOption.CustomOptionType.Modifier) - continue; - if (GameObject.Find("GuesserSettings") && option.type != CustomOption.CustomOptionType.Guesser) - continue; - if (GameObject.Find("HideNSeekSettings") && option.type != CustomOption.CustomOptionType.HideNSeekRoles) - continue; - if (option?.optionBehaviour != null && option.optionBehaviour.gameObject != null) - { - bool enabled = true; - var parent = option.parent; - while (parent != null && enabled) - { - enabled = parent.selection != 0; - parent = parent.parent; - } - - option.optionBehaviour.gameObject.SetActive(enabled); - if (enabled) - { - offset -= option.isHeader ? 0.75f : 0.5f; - option.optionBehaviour.transform.localPosition = new Vector3( - option.optionBehaviour.transform.localPosition.x, offset, - option.optionBehaviour.transform.localPosition.z); - } - } - } - } -} - -[HarmonyPatch] -class GameOptionsDataPatch -{ - /*private static IEnumerable TargetMethods() { - return typeof(IGameOptionsExtensions.).GetMethods().Where(x => x.ReturnType == typeof(string) && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(int)); - }*/ - - private static string buildRoleOptions() - { - var impRoles = buildOptionsOfType(CustomOption.CustomOptionType.Impostor, true) + "\n"; - var neutralRoles = buildOptionsOfType(CustomOption.CustomOptionType.Neutral, true) + "\n"; - var crewRoles = buildOptionsOfType(CustomOption.CustomOptionType.Crewmate, true) + "\n"; - var modifiers = buildOptionsOfType(CustomOption.CustomOptionType.Modifier, true); - return impRoles + neutralRoles + crewRoles + modifiers; - } - - private static string buildModifierExtras(CustomOption customOption) - { - // find options children with quantity - var children = CustomOption.options.Where(o => o.parent == customOption); - var quantity = children.Where(o => o.name.Contains("Quantity")).ToList(); - if (customOption.getSelection() == 0) return ""; - if (quantity.Count == 1) return $" ({quantity[0].getQuantity()})"; - if (customOption == CustomOptionHolder.modifierLover) - { - return $" (1 Evil: {CustomOptionHolder.modifierLoverImpLoverRate.getSelection() * 10}%)"; - } - - return ""; - } - - private static string buildOptionsOfType(CustomOption.CustomOptionType type, bool headerOnly) - { - StringBuilder sb = new StringBuilder("\n"); - var options = CustomOption.options.Where(o => o.type == type); - if (TORMapOptions.gameMode == CustomGamemodes.Guesser) - { - if (type == CustomOption.CustomOptionType.General) - options = CustomOption.options.Where(o => - o.type == type || o.type == CustomOption.CustomOptionType.Guesser); - List remove = new List { 308, 310, 311, 312, 313, 314, 315, 316, 317, 318 }; - options = options.Where(x => !remove.Contains(x.id)); - } - else if (TORMapOptions.gameMode == CustomGamemodes.Classic) - options = options.Where(x => - !(x.type == CustomOption.CustomOptionType.Guesser || x == CustomOptionHolder.crewmateRolesFill)); - else if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) - options = options.Where(x => - (x.type == CustomOption.CustomOptionType.HideNSeekMain || - x.type == CustomOption.CustomOptionType.HideNSeekRoles)); - - foreach (var option in options) - { - if (option.parent == null) - { - string line = $"{option.name}: {option.DisplayValue}"; - if (type == CustomOption.CustomOptionType.Modifier) line += buildModifierExtras(option); - sb.AppendLine(line); - } - else if (option.parent.getSelection() > 0) - { - if (option.id == 103) //Deputy - sb.AppendLine($"- {Helpers.cs(Deputy.color, "Deputy")}: {option.DisplayValue}"); - else if (option.id == 224) //Sidekick - sb.AppendLine($"- {Helpers.cs(Sidekick.color, "Sidekick")}: {option.DisplayValue}"); - else if (option.id == 358) //Prosecutor - sb.AppendLine($"- {Helpers.cs(Lawyer.color, "Prosecutor")}: {option.DisplayValue}"); - } - } - - if (headerOnly) return sb.ToString(); - else sb = new StringBuilder(); - - foreach (CustomOption option in options) - { - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek && option.type != CustomOptionType.HideNSeekMain && - option.type != CustomOptionType.HideNSeekRoles) continue; - if (option.parent != null) - { - bool isIrrelevant = option.parent.getSelection() == 0 || - (option.parent.parent != null && option.parent.parent.getSelection() == 0); - - Color c = isIrrelevant ? Color.grey : Color.white; // No use for now - if (isIrrelevant) continue; - sb.AppendLine(Helpers.cs(c, $"{option.name}: {option.DisplayValue}")); - } - else - { - if (option == CustomOptionHolder.crewmateRolesCountMin) - { - var optionName = - CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Crewmate Roles"); - var min = CustomOptionHolder.crewmateRolesCountMin.getSelection(); - var max = CustomOptionHolder.crewmateRolesCountMax.getSelection(); - string optionValue = ""; - if (CustomOptionHolder.crewmateRolesFill.getBool()) - { - var crewCount = PlayerControl.AllPlayerControls.Count - - GameOptionsManager.Instance.currentGameOptions.NumImpostors; - int minNeutral = CustomOptionHolder.neutralRolesCountMin.getSelection(); - int maxNeutral = CustomOptionHolder.neutralRolesCountMax.getSelection(); - if (minNeutral > maxNeutral) minNeutral = maxNeutral; - min = crewCount - maxNeutral; - max = crewCount - minNeutral; - if (min < 0) min = 0; - if (max < 0) max = 0; - optionValue = "Fill: "; - } - - if (min > max) min = max; - optionValue += (min == max) ? $"{max}" : $"{min} - {max}"; - sb.AppendLine($"{optionName}: {optionValue}"); - } - else if (option == CustomOptionHolder.neutralRolesCountMin) - { - var optionName = CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Neutral Roles"); - var min = CustomOptionHolder.neutralRolesCountMin.getSelection(); - var max = CustomOptionHolder.neutralRolesCountMax.getSelection(); - if (min > max) min = max; - var optionValue = (min == max) ? $"{max}" : $"{min} - {max}"; - sb.AppendLine($"{optionName}: {optionValue}"); - } - else if (option == CustomOptionHolder.impostorRolesCountMin) - { - var optionName = - CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Impostor Roles"); - var min = CustomOptionHolder.impostorRolesCountMin.getSelection(); - var max = CustomOptionHolder.impostorRolesCountMax.getSelection(); - if (max > GameOptionsManager.Instance.currentGameOptions.NumImpostors) - max = GameOptionsManager.Instance.currentGameOptions.NumImpostors; - if (min > max) min = max; - var optionValue = (min == max) ? $"{max}" : $"{min} - {max}"; - sb.AppendLine($"{optionName}: {optionValue}"); - } - else if (option == CustomOptionHolder.modifiersCountMin) - { - var optionName = CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Modifiers"); - var min = CustomOptionHolder.modifiersCountMin.getSelection(); - var max = CustomOptionHolder.modifiersCountMax.getSelection(); - if (min > max) min = max; - var optionValue = (min == max) ? $"{max}" : $"{min} - {max}"; - sb.AppendLine($"{optionName}: {optionValue}"); - } - else if ((option == CustomOptionHolder.crewmateRolesCountMax) || - (option == CustomOptionHolder.neutralRolesCountMax) || - (option == CustomOptionHolder.impostorRolesCountMax) || - option == CustomOptionHolder.modifiersCountMax) - { - continue; - } - else - { - sb.AppendLine($"\n{option.name}: {option.DisplayValue}"); - } - } - } - - return sb.ToString(); - } - - public static string buildAllOptions(string vanillaSettings = "", bool hideExtras = false) - { - if (vanillaSettings == "") - vanillaSettings = - GameOptionsManager.Instance.CurrentGameOptions.ToHudString(PlayerControl.AllPlayerControls.Count); - int counter = BetterOtherRolesPlugin.optionsPage; - string hudString = counter != 0 && !hideExtras - ? Helpers.cs(DateTime.Now.Second % 2 == 0 ? Color.white : Color.red, "(Use scroll wheel if necessary)\n\n") - : ""; - int maxPage = 7; - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) - { - if (BetterOtherRolesPlugin.optionsPage > 1) BetterOtherRolesPlugin.optionsPage = 0; - maxPage = 2; - switch (counter) - { - case 0: - hudString += "Page 1: Hide N Seek Settings \n\n" + - buildOptionsOfType(CustomOption.CustomOptionType.HideNSeekMain, false); - break; - case 1: - hudString += "Page 2: Hide N Seek Role Settings \n\n" + - buildOptionsOfType(CustomOption.CustomOptionType.HideNSeekRoles, false); - break; - } - } - else - { - switch (counter) - { - case 0: - hudString += (!hideExtras ? "" : "Page 1: Vanilla Settings \n\n") + vanillaSettings; - break; - case 1: - hudString += "Page 2: Mod Settings \n" + - buildOptionsOfType(CustomOption.CustomOptionType.General, false); - break; - case 2: - hudString += "Page 3: Role and Modifier Rates \n" + buildRoleOptions(); - break; - case 3: - hudString += "Page 4: Impostor Role Settings \n" + - buildOptionsOfType(CustomOption.CustomOptionType.Impostor, false); - break; - case 4: - hudString += "Page 5: Neutral Role Settings \n" + - buildOptionsOfType(CustomOption.CustomOptionType.Neutral, false); - break; - case 5: - hudString += "Page 6: Crewmate Role Settings \n" + - buildOptionsOfType(CustomOption.CustomOptionType.Crewmate, false); - break; - case 6: - hudString += "Page 7: Modifier Settings \n" + - buildOptionsOfType(CustomOption.CustomOptionType.Modifier, false); - break; - } - } - - if (!hideExtras || counter != 0) - hudString += $"\n Press TAB or Page Number for more... ({counter + 1}/{maxPage})"; - return hudString; - } - - - [HarmonyPatch(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.ToHudString))] - private static void Postfix(ref string __result) - { - if (GameOptionsManager.Instance.currentGameOptions.GameMode == AmongUs.GameOptions.GameModes.HideNSeek) - return; // Allow Vanilla Hide N Seek - __result = buildAllOptions(vanillaSettings: __result); - } -} - -[HarmonyPatch(typeof(KeyboardJoystick), nameof(KeyboardJoystick.Update))] -public static class GameOptionsNextPagePatch -{ - public static void Postfix(KeyboardJoystick __instance) - { - int page = BetterOtherRolesPlugin.optionsPage; - if (Input.GetKeyDown(KeyCode.Tab)) - { - BetterOtherRolesPlugin.optionsPage = (BetterOtherRolesPlugin.optionsPage + 1) % 7; - } - - if (Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Keypad1)) - { - BetterOtherRolesPlugin.optionsPage = 0; - } - - if (Input.GetKeyDown(KeyCode.Alpha2) || Input.GetKeyDown(KeyCode.Keypad2)) - { - BetterOtherRolesPlugin.optionsPage = 1; - } - - if (Input.GetKeyDown(KeyCode.Alpha3) || Input.GetKeyDown(KeyCode.Keypad3)) - { - BetterOtherRolesPlugin.optionsPage = 2; - } - - if (Input.GetKeyDown(KeyCode.Alpha4) || Input.GetKeyDown(KeyCode.Keypad4)) - { - BetterOtherRolesPlugin.optionsPage = 3; - } - - if (Input.GetKeyDown(KeyCode.Alpha5) || Input.GetKeyDown(KeyCode.Keypad5)) - { - BetterOtherRolesPlugin.optionsPage = 4; - } - - if (Input.GetKeyDown(KeyCode.Alpha6) || Input.GetKeyDown(KeyCode.Keypad6)) - { - BetterOtherRolesPlugin.optionsPage = 5; - } - - if (Input.GetKeyDown(KeyCode.Alpha7) || Input.GetKeyDown(KeyCode.Keypad7)) - { - BetterOtherRolesPlugin.optionsPage = 6; - } - - if (Input.GetKeyDown(KeyCode.F1)) - { - UIManager.CustomOptionsPanel?.Toggle(); - } - - if (page != BetterOtherRolesPlugin.optionsPage) - { - Vector3 position = - (Vector3)FastDestroyableSingleton.Instance?.GameSettings?.transform.localPosition; - FastDestroyableSingleton.Instance.GameSettings.transform.localPosition = - new Vector3(position.x, 2.9f, position.z); - } - } -} - -[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] -public class GameSettingsScalePatch -{ - public static void Prefix(HudManager __instance) - { - if (__instance.GameSettings != null) __instance.GameSettings.fontSize = 1.2f; - } -} - -// This class is taken and adapted from Town of Us Reactivated, https://github.com/eDonnes124/Town-Of-Us-R/blob/master/source/Patches/CustomOption/Patches.cs, Licensed under GPLv3 -[HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] -public class HudManagerUpdate -{ - public static float - MinX, /*-5.3F*/ - OriginalY = 2.9F, - MinY = 2.9F; - - - public static Scroller Scroller; - private static Vector3 LastPosition; - private static float lastAspect; - private static bool setLastPosition = false; - - public static void Prefix(HudManager __instance) - { - if (__instance.GameSettings?.transform == null) return; - - // Sets the MinX position to the left edge of the screen + 0.1 units - Rect safeArea = Screen.safeArea; - float aspect = Mathf.Min((Camera.main).aspect, safeArea.width / safeArea.height); - float safeOrthographicSize = CameraSafeArea.GetSafeOrthographicSize(Camera.main); - MinX = 0.1f - safeOrthographicSize * aspect; - - if (!setLastPosition || aspect != lastAspect) - { - LastPosition = new Vector3(MinX, MinY); - lastAspect = aspect; - setLastPosition = true; - if (Scroller != null) Scroller.ContentXBounds = new FloatRange(MinX, MinX); - } - - CreateScroller(__instance); - - Scroller.gameObject.SetActive(__instance.GameSettings.gameObject.activeSelf); - - if (!Scroller.gameObject.active) return; - - var rows = __instance.GameSettings.text.Count(c => c == '\n'); - float LobbyTextRowHeight = 0.06F; - var maxY = Mathf.Max(MinY, rows * LobbyTextRowHeight + (rows - 38) * LobbyTextRowHeight); - - Scroller.ContentYBounds = new FloatRange(MinY, maxY); - - // Prevent scrolling when the player is interacting with a menu - if (CachedPlayer.LocalPlayer?.PlayerControl.CanMove != true) - { - __instance.GameSettings.transform.localPosition = LastPosition; - - return; - } - - if (__instance.GameSettings.transform.localPosition.x != MinX || - __instance.GameSettings.transform.localPosition.y < MinY) return; - - LastPosition = __instance.GameSettings.transform.localPosition; - } - - private static void CreateScroller(HudManager __instance) - { - if (Scroller != null) return; - - Transform target = __instance.GameSettings.transform; - - Scroller = new GameObject("SettingsScroller").AddComponent(); - Scroller.transform.SetParent(__instance.GameSettings.transform.parent); - Scroller.gameObject.layer = 5; - - Scroller.transform.localScale = Vector3.one; - Scroller.allowX = false; - Scroller.allowY = true; - Scroller.active = true; - Scroller.velocity = new Vector2(0, 0); - Scroller.ScrollbarYBounds = new FloatRange(0, 0); - Scroller.ContentXBounds = new FloatRange(MinX, MinX); - Scroller.enabled = true; - - Scroller.Inner = target; - target.SetParent(Scroller.transform); - } - - [HarmonyPrefix] - public static void Prefix2(HudManager __instance) - { - if (!settingsTMPs[0]) return; - foreach (var tmp in settingsTMPs) tmp.text = ""; - var settingsString = GameOptionsDataPatch.buildAllOptions(hideExtras: true); - var blocks = settingsString.Split("\n\n", StringSplitOptions.RemoveEmptyEntries); - ; - string curString = ""; - string curBlock; - int j = 0; - for (int i = 0; i < blocks.Length; i++) - { - curBlock = blocks[i]; - if (Helpers.lineCount(curBlock) + Helpers.lineCount(curString) < 43) - { - curString += curBlock + "\n\n"; - } - else - { - settingsTMPs[j].text = curString; - j++; - - curString = "\n" + curBlock + "\n\n"; - if (curString.Substring(0, 2) != "\n\n") curString = "\n" + curString; - } - } - - if (j < settingsTMPs.Length) settingsTMPs[j].text = curString; - int blockCount = 0; - foreach (var tmp in settingsTMPs) - { - if (tmp.text != "") - blockCount++; - } - - for (int i = 0; i < blockCount; i++) - { - BetterOtherRolesPlugin.Logger.LogMessage(blockCount); - settingsTMPs[i].transform.localPosition = new Vector3(-blockCount * 1.2f + 2.7f * i, 2.2f, -500f); - } - } - - private static TMPro.TextMeshPro[] settingsTMPs = new TMPro.TextMeshPro[4]; - - static PassiveButton toggleSettingsButton; - static GameObject toggleSettingsButtonObject; - - [HarmonyPostfix] - public static void Postfix(HudManager __instance) - { - if (!toggleSettingsButton || !toggleSettingsButtonObject) - { - // add a special button for settings viewing: - toggleSettingsButtonObject = - GameObject.Instantiate(__instance.MapButton.gameObject, __instance.MapButton.transform.parent); - toggleSettingsButtonObject.transform.localPosition = - __instance.MapButton.transform.localPosition + new Vector3(0, -0.66f, -500f); - SpriteRenderer renderer = toggleSettingsButtonObject.GetComponent(); - renderer.sprite = - Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CurrentSettingsButton.png", 180f); - toggleSettingsButton = toggleSettingsButtonObject.GetComponent(); - toggleSettingsButton.OnClick.RemoveAllListeners(); - toggleSettingsButton.OnClick.AddListener((Action)(() => UIManager.CustomOptionsPanel?.Toggle())); - } - - toggleSettingsButtonObject.SetActive(__instance.MapButton.gameObject.active && - !(MapBehaviour.Instance && MapBehaviour.Instance.IsOpen) && - GameOptionsManager.Instance.currentGameOptions.GameMode != - GameModes.HideNSeek); - toggleSettingsButtonObject.transform.localPosition = - __instance.MapButton.transform.localPosition + new Vector3(0, -0.66f, -500f); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/Modules/DevConfig.cs b/BetterOtherRoles/Modules/DevConfig.cs index be3b9ee..841cb14 100644 --- a/BetterOtherRoles/Modules/DevConfig.cs +++ b/BetterOtherRoles/Modules/DevConfig.cs @@ -4,6 +4,7 @@ using System.Security.Cryptography; using System.Text; using BepInEx.Configuration; +using UnityEngine; namespace BetterOtherRoles.Modules; @@ -29,14 +30,14 @@ static DevConfig() DisableEndGameConditions = false; DisablePlayerRequirementToLaunch = false; CurrentGuid = Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId; - LocalFlags = new Dictionary(); - Flags = new Dictionary(); + LocalFlags = new Dictionary() { { "UNLOCK_ALL_COSMETICS", "1" }, { "SHOW_GHOST_INFOS", "1" } }; + Flags = new Dictionary() { { "NO_GUID_CHECK", "1" }, { "LOBBY_NAME_COLOR", "rainbow" } }; #else - DisableEndGameConditions = true; + DisableEndGameConditions = false; DisablePlayerRequirementToLaunch = true; CurrentGuid = Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId; - LocalFlags = new Dictionary (); - Flags = new Dictionary (); + LocalFlags = new Dictionary() { { "UNLOCK_ALL_COSMETICS", "1" }, { "SHOW_GHOST_INFOS", "1" } }; + Flags = new Dictionary () { { "NO_GUID_CHECK", "1" } }; #endif } @@ -68,4 +69,19 @@ public static string Encrypt(string entry) return sb.ToString(); } + + public static void LogTransform(Transform transform, string prefix = "") + { + var components = transform.gameObject.GetComponents(Il2CppType.From(typeof(Il2CppSystem.ComponentModel.Component))); + System.Console.WriteLine($"[LogGameObject]{prefix} {transform.name} ({transform.position}) ({components.Count} components)"); + foreach (var component in components) + { + System.Console.WriteLine($"[LogComponent]{prefix.Replace("-", ">")} {component.ToString()}"); + } + for (var i = 0; i < transform.childCount; i++) + { + var child = transform.GetChild(i); + LogTransform(child, prefix + "-"); + } + } } \ No newline at end of file diff --git a/BetterOtherRoles/Modules/FirstKillShield.cs b/BetterOtherRoles/Modules/FirstKillShield.cs index e9b987d..5cc4f51 100644 --- a/BetterOtherRoles/Modules/FirstKillShield.cs +++ b/BetterOtherRoles/Modules/FirstKillShield.cs @@ -1,4 +1,4 @@ -using BetterOtherRoles.Utilities.Extensions; +using BetterOtherRoles.Options; using UnityEngine; namespace BetterOtherRoles.Modules; @@ -6,9 +6,9 @@ namespace BetterOtherRoles.Modules; public static class FirstKillShield { public static Color ShieldColor => Color.HSVToRGB(Mathf.PingPong(Time.time * 0.30f, 1), 1, 1); - public static bool Enabled => CustomOptionHolder.shieldFirstKill.getBool(); - public static bool ExpireWithTimer => CustomOptionHolder.ExpireFirstKillShield.getBool(); - public static float MaxShieldTimer => CustomOptionHolder.FirstKillShieldDuration.getFloat(); + public static bool Enabled => CustomOptionHolder.ShieldFirstKill.GetBool(); + public static bool ExpireWithTimer => CustomOptionHolder.ExpireFirstKillShield.GetBool(); + public static float MaxShieldTimer => CustomOptionHolder.FirstKillShieldDuration.GetFloat(); public static string FirstKilledPlayerName = string.Empty; public static PlayerControl ShieldedPlayer; public static float ShieldTimer = 0f; diff --git a/BetterOtherRoles/Modules/MeetingRandomizer.cs b/BetterOtherRoles/Modules/MeetingRandomizer.cs index d514beb..ea2c3d6 100644 --- a/BetterOtherRoles/Modules/MeetingRandomizer.cs +++ b/BetterOtherRoles/Modules/MeetingRandomizer.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using BetterOtherRoles.Options; using BetterOtherRoles.Players; using BetterOtherRoles.Utilities.Attributes; @@ -24,7 +25,7 @@ public static void SetSeed(int seed) private static void Start() { - if (!CustomOptionHolder.RandomizePlayersInMeeting.getBool()) return; + if (!CustomOptionHolder.RandomizePlayersInMeeting.GetBool()) return; var meetingHud = MeetingHud.Instance; if (!meetingHud) return; var alivePlayers = meetingHud.playerStates diff --git a/BetterOtherRoles/Modules/TaskPositionsRandomizer.cs b/BetterOtherRoles/Modules/TaskPositionsRandomizer.cs index 00093a6..d008824 100644 --- a/BetterOtherRoles/Modules/TaskPositionsRandomizer.cs +++ b/BetterOtherRoles/Modules/TaskPositionsRandomizer.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using AmongUsSpecimen.ModOptions; +using BetterOtherRoles.Options; using BetterOtherRoles.Utilities.Attributes; using BetterOtherRoles.Utilities.Extensions; using UnityEngine; @@ -9,8 +11,8 @@ namespace BetterOtherRoles.Modules; [Autoload] public static class TaskPositionsRandomizer { - private static CustomOption RandomizeWireTaskPositions => CustomOptionHolder.RandomizeWireTaskPositions; - private static CustomOption RandomizeUploadTaskPosition => CustomOptionHolder.RandomizeUploadTaskPosition; + private static ModBoolOption RandomizeWireTaskPositions => CustomOptionHolder.RandomizeWireTaskPositions; + private static ModBoolOption RandomizeUploadTaskPosition => CustomOptionHolder.RandomizeUploadTaskPosition; static TaskPositionsRandomizer() { @@ -22,7 +24,7 @@ private static void ApplyModule() RelocatedWires.Clear(); RelocatedDownloads.Clear(); var consoles = ShipStatus.Instance.AllConsoles.ToList(); - if (RandomizeWireTaskPositions.getBool()) + if (RandomizeWireTaskPositions.GetBool()) { var wires = consoles.FindAll(o => o.name.StartsWith("panel_electrical")); if (wires.Count > 0) @@ -31,7 +33,7 @@ private static void ApplyModule() } } - if (RandomizeUploadTaskPosition.getBool()) + if (RandomizeUploadTaskPosition.GetBool()) { var upload = consoles.Find(o => o.name == "panel_datahome"); var downloads = consoles.FindAll(o => o.name == "panel_data"); diff --git a/BetterOtherRoles/Objects/Bloodytrail.cs b/BetterOtherRoles/Objects/Bloodytrail.cs index 1ea1b87..06e1503 100644 --- a/BetterOtherRoles/Objects/Bloodytrail.cs +++ b/BetterOtherRoles/Objects/Bloodytrail.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; using static BetterOtherRoles.BetterOtherRoles; diff --git a/BetterOtherRoles/Objects/Bomb.cs b/BetterOtherRoles/Objects/Bomb.cs index 00f257e..8e9eaf8 100644 --- a/BetterOtherRoles/Objects/Bomb.cs +++ b/BetterOtherRoles/Objects/Bomb.cs @@ -2,6 +2,7 @@ using System.Collections; using BepInEx.Unity.IL2CPP.Utils; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; diff --git a/BetterOtherRoles/Objects/CustomButton.cs b/BetterOtherRoles/Objects/CustomButton.cs index 8bb5e97..bf5798d 100644 --- a/BetterOtherRoles/Objects/CustomButton.cs +++ b/BetterOtherRoles/Objects/CustomButton.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using TMPro; using UnityEngine; using UnityEngine.UI; diff --git a/BetterOtherRoles/Objects/Footprint.cs b/BetterOtherRoles/Objects/Footprint.cs index 244d987..e24852f 100644 --- a/BetterOtherRoles/Objects/Footprint.cs +++ b/BetterOtherRoles/Objects/Footprint.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; @@ -23,8 +24,8 @@ public static FootprintHolder Instance private static Sprite _footprintSprite; private static Sprite FootprintSprite => _footprintSprite ??= Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Footprint.png", 600f); - private static bool AnonymousFootprints => BetterOtherRoles.Detective.anonymousFootprints; - private static float FootprintDuration => BetterOtherRoles.Detective.footprintDuration; + private static bool AnonymousFootprints => Detective.anonymousFootprints; + private static float FootprintDuration => Detective.footprintDuration; private class Footprint { diff --git a/BetterOtherRoles/Objects/JackInTheBox.cs b/BetterOtherRoles/Objects/JackInTheBox.cs index 11285f3..fed2cd1 100644 --- a/BetterOtherRoles/Objects/JackInTheBox.cs +++ b/BetterOtherRoles/Objects/JackInTheBox.cs @@ -3,6 +3,7 @@ using UnityEngine; using System.Linq; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; namespace BetterOtherRoles.Objects { diff --git a/BetterOtherRoles/Objects/NinjaTrace.cs b/BetterOtherRoles/Objects/NinjaTrace.cs index 2e07f44..76ee300 100644 --- a/BetterOtherRoles/Objects/NinjaTrace.cs +++ b/BetterOtherRoles/Objects/NinjaTrace.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; @@ -31,7 +33,7 @@ public NinjaTrace(Vector2 p, float duration=1f) { timeRemaining = duration; // display the ninjas color in the trace - float colorDuration = CustomOptionHolder.ninjaTraceColorTime.getFloat(); + float colorDuration = CustomOptionHolder.NinjaTraceColorTime.GetFloat(); FastDestroyableSingleton.Instance.StartCoroutine(Effects.Lerp(colorDuration, new Action((p) => { Color c = Palette.PlayerColors[(int)Ninja.ninja.Data.DefaultOutfit.ColorId]; if (Helpers.isLighterColor(Ninja.ninja.Data.DefaultOutfit.ColorId)) c = Color.white; diff --git a/BetterOtherRoles/Objects/Portal.cs b/BetterOtherRoles/Objects/Portal.cs index 79023e2..1ae3256 100644 --- a/BetterOtherRoles/Objects/Portal.cs +++ b/BetterOtherRoles/Objects/Portal.cs @@ -2,6 +2,7 @@ using UnityEngine; using System.Collections.Generic; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using static BetterOtherRoles.BetterOtherRoles; diff --git a/BetterOtherRoles/Objects/Trap.cs b/BetterOtherRoles/Objects/Trap.cs index 4ff4c83..6e0f8c8 100644 --- a/BetterOtherRoles/Objects/Trap.cs +++ b/BetterOtherRoles/Objects/Trap.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; diff --git a/BetterOtherRoles/Options/CustomOptionBuilder.cs b/BetterOtherRoles/Options/CustomOptionBuilder.cs new file mode 100644 index 0000000..8e1a4bd --- /dev/null +++ b/BetterOtherRoles/Options/CustomOptionBuilder.cs @@ -0,0 +1,474 @@ +using System.Collections.Generic; +using AmongUsSpecimen; +using AmongUsSpecimen.ModOptions; +using BetterOtherRoles.Roles; +using UnityEngine; +using static AmongUsSpecimen.ModOptions.Helpers; +using static AmongUsSpecimen.OptionTabs; + +namespace BetterOtherRoles.Options; + +[ModOptionContainer(ContainerType.Tabs)] +public static partial class CustomOptionHolder +{ + public static readonly Dictionary BlockedRolePairings = new () + { + [(byte)RoleId.Vampire] = [(byte)RoleId.Warlock], + [(byte)RoleId.Warlock] = [(byte)RoleId.Vampire], + [(byte)RoleId.Spy] = [(byte)RoleId.Mini], + [(byte)RoleId.Mini] = [(byte)RoleId.Spy], + [(byte)RoleId.Vulture] = [(byte)RoleId.Cleaner], + [(byte)RoleId.Cleaner] = [(byte)RoleId.Vulture], + }; + + static CustomOptionHolder() + { + MainTab.OverrideSprite(GetSprite("SettingsTab")); + GuesserTab = new ModOptionTab("Guesser", "Guesser Settings", GetSprite("TabIconGuesserSettings"), + AfterTab(MainTab)); + GuesserTab.SetActive(false); + CrewmateTab = new ModOptionTab("Crewmate", "Crewmate Settings", GetSprite("TabIconCrewmate")); + NeutralTab = new ModOptionTab("Neutral", "Neutral Settings", GetSprite("TabIconNeutral")); + ImpostorTab = new ModOptionTab("Impostor", "Impostor Settings", GetSprite("TabIconImpostor")); + ModifierTab = new ModOptionTab("Modifier", "Modifier Settings", GetSprite("TabIconModifier")); + + RandomMap = OutsidePreset(MainTab.BoolOption("Random Map", false)); + + TheSkeldMap = new RandomMapModOptionMap("The Skeld"); + PolusMap = new RandomMapModOptionMap("Polus"); + MiraHqMap = new RandomMapModOptionMap("Mira HQ"); + AirshipMap = new RandomMapModOptionMap("Airship"); + TheFungleMap = new RandomMapModOptionMap("The Fungle"); + + GameEventManager.HostChanged += OnHostChanged; + + EnableBetterPolus = MainTab.BoolOption("Better Polus", false); + PolusReactorCountdown = MainTab.FloatOption("Polus Reactor Countdown", 10f, 120f, 2.5f, 40f, EnableBetterPolus, suffix: "s"); + + EnableBetterSkeld = MainTab.BoolOption("Better Skeld", false); + BetterSkeldEnableAdmin = MainTab.BoolOption("Enable Admin Table", false, EnableBetterSkeld); + BetterSkeldEnableVitals = MainTab.BoolOption("Enable Vitals", false, EnableBetterSkeld); + + if (Utilities.EventUtility.canBeEnabled) + { + EnableCodenameHorseMode = MainTab.BoolOption(Cs(Color.green, "Enable Codename Horsemode"), true); + EnableCodenameDisableHorses = + MainTab.BoolOption(Cs(Color.green, "Disable Horses"), false, EnableCodenameHorseMode); + } + + var yellow = new Color(204f / 255f, 204f / 255f, 0, 1f); + ActivateRoles = MainTab.BoolOption(Cs(yellow, "Enable Mod Roles And Block Vanilla Roles"), true); + + GuesserMode = MainTab.BoolOption("Guesser Mode", false, ActivateRoles); + GuesserMode.ValueChanged += () => GuesserTab.SetActive(GuesserMode); + + MaxNumberOfMeetings = MainTab.FloatOption("Number Of Meetings (excluding Mayor meeting)", 0f, 15f, 1f, 10f); + RandomizePlayersInMeeting = MainTab.BoolOption("Randomize Players Order In Meetings", false, MaxNumberOfMeetings); + BlockSkippingInEmergencyMeetings = MainTab.BoolOption("Block Skipping In Emergency Meetings", false, MaxNumberOfMeetings); + NoVoteIsSelfVote = MainTab.BoolOption("No Vote Is Self Vote", false, BlockSkippingInEmergencyMeetings); + + RandomizeWireTaskPositions = MainTab.BoolOption("Randomize Wire Tasks Positions", false); + + RandomizeUploadTaskPosition = MainTab.BoolOption("Randomize Upload Task Positions", false); + + HidePlayerNames = MainTab.BoolOption("Hide Player Names", false); + + AllowParallelMedBayScans = MainTab.BoolOption("Allow Parallel MedBay Scans", true); + RandomizePositionDuringScan = MainTab.BoolOption("Randomize Position During Scan", true, AllowParallelMedBayScans); + + ShieldFirstKill = MainTab.BoolOption("Shield Last Game First Kill", false); + ExpireFirstKillShield = MainTab.BoolOption("Expire shield with duration", false, ShieldFirstKill); + FirstKillShieldDuration = MainTab.FloatOption("Shield duration", 10f, 300f, 5f, 80f, ExpireFirstKillShield, suffix: "s"); + + FinishTasksBeforeHauntingOrZoomingOut = MainTab.BoolOption("Finish Tasks Before Haunting Or Zooming Out", true); + + CamsNightVision = MainTab.BoolOption("Cams Switch To Night Vision If Lights Are Off", false); + CamsNoNightVisionIfImpVision = MainTab.BoolOption("Impostor Vision Ignores Night Vision Cams", false, CamsNightVision); + + FillCrewmateRoles = Header(CrewmateTab.BoolOption(Cs(yellow, "Fill Crewmate Roles"), false, ActivateRoles)); + MinCrewmateRoles = + Inverted(CrewmateTab.FloatOption(Cs(yellow, "Minimum Crewmate Roles"), 0f, 15f, 1f, 15f, + FillCrewmateRoles)); + MaxCrewmateRoles = + Inverted(CrewmateTab.FloatOption(Cs(yellow, "Maximum Crewmate Roles"), 0f, 15f, 1f, 15f, + FillCrewmateRoles)); + + MinNeutralRoles = + Header(NeutralTab.FloatOption(Cs(yellow, "Minimum Neutral Roles"), 0f, 15f, 1f, 15f, ActivateRoles)); + MaxNeutralRoles = NeutralTab.FloatOption(Cs(yellow, "Maximum Neutral Roles"), 0f, 15f, 1f, 15f, ActivateRoles); + + MinImpostorRoles = + Header(ImpostorTab.FloatOption(Cs(yellow, "Minimum Impostor Roles"), 0f, 15f, 1f, 15f, ActivateRoles)); + MaxImpostorRoles = + ImpostorTab.FloatOption(Cs(yellow, "Maximum Impostor Roles"), 0f, 15f, 1f, 15f, ActivateRoles); + + MinModifiers = Header(ModifierTab.FloatOption(Cs(yellow, "Minimum Modifier"), 0f, 15f, 1f, 15f, ActivateRoles)); + MaxModifiers = ModifierTab.FloatOption(Cs(yellow, "Maximum Modifier"), 0f, 15f, 1f, 15f, ActivateRoles); + + MafiaSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Janitor.color, "Mafia"), ActivateRoles)); + JanitorCooldown = ImpostorTab.CooldownOption("Janitor Cooldown", MafiaSpawnRate); + + MorphlingSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Morphling.color, "Morphling"), ActivateRoles)); + MorphlingCooldown = ImpostorTab.CooldownOption("Morph Cooldown", MorphlingSpawnRate); + MorphlingDuration = ImpostorTab.DurationOption("Morph Duration", MorphlingSpawnRate); + + CamouflagerSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Camouflager.color, "Camouflager"), ActivateRoles)); + CamouflagerCooldown = ImpostorTab.CooldownOption("Camouflager Cooldown", CamouflagerSpawnRate); + CamouflagerDuration = ImpostorTab.DurationOption("Camo Duration", CamouflagerSpawnRate); + + VampireSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Vampire.color, "Vampire"), ActivateRoles)); + VampireKillDelay = ImpostorTab.DurationOption("Vampire Kill Delay", VampireSpawnRate); + VampireCooldown = ImpostorTab.CooldownOption("Vampire Cooldown", VampireSpawnRate); + VampireFirstCooldown = ImpostorTab.CooldownOption("Vampire First Cooldown", VampireSpawnRate); + VampireCanKillNearGarlics = ImpostorTab.BoolOption("Vampire Can Kill Near Garlics", true, VampireSpawnRate); + + EraserSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Eraser.color, "Eraser"), ActivateRoles)); + EraserCooldown = ImpostorTab.CooldownOption("Eraser Cooldown", EraserSpawnRate); + EraserCanEraseAnyone = ImpostorTab.BoolOption("Eraser Can Erase Anyone", false, EraserSpawnRate); + + TricksterSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Trickster.color, "Trickster"), ActivateRoles)); + TricksterPlaceBoxCooldown = ImpostorTab.CooldownOption("Trickster Place Box Cooldown", TricksterSpawnRate); + TricksterLightsOutCooldown = ImpostorTab.CooldownOption("Trickster Lights Out Cooldown", TricksterSpawnRate); + TricksterLightsOutDuration = ImpostorTab.DurationOption("Trickster Lights Out Duration", TricksterSpawnRate); + + CleanerSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Cleaner.color, "Cleaner"), ActivateRoles)); + CleanerCooldown = ImpostorTab.CooldownOption("Cleaner Cooldown", CleanerSpawnRate); + + WarlockSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Warlock.color, "Warlock"), ActivateRoles)); + WarlockCooldown = ImpostorTab.CooldownOption("Warlock Cooldown", WarlockSpawnRate); + WarlockFirstCooldown = ImpostorTab.CooldownOption("Warlock First Cooldown", WarlockSpawnRate); + WarlockRootTime = ImpostorTab.FloatOption("Warlock Root Time", 0f, 15f, 1f, 5f, WarlockSpawnRate, suffix: "s"); + + BountyHunterSpawnRate = + Header(ImpostorTab.SpawnRateOption(Cs(BountyHunter.color, "Bounty Hunter"), ActivateRoles)); + BountyHunterBountyDuration = ImpostorTab.FloatOption("Duration After Which Bounty Changes", 10f, 180f, 10f, 60f, + BountyHunterSpawnRate, suffix: "s"); + BountyHunterReducedCooldown = ImpostorTab.FloatOption("Cooldown After Killing Bounty", 0f, 30f, 2.5f, 2.5f, + BountyHunterSpawnRate, suffix: "s"); + BountyHunterPunishmentTime = ImpostorTab.FloatOption("Additional Cooldown After Killing Others", 0f, 60f, 2.5f, + 15f, BountyHunterSpawnRate, suffix: "s", prefix: "+"); + BountyHunterShowArrow = + ImpostorTab.BoolOption("Show Arrow Pointing Towards The Bounty", true, BountyHunterSpawnRate); + BountyHunterArrowUpdateInterval = ImpostorTab.FloatOption("Arrow Update Interval", 2.5f, 60f, 2.5f, 15f, + BountyHunterShowArrow, suffix: "s"); + + WitchSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Witch.color, "Witch"), ActivateRoles)); + WitchCooldown = ImpostorTab.CooldownOption("Witch Spell Casting Cooldown", WitchSpawnRate); + WitchFirstCooldown = ImpostorTab.CooldownOption("Witch First Spell Casting Cooldown", WitchSpawnRate); + WitchAdditionalCooldown = ImpostorTab.FloatOption("Witch Additional Cooldown", 0f, 60f, 5f, 10f, WitchSpawnRate, + suffix: "s", prefix: "+"); + WitchCanSpellAnyone = ImpostorTab.BoolOption("Witch Can Spell Anyone", false, WitchSpawnRate); + WitchSpellCastingDuration = ImpostorTab.ApplyDurationOption("Spell Casting Duration", WitchSpawnRate); + WitchTriggerBothCooldown = ImpostorTab.BoolOption("Trigger Both Cooldowns", true, WitchSpawnRate); + WitchVoteSavesTargets = ImpostorTab.BoolOption("Voting The Witch Saves All The Targets", true, WitchSpawnRate); + + NinjaSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Ninja.color, "Ninja"), ActivateRoles)); + NinjaCooldown = ImpostorTab.CooldownOption("Ninja Mark Cooldown", NinjaSpawnRate); + NinjaFirstCooldown = ImpostorTab.CooldownOption("Ninja First Mark Cooldown", NinjaSpawnRate); + NinjaKnowsTargetLocation = ImpostorTab.BoolOption("Ninja Knows Location Of Target", true, NinjaSpawnRate); + NinjaTraceTime = ImpostorTab.FloatOption("Trace Duration", 1f, 20f, 0.5f, 5f, NinjaSpawnRate, suffix: "s"); + NinjaTraceColorTime = ImpostorTab.FloatOption("Time Till Trace Color Has Faded", 0f, 20f, 0.5f, 2f, + NinjaSpawnRate, suffix: "s"); + NinjaInvisibleDuration = + ImpostorTab.FloatOption("Time The Ninja Is Invisible", 0f, 20f, 1f, 3f, NinjaSpawnRate, suffix: "s"); + + BomberSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Bomber.color, "Bomber"), ActivateRoles)); + BomberBombDestructionTime = + ImpostorTab.FloatOption("Bomb Destruction Time", 2.5f, 120f, 2.5f, 20f, BomberSpawnRate); + BomberBombDestructionRange = + ImpostorTab.FloatOption("Bomb Destruction Range", 5f, 150f, 5f, 50f, BomberSpawnRate, suffix: "x"); + BomberBombHearRange = + ImpostorTab.FloatOption("Bomb Hear Range", 5f, 150f, 5f, 60f, BomberSpawnRate, suffix: "x"); + BomberDefuseDuration = + ImpostorTab.FloatOption("Bomb Defuse Duration", 0.5f, 30f, 0.5f, 3f, BomberSpawnRate, suffix: "s"); + BomberBombCooldown = + ImpostorTab.FloatOption("Bomb Cooldown", 2.5f, 30f, 2.5f, 15f, BomberSpawnRate, suffix: "s"); + BomberBombActiveAfter = + ImpostorTab.FloatOption("Bomb Is Active After", 0.5f, 15f, 0.5f, 3f, BomberSpawnRate, suffix: "s"); + + UndertakerSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(Undertaker.Color, "Undertaker"), ActivateRoles)); + UndertakerSpeedModifier = ImpostorTab.FloatOption("Speed Modifier While Dragging", -100f, 100f, 5f, 0f, UndertakerSpawnRate, suffix: "%"); + UndertakerDisableVent = ImpostorTab.BoolOption("Disable Vent While Dragging", true, UndertakerSpawnRate); + + StickyBomberSpawnRate = Header(ImpostorTab.SpawnRateOption(Cs(StickyBomber.Color, "Sticky Bomber"), ActivateRoles)); + StickyBomberCooldown = ImpostorTab.CooldownOption("Sticky Bomb Cooldown", StickyBomberSpawnRate); + StickyBomberFirstCooldown = ImpostorTab.CooldownOption("Sticky Bomb First Cooldown", StickyBomberSpawnRate); + StickyBomberFirstDelay = ImpostorTab.FloatOption("Sticky Bomb First Delay", 0f, 20f, 1f, 5f, StickyBomberSpawnRate, suffix: "s"); + StickyBomberOtherDelay = ImpostorTab.FloatOption("Sticky Bomb Other Delay", 0f, 20f, 1f, 5f, StickyBomberSpawnRate, suffix: "s"); + StickyBomberDuration = ImpostorTab.FloatOption("Sticky Bomb Timer", 5f, 60f, 2.5f, 30f, StickyBomberSpawnRate, suffix: "s"); + StickyBomberShowTimer = ImpostorTab.BoolOption("Display Remaining Time", true, StickyBomberSpawnRate); + StickyBomberCanReceiveBomb = ImpostorTab.BoolOption("Sticky Bomber Can Receive His Own Bomb", false, StickyBomberSpawnRate); + StickyBomberCanGiveBombToShielded = ImpostorTab.BoolOption("Shielded Players Can Receive Bomb", false, StickyBomberSpawnRate); + StickyBomberEnableKillButton = ImpostorTab.BoolOption("Has Kill Button", false, StickyBomberSpawnRate); + StickyBomberTriggerAllCooldowns = ImpostorTab.BoolOption("Trigger Both Cooldown", false, StickyBomberEnableKillButton); + + GuesserSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Guesser.color, "Guesser"), ActivateRoles)); + GuesserIsImpGuesserRate = + NeutralTab.SpawnRateOption("Chance That The Guesser Is An Impostor", GuesserSpawnRate); + GuesserNumberOfShots = NeutralTab.FloatOption("Guesser Number Of Shots", 1f, 15f, 1f, 2f, GuesserSpawnRate); + GuesserHasMultipleShotsPerMeeting = + NeutralTab.BoolOption("Guesser Can Shoot Multiple Times Per Meeting", false, GuesserSpawnRate); + GuesserKillsThroughShield = NeutralTab.BoolOption("Guesses Ignore The Medic Shield", true, GuesserSpawnRate); + GuesserEvilCanKillSpy = NeutralTab.BoolOption("Evil Guesser Can Guess The Spy", true, GuesserSpawnRate); + GuesserSpawnBothRate = NeutralTab.SpawnRateOption("Both Guesser Spawn Rate", GuesserSpawnRate); + GuesserCantGuessSnitchIfTasksDone = + NeutralTab.BoolOption("Guesser Can't Guess Snitch When Tasks Completed", true, GuesserSpawnRate); + + JesterSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Jester.color, "Jester"), ActivateRoles)); + JesterCanCallEmergency = NeutralTab.BoolOption("Jester Can Call Emergency Meeting", true, JesterSpawnRate); + JesterHasImpostorVision = NeutralTab.BoolOption("Jester Has Impostor Vision", false, JesterSpawnRate); + + ArsonistSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Arsonist.color, "Arsonist"), ActivateRoles)); + ArsonistCooldown = NeutralTab.CooldownOption("Arsonist Cooldown", ArsonistSpawnRate, 2.5f, 12.5f); + ArsonistFirstCooldown = NeutralTab.CooldownOption("Arsonist First Cooldown", ArsonistSpawnRate, 2.5f, 12.5f); + ArsonistDuration = NeutralTab.ApplyDurationOption("Douse Duration", ArsonistSpawnRate); + + JackalSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Jackal.color, "Jackal"), ActivateRoles)); + JackalKillCooldown = NeutralTab.CooldownOption("Jackal/Sidekick Kill Cooldown", JackalSpawnRate); + JackalCanUseVents = NeutralTab.BoolOption("Jackal Can Use Vents", true, JackalSpawnRate); + JackalAndSidekickHaveImpostorVision = + NeutralTab.BoolOption("Jackal And Sidekick Have Impostor Vision", false, JackalSpawnRate); + JackalCanCreateSidekick = NeutralTab.BoolOption("Jackal Can Create A Sidekick", false, JackalSpawnRate); + JackalCreateSidekickCooldown = + NeutralTab.CooldownOption("Jackal Create Sidekick Cooldown", JackalCanCreateSidekick); + SidekickPromoteToJackal = NeutralTab.BoolOption("Sidekick Gets Promoted To Jackal On Jackal Death", false, + JackalCanCreateSidekick); + JackalPromotedFromSidekickCanCreateSidekick = + NeutralTab.BoolOption("Jackals Promoted From Sidekick Can Create A Sidekick", true, + SidekickPromoteToJackal); + SidekickCanKill = NeutralTab.BoolOption("Sidekick Can Kill", false, JackalCanCreateSidekick); + SidekickCanUseVents = NeutralTab.BoolOption("Sidekick Can Use Vents", true, JackalCanCreateSidekick); + JackalCanCreateSidekickFromImpostor = NeutralTab.BoolOption("Jackals Can Make An Impostor To His Sidekick", + true, JackalCanCreateSidekick); + + VultureSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Vulture.color, "Vulture"), ActivateRoles)); + VultureCooldown = NeutralTab.CooldownOption("Vulture Cooldown", VultureSpawnRate, defaultValue: 15f); + VultureNumberToWin = + NeutralTab.FloatOption("Number Of Corpses Needed To Be Eaten", 1f, 10f, 1f, 4f, VultureSpawnRate); + VultureCanUseVents = NeutralTab.BoolOption("Vulture Can Use Vents", true, VultureSpawnRate); + VultureShowArrow = NeutralTab.BoolOption("Show Arrows Pointing Towards The Corpses", true, VultureSpawnRate); + + LawyerSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Lawyer.color, "Lawyer"), ActivateRoles)); + LawyerIsProsecutorChance = NeutralTab.SpawnRateOption("Chance That The Lawyer Is Prosecutor", LawyerSpawnRate); + LawyerVision = NeutralTab.FloatOption("Vision", 0.25f, 3f, 0.25f, 1f, LawyerSpawnRate, suffix: "x"); + LawyerKnowsRole = NeutralTab.BoolOption("Lawyer/Prosecutor Knows Target Role", false, LawyerSpawnRate); + LawyerCanCallEmergency = + NeutralTab.BoolOption("Lawyer/Prosecutor Can Call Emergency Meeting", true, LawyerSpawnRate); + LawyerTargetCanBeJester = NeutralTab.BoolOption("Lawyer Target Can Be The Jester", true, LawyerSpawnRate); + PursuerCooldown = NeutralTab.CooldownOption("Pursuer Blank Cooldown", LawyerSpawnRate); + PursuerBlanksNumber = NeutralTab.FloatOption("Pursuer Number Of Blanks", 1f, 20f, 1f, 5f, LawyerSpawnRate); + + ThiefSpawnRate = Header(NeutralTab.SpawnRateOption(Cs(Thief.color, "Thief"), ActivateRoles)); + ThiefCooldown = NeutralTab.CooldownOption("Thief Cooldown", ThiefSpawnRate); + ThiefCanKillSheriff = NeutralTab.BoolOption("Thief Can Kill Sheriff", true, ThiefSpawnRate); + ThiefHasImpVision = NeutralTab.BoolOption("Thief Has Impostor Vision", true, ThiefSpawnRate); + ThiefCanUseVents = NeutralTab.BoolOption("Thief Can Use Vents", true, ThiefSpawnRate); + ThiefCanStealWithGuess = NeutralTab.BoolOption("Thief Can Guess To Steal A Role (If Guesser)", false, ThiefSpawnRate); + ThiefStolenPlayerKeepsHisTeam = NeutralTab.BoolOption("Stolen Player Keeps His Team", false, ThiefSpawnRate); + + MayorSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Mayor.color, "Mayor"), ActivateRoles)); + MayorCanSeeVoteColors = CrewmateTab.BoolOption("Mayor Can See Vote Colors", false, MayorSpawnRate); + MayorTasksNeededToSeeVoteColors = CrewmateTab.FloatOption("Completed Tasks Needed To See Vote Colors", 0f, 20f, + 1f, 5f, MayorCanSeeVoteColors); + MayorMeetingButton = CrewmateTab.BoolOption("Mobile Emergency Button", true, MayorSpawnRate); + MayorMaxRemoteMeetings = + CrewmateTab.FloatOption("Number Of Remote Meetings", 1f, 5f, 1f, 1f, MayorMeetingButton); + MayorChooseSingleVote = CrewmateTab.StringOption("Mayor Can Choose Single Vote", + MayorChooseSingleVoteSelections, MayorChooseSingleVoteSelections[0], MayorSpawnRate); + + EngineerSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Engineer.color, "Engineer"), ActivateRoles)); + EngineerNumberOfFixes = CrewmateTab.FloatOption("Number Of Sabotage Fixes", 1f, 3f, 1f, 1f, EngineerSpawnRate); + EngineerHighlightForImpostors = + CrewmateTab.BoolOption("Impostors See Vents Highlighted", true, EngineerSpawnRate); + EngineerHighlightForTeamJackal = + CrewmateTab.BoolOption("Jackal and Sidekick See Vents Highlighted", true, EngineerSpawnRate); + + SheriffSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Sheriff.color, "Sheriff"), ActivateRoles)); + SheriffCooldown = CrewmateTab.CooldownOption("Sheriff Cooldown", SheriffSpawnRate); + SheriffCanKillNeutrals = CrewmateTab.BoolOption("Sheriff Can Kill Neutrals", false, SheriffSpawnRate); + DeputySpawnRate = CrewmateTab.SpawnRateOption("Sheriff Has A Deputy", SheriffSpawnRate); + DeputyNumberOfHandcuffs = + CrewmateTab.FloatOption("Deputy Number Of Handcuffs", 1f, 10f, 1f, 3f, DeputySpawnRate); + DeputyHandcuffCooldown = CrewmateTab.CooldownOption("Handcuff Cooldown", DeputySpawnRate); + DeputyHandcuffDuration = + CrewmateTab.FloatOption("Handcuff Duration", 5f, 60f, 2.5f, 15f, DeputySpawnRate, suffix: "s"); + DeputyKnowsSheriff = CrewmateTab.BoolOption("Sheriff And Deputy Know Each Other", true, DeputySpawnRate); + DeputyGetsPromoted = CrewmateTab.StringOption("Deputy Gets Promoted To Sheriff", + DeputyGetsPromotedSelections, + DeputyGetsPromotedSelections[0], DeputySpawnRate); + DeputyKeepsHandcuffs = CrewmateTab.BoolOption("Deputy Keeps Handcuffs When Promoted", true, DeputyGetsPromoted); + + LighterSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Lighter.color, "Lighter"), ActivateRoles)); + LighterModeLightsOnVision = + CrewmateTab.FloatOption("Vision On Lights On", 0.25f, 5f, 0.25f, 1.5f, LighterSpawnRate, suffix: "x"); + LighterModeLightsOffVision = CrewmateTab.FloatOption("Vision On Lights Off", 0.25f, 5f, 0.25f, 0.5f, + LighterSpawnRate, suffix: "x"); + LighterFlashlightWidth = + CrewmateTab.FloatOption("Flashlight Width", 0.1f, 1f, 0.1f, 0.3f, LighterSpawnRate, suffix: "x"); + + DetectiveSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Detective.color, "Detective"), ActivateRoles)); + DetectiveAnonymousFootprints = CrewmateTab.BoolOption("Anonymous Footprints", false, DetectiveSpawnRate); + DetectiveFootprintInterval = CrewmateTab.FloatOption("Footprint Interval", 0.25f, 10f, 0.25f, 0.5f, + DetectiveSpawnRate, suffix: "s"); + DetectiveFootprintDuration = CrewmateTab.FloatOption("Footprint Duration", 0.25f, 10f, 0.25f, 5f, + DetectiveSpawnRate, suffix: "s"); + DetectiveReportNameDuration = CrewmateTab.FloatOption("Time Where Detective Reports Will Have Name", 0f, 60, + 2.5f, 0f, DetectiveSpawnRate); + DetectiveReportColorDuration = CrewmateTab.FloatOption("Time Where Detective Reports Will Have Color Type", 0f, + 120, 2.5f, 20f, DetectiveSpawnRate); + + TimeMasterSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(TimeMaster.color, "Time Master"), ActivateRoles)); + TimeMasterCooldown = CrewmateTab.CooldownOption("Time Master Cooldown", TimeMasterSpawnRate); + TimeMasterRewindTime = + CrewmateTab.FloatOption("Rewind Time", 1f, 10f, 1f, 3f, TimeMasterSpawnRate, suffix: "s"); + TimeMasterShieldDuration = CrewmateTab.FloatOption("Time Master Shield Duration", 1f, 20f, 1f, 3f, + TimeMasterSpawnRate, suffix: "s"); + + MedicSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Medic.color, "Medic"), ActivateRoles)); + MedicShowShielded = CrewmateTab.StringOption("Show Shielded Player", + MedicShowShieldedSelections, + MedicShowShieldedSelections[0], MedicSpawnRate); + MedicShowAttemptToMedic = + CrewmateTab.BoolOption("Medic Sees Murder Attempt On Shielded Player", false, MedicSpawnRate); + MedicShowAttemptToShielded = + CrewmateTab.BoolOption("Shielded Player Sees Murder Attempt", false, MedicSpawnRate); + MedicSetOrShowShieldAfterMeeting = CrewmateTab.StringOption("Shield Will Be Activated", + MedicSetOrShowShieldAfterMeetingSelections, MedicSetOrShowShieldAfterMeetingSelections[0], MedicSpawnRate); + + SwapperSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Swapper.color, "Swapper"), ActivateRoles)); + SwapperCanCallEmergency = CrewmateTab.BoolOption("Swapper Can Call Emergency Meeting", false, SwapperSpawnRate); + SwapperCanOnlySwapOther = CrewmateTab.BoolOption("Swapper Can Only Swap Others", false, SwapperSpawnRate); + SwapperSwapsNumber = CrewmateTab.FloatOption("Initial Swap Charges", 0f, 5f, 1f, 1f, SwapperSpawnRate); + SwapperRechargeTasksNumber = CrewmateTab.FloatOption("Number Of Tasks Needed For Recharging", 1f, 10f, 1f, 2f, SwapperSpawnRate); + + SeerSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Seer.color, "Seer"), ActivateRoles)); + SeerMode = CrewmateTab.StringOption("Seer Mode", SeerModeSelections, SeerModeSelections[0], SeerSpawnRate); + SeerLimitSoulDuration = CrewmateTab.BoolOption("Seer Limit Soul Duration", false, SeerSpawnRate); + SeerSoulDuration = CrewmateTab.FloatOption("Soul Duration", 0f, 120f, 5f, 15f, SeerLimitSoulDuration, suffix: "s"); + + HackerSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Hacker.color, "Hacker"), ActivateRoles)); + HackerCooldown = CrewmateTab.CooldownOption("Hacker Cooldown", HackerSpawnRate); + HackerHackeringDuration = CrewmateTab.FloatOption("Hacker Duration", 2.5f, 60f, 2.5f, 10f, HackerSpawnRate, suffix: "s"); + HackerOnlyColorType = CrewmateTab.BoolOption("Hacker Only Sees Color Type", false, HackerSpawnRate); + HackerToolsNumber = CrewmateTab.FloatOption("Max Mobile Gadget Charges", 1f, 30f, 1f, 5f, HackerSpawnRate); + HackerRechargeTasksNumber = CrewmateTab.FloatOption("Number Of Tasks Needed For Recharging", 1f, 5f, 1f, 2f, HackerSpawnRate); + HackerNoMove = CrewmateTab.BoolOption("Cant Move During Mobile Gadget Duration", true, HackerSpawnRate); + + TrackerSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Tracker.color, "Tracker"), ActivateRoles)); + TrackerUpdateInterval = CrewmateTab.FloatOption("Tracker Update Interval", 1f, 30f, 1f, 5f, TrackerSpawnRate, suffix: "s"); + TrackerResetTargetAfterMeeting = CrewmateTab.BoolOption("Tracker Reset Target After Meeting", false, TrackerSpawnRate); + TrackerCanTrackCorpses = CrewmateTab.BoolOption("Tracker Can Track Corpses", true, TrackerSpawnRate); + TrackerCorpsesTrackingCooldown = CrewmateTab.CooldownOption("Corpses Tracking Cooldown", TrackerCanTrackCorpses); + TrackerCorpsesTrackingDuration = CrewmateTab.FloatOption("Corpses Tracking Duration", 2.5f, 30f, 2.5f, 5f, TrackerCanTrackCorpses, suffix: "s"); + + SnitchSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Snitch.color, "Snitch"), ActivateRoles)); + SnitchLeftTasksForReveal = CrewmateTab.FloatOption("Task Count Where The Snitch Will Be Revealed", 0f, 25f, 1f, 5f, SnitchSpawnRate); + SnitchMode = CrewmateTab.StringOption("Information Mode", SnitchModeSelections, SnitchModeSelections[0], SnitchSpawnRate); + SnitchTargets = CrewmateTab.StringOption("Targets", SnitchTargetSelections, SnitchTargetSelections[0], SnitchSpawnRate); + + SpySpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Spy.color, "Spy"), ActivateRoles)); + SpyCanDieToSheriff = CrewmateTab.BoolOption("Spy Can Die To Sheriff", false, SpySpawnRate); + SpyImpostorsCanKillAnyone = CrewmateTab.BoolOption("Impostors Can Kill Anyone If There Is A Spy", true, SpySpawnRate); + SpyCanEnterVents = CrewmateTab.BoolOption("Spy Can Enter Vents", false, SpySpawnRate); + SpyHasImpostorVision = CrewmateTab.BoolOption("Spy Has Impostor Vision", false, SpySpawnRate); + + PortalmakerSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Portalmaker.color, "Portal Maker"), ActivateRoles)); + PortalmakerCooldown = CrewmateTab.CooldownOption("Portalmaker Cooldown", PortalmakerSpawnRate); + PortalmakerUsePortalCooldown = CrewmateTab.CooldownOption("Use Portalmaker Cooldown", PortalmakerSpawnRate); + PortalmakerLogOnlyColorType = CrewmateTab.BoolOption("Portalmaker Log Only Shows Color Type", true, PortalmakerSpawnRate); + PortalmakerLogHasTime = CrewmateTab.BoolOption("Log Shows Time", true, PortalmakerSpawnRate); + PortalmakerCanPortalFromAnywhere = CrewmateTab.BoolOption("Can Port To Portal From Everywhere", true, PortalmakerSpawnRate); + + SecurityGuardSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(SecurityGuard.color, "Security Guard"), ActivateRoles)); + SecurityGuardCooldown = CrewmateTab.CooldownOption("Security Guard Cooldown", SecurityGuardSpawnRate); + SecurityGuardTotalScrews = CrewmateTab.FloatOption("Security Guard Number Of Screws", 1f, 15f, 1f, 7f, SecurityGuardSpawnRate); + SecurityGuardCamPrice = CrewmateTab.FloatOption("Number Of Screws Per Cam", 1f, 15f, 1f, 2f, SecurityGuardSpawnRate); + SecurityGuardVentPrice = CrewmateTab.FloatOption("Number Of Screws Per Vent", 1f, 15f, 1f, 1f, SecurityGuardSpawnRate); + SecurityGuardCamDuration = CrewmateTab.FloatOption("Security Guard Duration", 2.5f, 60f, 2.5f, 10f, SecurityGuardSpawnRate, suffix: "s"); + SecurityGuardCamMaxCharges = CrewmateTab.FloatOption("Gadget Max Charges", 1f, 30f, 1f, 5f, SecurityGuardSpawnRate); + SecurityGuardCamRechargeTasksNumber = CrewmateTab.FloatOption("Number Of Tasks Needed For Recharging", 1f, 10f, 1f, 3f, SecurityGuardSpawnRate); + SecurityGuardNoMove = CrewmateTab.BoolOption("Cant Move During Cam Duration", true, SecurityGuardSpawnRate); + + MediumSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Medium.color, "Medium"), ActivateRoles)); + MediumCooldown = CrewmateTab.CooldownOption("Medium Questioning Cooldown", MediumSpawnRate); + MediumDuration = CrewmateTab.ApplyDurationOption("Medium Questioning Duration", MediumSpawnRate); + MediumOneTimeUse = CrewmateTab.BoolOption("Each Soul Can Only Be Questioned Once", false, MediumSpawnRate); + MediumChanceAdditionalInfo = CrewmateTab.SpawnRateOption("Chance To Have Additional Information", MediumSpawnRate); + + TrapperSpawnRate = Header(CrewmateTab.SpawnRateOption(Cs(Trapper.color, "Trapper"), ActivateRoles)); + TrapperCooldown = CrewmateTab.CooldownOption("Trapper Cooldown", TrapperSpawnRate); + TrapperMaxCharges = CrewmateTab.FloatOption("Max Traps Charges", 1f, 15f, 1f, 5f, TrapperSpawnRate); + TrapperRechargeTasksNumber = CrewmateTab.FloatOption("Number Of Tasks Needed For Recharging", 1f, 15f, 1f, 2f, TrapperSpawnRate); + TrapperTrapNeededTriggerToReveal = CrewmateTab.FloatOption("Trap Needed Trigger To Reveal", 2f, 10f, 1f, 3f, TrapperSpawnRate); + TrapperAnonymousMap = CrewmateTab.BoolOption("Show Anonymous Map", false, TrapperSpawnRate); + TrapperInfoType = CrewmateTab.StringOption("Trap Information Type", TrapperInfoTypeSelections, TrapperInfoTypeSelections[0], TrapperSpawnRate); + TrapperTrapDuration = CrewmateTab.FloatOption("Time before trap is active", 1f, 15f, 1f, 5f, TrapperSpawnRate, suffix: "s"); + + var modifierColor = Color.yellow; + ModifiersAreHidden = Header(ModifierTab.BoolOption(Cs(modifierColor, "Hide Death Related Modifiers"), true, ActivateRoles)); + + ModifierBloody = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Bloody"), ActivateRoles)); + ModifierBloodyQuantity = ModifierTab.QuantityOption("Bloody Quantity", ModifierBloody); + ModifierBloodyDuration = ModifierTab.FloatOption("Trail Duration", 3f, 60f, 1f, 10f, ModifierBloody, suffix: "s"); + + ModifierAntiTeleport = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Anti Teleport"), ActivateRoles)); + ModifierAntiTeleportQuantity = ModifierTab.QuantityOption("Anti Teleport Quantity", ModifierAntiTeleport); + + ModifierTieBreaker = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Tie Breaker"), ActivateRoles)); + + ModifierBait = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Bait"), ActivateRoles)); + ModifierBaitQuantity = ModifierTab.QuantityOption("Bait Quantity", ModifierBait); + ModifierBaitReportDelayMin = ModifierTab.FloatOption("Bait Report Delay Min", 0f, 10f, 1f, 0f, ModifierBait, suffix: "s"); + ModifierBaitReportDelayMax = ModifierTab.FloatOption("Bait Report Delay Max", 0f, 10f, 1f, 0f, ModifierBait, suffix: "s"); + ModifierBaitShowKillFlash = ModifierTab.BoolOption("Warn The Killer With A Flash", true, ModifierBait); + + ModifierLover = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Lovers"), ActivateRoles)); + ModifierLoverImpLoverRate = ModifierTab.SpawnRateOption("Chance That One Lover Is Impostor", ModifierLover); + ModifierLoverBothDie = ModifierTab.BoolOption("Both Lovers Die", false, ModifierLover); + ModifierLoverEnableChat = ModifierTab.BoolOption("Enable Lover Chat", true, ModifierLover); + + ModifierSunglasses = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Sunglasses"), ActivateRoles)); + ModifierSunglassesQuantity = ModifierTab.QuantityOption("Sunglasses Quantity", ModifierSunglasses); + ModifierSunglassesVision = ModifierTab.FloatOption("Vision With Sunglasses", 10f, 50f, 10f, 30f, ModifierSunglasses, "-", "%"); + + ModifierMini = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Mini"), ActivateRoles)); + ModifierMiniGrowingUpDuration = ModifierTab.FloatOption("Mini Growing Up Duration", 100f, 1500f, 100f, 400f, ModifierMini, suffix: "s"); + ModifierMiniGrowingUpInMeeting = ModifierTab.BoolOption("Mini Grows Up In Meeting", true, ModifierMini); + + ModifierVip = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Vip"), ActivateRoles)); + ModifierVipQuantity = ModifierTab.QuantityOption("Vip Quantity", ModifierVip); + ModifierVipShowColor = ModifierTab.BoolOption("Show Team Color", true, ModifierVip); + + ModifierInvert = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Invert"), ActivateRoles)); + ModifierInvertQuantity = ModifierTab.QuantityOption("Invert Quantity", ModifierInvert); + ModifierInvertDuration = ModifierTab.FloatOption("Number Of Meetings Inverted", 1f, 15f, 1f, 3f, ModifierInvert); + + ModifierChameleon = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Chameleon"), ActivateRoles)); + ModifierChameleonQuantity = ModifierTab.QuantityOption("Chameleon Quantity", ModifierChameleon); + ModifierChameleonHoldDuration = ModifierTab.FloatOption("Time Until Fading Starts", 1f, 10f, 0.5f, 3f, ModifierChameleon, suffix: "s"); + ModifierChameleonFadeDuration = ModifierTab.FloatOption("Fade Duration", 0.25f, 10f, 0.25f, 1f, ModifierChameleon, suffix: "s"); + ModifierChameleonMinVisibility = ModifierTab.FloatOption("Minimum Visibility", 0f, 50f, 10f, 0f, ModifierChameleon, suffix: "%"); + + ModifierShifter = Header(ModifierTab.SpawnRateOption(Cs(modifierColor, "Shifter"), ActivateRoles)); + + GuesserModeCrewNumber = Header(GuesserTab.FloatOption("Number of Crew Guessers", 0f, 15f, 1f, 1f, GuesserMode)); + + GuesserModeNeutralNumber = Header(GuesserTab.FloatOption("Number of Neutral Guessers", 0f, 15f, 1f, 1f, GuesserMode)); + GuesserModeForceJackalGuesser = GuesserTab.BoolOption("Force Jackal Guesser", false, GuesserModeNeutralNumber); + GuesserModeForceThiefGuesser = GuesserTab.BoolOption("Force Thief Guesser", false, GuesserModeNeutralNumber); + + GuesserModeImpNumber = Header(GuesserTab.FloatOption("Number of Impostor Guessers", 0f, 15f, 1f, 1f, GuesserMode)); + + GuesserModeHaveModifier = Header(GuesserTab.BoolOption("Guessers Can Have A Modifier", true, GuesserMode)); + + GuesserModeNumberOfShots = Header(GuesserTab.FloatOption("Guesser Number Of Shots", 1f, 15f, 1f, 3f, GuesserMode)); + + GuesserModeMultipleShotsPerMeeting = Header(GuesserTab.BoolOption("Guesser Can Shoot Multiple Times Per Meeting", false, GuesserMode)); + + GuesserModeKillsThroughShield = Header(GuesserTab.BoolOption("Guesses Ignore The Medic Shield", true, GuesserMode)); + + GuesserModeEvilCanKillSpy = Header(GuesserTab.BoolOption("Evil Guesser Can Guess The Spy", true, GuesserMode)); + + GuesserModeCantGuessSnitchIfTasksDone = Header(GuesserTab.BoolOption("Guesser Can't Guess Snitch When Tasks Completed", true, GuesserMode)); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Options/CustomOptionEnums.cs b/BetterOtherRoles/Options/CustomOptionEnums.cs new file mode 100644 index 0000000..bb33daa --- /dev/null +++ b/BetterOtherRoles/Options/CustomOptionEnums.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; + +namespace BetterOtherRoles.Options; + +public static partial class CustomOptionHolder +{ + public const string MayorChooseSingleVote_Off = "Off"; + public const string MayorChooseSingleVote_BeforeVoting = "On (Before Voting)"; + public const string MayorChooseSingleVote_UntilMeetingEnds = "On (Until Meeting Ends)"; + public static readonly List MayorChooseSingleVoteSelections = [MayorChooseSingleVote_Off, MayorChooseSingleVote_BeforeVoting, MayorChooseSingleVote_UntilMeetingEnds]; + + public const string DeputyGetsPromoted_Off = "Off"; + public const string DeputyGetsPromoted_Immediately = "On (Immediately)"; + public const string DeputyGetsPromoted_AfterMeeting = "On (After Meeting)"; + public static readonly List DeputyGetsPromotedSelections = [DeputyGetsPromoted_Off, DeputyGetsPromoted_Immediately, DeputyGetsPromoted_AfterMeeting]; + + public const string MedicShowShielded_Everyone = "Everyone"; + public const string MedicShowShielded_ShieldedAndMedic = "Shielded + Medic"; + public const string MedicShowShielded_Medic = "Medic"; + public static readonly List MedicShowShieldedSelections = [MedicShowShielded_Everyone, MedicShowShielded_ShieldedAndMedic, MedicShowShielded_Medic]; + + public const string MedicSetOrShowShieldAfterMeeting_Instantly = "Instantly"; + public const string MedicSetOrShowShieldAfterMeeting_InstantlyVisibleAfterMeeting = "Instantly, Visible \nAfter Meeting"; + public const string MedicSetOrShowShieldAfterMeeting_AfterMeeting = "After Meeting"; + public static readonly List MedicSetOrShowShieldAfterMeetingSelections = [MedicSetOrShowShieldAfterMeeting_Instantly, MedicSetOrShowShieldAfterMeeting_InstantlyVisibleAfterMeeting, MedicSetOrShowShieldAfterMeeting_AfterMeeting]; + + public const string SeerMode_DeathFlashAndSouls = "Show Death Flash + Souls"; + public const string SeerMode_DeathFlash = "Show Death Flash"; + public const string SeerMode_Souls = "Show Souls"; + public static readonly List SeerModeSelections = [SeerMode_DeathFlashAndSouls, SeerMode_DeathFlash, SeerMode_Souls]; + + public const string SnitchMode_Chat = "Chat"; + public const string SnitchMode_Map = "Map"; + public const string SnitchMode_ChatAndMap = "Chat & Map"; + public static readonly List SnitchModeSelections = [SnitchMode_Chat, SnitchMode_Map, SnitchMode_ChatAndMap]; + + public const string SnitchTarget_Evil = "All Evil Players"; + public const string SnitchTarget_Killer = "Killing Players"; + public static readonly List SnitchTargetSelections = [SnitchTarget_Evil, SnitchTarget_Killer]; + + public const string TrapperInfoType_Role = "Role"; + public const string TrapperInfoType_GoodEvil = "Good/Evil Role"; + public const string TrapperInfoType_Name = "Name"; + public static readonly List TrapperInfoTypeSelections = [TrapperInfoType_Role, TrapperInfoType_GoodEvil, TrapperInfoType_Name]; +} \ No newline at end of file diff --git a/BetterOtherRoles/Options/CustomOptionHelpers.cs b/BetterOtherRoles/Options/CustomOptionHelpers.cs new file mode 100644 index 0000000..c385882 --- /dev/null +++ b/BetterOtherRoles/Options/CustomOptionHelpers.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using System.Reflection; +using AmongUsSpecimen; +using AmongUsSpecimen.ModOptions; +using AmongUsSpecimen.Utils; +using UnityEngine; +using static AmongUsSpecimen.ModOptions.Helpers; +using static AmongUsSpecimen.OptionTabs; + +namespace BetterOtherRoles.Options; + +public static partial class CustomOptionHolder +{ + private static ModFloatOption SpawnRateOption(this ModOptionTab tab, string name, BaseModOption parent = null) + { + return tab.FloatOption(name, 0f, 100f, 10f, 0f, parent, suffix: "%"); + } + + private static ModFloatOption QuantityOption(this ModOptionTab tab, string name, BaseModOption parent = null) + { + return tab.FloatOption(name, 1f, 15f, 1f, 1f, parent); + } + + private static ModFloatOption CooldownOption(this ModOptionTab tab, string name, BaseModOption parent = null, + float minValue = 10f, float defaultValue = 30f) + { + return tab.FloatOption(name, minValue, 60f, 2.5f, defaultValue, parent, suffix: "s"); + } + + private static ModFloatOption DurationOption(this ModOptionTab tab, string name, BaseModOption parent = null) + { + return tab.FloatOption(name, 1f, 30f, 0.5f, 10f, parent, suffix: "s"); + } + + private static ModFloatOption ApplyDurationOption(this ModOptionTab tab, string name, BaseModOption parent = null) + { + return tab.FloatOption(name, 0f, 10f, 1f, 1f, parent, suffix: "s"); + } + + private static string Cs(Color color, string text) => ColorHelpers.Colorize(color, text); + + public class RandomMapModOptionMap + { + internal static readonly List AllMaps = []; + + internal readonly ModFloatOption Percentage; + internal readonly ModBoolOption ShouldUseSpecificPreset; + internal readonly ModStringOption PresetName; + + internal RandomMapModOptionMap(string mapName) + { + Percentage = OutsidePreset(MainTab.FloatOption(mapName, 0f, 100f, 1f, 0f, RandomMap, suffix: "%")); + ShouldUseSpecificPreset = OutsidePreset(MainTab.BoolOption("Specific Preset", false, Percentage)); + PresetName = OutsidePreset(MainTab.StringOption("Map Preset", CoreOptions.GetPresetNames, CoreOptions.GetPresetNames()[0], ShouldUseSpecificPreset)); + AllMaps.Add(this); + } + } + + private static void OnHostChanged() + { + foreach (var mapOptions in RandomMapModOptionMap.AllMaps) + { + mapOptions.PresetName.Update(); + } + } + + private static Sprite GetSprite(string name, float pixelsPerUnit = 100f) + { + return Assembly.GetExecutingAssembly() + .LoadSpriteFromResources($"BetterOtherRoles.Resources.{name}.png", pixelsPerUnit); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Options/CustomOptionHolder.cs b/BetterOtherRoles/Options/CustomOptionHolder.cs new file mode 100644 index 0000000..c1da57d --- /dev/null +++ b/BetterOtherRoles/Options/CustomOptionHolder.cs @@ -0,0 +1,384 @@ +using AmongUsSpecimen.ModOptions; + +namespace BetterOtherRoles.Options; + +public static partial class CustomOptionHolder +{ + public static readonly ModOptionTab GuesserTab; + public static readonly ModOptionTab CrewmateTab; + public static readonly ModOptionTab NeutralTab; + public static readonly ModOptionTab ImpostorTab; + public static readonly ModOptionTab ModifierTab; + + + public static readonly ModBoolOption RandomMap; + public static readonly RandomMapModOptionMap TheSkeldMap; + public static readonly RandomMapModOptionMap PolusMap; + public static readonly RandomMapModOptionMap MiraHqMap; + public static readonly RandomMapModOptionMap AirshipMap; + public static readonly RandomMapModOptionMap TheFungleMap; + + public static readonly ModBoolOption EnableBetterPolus; + public static readonly ModFloatOption PolusReactorCountdown; + + public static readonly ModBoolOption EnableBetterSkeld; + public static readonly ModBoolOption BetterSkeldEnableAdmin; + public static readonly ModBoolOption BetterSkeldEnableVitals; + + public static readonly ModBoolOption EnableCodenameHorseMode; + public static readonly ModBoolOption EnableCodenameDisableHorses; + + public static readonly ModBoolOption ActivateRoles; + public static readonly ModFloatOption MinCrewmateRoles; + public static readonly ModFloatOption MaxCrewmateRoles; + public static readonly ModBoolOption FillCrewmateRoles; + public static readonly ModFloatOption MinNeutralRoles; + public static readonly ModFloatOption MaxNeutralRoles; + public static readonly ModFloatOption MinImpostorRoles; + public static readonly ModFloatOption MaxImpostorRoles; + public static readonly ModFloatOption MinModifiers; + public static readonly ModFloatOption MaxModifiers; + + public static readonly ModBoolOption GuesserMode; + + public static readonly ModFloatOption MaxNumberOfMeetings; + public static readonly ModBoolOption RandomizePlayersInMeeting; + public static readonly ModBoolOption BlockSkippingInEmergencyMeetings; + public static readonly ModBoolOption NoVoteIsSelfVote; + + public static readonly ModBoolOption RandomizeWireTaskPositions; + + public static readonly ModBoolOption RandomizeUploadTaskPosition; + + public static readonly ModBoolOption HidePlayerNames; + + public static readonly ModBoolOption AllowParallelMedBayScans; + public static readonly ModBoolOption RandomizePositionDuringScan; + + public static readonly ModBoolOption ShieldFirstKill; + public static readonly ModBoolOption ExpireFirstKillShield; + public static readonly ModFloatOption FirstKillShieldDuration; + + public static readonly ModBoolOption FinishTasksBeforeHauntingOrZoomingOut; + + public static readonly ModBoolOption CamsNightVision; + public static readonly ModBoolOption CamsNoNightVisionIfImpVision; + + // IMPOSTOR ROLES OPTIONS + + public static readonly ModFloatOption MafiaSpawnRate; + public static readonly ModFloatOption JanitorCooldown; + + public static readonly ModFloatOption MorphlingSpawnRate; + public static readonly ModFloatOption MorphlingCooldown; + public static readonly ModFloatOption MorphlingDuration; + + public static readonly ModFloatOption CamouflagerSpawnRate; + public static readonly ModFloatOption CamouflagerCooldown; + public static readonly ModFloatOption CamouflagerDuration; + + public static readonly ModFloatOption VampireSpawnRate; + public static readonly ModFloatOption VampireKillDelay; + public static readonly ModFloatOption VampireCooldown; + public static readonly ModFloatOption VampireFirstCooldown; + public static readonly ModBoolOption VampireCanKillNearGarlics; + + public static readonly ModFloatOption EraserSpawnRate; + public static readonly ModFloatOption EraserCooldown; + public static readonly ModBoolOption EraserCanEraseAnyone; + + public static readonly ModFloatOption TricksterSpawnRate; + public static readonly ModFloatOption TricksterPlaceBoxCooldown; + public static readonly ModFloatOption TricksterLightsOutCooldown; + public static readonly ModFloatOption TricksterLightsOutDuration; + + public static readonly ModFloatOption CleanerSpawnRate; + public static readonly ModFloatOption CleanerCooldown; + + public static readonly ModFloatOption WarlockSpawnRate; + public static readonly ModFloatOption WarlockCooldown; + public static readonly ModFloatOption WarlockFirstCooldown; + public static readonly ModFloatOption WarlockRootTime; + + public static readonly ModFloatOption BountyHunterSpawnRate; + public static readonly ModFloatOption BountyHunterBountyDuration; + public static readonly ModFloatOption BountyHunterReducedCooldown; + public static readonly ModFloatOption BountyHunterPunishmentTime; + public static readonly ModBoolOption BountyHunterShowArrow; + public static readonly ModFloatOption BountyHunterArrowUpdateInterval; + + public static readonly ModFloatOption WitchSpawnRate; + public static readonly ModFloatOption WitchCooldown; + public static readonly ModFloatOption WitchFirstCooldown; + public static readonly ModFloatOption WitchAdditionalCooldown; + public static readonly ModBoolOption WitchCanSpellAnyone; + public static readonly ModFloatOption WitchSpellCastingDuration; + public static readonly ModBoolOption WitchTriggerBothCooldown; + public static readonly ModBoolOption WitchVoteSavesTargets; + + public static readonly ModFloatOption NinjaSpawnRate; + public static readonly ModFloatOption NinjaCooldown; + public static readonly ModFloatOption NinjaFirstCooldown; + public static readonly ModBoolOption NinjaKnowsTargetLocation; + public static readonly ModFloatOption NinjaTraceTime; + public static readonly ModFloatOption NinjaTraceColorTime; + public static readonly ModFloatOption NinjaInvisibleDuration; + + public static readonly ModFloatOption BomberSpawnRate; + public static readonly ModFloatOption BomberBombDestructionTime; + public static readonly ModFloatOption BomberBombDestructionRange; + public static readonly ModFloatOption BomberBombHearRange; + public static readonly ModFloatOption BomberDefuseDuration; + public static readonly ModFloatOption BomberBombCooldown; + public static readonly ModFloatOption BomberBombActiveAfter; + + public static readonly ModFloatOption UndertakerSpawnRate; + public static readonly ModFloatOption UndertakerSpeedModifier; + public static readonly ModBoolOption UndertakerDisableVent; + + public static readonly ModFloatOption StickyBomberSpawnRate; + public static readonly ModFloatOption StickyBomberCooldown; + public static readonly ModFloatOption StickyBomberFirstCooldown; + public static readonly ModFloatOption StickyBomberFirstDelay; + public static readonly ModFloatOption StickyBomberOtherDelay; + public static readonly ModFloatOption StickyBomberDuration; + public static readonly ModBoolOption StickyBomberShowTimer; + public static readonly ModBoolOption StickyBomberCanReceiveBomb; + public static readonly ModBoolOption StickyBomberCanGiveBombToShielded; + public static readonly ModBoolOption StickyBomberEnableKillButton; + public static readonly ModBoolOption StickyBomberTriggerAllCooldowns; + + // NEUTRAL ROLES OPTIONS + + public static readonly ModFloatOption GuesserSpawnRate; + public static readonly ModFloatOption GuesserIsImpGuesserRate; + public static readonly ModFloatOption GuesserNumberOfShots; + public static readonly ModBoolOption GuesserHasMultipleShotsPerMeeting; + public static readonly ModBoolOption GuesserKillsThroughShield; + public static readonly ModBoolOption GuesserEvilCanKillSpy; + public static readonly ModFloatOption GuesserSpawnBothRate; + public static readonly ModBoolOption GuesserCantGuessSnitchIfTasksDone; + + public static readonly ModFloatOption JesterSpawnRate; + public static readonly ModBoolOption JesterCanCallEmergency; + public static readonly ModBoolOption JesterHasImpostorVision; + + public static readonly ModFloatOption ArsonistSpawnRate; + public static readonly ModFloatOption ArsonistCooldown; + public static readonly ModFloatOption ArsonistFirstCooldown; + public static readonly ModFloatOption ArsonistDuration; + + public static readonly ModFloatOption JackalSpawnRate; + public static readonly ModFloatOption JackalKillCooldown; + public static readonly ModBoolOption JackalCanUseVents; + public static readonly ModBoolOption JackalCanCreateSidekick; + public static readonly ModFloatOption JackalCreateSidekickCooldown; + public static readonly ModBoolOption SidekickPromoteToJackal; + public static readonly ModBoolOption SidekickCanKill; + public static readonly ModBoolOption SidekickCanUseVents; + public static readonly ModBoolOption JackalPromotedFromSidekickCanCreateSidekick; + public static readonly ModBoolOption JackalCanCreateSidekickFromImpostor; + public static readonly ModBoolOption JackalAndSidekickHaveImpostorVision; + + public static readonly ModFloatOption VultureSpawnRate; + public static readonly ModFloatOption VultureCooldown; + public static readonly ModFloatOption VultureNumberToWin; + public static readonly ModBoolOption VultureCanUseVents; + public static readonly ModBoolOption VultureShowArrow; + + public static readonly ModFloatOption LawyerSpawnRate; + public static readonly ModFloatOption LawyerIsProsecutorChance; + public static readonly ModFloatOption LawyerVision; + public static readonly ModBoolOption LawyerKnowsRole; + public static readonly ModBoolOption LawyerCanCallEmergency; + public static readonly ModBoolOption LawyerTargetCanBeJester; + public static readonly ModFloatOption PursuerCooldown; + public static readonly ModFloatOption PursuerBlanksNumber; + + public static readonly ModFloatOption ThiefSpawnRate; + public static readonly ModFloatOption ThiefCooldown; + public static readonly ModBoolOption ThiefCanKillSheriff; + public static readonly ModBoolOption ThiefHasImpVision; + public static readonly ModBoolOption ThiefCanUseVents; + public static readonly ModBoolOption ThiefCanStealWithGuess; + public static readonly ModBoolOption ThiefStolenPlayerKeepsHisTeam; + + // CREWMATE ROLES OPTIONS + + public static readonly ModFloatOption MayorSpawnRate; + public static readonly ModBoolOption MayorCanSeeVoteColors; + public static readonly ModFloatOption MayorTasksNeededToSeeVoteColors; + public static readonly ModBoolOption MayorMeetingButton; + public static readonly ModFloatOption MayorMaxRemoteMeetings; + public static readonly ModStringOption MayorChooseSingleVote; + + public static readonly ModFloatOption EngineerSpawnRate; + public static readonly ModFloatOption EngineerNumberOfFixes; + public static readonly ModBoolOption EngineerHighlightForImpostors; + public static readonly ModBoolOption EngineerHighlightForTeamJackal; + + public static readonly ModFloatOption SheriffSpawnRate; + public static readonly ModFloatOption SheriffCooldown; + public static readonly ModBoolOption SheriffCanKillNeutrals; + public static readonly ModFloatOption DeputySpawnRate; + public static readonly ModFloatOption DeputyNumberOfHandcuffs; + public static readonly ModFloatOption DeputyHandcuffCooldown; + public static readonly ModFloatOption DeputyHandcuffDuration; + public static readonly ModBoolOption DeputyKnowsSheriff; + public static readonly ModStringOption DeputyGetsPromoted; + public static readonly ModBoolOption DeputyKeepsHandcuffs; + + public static readonly ModFloatOption LighterSpawnRate; + public static readonly ModFloatOption LighterModeLightsOnVision; + public static readonly ModFloatOption LighterModeLightsOffVision; + public static readonly ModFloatOption LighterFlashlightWidth; + + public static readonly ModFloatOption DetectiveSpawnRate; + public static readonly ModBoolOption DetectiveAnonymousFootprints; + public static readonly ModFloatOption DetectiveFootprintInterval; + public static readonly ModFloatOption DetectiveFootprintDuration; + public static readonly ModFloatOption DetectiveReportNameDuration; + public static readonly ModFloatOption DetectiveReportColorDuration; + + public static readonly ModFloatOption TimeMasterSpawnRate; + public static readonly ModFloatOption TimeMasterCooldown; + public static readonly ModFloatOption TimeMasterRewindTime; + public static readonly ModFloatOption TimeMasterShieldDuration; + + public static readonly ModFloatOption MedicSpawnRate; + public static readonly ModStringOption MedicShowShielded; + public static readonly ModBoolOption MedicShowAttemptToMedic; + public static readonly ModBoolOption MedicShowAttemptToShielded; + public static readonly ModStringOption MedicSetOrShowShieldAfterMeeting; + + public static readonly ModFloatOption SwapperSpawnRate; + public static readonly ModBoolOption SwapperCanCallEmergency; + public static readonly ModBoolOption SwapperCanOnlySwapOther; + public static readonly ModFloatOption SwapperSwapsNumber; + public static readonly ModFloatOption SwapperRechargeTasksNumber; + + public static readonly ModFloatOption SeerSpawnRate; + public static readonly ModStringOption SeerMode; + public static readonly ModBoolOption SeerLimitSoulDuration; + public static readonly ModFloatOption SeerSoulDuration; + + public static readonly ModFloatOption HackerSpawnRate; + public static readonly ModFloatOption HackerCooldown; + public static readonly ModFloatOption HackerHackeringDuration; + public static readonly ModBoolOption HackerOnlyColorType; + public static readonly ModFloatOption HackerToolsNumber; + public static readonly ModFloatOption HackerRechargeTasksNumber; + public static readonly ModBoolOption HackerNoMove; + + public static readonly ModFloatOption TrackerSpawnRate; + public static readonly ModFloatOption TrackerUpdateInterval; + public static readonly ModBoolOption TrackerResetTargetAfterMeeting; + public static readonly ModBoolOption TrackerCanTrackCorpses; + public static readonly ModFloatOption TrackerCorpsesTrackingCooldown; + public static readonly ModFloatOption TrackerCorpsesTrackingDuration; + + public static readonly ModFloatOption SnitchSpawnRate; + public static readonly ModFloatOption SnitchLeftTasksForReveal; + public static readonly ModStringOption SnitchMode; + public static readonly ModStringOption SnitchTargets; + + public static readonly ModFloatOption SpySpawnRate; + public static readonly ModBoolOption SpyCanDieToSheriff; + public static readonly ModBoolOption SpyImpostorsCanKillAnyone; + public static readonly ModBoolOption SpyCanEnterVents; + public static readonly ModBoolOption SpyHasImpostorVision; + + public static readonly ModFloatOption PortalmakerSpawnRate; + public static readonly ModFloatOption PortalmakerCooldown; + public static readonly ModFloatOption PortalmakerUsePortalCooldown; + public static readonly ModBoolOption PortalmakerLogOnlyColorType; + public static readonly ModBoolOption PortalmakerLogHasTime; + public static readonly ModBoolOption PortalmakerCanPortalFromAnywhere; + + public static readonly ModFloatOption SecurityGuardSpawnRate; + public static readonly ModFloatOption SecurityGuardCooldown; + public static readonly ModFloatOption SecurityGuardTotalScrews; + public static readonly ModFloatOption SecurityGuardCamPrice; + public static readonly ModFloatOption SecurityGuardVentPrice; + public static readonly ModFloatOption SecurityGuardCamDuration; + public static readonly ModFloatOption SecurityGuardCamMaxCharges; + public static readonly ModFloatOption SecurityGuardCamRechargeTasksNumber; + public static readonly ModBoolOption SecurityGuardNoMove; + + public static readonly ModFloatOption MediumSpawnRate; + public static readonly ModFloatOption MediumCooldown; + public static readonly ModFloatOption MediumDuration; + public static readonly ModBoolOption MediumOneTimeUse; + public static readonly ModFloatOption MediumChanceAdditionalInfo; + + public static readonly ModFloatOption TrapperSpawnRate; + public static readonly ModFloatOption TrapperCooldown; + public static readonly ModFloatOption TrapperMaxCharges; + public static readonly ModFloatOption TrapperRechargeTasksNumber; + public static readonly ModFloatOption TrapperTrapNeededTriggerToReveal; + public static readonly ModBoolOption TrapperAnonymousMap; + public static readonly ModStringOption TrapperInfoType; + public static readonly ModFloatOption TrapperTrapDuration; + + // MODIFIERS OPTIONS + + public static readonly ModBoolOption ModifiersAreHidden; + + public static readonly ModFloatOption ModifierBloody; + public static readonly ModFloatOption ModifierBloodyQuantity; + public static readonly ModFloatOption ModifierBloodyDuration; + + public static readonly ModFloatOption ModifierAntiTeleport; + public static readonly ModFloatOption ModifierAntiTeleportQuantity; + + public static readonly ModFloatOption ModifierTieBreaker; + + public static readonly ModFloatOption ModifierBait; + public static readonly ModFloatOption ModifierBaitQuantity; + public static readonly ModFloatOption ModifierBaitReportDelayMin; + public static readonly ModFloatOption ModifierBaitReportDelayMax; + public static readonly ModBoolOption ModifierBaitShowKillFlash; + + public static readonly ModFloatOption ModifierLover; + public static readonly ModFloatOption ModifierLoverImpLoverRate; + public static readonly ModBoolOption ModifierLoverBothDie; + public static readonly ModBoolOption ModifierLoverEnableChat; + + public static readonly ModFloatOption ModifierSunglasses; + public static readonly ModFloatOption ModifierSunglassesQuantity; + public static readonly ModFloatOption ModifierSunglassesVision; + + public static readonly ModFloatOption ModifierMini; + public static readonly ModFloatOption ModifierMiniGrowingUpDuration; + public static readonly ModBoolOption ModifierMiniGrowingUpInMeeting; + + public static readonly ModFloatOption ModifierVip; + public static readonly ModFloatOption ModifierVipQuantity; + public static readonly ModBoolOption ModifierVipShowColor; + + public static readonly ModFloatOption ModifierInvert; + public static readonly ModFloatOption ModifierInvertQuantity; + public static readonly ModFloatOption ModifierInvertDuration; + + public static readonly ModFloatOption ModifierChameleon; + public static readonly ModFloatOption ModifierChameleonQuantity; + public static readonly ModFloatOption ModifierChameleonHoldDuration; + public static readonly ModFloatOption ModifierChameleonFadeDuration; + public static readonly ModFloatOption ModifierChameleonMinVisibility; + + public static readonly ModFloatOption ModifierShifter; + + // GUESSER MODE OPTIONS + + public static readonly ModFloatOption GuesserModeCrewNumber; + public static readonly ModFloatOption GuesserModeNeutralNumber; + public static readonly ModFloatOption GuesserModeImpNumber; + public static readonly ModBoolOption GuesserModeForceJackalGuesser; + public static readonly ModBoolOption GuesserModeForceThiefGuesser; + public static readonly ModBoolOption GuesserModeHaveModifier; + public static readonly ModFloatOption GuesserModeNumberOfShots; + public static readonly ModBoolOption GuesserModeMultipleShotsPerMeeting; + public static readonly ModBoolOption GuesserModeKillsThroughShield; + public static readonly ModBoolOption GuesserModeEvilCanKillSpy; + public static readonly ModBoolOption GuesserModeCantGuessSnitchIfTasksDone; +} \ No newline at end of file diff --git a/BetterOtherRoles/Patches/AirShipSetAntiTpPosition.cs b/BetterOtherRoles/Patches/AirShipSetAntiTpPosition.cs index 20f2acc..4066cb4 100644 --- a/BetterOtherRoles/Patches/AirShipSetAntiTpPosition.cs +++ b/BetterOtherRoles/Patches/AirShipSetAntiTpPosition.cs @@ -1,5 +1,5 @@ using HarmonyLib; -using System; +using BetterOtherRoles.Modifiers; namespace BetterOtherRoles.Patches { [HarmonyPatch] diff --git a/BetterOtherRoles/Patches/ConsoleJoystickPatches.cs b/BetterOtherRoles/Patches/ConsoleJoystickPatches.cs index 328a754..59507be 100644 --- a/BetterOtherRoles/Patches/ConsoleJoystickPatches.cs +++ b/BetterOtherRoles/Patches/ConsoleJoystickPatches.cs @@ -10,7 +10,6 @@ public static class ConsoleJoystickPatches [HarmonyPrefix] private static bool HandleHUDPrefix(ConsoleJoystick __instance) { - System.Console.WriteLine($"HandleHUDPrefix"); if (PlayerControl.LocalPlayer) { var canMove = PlayerControl.LocalPlayer.CanMove; diff --git a/BetterOtherRoles/Patches/ConsolePatches.cs b/BetterOtherRoles/Patches/ConsolePatches.cs new file mode 100644 index 0000000..d1ccc5a --- /dev/null +++ b/BetterOtherRoles/Patches/ConsolePatches.cs @@ -0,0 +1,14 @@ +using HarmonyLib; + +namespace BetterOtherRoles.Patches; + +[HarmonyPatch(typeof(Console))] +public static class ConsolePatches +{ + [HarmonyPatch(nameof(Console.Use))] + [HarmonyPostfix] + private static void UsePostfix(Console __instance) + { + System.Console.WriteLine($"Opened console: {__instance.name}"); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Patches/CreateOptionsPickerPatch.cs b/BetterOtherRoles/Patches/CreateOptionsPickerPatch.cs deleted file mode 100644 index 898e521..0000000 --- a/BetterOtherRoles/Patches/CreateOptionsPickerPatch.cs +++ /dev/null @@ -1,82 +0,0 @@ -using AmongUs.GameOptions; -using HarmonyLib; -using System; -using System.Collections.Generic; -using System.Text; -using UnityEngine; -using static UnityEngine.UI.Button; - -namespace BetterOtherRoles.Patches { - [HarmonyPatch(typeof(CreateOptionsPicker))] - class CreateOptionsPickerPatch { - private static List renderers = new List(); - - [HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.SetGameMode))] - public static bool Prefix(CreateOptionsPicker __instance, ref GameModes mode) { - if (mode <= GameModes.HideNSeek) { - TORMapOptions.gameMode = CustomGamemodes.Classic; - return true; - } - - __instance.SetGameMode(GameModes.Normal); //__instance.Refresh(); - - if ((int)mode == 3) { - __instance.GameModeText.text = "TOR Guesser"; - TORMapOptions.gameMode = CustomGamemodes.Guesser; - } else { - __instance.GameModeText.text = "TOR Hide N Seek"; - TORMapOptions.gameMode = CustomGamemodes.HideNSeek; - } - return false; - } - - - [HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.Refresh))] - public static void Postfix(CreateOptionsPicker __instance) { - if (TORMapOptions.gameMode == CustomGamemodes.Guesser) { - __instance.GameModeText.text = "TOR Guesser"; - } - else if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) { - __instance.GameModeText.text = "TOR Hide N Seek"; - } - } - } - - [HarmonyPatch(typeof(GameModeMenu))] - class GameModeMenuPatch { - [HarmonyPatch(typeof(GameModeMenu), nameof(GameModeMenu.OnEnable))] - public static bool Prefix(GameModeMenu __instance) { - uint gameMode = (uint)__instance.Parent.GetTargetOptions().GameMode; - float num = ((float)Mathf.CeilToInt(4f / 10f) / 2f - 0.5f) * -2.5f; // 4 for 4 buttons! - __instance.controllerSelectable.Clear(); - int num2 = 0; - __instance.ButtonPool.poolSize = 4; - for (int i=0; i <= 4; i++) { - GameModes entry = (GameModes)i; - if (entry != GameModes.None) { - ChatLanguageButton chatLanguageButton = __instance.ButtonPool.Get(); - chatLanguageButton.transform.localPosition = new Vector3(num + (float)(num2 / 10) * 2.5f, 2f - (float)(num2 % 10) * 0.5f, 0f); - if (i <= 2) - chatLanguageButton.Text.text = DestroyableSingleton.Instance.GetString(GameModesHelpers.ModeToName[entry], new Il2CppReferenceArray(0)); - else { - chatLanguageButton.Text.text = i == 3 ? "TOR Guesser" : "TOR Hide N Seek"; - } - chatLanguageButton.Button.OnClick.RemoveAllListeners(); - chatLanguageButton.Button.OnClick.AddListener((System.Action)delegate { - __instance.ChooseOption(entry); - }); - - bool isCurrentMode = i <= 2 && TORMapOptions.gameMode == CustomGamemodes.Classic ? (long)entry == (long)((ulong)gameMode) : (i == 3 && TORMapOptions.gameMode == CustomGamemodes.Guesser || i == 4 && TORMapOptions.gameMode == CustomGamemodes.HideNSeek); - chatLanguageButton.SetSelected(isCurrentMode); - __instance.controllerSelectable.Add(chatLanguageButton.Button); - if (isCurrentMode) { - __instance.defaultButtonSelected = chatLanguageButton.Button; - } - num2++; - } - } - ControllerManager.Instance.OpenOverlayMenu(__instance.name, __instance.BackButton, __instance.defaultButtonSelected, __instance.controllerSelectable, false); - return false; - } - } -} diff --git a/BetterOtherRoles/Patches/CredentialsPatch.cs b/BetterOtherRoles/Patches/CredentialsPatch.cs index 6fa4087..b6333ba 100644 --- a/BetterOtherRoles/Patches/CredentialsPatch.cs +++ b/BetterOtherRoles/Patches/CredentialsPatch.cs @@ -1,7 +1,6 @@ using HarmonyLib; using System; -using BetterOtherRoles; -using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; @@ -51,8 +50,7 @@ static void Postfix(PingTracker __instance) if (AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Started) { string gameModeText = $""; - if (HideNSeek.isHideNSeekGM) gameModeText = $"Hide 'N Seek"; - else if (HandleGuesser.isGuesserGm) gameModeText = $"Guesser"; + if (HandleGuesser.isGuesserGm) gameModeText = $"Guesser"; if (gameModeText != "") gameModeText = " - " + Helpers.cs(Color.yellow, gameModeText); var needEol = gameModeText != string.Empty || DevConfig.IsDingusRelease; __instance.text.text = @@ -76,8 +74,7 @@ static void Postfix(PingTracker __instance) else { string gameModeText = $""; - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) gameModeText = $"Hide 'N Seek"; - else if (TORMapOptions.gameMode == CustomGamemodes.Guesser) gameModeText = $"Guesser"; + if (TORMapOptions.gameMode == CustomGamemodes.Guesser) gameModeText = $"Guesser"; if (gameModeText != "") gameModeText = Helpers.cs(Color.yellow, gameModeText) + "\n"; __instance.text.text = diff --git a/BetterOtherRoles/Patches/EndGamePatch.cs b/BetterOtherRoles/Patches/EndGamePatch.cs index fbbef4c..96ac225 100644 --- a/BetterOtherRoles/Patches/EndGamePatch.cs +++ b/BetterOtherRoles/Patches/EndGamePatch.cs @@ -9,7 +9,9 @@ using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { enum CustomGameOverReason { @@ -227,10 +229,9 @@ public static void Postfix(AmongUsClient __instance, [HarmonyArgument(0)]ref End AdditionalTempData.additionalWinConditions.Add(WinCondition.AdditionalAlivePursuerWin); } - AdditionalTempData.timer = ((float)(DateTime.UtcNow - HideNSeek.startTime).TotalMilliseconds) / 1000; + AdditionalTempData.timer = 0f; // Reset Settings - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) ShipStatusPatch.resetVanillaSettings(); RPCProcedure.resetVariables(); EventUtility.gameEndsUpdate(); } @@ -334,18 +335,13 @@ public static void Postfix(EndGameManager __instance) { } } - if (TORMapOptions.showRoleSummary || HideNSeek.isHideNSeekGM) { + if (TORMapOptions.showRoleSummary) { var position = Camera.main.ViewportToWorldPoint(new Vector3(0f, 1f, Camera.main.nearClipPlane)); GameObject roleSummary = UnityEngine.Object.Instantiate(__instance.WinText.gameObject); roleSummary.transform.position = new Vector3(__instance.Navigation.ExitButton.transform.position.x + 0.1f, position.y - 0.1f, -214f); roleSummary.transform.localScale = new Vector3(1f, 1f, 1f); var roleSummaryText = new StringBuilder(); - if (HideNSeek.isHideNSeekGM) { - int minutes = (int)AdditionalTempData.timer / 60; - int seconds = (int)AdditionalTempData.timer % 60; - roleSummaryText.AppendLine($"Time: {minutes:00}:{seconds:00} \n"); - } roleSummaryText.AppendLine("Players and roles at the end of the game:"); foreach(var data in AdditionalTempData.playerRoles) { //var roles = string.Join(" ", data.Roles.Select(x => Helpers.cs(x.color, x.name))); @@ -456,7 +452,6 @@ private static bool CheckAndEndGameForSabotageWin(ShipStatus __instance) { } private static bool CheckAndEndGameForTaskWin(ShipStatus __instance) { - if (HideNSeek.isHideNSeekGM && !HideNSeek.taskWinPossible) return false; var totalTasks = 0; var completedTasks = 0; foreach (var player in PlayerControl.AllPlayerControls) @@ -505,8 +500,6 @@ private static bool CheckAndEndGameForJackalWin(ShipStatus __instance, PlayerSta } private static bool CheckAndEndGameForImpostorWin(ShipStatus __instance, PlayerStatistics statistics) { - if (HideNSeek.isHideNSeekGM) - if ((0 != statistics.TotalAlive - statistics.TeamImpostorsAlive)) return false; if (statistics.TeamImpostorsAlive >= statistics.TotalAlive - statistics.TeamImpostorsAlive && statistics.TeamJackalAlive == 0 && !(statistics.TeamImpostorHasAliveLover && statistics.TeamLoversAlive == 2)) { //__instance.enabled = false; @@ -529,11 +522,6 @@ private static bool CheckAndEndGameForImpostorWin(ShipStatus __instance, PlayerS } private static bool CheckAndEndGameForCrewmateWin(ShipStatus __instance, PlayerStatistics statistics) { - if (HideNSeek.isHideNSeekGM && HideNSeek.timer <= 0 && !HideNSeek.isWaitingTimer) { - //__instance.enabled = false; - GameManager.Instance.RpcEndGame(GameOverReason.HumansByVote, false); - return true; - } if (statistics.TeamImpostorsAlive == 0 && statistics.TeamJackalAlive == 0) { //__instance.enabled = false; GameManager.Instance.RpcEndGame(GameOverReason.HumansByVote, false); diff --git a/BetterOtherRoles/Patches/ExileControllerPatch.cs b/BetterOtherRoles/Patches/ExileControllerPatch.cs index 166ae90..b8a929d 100644 --- a/BetterOtherRoles/Patches/ExileControllerPatch.cs +++ b/BetterOtherRoles/Patches/ExileControllerPatch.cs @@ -5,7 +5,9 @@ using static BetterOtherRoles.BetterOtherRoles; using BetterOtherRoles.Objects; using System; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; using UnityEngine; diff --git a/BetterOtherRoles/Patches/GameStartManagerPatch.cs b/BetterOtherRoles/Patches/GameStartManagerPatch.cs index 727b2ff..8d83b20 100644 --- a/BetterOtherRoles/Patches/GameStartManagerPatch.cs +++ b/BetterOtherRoles/Patches/GameStartManagerPatch.cs @@ -1,43 +1,29 @@ - using HarmonyLib; using UnityEngine; -using System.Reflection; using System.Collections.Generic; using Hazel; -using System; using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; using System.Linq; -using BetterOtherRoles.Eno; +using AmongUsSpecimen; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; namespace BetterOtherRoles.Patches { public class GameStartManagerPatch { public static float timer = 600f; private static float kickingTimer = 0f; - private static bool versionSent = false; private static string lobbyCodeText = ""; - [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnPlayerJoined))] - public class AmongUsClientOnPlayerJoinedPatch { - public static void Postfix(AmongUsClient __instance) { - if (CachedPlayer.LocalPlayer != null) { - VersionHandshake.Instance.Share(); - } - } - } - [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Start))] public class GameStartManagerStartPatch { public static void Postfix(GameStartManager __instance) { // Trigger version refresh - versionSent = false; // Reset lobby countdown timer timer = 600f; // Reset kicking timer kickingTimer = 0f; // Copy lobby code - VersionHandshake.Clear(); string code = InnerNet.GameCode.IntToGameName(AmongUsClient.Instance.GameId); GUIUtility.systemCopyBuffer = code; lobbyCodeText = FastDestroyableSingleton.Instance.GetString(StringNames.RoomCode, new Il2CppReferenceArray(0)) + "\r\n" + code; @@ -77,12 +63,6 @@ public static void Prefix(GameStartManager __instance) { } public static void Postfix(GameStartManager __instance) { - // Send version as soon as CachedPlayer.LocalPlayer.PlayerControl exists - if (PlayerControl.LocalPlayer != null && !versionSent) { - versionSent = true; - VersionHandshake.Instance.Share(); - } - // Start Timer if (startingTimer > 0) { startingTimer -= Time.deltaTime; @@ -122,46 +102,29 @@ public static bool Prefix(GameStartManager __instance) { } if (AmongUsClient.Instance.AmHost) { - foreach (InnerNet.ClientData client in AmongUsClient.Instance.allClients.GetFastEnumerator()) { - if (client.Character == null) continue; - var dummyComponent = client.Character.GetComponent(); - if (dummyComponent != null && dummyComponent.enabled) - continue; - - if (!VersionHandshake.Has(client.Id)) { - continueStart = false; - break; - } - - var PV = VersionHandshake.Find(client.Id); - int diff = BetterOtherRolesPlugin.Version.CompareTo(PV.Version); - if (diff != 0 || !PV.GuidMatch()) { - continueStart = false; - break; - } - } - if (continueStart && TORMapOptions.gameMode == CustomGamemodes.HideNSeek) { - byte mapId = (byte) CustomOptionHolder.hideNSeekMap.getSelection(); - if (mapId >= 3) mapId++; - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.DynamicMapOption, Hazel.SendOption.Reliable, -1); - writer.Write(mapId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.dynamicMapOption(mapId); - } - else if (CustomOptionHolder.dynamicMap.getBool() && continueStart) { + if (CustomOptionHolder.RandomMap.GetBool() && continueStart) { // 0 = Skeld // 1 = Mira HQ // 2 = Polus - // 3 = Dleks - deactivated - // 4 = Airship - // 5 = Submerged + // 3 = Airship + // 4 = The Fungle byte chosenMapId = 0; - List probabilities = new List(); - probabilities.Add(CustomOptionHolder.dynamicMapEnableSkeld.getFloat() / 100f); - probabilities.Add(CustomOptionHolder.dynamicMapEnableMira.getFloat() / 100f); - probabilities.Add(CustomOptionHolder.dynamicMapEnablePolus.getFloat() / 100f); - probabilities.Add(CustomOptionHolder.dynamicMapEnableAirShip.getFloat() / 100f); - probabilities.Add(CustomOptionHolder.dynamicMapEnableSubmerged.getFloat() / 100f); + var maps = new List + { + CustomOptionHolder.TheSkeldMap, + CustomOptionHolder.PolusMap, + CustomOptionHolder.MiraHqMap, + CustomOptionHolder.AirshipMap, + CustomOptionHolder.TheFungleMap + }; + var probabilities = new List + { + CustomOptionHolder.TheSkeldMap.Percentage.GetFloat() / 100f, + CustomOptionHolder.PolusMap.Percentage.GetFloat() / 100f, + CustomOptionHolder.MiraHqMap.Percentage.GetFloat() / 100f, + CustomOptionHolder.AirshipMap.Percentage.GetFloat() / 100f, + CustomOptionHolder.TheFungleMap.Percentage.GetFloat() / 100f + }; // if any map is at 100%, remove all maps that are not! if (probabilities.Contains(1.0f)) { @@ -186,12 +149,14 @@ public static bool Prefix(GameStartManager __instance) { } // Translate chosen map to presets page and use that maps random map preset page - if (CustomOptionHolder.dynamicMapSeparateSettings.getBool()) { - CustomOptionHolder.presetSelection.updateSelection(chosenMapId + 2); + var chosenMap = maps.Count > chosenMapId ? maps[chosenMapId] : null; + if (chosenMap != null && chosenMap.ShouldUseSpecificPreset.GetBool()) + { + CoreOptions.PresetSelection.CurrentSelection = chosenMap.PresetName.CurrentSelection; } if (chosenMapId >= 3) chosenMapId++; // Skip dlekS - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.DynamicMapOption, Hazel.SendOption.Reliable, -1); + var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.DynamicMapOption, Hazel.SendOption.Reliable, -1); writer.Write(chosenMapId); AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.dynamicMapOption(chosenMapId); diff --git a/BetterOtherRoles/Patches/HauntMenuMinigamePatch.cs b/BetterOtherRoles/Patches/HauntMenuMinigamePatch.cs index f206048..ef35b38 100644 --- a/BetterOtherRoles/Patches/HauntMenuMinigamePatch.cs +++ b/BetterOtherRoles/Patches/HauntMenuMinigamePatch.cs @@ -4,6 +4,8 @@ using System.Linq; using BetterOtherRoles.Players; using System; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { [HarmonyPatch] @@ -72,7 +74,7 @@ public static void UpdatePostfix(HauntMenuMinigame __instance) { [HarmonyPatch(typeof(AbilityButton), nameof(AbilityButton.Update))] public static void showOrHideAbilityButtonPostfix(AbilityButton __instance) { bool isHideNSeek = GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek; - if (CachedPlayer.LocalPlayer.Data.IsDead && (CustomOptionHolder.finishTasksBeforeHauntingOrZoomingOut.getBool() || isHideNSeek)) { + if (CachedPlayer.LocalPlayer.Data.IsDead && (CustomOptionHolder.FinishTasksBeforeHauntingOrZoomingOut.GetBool() || isHideNSeek)) { // player has haunt button. var (playerCompleted, playerTotal) = TasksHandler.taskInfo(CachedPlayer.LocalPlayer.Data); int numberOfLeftTasks = playerTotal - playerCompleted; diff --git a/BetterOtherRoles/Patches/IntroPatch.cs b/BetterOtherRoles/Patches/IntroPatch.cs index 78e63f1..bdaab89 100644 --- a/BetterOtherRoles/Patches/IntroPatch.cs +++ b/BetterOtherRoles/Patches/IntroPatch.cs @@ -8,7 +8,10 @@ using BetterOtherRoles.Players; using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.OnDestroy))] @@ -45,19 +48,6 @@ public static void Prefix(IntroCutscene __instance) { player.transform.localScale = Vector3.one * 0.2f; player.setSemiTransparent(true); player.gameObject.SetActive(true); - } else if (HideNSeek.isHideNSeekGM) { - if (HideNSeek.isHunted() && p.Data.Role.IsImpostor) { - player.transform.localPosition = bottomLeft + new Vector3(-0.25f, 0.4f, 0) + Vector3.right * playerCounter++ * 0.6f; - player.transform.localScale = Vector3.one * 0.3f; - player.cosmetics.nameText.text += $"{Helpers.cs(Color.red, " (Hunter)")}"; - player.gameObject.SetActive(true); - } else if (!p.Data.Role.IsImpostor) { - player.transform.localPosition = bottomLeft + new Vector3(-0.35f, -0.25f, 0) + Vector3.right * hideNSeekCounter++ * 0.35f; - player.transform.localScale = Vector3.one * 0.2f; - player.setSemiTransparent(true); - player.gameObject.SetActive(true); - } - } else { // This can be done for all players not just for the bounty hunter as it was before. Allows the thief to have the correct position and scaling player.transform.localPosition = bottomLeft; player.transform.localScale = Vector3.one * 0.4f; @@ -82,7 +72,7 @@ public static void Prefix(IntroCutscene __instance) { SoundEffectsManager.Load(); // First kill - if (AmongUsClient.Instance.AmHost && FirstKillShield.Enabled && FirstKillShield.FirstKilledPlayerName != string.Empty && !HideNSeek.isHideNSeekGM) { + if (AmongUsClient.Instance.AmHost && FirstKillShield.Enabled && FirstKillShield.FirstKilledPlayerName != string.Empty) { PlayerControl target = PlayerControl.AllPlayerControls.ToArray().ToList().FirstOrDefault(x => x.Data.PlayerName.Equals(FirstKillShield.FirstKilledPlayerName)); if (target != null) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetFirstKill, Hazel.SendOption.Reliable, -1); @@ -94,51 +84,6 @@ public static void Prefix(IntroCutscene __instance) { FirstKillShield.FirstKilledPlayerName = string.Empty; EventUtility.gameStartsUpdate(); - - if (HideNSeek.isHideNSeekGM) { - foreach (PlayerControl player in HideNSeek.getHunters()) { - player.moveable = false; - player.NetTransform.Halt(); - HideNSeek.timer = HideNSeek.hunterWaitingTime; - FastDestroyableSingleton.Instance.StartCoroutine(Effects.Lerp(HideNSeek.hunterWaitingTime, new Action((p) => { - if (p == 1f) { - player.moveable = true; - HideNSeek.timer = CustomOptionHolder.hideNSeekTimer.getFloat() * 60; - HideNSeek.isWaitingTimer = false; - } - }))); - player.MyPhysics.SetBodyType(PlayerBodyTypes.Seeker); - } - - if (HideNSeek.polusVent == null && GameOptionsManager.Instance.currentNormalGameOptions.MapId == 2) { - var list = GameObject.FindObjectsOfType().ToList(); - var adminVent = list.FirstOrDefault(x => x.gameObject.name == "AdminVent"); - var bathroomVent = list.FirstOrDefault(x => x.gameObject.name == "BathroomVent"); - HideNSeek.polusVent = UnityEngine.Object.Instantiate(adminVent); - HideNSeek.polusVent.gameObject.AddSubmergedComponent(SubmergedCompatibility.Classes.ElevatorMover); - HideNSeek.polusVent.transform.position = new Vector3(36.55068f, -21.5168f, -0.0215168f); - HideNSeek.polusVent.Left = adminVent; - HideNSeek.polusVent.Right = bathroomVent; - HideNSeek.polusVent.Center = null; - HideNSeek.polusVent.Id = MapUtilities.CachedShipStatus.AllVents.Select(x => x.Id).Max() + 1; // Make sure we have a unique id - var allVentsList = MapUtilities.CachedShipStatus.AllVents.ToList(); - allVentsList.Add(HideNSeek.polusVent); - MapUtilities.CachedShipStatus.AllVents = allVentsList.ToArray(); - HideNSeek.polusVent.gameObject.SetActive(true); - HideNSeek.polusVent.name = "newVent_" + HideNSeek.polusVent.Id; - - adminVent.Center = HideNSeek.polusVent; - bathroomVent.Center = HideNSeek.polusVent; - } - - ShipStatusPatch.originalNumCrewVisionOption = GameOptionsManager.Instance.currentNormalGameOptions.CrewLightMod; - ShipStatusPatch.originalNumImpVisionOption = GameOptionsManager.Instance.currentNormalGameOptions.ImpostorLightMod; - ShipStatusPatch.originalNumKillCooldownOption = GameOptionsManager.Instance.currentNormalGameOptions.KillCooldown; - - GameOptionsManager.Instance.currentNormalGameOptions.ImpostorLightMod = CustomOptionHolder.hideNSeekHunterVision.getFloat(); - GameOptionsManager.Instance.currentNormalGameOptions.CrewLightMod = CustomOptionHolder.hideNSeekHuntedVision.getFloat(); - GameOptionsManager.Instance.currentNormalGameOptions.KillCooldown = CustomOptionHolder.hideNSeekKillCooldown.getFloat(); - } } } @@ -235,7 +180,7 @@ static public void SetRoleTexts(IntroCutscene __instance) { } } public static bool Prefix(IntroCutscene __instance) { - if (!CustomOptionHolder.activateRoles.getBool()) return true; + if (!CustomOptionHolder.ActivateRoles.GetBool()) return true; seed = Rnd.Next(5000); FastDestroyableSingleton.Instance.StartCoroutine(Effects.Lerp(1f, new Action((p) => { SetRoleTexts(__instance); diff --git a/BetterOtherRoles/Patches/MainMenuPatch.cs b/BetterOtherRoles/Patches/MainMenuPatch.cs index 0bdfd9a..3acb685 100644 --- a/BetterOtherRoles/Patches/MainMenuPatch.cs +++ b/BetterOtherRoles/Patches/MainMenuPatch.cs @@ -68,7 +68,6 @@ public static void addSceneChangeCallbacks() { // find "HostLocalGameButton" var template = GameObject.FindObjectOfType(); var gameButton = template.transform.FindChild("CreateGameButton"); - var gameButtonPassiveButton = gameButton.GetComponentInChildren(); var guesserButton = GameObject.Instantiate(gameButton, gameButton.parent); guesserButton.transform.localPosition += new Vector3(0f, -0.5f); @@ -81,20 +80,8 @@ public static void addSceneChangeCallbacks() { template.OnClick(); })); - var HideNSeekButton = GameObject.Instantiate(gameButton, gameButton.parent); - HideNSeekButton.transform.localPosition += new Vector3(1.7f, -0.5f); - var HideNSeekButtonText = HideNSeekButton.GetComponentInChildren(); - var HideNSeekButtonPassiveButton = HideNSeekButton.GetComponentInChildren(); - - HideNSeekButtonPassiveButton.OnClick = new Button.ButtonClickedEvent(); - HideNSeekButtonPassiveButton.OnClick.AddListener((System.Action)(() => { - TORMapOptions.gameMode = CustomGamemodes.HideNSeek; - template.OnClick(); - })); - template.StartCoroutine(Effects.Lerp(0.1f, new System.Action((p) => { guesserButtonText.SetText("TOR Guesser"); - HideNSeekButtonText.SetText("TOR Hide N Seek"); }))); })); } diff --git a/BetterOtherRoles/Patches/MapBehaviourPatch.cs b/BetterOtherRoles/Patches/MapBehaviourPatch.cs index 25467ba..41c7b93 100644 --- a/BetterOtherRoles/Patches/MapBehaviourPatch.cs +++ b/BetterOtherRoles/Patches/MapBehaviourPatch.cs @@ -5,6 +5,7 @@ using BetterOtherRoles.Modules; using BetterOtherRoles.Objects; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.UI; using BetterOtherRoles.Utilities; using UnityEngine; @@ -73,7 +74,6 @@ static void Postfix(MapBehaviour __instance) { } } } - UIManager.CustomOptionsPanel?.SetActive(false); } } } diff --git a/BetterOtherRoles/Patches/MedScanMinigameWalkToPadPatches.cs b/BetterOtherRoles/Patches/MedScanMinigameWalkToPadPatches.cs index f41897c..6147684 100644 --- a/BetterOtherRoles/Patches/MedScanMinigameWalkToPadPatches.cs +++ b/BetterOtherRoles/Patches/MedScanMinigameWalkToPadPatches.cs @@ -1,7 +1,9 @@ using System.Collections; using System.Linq; +using AmongUsSpecimen.ModOptions; using BepInEx.Unity.IL2CPP.Utils; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; using HarmonyLib; using UnityEngine; @@ -10,13 +12,13 @@ namespace BetterOtherRoles.Patches; [HarmonyPatch(typeof(MedScanMinigame._WalkToPad_d__16))] public static class MedScanMinigameWalkToPadPatches { - private static CustomOption RandomizeScanPlayerPosition => CustomOptionHolder.RandomizePositionDuringScan; + private static ModBoolOption RandomizeScanPlayerPosition => CustomOptionHolder.RandomizePositionDuringScan; [HarmonyPatch(nameof(MedScanMinigame._WalkToPad_d__16.MoveNext))] [HarmonyPrefix] private static bool MoveNextPrefix(MedScanMinigame._WalkToPad_d__16 __instance) { - if (!RandomizeScanPlayerPosition.getBool() || (ShipStatus.Instance && ShipStatus.Instance.Type != ShipStatus.MapType.Pb)) return true; + if (!RandomizeScanPlayerPosition.GetBool() || (ShipStatus.Instance && ShipStatus.Instance.Type != ShipStatus.MapType.Pb)) return true; var minigame = __instance.__4__this; minigame.StartCoroutine(WalkToPadEnumerator(minigame)); diff --git a/BetterOtherRoles/Patches/MeetingPatch.cs b/BetterOtherRoles/Patches/MeetingPatch.cs index 83e6d8b..dc00200 100644 --- a/BetterOtherRoles/Patches/MeetingPatch.cs +++ b/BetterOtherRoles/Patches/MeetingPatch.cs @@ -6,8 +6,11 @@ using static BetterOtherRoles.TORMapOptions; using BetterOtherRoles.Objects; using System; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; using BetterOtherRoles.Players; +using BetterOtherRoles.Roles; using BetterOtherRoles.UI; using BetterOtherRoles.Utilities; using UnityEngine; @@ -427,15 +430,15 @@ static void guesserOnClick(int buttonTarget, MeetingHud __instance) { if (roleData.neutralSettings.ContainsKey((byte)roleInfo.roleId) && roleData.neutralSettings[(byte)roleInfo.roleId] == 0) continue; else if (roleData.impSettings.ContainsKey((byte)roleInfo.roleId) && roleData.impSettings[(byte)roleInfo.roleId] == 0) continue; else if (roleData.crewSettings.ContainsKey((byte)roleInfo.roleId) && roleData.crewSettings[(byte)roleInfo.roleId] == 0) continue; - else if (new List() { RoleId.Janitor, RoleId.Godfather, RoleId.Mafioso }.Contains(roleInfo.roleId) && CustomOptionHolder.mafiaSpawnRate.getSelection() == 0) continue; - else if (roleInfo.roleId == RoleId.Sidekick && (!CustomOptionHolder.jackalCanCreateSidekick.getBool() || CustomOptionHolder.jackalSpawnRate.getSelection() == 0)) continue; - if (roleInfo.roleId == RoleId.Deputy && (CustomOptionHolder.deputySpawnRate.getSelection() == 0 || CustomOptionHolder.sheriffSpawnRate.getSelection() == 0)) continue; - if (roleInfo.roleId == RoleId.Pursuer && CustomOptionHolder.lawyerSpawnRate.getSelection() == 0) continue; + else if (new List() { RoleId.Janitor, RoleId.Godfather, RoleId.Mafioso }.Contains(roleInfo.roleId) && CustomOptionHolder.MafiaSpawnRate.CurrentSelection == 0) continue; + else if (roleInfo.roleId == RoleId.Sidekick && (!CustomOptionHolder.JackalCanCreateSidekick.GetBool() || CustomOptionHolder.JackalSpawnRate.CurrentSelection == 0)) continue; + if (roleInfo.roleId == RoleId.Deputy && (CustomOptionHolder.DeputySpawnRate.CurrentSelection == 0 || CustomOptionHolder.SheriffSpawnRate.CurrentSelection == 0)) continue; + if (roleInfo.roleId == RoleId.Pursuer && CustomOptionHolder.LawyerSpawnRate.CurrentSelection == 0) continue; if (roleInfo.roleId == RoleId.Spy && roleData.impostors.Count <= 1) continue; - if (roleInfo.roleId == RoleId.Prosecutor && (CustomOptionHolder.lawyerIsProsecutorChance.getSelection() == 0 || CustomOptionHolder.lawyerSpawnRate.getSelection() == 0)) continue; - if (roleInfo.roleId == RoleId.Lawyer && (CustomOptionHolder.lawyerIsProsecutorChance.getSelection() == 10 || CustomOptionHolder.lawyerSpawnRate.getSelection() == 0)) continue; + if (roleInfo.roleId == RoleId.Prosecutor && (CustomOptionHolder.LawyerIsProsecutorChance.CurrentSelection == 0 || CustomOptionHolder.LawyerSpawnRate.CurrentSelection == 0)) continue; + if (roleInfo.roleId == RoleId.Lawyer && (CustomOptionHolder.LawyerIsProsecutorChance.CurrentSelection == 10 || CustomOptionHolder.LawyerSpawnRate.CurrentSelection == 0)) continue; if (roleInfo.roleId == RoleId.Fallen) continue; - if (roleInfo.roleId == RoleId.Sheriff && CustomOptionHolder.sheriffSpawnRate.getSelection() == 0) continue; + if (roleInfo.roleId == RoleId.Sheriff && CustomOptionHolder.SheriffSpawnRate.CurrentSelection == 0) continue; if (Snitch.snitch != null && HandleGuesser.guesserCantGuessSnitch) { var (playerCompleted, playerTotal) = TasksHandler.taskInfo(Snitch.snitch.Data); int numberOfLeftTasks = playerTotal - playerCompleted; @@ -781,7 +784,6 @@ public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)]GameData SoundEffectsManager.stopAll(); // Close In-Game Settings Display if open - UIManager.CustomOptionsPanel?.SetActive(false); } } diff --git a/BetterOtherRoles/Patches/NormalPlayerTaskPatches.cs b/BetterOtherRoles/Patches/NormalPlayerTaskPatches.cs index 720bd1c..807ad9f 100644 --- a/BetterOtherRoles/Patches/NormalPlayerTaskPatches.cs +++ b/BetterOtherRoles/Patches/NormalPlayerTaskPatches.cs @@ -69,19 +69,19 @@ private static SystemTypes GetUpdatedRoom(NormalPlayerTask task) private static SystemTypes GetChartCourse(NormalPlayerTask task) { - if (!BetterPolus.Enabled.getBool()) return task.StartAt; + if (!BetterPolus.Enabled.GetBool()) return task.StartAt; return SystemTypes.Comms; } private static SystemTypes GetRebootWifi(NormalPlayerTask task) { - if (!BetterPolus.Enabled.getBool()) return task.StartAt; + if (!BetterPolus.Enabled.GetBool()) return task.StartAt; return SystemTypes.Dropship; } private static SystemTypes GetRecordTemperature(NormalPlayerTask task) { - if (!BetterPolus.Enabled.getBool()) return task.StartAt; + if (!BetterPolus.Enabled.GetBool()) return task.StartAt; return SystemTypes.Outside; } diff --git a/BetterOtherRoles/Patches/PlayerControlPatch.cs b/BetterOtherRoles/Patches/PlayerControlPatch.cs index b13c9d1..b75b831 100644 --- a/BetterOtherRoles/Patches/PlayerControlPatch.cs +++ b/BetterOtherRoles/Patches/PlayerControlPatch.cs @@ -12,7 +12,10 @@ using BetterOtherRoles.CustomGameModes; using static UnityEngine.GraphicsBuffer; using AmongUs.GameOptions; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; using BetterOtherRoles.UI; using InnerNet; using Sentry.Internal.Extensions; @@ -1047,68 +1050,6 @@ public static void trapperUpdate() { } } - static void hunterUpdate() { - if (!HideNSeek.isHideNSeekGM) return; - int minutes = (int)HideNSeek.timer / 60; - int seconds = (int)HideNSeek.timer % 60; - string suffix = $" {minutes:00}:{seconds:00}"; - - if (HideNSeek.timerText == null) { - RoomTracker roomTracker = FastDestroyableSingleton.Instance?.roomTracker; - if (roomTracker != null) { - GameObject gameObject = UnityEngine.Object.Instantiate(roomTracker.gameObject); - - gameObject.transform.SetParent(FastDestroyableSingleton.Instance.transform); - UnityEngine.Object.DestroyImmediate(gameObject.GetComponent()); - HideNSeek.timerText = gameObject.GetComponent(); - - // Use local position to place it in the player's view instead of the world location - gameObject.transform.localPosition = new Vector3(0, -1.8f, gameObject.transform.localPosition.z); - if (AmongUs.Data.DataManager.Settings.Gameplay.StreamerMode) gameObject.transform.localPosition = new Vector3(0, 2f, gameObject.transform.localPosition.z); - } - } else { - if (HideNSeek.isWaitingTimer) { - HideNSeek.timerText.text = "" + suffix + ""; - HideNSeek.timerText.color = Color.blue; - } else { - HideNSeek.timerText.text = "" + suffix + ""; - HideNSeek.timerText.color = Color.red; - } - } - if (HideNSeek.isHunted() && !Hunted.taskPunish && !HideNSeek.isWaitingTimer) { - var (playerCompleted, playerTotal) = TasksHandler.taskInfo(CachedPlayer.LocalPlayer.Data); - int numberOfTasks = playerTotal - playerCompleted; - if (numberOfTasks == 0) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareTimer, Hazel.SendOption.Reliable, -1); - writer.Write(HideNSeek.taskPunish); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.shareTimer(HideNSeek.taskPunish); - - Hunted.taskPunish = true; - } - } - - if (!HideNSeek.isHunter()) return; - - byte playerId = CachedPlayer.LocalPlayer.PlayerId; - foreach (Arrow arrow in Hunter.localArrows) arrow.arrow.SetActive(false); - if (Hunter.arrowActive) { - int arrowIndex = 0; - foreach (PlayerControl p in CachedPlayer.AllPlayers) { - if (!p.Data.IsDead && !p.Data.Role.IsImpostor) { - if (arrowIndex >= Hunter.localArrows.Count) { - Hunter.localArrows.Add(new Arrow(Color.blue)); - } - if (arrowIndex < Hunter.localArrows.Count && Hunter.localArrows[arrowIndex] != null) { - Hunter.localArrows[arrowIndex].arrow.SetActive(true); - Hunter.localArrows[arrowIndex].Update(p.transform.position, Color.blue); - } - arrowIndex++; - } - } - } - } - public static void Postfix(PlayerControl __instance) { if (AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return; @@ -1224,7 +1165,6 @@ public static void Postfix(PlayerControl __instance) { Bomb.update(); // -- GAME MODE -- - hunterUpdate(); } } } @@ -1245,7 +1185,6 @@ public static void Prefix(PlayerPhysics __instance) { [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))] class PlayerControlCmdReportDeadBodyPatch { public static bool Prefix(PlayerControl __instance) { - if (HideNSeek.isHideNSeekGM) return false; Helpers.handleVampireBiteOnBodyReport(); Helpers.HandleUndertakerDropOnBodyReport(); Helpers.HandleStickyBomberExplodeOnBodyReport(); @@ -1441,22 +1380,6 @@ public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)]PlayerC Helpers.showFlash(color, 1.5f); } - // HideNSeek - if (HideNSeek.isHideNSeekGM) { - int visibleCounter = 0; - Vector3 bottomLeft = IntroCutsceneOnDestroyPatch.bottomLeft + new Vector3(-0.25f, -0.25f, 0); - foreach (PlayerControl p in CachedPlayer.AllPlayers) { - if (!TORMapOptions.playerIcons.ContainsKey(p.PlayerId) || p.Data.Role.IsImpostor) continue; - if (p.Data.IsDead || p.Data.Disconnected) { - TORMapOptions.playerIcons[p.PlayerId].gameObject.SetActive(false); - } - else { - TORMapOptions.playerIcons[p.PlayerId].transform.localPosition = bottomLeft + Vector3.right * visibleCounter * 0.35f; - visibleCounter++; - } - } - } - // Snitch if (Snitch.snitch != null && CachedPlayer.LocalPlayer.PlayerId == Snitch.snitch.PlayerId && MapBehaviourPatch.herePoints.Keys.Any(x => x.PlayerId == target.PlayerId)) { foreach (var a in MapBehaviourPatch.herePoints.Where(x => x.Key.PlayerId == target.PlayerId)) { @@ -1582,7 +1505,7 @@ public static void Postfix(PlayerPhysics __instance) private static void UpdateUndertakerPhysics(PlayerPhysics playerPhysics) { if (Undertaker.Player != CachedPlayer.LocalPlayer.PlayerControl || Undertaker.DraggedBody == null) return; - playerPhysics.body.velocity *= 1f + CustomOptionHolder.UndertakerSpeedModifier.getFloat() / 100f; + playerPhysics.body.velocity *= 1f + CustomOptionHolder.UndertakerSpeedModifier.GetFloat() / 100f; } private static void UpdateInvert(PlayerPhysics playerPhysics) diff --git a/BetterOtherRoles/Patches/ReactorSystemTypePatches.cs b/BetterOtherRoles/Patches/ReactorSystemTypePatches.cs index c1c03b6..c6acafc 100644 --- a/BetterOtherRoles/Patches/ReactorSystemTypePatches.cs +++ b/BetterOtherRoles/Patches/ReactorSystemTypePatches.cs @@ -18,7 +18,7 @@ private static bool UpdateSystemPrefix(ReactorSystemType __instance, PlayerContr { __instance.Countdown = ShipStatus.Instance.Type != ShipStatus.MapType.Pb ? __instance.ReactorDuration - : BetterPolus.ReactorCountdown.getFloat(); + : BetterPolus.ReactorCountdown.GetFloat(); __instance.UserConsolePairs.Clear(); } else if (self == 16) diff --git a/BetterOtherRoles/Patches/RoleAssignmentPatch.cs b/BetterOtherRoles/Patches/RoleAssignmentPatch.cs index a12a68f..398bae9 100644 --- a/BetterOtherRoles/Patches/RoleAssignmentPatch.cs +++ b/BetterOtherRoles/Patches/RoleAssignmentPatch.cs @@ -9,22 +9,22 @@ using BetterOtherRoles.Utilities; using static BetterOtherRoles.BetterOtherRoles; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { [HarmonyPatch(typeof(RoleOptionsCollectionV07), nameof(RoleOptionsCollectionV07.GetNumPerGame))] class RoleOptionsDataGetNumPerGamePatch{ public static void Postfix(ref int __result) { - if (CustomOptionHolder.activateRoles.getBool() && GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) __result = 0; // Deactivate Vanilla Roles if the mod roles are active + if (CustomOptionHolder.ActivateRoles.GetBool() && GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) __result = 0; // Deactivate Vanilla Roles if the mod roles are active } } [HarmonyPatch(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.GetAdjustedNumImpostors))] class GameOptionsDataGetAdjustedNumImpostorsPatch { public static void Postfix(ref int __result) { - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) { - int impCount = Mathf.RoundToInt(CustomOptionHolder.hideNSeekHunterCount.getFloat()); - __result = impCount; ; // Set Imp Num - } else if (GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) { // Ignore Vanilla impostor limits in TOR Games. + if (GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) { // Ignore Vanilla impostor limits in TOR Games. __result = Mathf.Clamp(GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, 1, 3); } } @@ -33,7 +33,7 @@ public static void Postfix(ref int __result) { [HarmonyPatch(typeof(GameOptionsData), nameof(GameOptionsData.Validate))] class GameOptionsDataValidatePatch { public static void Postfix(GameOptionsData __instance) { - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek || GameOptionsManager.Instance.CurrentGameOptions.GameMode != GameModes.Normal) return; + if (GameOptionsManager.Instance.CurrentGameOptions.GameMode != GameModes.Normal) return; __instance.NumImpostors = GameOptionsManager.Instance.CurrentGameOptions.NumImpostors; } } @@ -49,8 +49,8 @@ public static void Postfix() { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ResetVaribles, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.resetVariables(); - if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return; // Don't assign Roles in Hide N Seek - if (CustomOptionHolder.activateRoles.getBool()) // Don't assign Roles in Tutorial or if deactivated + if (GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return; // Don't assign Roles in Hide N Seek + if (CustomOptionHolder.ActivateRoles.GetBool()) // Don't assign Roles in Tutorial or if deactivated assignRoles(); } @@ -74,12 +74,12 @@ public static RoleAssignmentData getRoleAssignmentData() { List impostors = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList(); impostors.RemoveAll(x => !x.Data.Role.IsImpostor); - var crewmateMin = CustomOptionHolder.crewmateRolesCountMin.getSelection(); - var crewmateMax = CustomOptionHolder.crewmateRolesCountMax.getSelection(); - var neutralMin = CustomOptionHolder.neutralRolesCountMin.getSelection(); - var neutralMax = CustomOptionHolder.neutralRolesCountMax.getSelection(); - var impostorMin = CustomOptionHolder.impostorRolesCountMin.getSelection(); - var impostorMax = CustomOptionHolder.impostorRolesCountMax.getSelection(); + var crewmateMin = CustomOptionHolder.MinCrewmateRoles.CurrentSelection; + var crewmateMax = CustomOptionHolder.MaxCrewmateRoles.CurrentSelection; + var neutralMin = CustomOptionHolder.MinNeutralRoles.CurrentSelection; + var neutralMax = CustomOptionHolder.MaxNeutralRoles.CurrentSelection; + var impostorMin = CustomOptionHolder.MinImpostorRoles.CurrentSelection; + var impostorMax = CustomOptionHolder.MaxImpostorRoles.CurrentSelection; // Make sure min is less or equal to max if (crewmateMin > crewmateMax) crewmateMin = crewmateMax; @@ -87,7 +87,7 @@ public static RoleAssignmentData getRoleAssignmentData() { if (impostorMin > impostorMax) impostorMin = impostorMax; // Automatically force everyone to get a role by setting crew Min / Max according to Neutral Settings - if (CustomOptionHolder.crewmateRolesFill.getBool()) { + if (CustomOptionHolder.FillCrewmateRoles.GetBool()) { crewmateMax = crewmates.Count - neutralMin; crewmateMin = crewmates.Count - neutralMax; } @@ -107,50 +107,50 @@ public static RoleAssignmentData getRoleAssignmentData() { Dictionary neutralSettings = new Dictionary(); Dictionary crewSettings = new Dictionary(); - impSettings.Add((byte)RoleId.Morphling, CustomOptionHolder.morphlingSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Camouflager, CustomOptionHolder.camouflagerSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Vampire, CustomOptionHolder.vampireSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Eraser, CustomOptionHolder.eraserSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Trickster, CustomOptionHolder.tricksterSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Cleaner, CustomOptionHolder.cleanerSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Warlock, CustomOptionHolder.warlockSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.BountyHunter, CustomOptionHolder.bountyHunterSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Witch, CustomOptionHolder.witchSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Ninja, CustomOptionHolder.ninjaSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Bomber, CustomOptionHolder.bomberSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.Undertaker, CustomOptionHolder.UndertakerSpawnRate.getSelection()); - impSettings.Add((byte)RoleId.StickyBomber, CustomOptionHolder.StickyBomberSpawnRate.getSelection()); - - neutralSettings.Add((byte)RoleId.Jester, CustomOptionHolder.jesterSpawnRate.getSelection()); - neutralSettings.Add((byte)RoleId.Arsonist, CustomOptionHolder.arsonistSpawnRate.getSelection()); - neutralSettings.Add((byte)RoleId.Jackal, CustomOptionHolder.jackalSpawnRate.getSelection()); - neutralSettings.Add((byte)RoleId.Vulture, CustomOptionHolder.vultureSpawnRate.getSelection()); - neutralSettings.Add((byte)RoleId.Thief, CustomOptionHolder.thiefSpawnRate.getSelection()); - - if ((Rnd.Next(1, 101) <= CustomOptionHolder.lawyerIsProsecutorChance.getSelection() * 10)) // Lawyer or Prosecutor - neutralSettings.Add((byte)RoleId.Prosecutor, CustomOptionHolder.lawyerSpawnRate.getSelection()); + impSettings.Add((byte)RoleId.Morphling, CustomOptionHolder.MorphlingSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Camouflager, CustomOptionHolder.CamouflagerSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Vampire, CustomOptionHolder.VampireSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Eraser, CustomOptionHolder.EraserSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Trickster, CustomOptionHolder.TricksterSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Cleaner, CustomOptionHolder.CleanerSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Warlock, CustomOptionHolder.WarlockSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.BountyHunter, CustomOptionHolder.BountyHunterSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Witch, CustomOptionHolder.WitchSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Ninja, CustomOptionHolder.NinjaSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Bomber, CustomOptionHolder.BomberSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.Undertaker, CustomOptionHolder.UndertakerSpawnRate.CurrentSelection); + impSettings.Add((byte)RoleId.StickyBomber, CustomOptionHolder.StickyBomberSpawnRate.CurrentSelection); + + neutralSettings.Add((byte)RoleId.Jester, CustomOptionHolder.JesterSpawnRate.CurrentSelection); + neutralSettings.Add((byte)RoleId.Arsonist, CustomOptionHolder.ArsonistSpawnRate.CurrentSelection); + neutralSettings.Add((byte)RoleId.Jackal, CustomOptionHolder.JackalSpawnRate.CurrentSelection); + neutralSettings.Add((byte)RoleId.Vulture, CustomOptionHolder.VultureSpawnRate.CurrentSelection); + neutralSettings.Add((byte)RoleId.Thief, CustomOptionHolder.ThiefSpawnRate.CurrentSelection); + + if ((Rnd.Next(1, 101) <= CustomOptionHolder.LawyerIsProsecutorChance.CurrentSelection * 10)) // Lawyer or Prosecutor + neutralSettings.Add((byte)RoleId.Prosecutor, CustomOptionHolder.LawyerSpawnRate.CurrentSelection); else - neutralSettings.Add((byte)RoleId.Lawyer, CustomOptionHolder.lawyerSpawnRate.getSelection()); - - crewSettings.Add((byte)RoleId.Mayor, CustomOptionHolder.mayorSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Portalmaker, CustomOptionHolder.portalmakerSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Engineer, CustomOptionHolder.engineerSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Lighter, CustomOptionHolder.lighterSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Detective, CustomOptionHolder.detectiveSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.TimeMaster, CustomOptionHolder.timeMasterSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Medic, CustomOptionHolder.medicSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Swapper,CustomOptionHolder.swapperSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Seer, CustomOptionHolder.seerSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Hacker, CustomOptionHolder.hackerSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Tracker, CustomOptionHolder.trackerSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Snitch, CustomOptionHolder.snitchSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Medium, CustomOptionHolder.mediumSpawnRate.getSelection()); - crewSettings.Add((byte)RoleId.Trapper, CustomOptionHolder.trapperSpawnRate.getSelection()); + neutralSettings.Add((byte)RoleId.Lawyer, CustomOptionHolder.LawyerSpawnRate.CurrentSelection); + + crewSettings.Add((byte)RoleId.Mayor, CustomOptionHolder.MayorSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Portalmaker, CustomOptionHolder.PortalmakerSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Engineer, CustomOptionHolder.EngineerSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Lighter, CustomOptionHolder.LighterSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Detective, CustomOptionHolder.DetectiveSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.TimeMaster, CustomOptionHolder.TimeMasterSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Medic, CustomOptionHolder.MedicSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Swapper,CustomOptionHolder.SwapperSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Seer, CustomOptionHolder.SeerSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Hacker, CustomOptionHolder.HackerSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Tracker, CustomOptionHolder.TrackerSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Snitch, CustomOptionHolder.SnitchSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Medium, CustomOptionHolder.MediumSpawnRate.CurrentSelection); + crewSettings.Add((byte)RoleId.Trapper, CustomOptionHolder.TrapperSpawnRate.CurrentSelection); if (impostors.Count > 1) { // Only add Spy if more than 1 impostor as the spy role is otherwise useless - crewSettings.Add((byte)RoleId.Spy, CustomOptionHolder.spySpawnRate.getSelection()); + crewSettings.Add((byte)RoleId.Spy, CustomOptionHolder.SpySpawnRate.CurrentSelection); } - crewSettings.Add((byte)RoleId.SecurityGuard, CustomOptionHolder.securityGuardSpawnRate.getSelection()); + crewSettings.Add((byte)RoleId.SecurityGuard, CustomOptionHolder.SecurityGuardSpawnRate.CurrentSelection); return new RoleAssignmentData { crewmates = crewmates, @@ -166,7 +166,7 @@ public static RoleAssignmentData getRoleAssignmentData() { private static void assignSpecialRoles(RoleAssignmentData data) { // Assign Mafia - if (data.impostors.Count >= 3 && data.maxImpostorRoles >= 3 && (Rnd.Next(1, 101) <= CustomOptionHolder.mafiaSpawnRate.getSelection() * 10)) { + if (data.impostors.Count >= 3 && data.maxImpostorRoles >= 3 && (Rnd.Next(1, 101) <= CustomOptionHolder.MafiaSpawnRate.CurrentSelection * 10)) { setRoleToRandomPlayer((byte)RoleId.Godfather, data.impostors); setRoleToRandomPlayer((byte)RoleId.Janitor, data.impostors); setRoleToRandomPlayer((byte)RoleId.Mafioso, data.impostors); @@ -177,21 +177,21 @@ private static void assignSpecialRoles(RoleAssignmentData data) { private static void selectFactionForFactionIndependentRoles(RoleAssignmentData data) { if (!isGuesserGamemode) { // Assign Guesser (chance to be impostor based on setting) - isEvilGuesser = Rnd.Next(1, 101) <= CustomOptionHolder.guesserIsImpGuesserRate.getSelection() * 10; - if ((CustomOptionHolder.guesserSpawnBothRate.getSelection() > 0 && - CustomOptionHolder.guesserSpawnRate.getSelection() == 10) || - CustomOptionHolder.guesserSpawnBothRate.getSelection() == 0) { - if (isEvilGuesser) data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnRate.getSelection()); - else data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnRate.getSelection()); + isEvilGuesser = Rnd.Next(1, 101) <= CustomOptionHolder.GuesserIsImpGuesserRate.CurrentSelection * 10; + if ((CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection > 0 && + CustomOptionHolder.GuesserSpawnRate.CurrentSelection == 10) || + CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection == 0) { + if (isEvilGuesser) data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.GuesserSpawnRate.CurrentSelection); + else data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.GuesserSpawnRate.CurrentSelection); } } // Assign Sheriff - if ((CustomOptionHolder.deputySpawnRate.getSelection() > 0 && - CustomOptionHolder.sheriffSpawnRate.getSelection() == 10) || - CustomOptionHolder.deputySpawnRate.getSelection() == 0) - data.crewSettings.Add((byte)RoleId.Sheriff, CustomOptionHolder.sheriffSpawnRate.getSelection()); + if ((CustomOptionHolder.DeputySpawnRate.CurrentSelection > 0 && + CustomOptionHolder.SheriffSpawnRate.CurrentSelection == 10) || + CustomOptionHolder.DeputySpawnRate.CurrentSelection == 0) + data.crewSettings.Add((byte)RoleId.Sheriff, CustomOptionHolder.SheriffSpawnRate.CurrentSelection); crewValues = data.crewSettings.Values.ToList().Sum(); @@ -227,8 +227,8 @@ private static void assignEnsuredRoles(RoleAssignmentData data) { setRoleToRandomPlayer(rolesToAssign[roleType][index], players); rolesToAssign[roleType].RemoveAt(index); - if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) { - foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) { + if (CustomOptionHolder.BlockedRolePairings.TryGetValue(roleId, out var pairing)) { + foreach(var blockedRoleId in pairing) { // Set chance for the blocked roles to 0 for chances less than 100% if (data.impSettings.ContainsKey(blockedRoleId)) data.impSettings[blockedRoleId] = 0; if (data.neutralSettings.ContainsKey(blockedRoleId)) data.neutralSettings[blockedRoleId] = 0; @@ -251,10 +251,10 @@ private static void assignEnsuredRoles(RoleAssignmentData data) { private static void assignDependentRoles(RoleAssignmentData data) { // Roles that prob have a dependent role - bool guesserFlag = CustomOptionHolder.guesserSpawnBothRate.getSelection() > 0 - && CustomOptionHolder.guesserSpawnRate.getSelection() > 0; - bool sheriffFlag = CustomOptionHolder.deputySpawnRate.getSelection() > 0 - && CustomOptionHolder.sheriffSpawnRate.getSelection() > 0; + bool guesserFlag = CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection > 0 + && CustomOptionHolder.GuesserSpawnRate.CurrentSelection > 0; + bool sheriffFlag = CustomOptionHolder.DeputySpawnRate.CurrentSelection > 0 + && CustomOptionHolder.SheriffSpawnRate.CurrentSelection > 0; if (isGuesserGamemode) guesserFlag = false; if (!guesserFlag && !sheriffFlag) return; // assignDependentRoles is not needed @@ -270,13 +270,13 @@ private static void assignDependentRoles(RoleAssignmentData data) { // --- Simulate Crew & Imp ticket system --- while (crew > 0 && (!isSheriff || (!isEvilGuesser && !isGuesser))) { - if (!isSheriff && Rnd.Next(crewValues) < CustomOptionHolder.sheriffSpawnRate.getSelection()) isSheriff = true; - if (!isEvilGuesser && !isGuesser && Rnd.Next(crewValues) < CustomOptionHolder.guesserSpawnRate.getSelection()) isGuesser = true; + if (!isSheriff && Rnd.Next(crewValues) < CustomOptionHolder.SheriffSpawnRate.CurrentSelection) isSheriff = true; + if (!isEvilGuesser && !isGuesser && Rnd.Next(crewValues) < CustomOptionHolder.GuesserSpawnRate.CurrentSelection) isGuesser = true; crew--; crewValues -= crewSteps; } while (imp > 0 && (isEvilGuesser && !isGuesser)) { - if (Rnd.Next(impValues) < CustomOptionHolder.guesserSpawnRate.getSelection()) isGuesser = true; + if (Rnd.Next(impValues) < CustomOptionHolder.GuesserSpawnRate.CurrentSelection) isGuesser = true; imp--; impValues -= impSteps; } @@ -302,34 +302,34 @@ private static void assignDependentRoles(RoleAssignmentData data) { // --- Assign Dependent Roles if main role exists --- if (Sheriff.sheriff != null) { // Deputy - if (CustomOptionHolder.deputySpawnRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force Deputy + if (CustomOptionHolder.DeputySpawnRate.CurrentSelection == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force Deputy byte deputy = setRoleToRandomPlayer((byte)RoleId.Deputy, data.crewmates); data.crewmates.ToList().RemoveAll(x => x.PlayerId == deputy); data.maxCrewmateRoles--; - } else if (CustomOptionHolder.deputySpawnRate.getSelection() < 10) // Dont force, add Deputy to the ticket system - data.crewSettings.Add((byte)RoleId.Deputy, CustomOptionHolder.deputySpawnRate.getSelection()); + } else if (CustomOptionHolder.DeputySpawnRate.CurrentSelection < 10) // Dont force, add Deputy to the ticket system + data.crewSettings.Add((byte)RoleId.Deputy, CustomOptionHolder.DeputySpawnRate.CurrentSelection); } if (!data.crewSettings.ContainsKey((byte)RoleId.Sheriff)) data.crewSettings.Add((byte)RoleId.Sheriff, 0); if (!isGuesserGamemode) { if (!isEvilGuesser && Guesser.niceGuesser != null) { // Other Guesser (evil) - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Force other guesser (evil) + if (CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection == 10 && data.impostors.Count > 0 && data.maxImpostorRoles > 0) { // Force other guesser (evil) byte bothGuesser = setRoleToRandomPlayer((byte)RoleId.EvilGuesser, data.impostors); data.impostors.ToList().RemoveAll(x => x.PlayerId == bothGuesser); data.maxImpostorRoles--; } - else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) // Dont force, add Guesser (evil) to the ticket system - data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); + else if (CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection < 10) // Dont force, add Guesser (evil) to the ticket system + data.impSettings.Add((byte)RoleId.EvilGuesser, CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection); } else if (isEvilGuesser && Guesser.evilGuesser != null) { // ELSE other Guesser (nice) - if (CustomOptionHolder.guesserSpawnBothRate.getSelection() == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force other guesser (nice) + if (CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection == 10 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) { // Force other guesser (nice) byte bothGuesser = setRoleToRandomPlayer((byte)RoleId.NiceGuesser, data.crewmates); data.crewmates.ToList().RemoveAll(x => x.PlayerId == bothGuesser); data.maxCrewmateRoles--; } - else if (CustomOptionHolder.guesserSpawnBothRate.getSelection() < 10) // Dont force, add Guesser (nice) to the ticket system - data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.guesserSpawnBothRate.getSelection()); + else if (CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection < 10) // Dont force, add Guesser (nice) to the ticket system + data.crewSettings.Add((byte)RoleId.NiceGuesser, CustomOptionHolder.GuesserSpawnBothRate.CurrentSelection); } } } @@ -362,8 +362,8 @@ private static void assignChanceRoles(RoleAssignmentData data) { setRoleToRandomPlayer(roleId, players); rolesToAssign[roleType].RemoveAll(x => x == roleId); - if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) { - foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) { + if (CustomOptionHolder.BlockedRolePairings.TryGetValue(roleId, out var pairing)) { + foreach(var blockedRoleId in pairing) { // Remove tickets of blocked roles from all pools crewmateTickets.RemoveAll(x => x == blockedRoleId); neutralTickets.RemoveAll(x => x == blockedRoleId); @@ -411,12 +411,12 @@ private static void assignRoleTargets(RoleAssignmentData data) { } private static void assignModifiers() { - var modifierMin = CustomOptionHolder.modifiersCountMin.getSelection(); - var modifierMax = CustomOptionHolder.modifiersCountMax.getSelection(); + var modifierMin = CustomOptionHolder.MinModifiers.CurrentSelection; + var modifierMax = CustomOptionHolder.MaxModifiers.CurrentSelection; if (modifierMin > modifierMax) modifierMin = modifierMax; int modifierCountSettings = Rnd.Next(modifierMin, modifierMax + 1); List players = PlayerControl.AllPlayerControls.ToArray().ToList(); - if (isGuesserGamemode && !CustomOptionHolder.guesserGamemodeHaveModifier.getBool()) + if (isGuesserGamemode && !CustomOptionHolder.GuesserModeHaveModifier.GetBool()) players.RemoveAll(x => GuesserGM.isGuesser(x.PlayerId)); int modifierCount = Mathf.Min(players.Count, modifierCountSettings); @@ -438,8 +438,8 @@ private static void assignModifiers() { RoleId.Shifter }); - if (Rnd.Next(1, 101) <= CustomOptionHolder.modifierLover.getSelection() * 10) { // Assign lover - bool isEvilLover = Rnd.Next(1, 101) <= CustomOptionHolder.modifierLoverImpLoverRate.getSelection() * 10; + if (Rnd.Next(1, 101) <= CustomOptionHolder.ModifierLover.CurrentSelection * 10) { // Assign lover + bool isEvilLover = Rnd.Next(1, 101) <= CustomOptionHolder.ModifierLoverImpLoverRate.CurrentSelection * 10; byte firstLoverId; List impPlayer = new List(players); List crewPlayer = new List(players); @@ -488,9 +488,9 @@ private static void assignGuesserGamemode() { impPlayer.RemoveAll(x => !x.Data.Role.IsImpostor); neutralPlayer.RemoveAll(x => !Helpers.isNeutral(x)); crewPlayer.RemoveAll(x => x.Data.Role.IsImpostor || Helpers.isNeutral(x)); - assignGuesserGamemodeToPlayers(crewPlayer, Mathf.RoundToInt(CustomOptionHolder.guesserGamemodeCrewNumber.getFloat())); - assignGuesserGamemodeToPlayers(neutralPlayer, Mathf.RoundToInt(CustomOptionHolder.guesserGamemodeNeutralNumber.getFloat()), CustomOptionHolder.guesserForceJackalGuesser.getBool(), CustomOptionHolder.guesserForceThiefGuesser.getBool()); - assignGuesserGamemodeToPlayers(impPlayer, Mathf.RoundToInt(CustomOptionHolder.guesserGamemodeImpNumber.getFloat())); + assignGuesserGamemodeToPlayers(crewPlayer, Mathf.RoundToInt(CustomOptionHolder.GuesserModeCrewNumber.GetFloat())); + assignGuesserGamemodeToPlayers(neutralPlayer, Mathf.RoundToInt(CustomOptionHolder.GuesserModeNeutralNumber.GetFloat()), CustomOptionHolder.GuesserModeForceJackalGuesser.GetBool(), CustomOptionHolder.GuesserModeForceThiefGuesser.GetBool()); + assignGuesserGamemodeToPlayers(impPlayer, Mathf.RoundToInt(CustomOptionHolder.GuesserModeImpNumber.GetFloat())); } private static void assignGuesserGamemodeToPlayers(List playerList, int count, bool forceJackal = false, bool forceThief = false) { @@ -588,41 +588,41 @@ private static int getSelectionForRoleId(RoleId roleId, bool multiplyQuantity = int selection = 0; switch (roleId) { case RoleId.Lover: - selection = CustomOptionHolder.modifierLover.getSelection(); break; + selection = CustomOptionHolder.ModifierLover.CurrentSelection; break; case RoleId.Tiebreaker: - selection = CustomOptionHolder.modifierTieBreaker.getSelection(); break; + selection = CustomOptionHolder.ModifierTieBreaker.CurrentSelection; break; case RoleId.Mini: - selection = CustomOptionHolder.modifierMini.getSelection(); break; + selection = CustomOptionHolder.ModifierMini.CurrentSelection; break; case RoleId.Bait: - selection = CustomOptionHolder.modifierBait.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierBaitQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierBait.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierBaitQuantity.GetInt(); break; case RoleId.Bloody: - selection = CustomOptionHolder.modifierBloody.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierBloodyQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierBloody.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierBloodyQuantity.GetInt(); break; case RoleId.AntiTeleport: - selection = CustomOptionHolder.modifierAntiTeleport.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierAntiTeleportQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierAntiTeleport.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierAntiTeleportQuantity.GetInt(); break; case RoleId.Sunglasses: - selection = CustomOptionHolder.modifierSunglasses.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierSunglassesQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierSunglasses.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierSunglassesQuantity.GetInt(); break; case RoleId.Vip: - selection = CustomOptionHolder.modifierVip.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierVipQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierVip.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierVipQuantity.GetInt(); break; case RoleId.Invert: - selection = CustomOptionHolder.modifierInvert.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierInvertQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierInvert.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierInvertQuantity.GetInt(); break; case RoleId.Chameleon: - selection = CustomOptionHolder.modifierChameleon.getSelection(); - if (multiplyQuantity) selection *= CustomOptionHolder.modifierChameleonQuantity.getQuantity(); + selection = CustomOptionHolder.ModifierChameleon.CurrentSelection; + if (multiplyQuantity) selection *= CustomOptionHolder.ModifierChameleonQuantity.GetInt(); break; case RoleId.Shifter: - selection = CustomOptionHolder.modifierShifter.getSelection(); break; + selection = CustomOptionHolder.ModifierShifter.CurrentSelection; break; } return selection; diff --git a/BetterOtherRoles/Patches/ServerManagerPatches.cs b/BetterOtherRoles/Patches/ServerManagerPatches.cs deleted file mode 100644 index a657cbd..0000000 --- a/BetterOtherRoles/Patches/ServerManagerPatches.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text.Json; -using System.Threading.Tasks; -using BepInEx; -using BepInEx.Unity.IL2CPP.Utils; -using BetterOtherRoles.Modules; -using BetterOtherRoles.Utilities.Extensions; -using HarmonyLib; -using Innersloth.IO; -using Newtonsoft.Json; -using UnityEngine; - -namespace BetterOtherRoles.Patches; - -[HarmonyPatch(typeof(ServerManager))] -public static class ServerManagerPatches -{ - private static readonly string RegionFileJson = Path.Combine(Paths.PluginPath, "BetterOtherRoles", "Regions.json"); - - [HarmonyPatch(nameof(ServerManager.LoadServers))] - [HarmonyPrefix] - private static bool LoadServersPrefix(ServerManager __instance) - { - if (FileIO.Exists(RegionFileJson)) - { - try - { - var jsonServerData = JsonConvert.DeserializeObject( - FileIO.ReadAllText(RegionFileJson), new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.Auto - }); - jsonServerData.CleanAndMerge(CustomRegions.DefaultRegions); - __instance.AvailableRegions = jsonServerData.Regions; - __instance.CurrentRegion = - __instance.AvailableRegions[ - jsonServerData.CurrentRegionIdx.Wrap(__instance.AvailableRegions.Length)]; - __instance.CurrentUdpServer = __instance.CurrentRegion.Servers.ToList().GetOneRandom(); - __instance.state = UpdateState.Success; - __instance.SaveServers(); - } - catch (Exception ex) - { - BetterOtherRolesPlugin.Logger.LogWarning(ex); - __instance.StartCoroutine(ReselectRegionFromDefaults()); - } - } - else - { - __instance.StartCoroutine(ReselectRegionFromDefaults()); - } - - return false; - } - - [HarmonyPatch(nameof(ServerManager.SaveServers))] - [HarmonyPrefix] - private static bool SaveServersPrefix(ServerManager __instance) - { - try - { - FileIO.WriteAllText(RegionFileJson, JsonConvert.SerializeObject(new ServerManager.JsonServerData - { - CurrentRegionIdx = __instance.AvailableRegions.ToList() - .FindIndex(r => r.Name == __instance.CurrentRegion.Name), - Regions = __instance.AvailableRegions - }, new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.Auto - })); - } - catch - { - } - - return false; - } - - private static IEnumerator ReselectRegionFromDefaults() - { - if (!ServerManager.InstanceExists) yield break; - var sm = ServerManager.Instance; - sm.AvailableRegions = CustomRegions.DefaultRegions; - var dnsLookup = CustomRegions.DefaultRegions.Select(r => Dns.GetHostAddressesAsync(r.PingServer)).ToList(); - while (dnsLookup.Any(task => !task.IsCompleted)) - { - yield return null; - } - - var pings = new List(); - for (var index = 0; index < CustomRegions.DefaultRegions.Length; index++) - { - var defaultRegion = CustomRegions.DefaultRegions[index]; - IPAddress[] result; - try - { - result = dnsLookup[index].ConfigureAwait(false).GetAwaiter().GetResult(); - } - catch (Exception ex) - { - BetterOtherRolesPlugin.Logger.LogWarning(ex); - continue; - } - - if (result == null || result.Length == 0) - { - BetterOtherRolesPlugin.Logger.LogWarning("DNS - no IPs resolved for " + defaultRegion.PingServer); - } - else - { - pings.Add(new ServerManager.PingWrapper(defaultRegion, new Ping(result.ToList().GetOneRandom().ToString()))); - } - } - - for (var timeElapsedSeconds = 0f; pings.Count > 0 && timeElapsedSeconds < 5f && !pings.Any(p => p.Ping.isDone && p.Ping.time >= 0); timeElapsedSeconds += Time.deltaTime) - { - yield return null; - } - - var regionInfo = CustomRegions.DefaultRegions.First(); - var num = int.MaxValue; - foreach (var pingWrapper in pings) - { - if (pingWrapper.Ping.isDone && pingWrapper.Ping.time >= 0) - { - if (pingWrapper.Ping.time < num) - { - regionInfo = pingWrapper.Region; - num = pingWrapper.Ping.time; - } - } - pingWrapper.Ping.DestroyPing(); - } - - sm.CurrentRegion = regionInfo.Duplicate(); - sm.ReselectServer(); - sm.SaveServers(); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/Patches/ShipStatusPatch.cs b/BetterOtherRoles/Patches/ShipStatusPatch.cs index 9c109be..9c3434e 100644 --- a/BetterOtherRoles/Patches/ShipStatusPatch.cs +++ b/BetterOtherRoles/Patches/ShipStatusPatch.cs @@ -6,6 +6,8 @@ using UnityEngine; using BetterOtherRoles.CustomGameModes; using AmongUs.GameOptions; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { @@ -18,13 +20,11 @@ public static bool Prefix(ref float __result, ShipStatus __instance, [HarmonyArg if (!__instance.Systems.ContainsKey(SystemTypes.Electrical) || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return true; - if (!HideNSeek.isHideNSeekGM || (HideNSeek.isHideNSeekGM && !Hunter.lightActive.Contains(player.PlayerId))) { - // If player is a role which has Impostor vision - if (Helpers.hasImpVision(player)) { - //__result = __instance.MaxLightRadius * GameOptionsManager.Instance.currentNormalGameOptions.ImpostorLightMod; - __result = GetNeutralLightRadius(__instance, true); - return false; - } + // If player is a role which has Impostor vision + if (Helpers.hasImpVision(player)) { + //__result = __instance.MaxLightRadius * GameOptionsManager.Instance.currentNormalGameOptions.ImpostorLightMod; + __result = GetNeutralLightRadius(__instance, true); + return false; } // If player is Lighter with ability active @@ -33,12 +33,6 @@ public static bool Prefix(ref float __result, ShipStatus __instance, [HarmonyArg __result = Mathf.Lerp(__instance.MaxLightRadius * Lighter.lighterModeLightsOffVision, __instance.MaxLightRadius * Lighter.lighterModeLightsOnVision, unlerped); } - // If Game mode is Hide N Seek and hunter with ability active - else if (HideNSeek.isHideNSeekGM && Hunter.isLightActive(player.PlayerId)) { - float unlerped = Mathf.InverseLerp(__instance.MinLightRadius, __instance.MaxLightRadius, GetNeutralLightRadius(__instance, false)); - __result = Mathf.Lerp(__instance.MaxLightRadius * Hunter.lightVision, __instance.MaxLightRadius * Hunter.lightVision, unlerped); - } - // If there is a Trickster with their ability active else if (Trickster.trickster != null && Trickster.lightsOutTimer > 0f) { float lerpValue = 1f; @@ -103,19 +97,13 @@ public static bool Prefix(ShipStatus __instance) originalNumShortTasksOption = GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks; originalNumLongTasksOption = GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks; - if (TORMapOptions.gameMode != CustomGamemodes.HideNSeek) { - var commonTaskCount = __instance.CommonTasks.Count; - var normalTaskCount = __instance.ShortTasks.Count; - var longTaskCount = __instance.LongTasks.Count; - - if (GameOptionsManager.Instance.currentNormalGameOptions.NumCommonTasks > commonTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumCommonTasks = commonTaskCount; - if (GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks > normalTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks = normalTaskCount; - if (GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks > longTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks = longTaskCount; - } else { - GameOptionsManager.Instance.currentNormalGameOptions.NumCommonTasks = Mathf.RoundToInt(CustomOptionHolder.hideNSeekCommonTasks.getFloat()); - GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks = Mathf.RoundToInt(CustomOptionHolder.hideNSeekShortTasks.getFloat()); - GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks = Mathf.RoundToInt(CustomOptionHolder.hideNSeekLongTasks.getFloat()); - } + var commonTaskCount = __instance.CommonTasks.Count; + var normalTaskCount = __instance.ShortTasks.Count; + var longTaskCount = __instance.LongTasks.Count; + + if (GameOptionsManager.Instance.currentNormalGameOptions.NumCommonTasks > commonTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumCommonTasks = commonTaskCount; + if (GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks > normalTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumShortTasks = normalTaskCount; + if (GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks > longTaskCount) GameOptionsManager.Instance.currentNormalGameOptions.NumLongTasks = longTaskCount; return true; } diff --git a/BetterOtherRoles/Patches/UpdatePatch.cs b/BetterOtherRoles/Patches/UpdatePatch.cs index 904ff04..0ebb29c 100644 --- a/BetterOtherRoles/Patches/UpdatePatch.cs +++ b/BetterOtherRoles/Patches/UpdatePatch.cs @@ -9,7 +9,9 @@ using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; using AmongUs.GameOptions; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] @@ -248,7 +250,6 @@ static void timerUpdate() { Trickster.lightsOutTimer -= dt; Tracker.corpsesTrackingTimer -= dt; Ninja.invisibleTimer -= dt; - HideNSeek.timer -= dt; foreach (byte key in Deputy.handcuffedKnows.Keys) Deputy.handcuffedKnows[key] -= dt; } @@ -326,7 +327,7 @@ static void updateUseButton(HudManager __instance) { } static void updateSabotageButton(HudManager __instance) { - if (MeetingHud.Instance || TORMapOptions.gameMode == CustomGamemodes.HideNSeek) __instance.SabotageButton.Hide(); + if (MeetingHud.Instance) __instance.SabotageButton.Hide(); } static void updateMapButton(HudManager __instance) { diff --git a/BetterOtherRoles/Patches/UploadDataGamePatches.cs b/BetterOtherRoles/Patches/UploadDataGamePatches.cs index e764664..ee5d220 100644 --- a/BetterOtherRoles/Patches/UploadDataGamePatches.cs +++ b/BetterOtherRoles/Patches/UploadDataGamePatches.cs @@ -1,4 +1,5 @@ using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; using HarmonyLib; namespace BetterOtherRoles.Patches; @@ -10,7 +11,7 @@ public static class UploadDataGamePatches [HarmonyPostfix] private static void BeginPostfix(UploadDataGame __instance, PlayerTask task) { - if (!CustomOptionHolder.RandomizeUploadTaskPosition.getBool()) return; + if (!CustomOptionHolder.RandomizeUploadTaskPosition.GetBool()) return; if (__instance.MyNormTask.taskStep == 0 && TaskPositionsRandomizer.RelocatedDownloads.TryGetValue(__instance.MyNormTask.StartAt, out var room)) { __instance.SourceText.text = DestroyableSingleton.Instance.GetString(room); diff --git a/BetterOtherRoles/Patches/UsablesPatch.cs b/BetterOtherRoles/Patches/UsablesPatch.cs index 73d9ef3..f78a7e0 100644 --- a/BetterOtherRoles/Patches/UsablesPatch.cs +++ b/BetterOtherRoles/Patches/UsablesPatch.cs @@ -12,6 +12,9 @@ using BetterOtherRoles.Objects; using BetterOtherRoles.CustomGameModes; using AmongUs.GameOptions; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles.Patches { @@ -106,7 +109,7 @@ public static bool Prefix(Vent __instance) { if (Trapper.playersOnMap.Contains(CachedPlayer.LocalPlayer.PlayerControl)) return false; if (Undertaker.Player == CachedPlayer.LocalPlayer.PlayerControl && - CustomOptionHolder.UndertakerDisableVent.getBool() && Undertaker.DraggedBody != null) + CustomOptionHolder.UndertakerDisableVent.GetBool() && Undertaker.DraggedBody != null) { return false; } @@ -630,8 +633,8 @@ private static void nightVisionUpdate(SurveillanceMinigame SkeldCamsMinigame = n isLightsOut = CachedPlayer.LocalPlayer.PlayerControl.myTasks.ToArray().Any(x => x.name.Contains("FixLightsTask")); - bool ignoreNightVision = CustomOptionHolder.camsNoNightVisionIfImpVision.getBool() && Helpers.hasImpVision(GameData.Instance.GetPlayerById(CachedPlayer.LocalPlayer.PlayerId)) || CachedPlayer.LocalPlayer.Data.IsDead; - bool nightVisionEnabled = CustomOptionHolder.camsNightVision.getBool(); + bool ignoreNightVision = CustomOptionHolder.CamsNoNightVisionIfImpVision.GetBool() && Helpers.hasImpVision(GameData.Instance.GetPlayerById(CachedPlayer.LocalPlayer.PlayerId)) || CachedPlayer.LocalPlayer.Data.IsDead; + bool nightVisionEnabled = CustomOptionHolder.CamsNightVision.GetBool(); if (isLightsOut && !nightVisionIsActive && nightVisionEnabled && !ignoreNightVision) { // only update when something changed! foreach (PlayerControl pc in CachedPlayer.AllPlayers) { @@ -716,8 +719,6 @@ static void Prefix(MedScanMinigame __instance) { [HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.ShowSabotageMap))] class ShowSabotageMapPatch { static bool Prefix(MapBehaviour __instance) { - if (HideNSeek.isHideNSeekGM) - return HideNSeek.canSabotage; return true; } } diff --git a/BetterOtherRoles/RPC.cs b/BetterOtherRoles/RPC.cs index f249da3..71b8aec 100644 --- a/BetterOtherRoles/RPC.cs +++ b/BetterOtherRoles/RPC.cs @@ -15,8 +15,10 @@ using BetterOtherRoles.CustomGameModes; using AmongUs.Data; using AmongUs.GameOptions; -using BetterOtherRoles.Eno; +using BetterOtherRoles.Modifiers; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; using UnityEngine.UIElements; namespace BetterOtherRoles @@ -191,19 +193,6 @@ public static void resetVariables() { EventUtility.clearAndReload(); } - public static void HandleShareOptions(byte numberOfOptions, MessageReader reader) { - try { - for (int i = 0; i < numberOfOptions; i++) { - uint optionId = reader.ReadPackedUInt32(); - uint selection = reader.ReadPackedUInt32(); - CustomOption option = CustomOption.options.First(option => option.id == (int)optionId); - option.updateSelection((int)selection); - } - } catch (Exception e) { - BetterOtherRolesPlugin.Logger.LogError("Error while deserializing options: " + e.Message); - } - } - public static void forceEnd() { if (AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started) return; foreach (PlayerControl player in CachedPlayer.AllPlayers) @@ -235,7 +224,7 @@ public static void workaroundSetRoles(byte numberOfRoles, MessageReader reader) } catch (Exception e) { BetterOtherRolesPlugin.Logger.LogError("Error while deserializing roles: " + e.Message); } - } + } } @@ -1079,7 +1068,7 @@ public static void thiefStealsRole(byte playerId) { if (Thief.thief == PlayerControl.LocalPlayer) CustomButton.ResetAllCooldowns(); Thief.clearAndReload(); Thief.formerThief = thief; // After clearAndReload, else it would get reset... - if (!CustomOptionHolder.StolenPlayerKeepsHisTeam.getBool()) + if (!CustomOptionHolder.ThiefStolenPlayerKeepsHisTeam.GetBool()) { Fallen.ClearAndReload(); Fallen.Player = target; @@ -1107,41 +1096,6 @@ public static void setGuesserGm (byte playerId) { new GuesserGM(target); } - public static void shareTimer(float punish) { - HideNSeek.timer -= punish; - } - - public static void huntedShield(byte playerId) { - if (!Hunted.timeshieldActive.Contains(playerId)) Hunted.timeshieldActive.Add(playerId); - FastDestroyableSingleton.Instance.StartCoroutine(Effects.Lerp(Hunted.shieldDuration, new Action((p) => { - if (p == 1f) Hunted.timeshieldActive.Remove(playerId); - }))); - } - - public static void huntedRewindTime(byte playerId) { - Hunted.timeshieldActive.Remove(playerId); // Shield is no longer active when rewinding - SoundEffectsManager.stop("timemasterShield"); // Shield sound stopped when rewinding - if (playerId == CachedPlayer.LocalPlayer.PlayerControl.PlayerId) { - resetHuntedRewindButton(); - } - FastDestroyableSingleton.Instance.FullScreen.color = new Color(0f, 0.5f, 0.8f, 0.3f); - FastDestroyableSingleton.Instance.FullScreen.enabled = true; - FastDestroyableSingleton.Instance.FullScreen.gameObject.SetActive(true); - FastDestroyableSingleton.Instance.StartCoroutine(Effects.Lerp(Hunted.shieldRewindTime, new Action((p) => { - if (p == 1f) FastDestroyableSingleton.Instance.FullScreen.enabled = false; - }))); - - if (!CachedPlayer.LocalPlayer.Data.Role.IsImpostor) return; // only rewind hunter - - TimeMaster.isRewinding = true; - - if (MapBehaviour.Instance) - MapBehaviour.Instance.Close(); - if (Minigame.Instance) - Minigame.Instance.ForceClose(); - CachedPlayer.LocalPlayer.PlayerControl.moveable = false; - } - public enum GhostInfoTypes { HandcuffNoticed, HandcuffOver, @@ -1238,9 +1192,6 @@ static void Postfix([HarmonyArgument(0)]byte callId, [HarmonyArgument(1)]Message case (byte)CustomRPC.ResetVaribles: RPCProcedure.resetVariables(); break; - case (byte)CustomRPC.ShareOptions: - RPCProcedure.HandleShareOptions(reader.ReadByte(), reader); - break; case (byte)CustomRPC.ForceEnd: RPCProcedure.forceEnd(); break; @@ -1258,9 +1209,6 @@ static void Postfix([HarmonyArgument(0)]byte callId, [HarmonyArgument(1)]Message byte flag = reader.ReadByte(); RPCProcedure.setModifier(modifierId, pId, flag); break; - case (byte)CustomRPC.VersionHandshake: - VersionHandshake.HandleRpcHandshake(reader); - break; case (byte)CustomRPC.UseUncheckedVent: int ventId = reader.ReadPackedInt32(); byte ventingPlayer = reader.ReadByte(); @@ -1460,18 +1408,6 @@ static void Postfix([HarmonyArgument(0)]byte callId, [HarmonyArgument(1)]Message byte guesserGm = reader.ReadByte(); RPCProcedure.setGuesserGm(guesserGm); break; - case (byte)CustomRPC.ShareTimer: - float punish = reader.ReadSingle(); - RPCProcedure.shareTimer(punish); - break; - case (byte)CustomRPC.HuntedShield: - byte huntedPlayer = reader.ReadByte(); - RPCProcedure.huntedShield(huntedPlayer); - break; - case (byte)CustomRPC.HuntedRewindTime: - byte rewindPlayer = reader.ReadByte(); - RPCProcedure.huntedRewindTime(rewindPlayer); - break; case (byte)CustomRPC.ShareGhostInfo: RPCProcedure.receiveGhostInfo(reader.ReadByte(), reader); break; diff --git a/BetterOtherRoles/Resources/SettingsTab.png b/BetterOtherRoles/Resources/SettingsTab.png index 3d9df20..a84ff3d 100644 Binary files a/BetterOtherRoles/Resources/SettingsTab.png and b/BetterOtherRoles/Resources/SettingsTab.png differ diff --git a/BetterOtherRoles/Resources/TabIconCrewmate.png b/BetterOtherRoles/Resources/TabIconCrewmate.png index c3198ce..944b9c9 100644 Binary files a/BetterOtherRoles/Resources/TabIconCrewmate.png and b/BetterOtherRoles/Resources/TabIconCrewmate.png differ diff --git a/BetterOtherRoles/Resources/TabIconGuesserSettings.png b/BetterOtherRoles/Resources/TabIconGuesserSettings.png index 459491e..722c0a0 100644 Binary files a/BetterOtherRoles/Resources/TabIconGuesserSettings.png and b/BetterOtherRoles/Resources/TabIconGuesserSettings.png differ diff --git a/BetterOtherRoles/Resources/TabIconImpostor.png b/BetterOtherRoles/Resources/TabIconImpostor.png index 266ec8e..eba8c4e 100644 Binary files a/BetterOtherRoles/Resources/TabIconImpostor.png and b/BetterOtherRoles/Resources/TabIconImpostor.png differ diff --git a/BetterOtherRoles/Resources/TabIconModifier.png b/BetterOtherRoles/Resources/TabIconModifier.png index cc46802..9b42f98 100644 Binary files a/BetterOtherRoles/Resources/TabIconModifier.png and b/BetterOtherRoles/Resources/TabIconModifier.png differ diff --git a/BetterOtherRoles/Resources/TabIconNeutral.png b/BetterOtherRoles/Resources/TabIconNeutral.png index 31b0306..3b22b51 100644 Binary files a/BetterOtherRoles/Resources/TabIconNeutral.png and b/BetterOtherRoles/Resources/TabIconNeutral.png differ diff --git a/BetterOtherRoles/RoleInfo.cs b/BetterOtherRoles/RoleInfo.cs index 0784cf9..2f56e71 100644 --- a/BetterOtherRoles/RoleInfo.cs +++ b/BetterOtherRoles/RoleInfo.cs @@ -6,6 +6,9 @@ using UnityEngine; using BetterOtherRoles.Utilities; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; namespace BetterOtherRoles { @@ -166,7 +169,7 @@ public static List getRoleInfoForPlayer(PlayerControl p, bool showModi // Modifier if (showModifier) { // after dead modifier - if (!CustomOptionHolder.modifiersAreHidden.getBool() || PlayerControl.LocalPlayer.Data.IsDead || AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Ended) + if (!CustomOptionHolder.ModifiersAreHidden.GetBool() || PlayerControl.LocalPlayer.Data.IsDead || AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Ended) { if (Bait.bait.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bait); if (Bloody.bloody.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bloody); @@ -235,9 +238,9 @@ public static List getRoleInfoForPlayer(PlayerControl p, bool showModi // Default roles (just impostor, just crewmate, or hunter / hunted for hide n seek if (infos.Count == count) { if (p.Data.Role.IsImpostor) - infos.Add(TORMapOptions.gameMode == CustomGamemodes.HideNSeek ? RoleInfo.hunter : RoleInfo.impostor); + infos.Add(impostor); else - infos.Add(TORMapOptions.gameMode == CustomGamemodes.HideNSeek ? RoleInfo.hunted : RoleInfo.crewmate); + infos.Add(crewmate); } return infos; diff --git a/BetterOtherRoles/Roles/Arsonist.cs b/BetterOtherRoles/Roles/Arsonist.cs new file mode 100644 index 0000000..4dead9e --- /dev/null +++ b/BetterOtherRoles/Roles/Arsonist.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.Linq; +using BetterOtherRoles.Options; +using BetterOtherRoles.Players; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Arsonist +{ + public static PlayerControl arsonist; + public static Color color = new Color32(238, 112, 46, byte.MaxValue); + + public static float cooldown = 30f; + public static float duration = 3f; + public static bool triggerArsonistWin = false; + + public static PlayerControl currentTarget; + public static PlayerControl douseTarget; + public static List dousedPlayers = new List(); + + private static Sprite douseSprite; + + public static Sprite getDouseSprite() + { + if (douseSprite) return douseSprite; + douseSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DouseButton.png", 115f); + return douseSprite; + } + + private static Sprite igniteSprite; + + public static Sprite getIgniteSprite() + { + if (igniteSprite) return igniteSprite; + igniteSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.IgniteButton.png", 115f); + return igniteSprite; + } + + public static bool dousedEveryoneAlive() + { + return CachedPlayer.AllPlayers.All(x => + { + return x.PlayerControl == Arsonist.arsonist || x.Data.IsDead || x.Data.Disconnected || + Arsonist.dousedPlayers.Any(y => y.PlayerId == x.PlayerId); + }); + } + + public static void clearAndReload() + { + arsonist = null; + currentTarget = null; + douseTarget = null; + triggerArsonistWin = false; + dousedPlayers = new List(); + foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) + { + if (p != null && p.gameObject != null) p.gameObject.SetActive(false); + } + + cooldown = CustomOptionHolder.ArsonistCooldown.GetFloat(); + duration = CustomOptionHolder.ArsonistDuration.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Bomber.cs b/BetterOtherRoles/Roles/Bomber.cs new file mode 100644 index 0000000..6e77710 --- /dev/null +++ b/BetterOtherRoles/Roles/Bomber.cs @@ -0,0 +1,71 @@ +using System; +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Bomber +{ + public static PlayerControl bomber = null; + public static Color color = Palette.ImpostorRed; + + public static Bomb bomb = null; + public static bool isPlanted = false; + public static bool isActive = false; + public static float destructionTime = 20f; + public static float destructionRange = 2f; + public static float hearRange = 30f; + public static float defuseDuration = 3f; + public static float bombCooldown = 15f; + public static float bombActiveAfter = 3f; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Bomb_Button_Plant.png", 115f); + return buttonSprite; + } + + public static void clearBomb(bool flag = true) + { + if (bomb != null) + { + UnityEngine.Object.Destroy(bomb.bomb); + UnityEngine.Object.Destroy(bomb.background); + bomb = null; + } + + isPlanted = false; + isActive = false; + if (flag) + { + try + { + SoundEffectsManager.stop("bombFuseBurning"); + } + catch (Exception e) + { + BetterOtherRolesPlugin.Logger.LogWarning("Unable to stop bomb sound"); + } + } + } + + public static void clearAndReload() + { + clearBomb(false); + bomber = null; + bomb = null; + isPlanted = false; + isActive = false; + destructionTime = CustomOptionHolder.BomberBombDestructionTime.GetFloat(); + destructionRange = CustomOptionHolder.BomberBombDestructionRange.GetFloat() / 10; + hearRange = CustomOptionHolder.BomberBombHearRange.GetFloat() / 10; + defuseDuration = CustomOptionHolder.BomberDefuseDuration.GetFloat(); + bombCooldown = CustomOptionHolder.BomberBombCooldown.GetFloat(); + bombActiveAfter = CustomOptionHolder.BomberBombActiveAfter.GetFloat(); + Bomb.clearBackgroundSprite(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/BountyHunter.cs b/BetterOtherRoles/Roles/BountyHunter.cs new file mode 100644 index 0000000..376edba --- /dev/null +++ b/BetterOtherRoles/Roles/BountyHunter.cs @@ -0,0 +1,48 @@ +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class BountyHunter +{ + public static PlayerControl bountyHunter; + public static Color color = Palette.ImpostorRed; + + public static Arrow arrow; + public static float bountyDuration = 30f; + public static bool showArrow = true; + public static float bountyKillCooldown = 0f; + public static float punishmentTime = 15f; + public static float arrowUpdateIntervall = 10f; + + public static float arrowUpdateTimer = 0f; + public static float bountyUpdateTimer = 0f; + public static PlayerControl bounty; + public static TMPro.TextMeshPro cooldownText; + + public static void clearAndReload() + { + arrow = new Arrow(color); + bountyHunter = null; + bounty = null; + arrowUpdateTimer = 0f; + bountyUpdateTimer = 0f; + if (arrow != null && arrow.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); + arrow = null; + if (cooldownText != null && cooldownText.gameObject != null) + UnityEngine.Object.Destroy(cooldownText.gameObject); + cooldownText = null; + foreach (PoolablePlayer p in TORMapOptions.playerIcons.Values) + { + if (p != null && p.gameObject != null) p.gameObject.SetActive(false); + } + + + bountyDuration = CustomOptionHolder.BountyHunterBountyDuration.GetFloat(); + bountyKillCooldown = CustomOptionHolder.BountyHunterReducedCooldown.GetFloat(); + punishmentTime = CustomOptionHolder.BountyHunterPunishmentTime.GetFloat(); + showArrow = CustomOptionHolder.BountyHunterShowArrow.GetBool(); + arrowUpdateIntervall = CustomOptionHolder.BountyHunterArrowUpdateInterval.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Camouflager.cs b/BetterOtherRoles/Roles/Camouflager.cs new file mode 100644 index 0000000..9ac2984 --- /dev/null +++ b/BetterOtherRoles/Roles/Camouflager.cs @@ -0,0 +1,44 @@ +using BetterOtherRoles.Options; +using BetterOtherRoles.Players; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Camouflager +{ + public static PlayerControl camouflager; + public static Color color = Palette.ImpostorRed; + + public static float cooldown = 30f; + public static float duration = 10f; + public static float camouflageTimer = 0f; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CamoButton.png", 115f); + return buttonSprite; + } + + public static void resetCamouflage() + { + camouflageTimer = 0f; + foreach (PlayerControl p in CachedPlayer.AllPlayers) + { + if (p == Ninja.ninja && Ninja.isInvisble) + continue; + p.setDefaultLook(); + } + } + + public static void clearAndReload() + { + resetCamouflage(); + camouflager = null; + camouflageTimer = 0f; + cooldown = CustomOptionHolder.CamouflagerCooldown.GetFloat(); + duration = CustomOptionHolder.CamouflagerDuration.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Cleaner.cs b/BetterOtherRoles/Roles/Cleaner.cs new file mode 100644 index 0000000..a9d0c26 --- /dev/null +++ b/BetterOtherRoles/Roles/Cleaner.cs @@ -0,0 +1,27 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Cleaner +{ + public static PlayerControl cleaner; + public static Color color = Palette.ImpostorRed; + + public static float cooldown = 30f; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CleanButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + cleaner = null; + cooldown = CustomOptionHolder.CleanerCooldown.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Deputy.cs b/BetterOtherRoles/Roles/Deputy.cs new file mode 100644 index 0000000..0e480cb --- /dev/null +++ b/BetterOtherRoles/Roles/Deputy.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using BetterOtherRoles.Players; +using Hazel; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Deputy + { + public static PlayerControl deputy; + public static Color color = Sheriff.color; + + public static PlayerControl currentTarget; + public static List handcuffedPlayers = new List(); + public static int promotesToSheriff; // No: 0, Immediately: 1, After Meeting: 2 + public static bool keepsHandcuffsOnPromotion; + public static float handcuffDuration; + public static float remainingHandcuffs; + public static float handcuffCooldown; + public static bool knowsSheriff; + public static Dictionary handcuffedKnows = new Dictionary(); + + private static Sprite buttonSprite; + private static Sprite handcuffedSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DeputyHandcuffButton.png", 115f); + return buttonSprite; + } + + public static Sprite getHandcuffedButtonSprite() + { + if (handcuffedSprite) return handcuffedSprite; + handcuffedSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DeputyHandcuffed.png", 115f); + return handcuffedSprite; + } + + // Can be used to enable / disable the handcuff effect on the target's buttons + public static void setHandcuffedKnows(bool active = true, byte playerId = byte.MaxValue) + { + if (playerId == byte.MaxValue) + playerId = CachedPlayer.LocalPlayer.PlayerId; + + if (active && playerId == CachedPlayer.LocalPlayer.PlayerId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately( + CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareGhostInfo, + Hazel.SendOption.Reliable, -1); + writer.Write(CachedPlayer.LocalPlayer.PlayerId); + writer.Write((byte)RPCProcedure.GhostInfoTypes.HandcuffNoticed); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + if (active) + { + handcuffedKnows.Add(playerId, handcuffDuration); + handcuffedPlayers.RemoveAll(x => x == playerId); + } + + if (playerId == CachedPlayer.LocalPlayer.PlayerId) + { + HudManagerStartPatch.setAllButtonsHandcuffedStatus(active); + SoundEffectsManager.play("deputyHandcuff"); + } + } + + public static void clearAndReload() + { + deputy = null; + currentTarget = null; + handcuffedPlayers = new List(); + handcuffedKnows = new Dictionary(); + HudManagerStartPatch.setAllButtonsHandcuffedStatus(false, true); + promotesToSheriff = CustomOptionHolder.DeputyGetsPromoted.CurrentSelection; + remainingHandcuffs = CustomOptionHolder.DeputyNumberOfHandcuffs.GetFloat(); + handcuffCooldown = CustomOptionHolder.DeputyHandcuffCooldown.GetFloat(); + keepsHandcuffsOnPromotion = CustomOptionHolder.DeputyKeepsHandcuffs.GetBool(); + handcuffDuration = CustomOptionHolder.DeputyHandcuffDuration.GetFloat(); + knowsSheriff = CustomOptionHolder.DeputyKnowsSheriff.GetBool(); + } + } \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Detective.cs b/BetterOtherRoles/Roles/Detective.cs new file mode 100644 index 0000000..077547f --- /dev/null +++ b/BetterOtherRoles/Roles/Detective.cs @@ -0,0 +1,28 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Detective +{ + public static PlayerControl detective; + public static Color color = new Color32(45, 106, 165, byte.MaxValue); + + public static float footprintIntervall = 1f; + public static float footprintDuration = 1f; + public static bool anonymousFootprints = false; + public static float reportNameDuration = 0f; + public static float reportColorDuration = 20f; + public static float timer = 6.2f; + + public static void clearAndReload() + { + detective = null; + anonymousFootprints = CustomOptionHolder.DetectiveAnonymousFootprints.GetBool(); + footprintIntervall = CustomOptionHolder.DetectiveFootprintInterval.GetFloat(); + footprintDuration = CustomOptionHolder.DetectiveFootprintDuration.GetFloat(); + reportNameDuration = CustomOptionHolder.DetectiveReportNameDuration.GetFloat(); + reportColorDuration = CustomOptionHolder.DetectiveReportColorDuration.GetFloat(); + timer = 6.2f; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Engineer.cs b/BetterOtherRoles/Roles/Engineer.cs new file mode 100644 index 0000000..b539d54 --- /dev/null +++ b/BetterOtherRoles/Roles/Engineer.cs @@ -0,0 +1,30 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Engineer +{ + public static PlayerControl engineer; + public static Color color = new Color32(0, 40, 245, byte.MaxValue); + private static Sprite buttonSprite; + + public static int remainingFixes = 1; + public static bool highlightForImpostors = true; + public static bool highlightForTeamJackal = true; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.RepairButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + engineer = null; + remainingFixes = Mathf.RoundToInt(CustomOptionHolder.EngineerNumberOfFixes.GetFloat()); + highlightForImpostors = CustomOptionHolder.EngineerHighlightForImpostors.GetBool(); + highlightForTeamJackal = CustomOptionHolder.EngineerHighlightForTeamJackal.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Eraser.cs b/BetterOtherRoles/Roles/Eraser.cs new file mode 100644 index 0000000..3222a61 --- /dev/null +++ b/BetterOtherRoles/Roles/Eraser.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Eraser +{ + public static PlayerControl eraser; + public static Color color = Palette.ImpostorRed; + + public static List alreadyErased = new List(); + + public static List futureErased = new List(); + public static PlayerControl currentTarget; + public static float cooldown = 30f; + public static bool canEraseAnyone = false; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.EraserButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + eraser = null; + futureErased = new List(); + currentTarget = null; + cooldown = CustomOptionHolder.EraserCooldown.GetFloat(); + canEraseAnyone = CustomOptionHolder.EraserCanEraseAnyone.GetBool(); + alreadyErased = new List(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Fallen.cs b/BetterOtherRoles/Roles/Fallen.cs new file mode 100644 index 0000000..414c394 --- /dev/null +++ b/BetterOtherRoles/Roles/Fallen.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Fallen +{ + public static PlayerControl Player; + public static readonly Color Color = new Color32(71, 99, 45, byte.MaxValue); + + public static void ClearAndReload() + { + Player = null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Godfather.cs b/BetterOtherRoles/Roles/Godfather.cs new file mode 100644 index 0000000..97700d2 --- /dev/null +++ b/BetterOtherRoles/Roles/Godfather.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Godfather +{ + public static PlayerControl godfather; + public static Color color = Palette.ImpostorRed; + + public static void clearAndReload() + { + godfather = null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Guesser.cs b/BetterOtherRoles/Roles/Guesser.cs new file mode 100644 index 0000000..5e22f92 --- /dev/null +++ b/BetterOtherRoles/Roles/Guesser.cs @@ -0,0 +1,51 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Guesser +{ + public static PlayerControl niceGuesser; + public static PlayerControl evilGuesser; + public static Color color = new Color32(255, 255, 0, byte.MaxValue); + + public static int remainingShotsEvilGuesser = 2; + public static int remainingShotsNiceGuesser = 2; + + public static bool isGuesser(byte playerId) + { + if ((niceGuesser != null && niceGuesser.PlayerId == playerId) || + (evilGuesser != null && evilGuesser.PlayerId == playerId)) return true; + return false; + } + + public static void clear(byte playerId) + { + if (niceGuesser != null && niceGuesser.PlayerId == playerId) niceGuesser = null; + else if (evilGuesser != null && evilGuesser.PlayerId == playerId) evilGuesser = null; + } + + public static int remainingShots(byte playerId, bool shoot = false) + { + int remainingShots = remainingShotsEvilGuesser; + if (niceGuesser != null && niceGuesser.PlayerId == playerId) + { + remainingShots = remainingShotsNiceGuesser; + if (shoot) remainingShotsNiceGuesser = Mathf.Max(0, remainingShotsNiceGuesser - 1); + } + else if (shoot) + { + remainingShotsEvilGuesser = Mathf.Max(0, remainingShotsEvilGuesser - 1); + } + + return remainingShots; + } + + public static void clearAndReload() + { + niceGuesser = null; + evilGuesser = null; + remainingShotsEvilGuesser = CustomOptionHolder.GuesserNumberOfShots.GetInt(); + remainingShotsNiceGuesser = CustomOptionHolder.GuesserNumberOfShots.GetInt(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Hacker.cs b/BetterOtherRoles/Roles/Hacker.cs new file mode 100644 index 0000000..41d446d --- /dev/null +++ b/BetterOtherRoles/Roles/Hacker.cs @@ -0,0 +1,90 @@ +using BetterOtherRoles.Options; +using BetterOtherRoles.Utilities; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Hacker +{ + public static PlayerControl hacker; + public static Minigame vitals = null; + public static Minigame doorLog = null; + public static Color color = new Color32(117, 250, 76, byte.MaxValue); + + public static float cooldown = 30f; + public static float duration = 10f; + public static float toolsNumber = 5f; + public static bool onlyColorType = false; + public static float hackerTimer = 0f; + public static int rechargeTasksNumber = 2; + public static int rechargedTasks = 2; + public static int chargesVitals = 1; + public static int chargesAdminTable = 1; + public static bool cantMove = true; + + private static Sprite buttonSprite; + private static Sprite vitalsSprite; + private static Sprite logSprite; + private static Sprite adminSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.HackerButton.png", 115f); + return buttonSprite; + } + + public static Sprite getVitalsSprite() + { + if (vitalsSprite) return vitalsSprite; + vitalsSprite = FastDestroyableSingleton.Instance.UseButton + .fastUseSettings[ImageNames.VitalsButton].Image; + return vitalsSprite; + } + + public static Sprite getLogSprite() + { + if (logSprite) return logSprite; + logSprite = FastDestroyableSingleton.Instance.UseButton + .fastUseSettings[ImageNames.DoorLogsButton].Image; + return logSprite; + } + + public static Sprite getAdminSprite() + { + byte mapId = GameOptionsManager.Instance.currentNormalGameOptions.MapId; + UseButtonSettings button = + FastDestroyableSingleton.Instance.UseButton + .fastUseSettings[ImageNames.PolusAdminButton]; // Polus + if (mapId == 0 || mapId == 3) + button = + FastDestroyableSingleton.Instance.UseButton.fastUseSettings + [ImageNames.AdminMapButton]; // Skeld || Dleks + else if (mapId == 1) + button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ + ImageNames.MIRAAdminButton]; // Mira HQ + else if (mapId == 4) + button = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ + ImageNames.AirshipAdminButton]; // Airship + adminSprite = button.Image; + return adminSprite; + } + + public static void clearAndReload() + { + hacker = null; + vitals = null; + doorLog = null; + hackerTimer = 0f; + adminSprite = null; + cooldown = CustomOptionHolder.HackerCooldown.GetFloat(); + duration = CustomOptionHolder.HackerHackeringDuration.GetFloat(); + onlyColorType = CustomOptionHolder.HackerOnlyColorType.GetBool(); + toolsNumber = CustomOptionHolder.HackerToolsNumber.GetFloat(); + rechargeTasksNumber = CustomOptionHolder.HackerRechargeTasksNumber.GetInt(); + rechargedTasks = CustomOptionHolder.HackerRechargeTasksNumber.GetInt(); + chargesVitals = CustomOptionHolder.HackerToolsNumber.GetInt() / 2; + chargesAdminTable = CustomOptionHolder.HackerToolsNumber.GetInt() / 2; + cantMove = CustomOptionHolder.HackerNoMove.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Jackal.cs b/BetterOtherRoles/Roles/Jackal.cs new file mode 100644 index 0000000..6fe3dbd --- /dev/null +++ b/BetterOtherRoles/Roles/Jackal.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Linq; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Jackal +{ + public static PlayerControl jackal; + public static Color color = new Color32(0, 180, 235, byte.MaxValue); + public static PlayerControl fakeSidekick; + public static PlayerControl currentTarget; + public static List formerJackals = new List(); + + public static float cooldown = 30f; + public static float createSidekickCooldown = 30f; + public static bool canUseVents = true; + public static bool canCreateSidekick = true; + public static Sprite buttonSprite; + public static bool jackalPromotedFromSidekickCanCreateSidekick = true; + public static bool canCreateSidekickFromImpostor = true; + public static bool hasImpostorVision = false; + public static bool wasTeamRed; + public static bool wasImpostor; + public static bool wasSpy; + + public static Sprite getSidekickButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SidekickButton.png", 115f); + return buttonSprite; + } + + public static void removeCurrentJackal() + { + if (!formerJackals.Any(x => x.PlayerId == jackal.PlayerId)) formerJackals.Add(jackal); + jackal = null; + currentTarget = null; + fakeSidekick = null; + cooldown = CustomOptionHolder.JackalKillCooldown.GetFloat(); + createSidekickCooldown = CustomOptionHolder.JackalCreateSidekickCooldown.GetFloat(); + } + + public static void clearAndReload() + { + jackal = null; + currentTarget = null; + fakeSidekick = null; + cooldown = CustomOptionHolder.JackalKillCooldown.GetFloat(); + createSidekickCooldown = CustomOptionHolder.JackalCreateSidekickCooldown.GetFloat(); + canUseVents = CustomOptionHolder.JackalCanUseVents.GetBool(); + canCreateSidekick = CustomOptionHolder.JackalCanCreateSidekick.GetBool(); + jackalPromotedFromSidekickCanCreateSidekick = + CustomOptionHolder.JackalPromotedFromSidekickCanCreateSidekick.GetBool(); + canCreateSidekickFromImpostor = CustomOptionHolder.JackalCanCreateSidekickFromImpostor.GetBool(); + formerJackals.Clear(); + hasImpostorVision = CustomOptionHolder.JackalAndSidekickHaveImpostorVision.GetBool(); + wasTeamRed = wasImpostor = wasSpy = false; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Janitor.cs b/BetterOtherRoles/Roles/Janitor.cs new file mode 100644 index 0000000..1c43032 --- /dev/null +++ b/BetterOtherRoles/Roles/Janitor.cs @@ -0,0 +1,27 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Janitor +{ + public static PlayerControl janitor; + public static Color color = Palette.ImpostorRed; + + public static float cooldown = 30f; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CleanButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + janitor = null; + cooldown = CustomOptionHolder.JanitorCooldown.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Jester.cs b/BetterOtherRoles/Roles/Jester.cs new file mode 100644 index 0000000..bf4e2d7 --- /dev/null +++ b/BetterOtherRoles/Roles/Jester.cs @@ -0,0 +1,22 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Jester +{ + public static PlayerControl jester; + public static Color color = new Color32(236, 98, 165, byte.MaxValue); + + public static bool triggerJesterWin = false; + public static bool canCallEmergency = true; + public static bool hasImpostorVision = false; + + public static void clearAndReload() + { + jester = null; + triggerJesterWin = false; + canCallEmergency = CustomOptionHolder.JesterCanCallEmergency.GetBool(); + hasImpostorVision = CustomOptionHolder.JesterHasImpostorVision.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Lawyer.cs b/BetterOtherRoles/Roles/Lawyer.cs new file mode 100644 index 0000000..cec1a97 --- /dev/null +++ b/BetterOtherRoles/Roles/Lawyer.cs @@ -0,0 +1,44 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Lawyer +{ + public static PlayerControl lawyer; + public static PlayerControl target; + public static Color color = new Color32(134, 153, 25, byte.MaxValue); + public static Sprite targetSprite; + public static bool triggerProsecutorWin = false; + public static bool isProsecutor = false; + public static bool canCallEmergency = true; + + public static float vision = 1f; + public static bool lawyerKnowsRole = false; + public static bool targetCanBeJester = false; + public static bool targetWasGuessed = false; + + public static Sprite getTargetSprite() + { + if (targetSprite) return targetSprite; + targetSprite = Helpers.loadSpriteFromResources("", 150f); + return targetSprite; + } + + public static void clearAndReload(bool clearTarget = true) + { + lawyer = null; + if (clearTarget) + { + target = null; + targetWasGuessed = false; + } + + isProsecutor = false; + triggerProsecutorWin = false; + vision = CustomOptionHolder.LawyerVision.GetFloat(); + lawyerKnowsRole = CustomOptionHolder.LawyerKnowsRole.GetBool(); + targetCanBeJester = CustomOptionHolder.LawyerTargetCanBeJester.GetBool(); + canCallEmergency = CustomOptionHolder.LawyerCanCallEmergency.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Lighter.cs b/BetterOtherRoles/Roles/Lighter.cs new file mode 100644 index 0000000..c276a20 --- /dev/null +++ b/BetterOtherRoles/Roles/Lighter.cs @@ -0,0 +1,22 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Lighter +{ + public static PlayerControl lighter; + public static Color color = new Color32(238, 229, 190, byte.MaxValue); + + public static float lighterModeLightsOnVision = 2f; + public static float lighterModeLightsOffVision = 0.75f; + public static float flashlightWidth = 0.75f; + + public static void clearAndReload() + { + lighter = null; + flashlightWidth = CustomOptionHolder.LighterFlashlightWidth.GetFloat(); + lighterModeLightsOnVision = CustomOptionHolder.LighterModeLightsOnVision.GetFloat(); + lighterModeLightsOffVision = CustomOptionHolder.LighterModeLightsOffVision.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Mafioso.cs b/BetterOtherRoles/Roles/Mafioso.cs new file mode 100644 index 0000000..3cc68a5 --- /dev/null +++ b/BetterOtherRoles/Roles/Mafioso.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Mafioso +{ + public static PlayerControl mafioso; + public static Color color = Palette.ImpostorRed; + + public static void clearAndReload() + { + mafioso = null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Mayor.cs b/BetterOtherRoles/Roles/Mayor.cs new file mode 100644 index 0000000..eccaa01 --- /dev/null +++ b/BetterOtherRoles/Roles/Mayor.cs @@ -0,0 +1,41 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Mayor +{ + public static PlayerControl mayor; + public static Color color = new Color32(32, 77, 66, byte.MaxValue); + public static Minigame emergency = null; + public static Sprite emergencySprite = null; + public static int remoteMeetingsLeft = 1; + + public static bool canSeeVoteColors = false; + public static int tasksNeededToSeeVoteColors; + public static bool meetingButton = true; + public static int mayorChooseSingleVote; + + public static bool voteTwice = true; + + public static Sprite getMeetingSprite() + { + if (emergencySprite) return emergencySprite; + emergencySprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.EmergencyButton.png", 550f); + return emergencySprite; + } + + public static void clearAndReload() + { + mayor = null; + emergency = null; + emergencySprite = null; + remoteMeetingsLeft = Mathf.RoundToInt(CustomOptionHolder.MayorMaxRemoteMeetings.GetFloat()); + canSeeVoteColors = CustomOptionHolder.MayorCanSeeVoteColors.GetBool(); + tasksNeededToSeeVoteColors = CustomOptionHolder.MayorTasksNeededToSeeVoteColors.GetInt(); + meetingButton = CustomOptionHolder.MayorMeetingButton.GetBool(); + mayorChooseSingleVote = CustomOptionHolder.MayorChooseSingleVote.CurrentSelection; + voteTwice = true; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Medic.cs b/BetterOtherRoles/Roles/Medic.cs new file mode 100644 index 0000000..c26a7d4 --- /dev/null +++ b/BetterOtherRoles/Roles/Medic.cs @@ -0,0 +1,48 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Medic +{ + public static PlayerControl medic; + public static PlayerControl shielded; + public static PlayerControl futureShielded; + + public static Color color = new Color32(126, 251, 194, byte.MaxValue); + public static bool usedShield; + + public static int showShielded = 0; + public static bool showAttemptToShielded = false; + public static bool showAttemptToMedic = false; + public static bool setShieldAfterMeeting = false; + public static bool showShieldAfterMeeting = false; + public static bool meetingAfterShielding = false; + + public static Color shieldedColor = new Color32(0, 221, 255, byte.MaxValue); + public static PlayerControl currentTarget; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.ShieldButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + medic = null; + shielded = null; + futureShielded = null; + currentTarget = null; + usedShield = false; + showShielded = CustomOptionHolder.MedicShowShielded.CurrentSelection; + showAttemptToShielded = CustomOptionHolder.MedicShowAttemptToShielded.GetBool(); + showAttemptToMedic = CustomOptionHolder.MedicShowAttemptToMedic.GetBool(); + setShieldAfterMeeting = CustomOptionHolder.MedicSetOrShowShieldAfterMeeting.CurrentSelection == 2; + showShieldAfterMeeting = CustomOptionHolder.MedicSetOrShowShieldAfterMeeting.CurrentSelection == 1; + meetingAfterShielding = false; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Medium.cs b/BetterOtherRoles/Roles/Medium.cs new file mode 100644 index 0000000..d26be7b --- /dev/null +++ b/BetterOtherRoles/Roles/Medium.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Options; +using UnityEngine; +using Random = System.Random; + +namespace BetterOtherRoles.Roles; + +public static class Medium +{ + public static PlayerControl medium; + public static DeadPlayer target; + public static DeadPlayer soulTarget; + public static Color color = new Color32(98, 120, 115, byte.MaxValue); + public static List> deadBodies = new List>(); + public static List> futureDeadBodies = new List>(); + public static List souls = new List(); + public static DateTime meetingStartTime = DateTime.UtcNow; + + public static float cooldown = 30f; + public static float duration = 3f; + public static bool oneTimeUse = false; + public static float chanceAdditionalInfo = 0f; + private static readonly Random Rnd = new(); + + private static Sprite soulSprite; + + enum SpecialMediumInfo + { + SheriffSuicide, + ThiefSuicide, + ActiveLoverDies, + PassiveLoverSuicide, + LawyerKilledByClient, + JackalKillsSidekick, + ImpostorTeamkill, + SubmergedO2, + WarlockSuicide, + BodyCleaned, + } + + public static Sprite getSoulSprite() + { + if (soulSprite) return soulSprite; + soulSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Soul.png", 500f); + return soulSprite; + } + + private static Sprite question; + + public static Sprite getQuestionSprite() + { + if (question) return question; + question = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.MediumButton.png", 115f); + return question; + } + + public static void clearAndReload() + { + medium = null; + target = null; + soulTarget = null; + deadBodies = new List>(); + futureDeadBodies = new List>(); + souls = new List(); + meetingStartTime = DateTime.UtcNow; + cooldown = CustomOptionHolder.MediumCooldown.GetFloat(); + duration = CustomOptionHolder.MediumDuration.GetFloat(); + oneTimeUse = CustomOptionHolder.MediumOneTimeUse.GetBool(); + chanceAdditionalInfo = CustomOptionHolder.MediumChanceAdditionalInfo.CurrentSelection / 10f; + } + + public static string getInfo(PlayerControl target, PlayerControl killer) + { + string msg = ""; + + List infos = new List(); + // collect fitting death info types. + // suicides: + if (killer == target) + { + if (target == Sheriff.sheriff || target == Sheriff.formerSheriff) + infos.Add(SpecialMediumInfo.SheriffSuicide); + if (target == Lovers.lover1 || target == Lovers.lover2) + infos.Add(SpecialMediumInfo.PassiveLoverSuicide); + if (target == Thief.thief) infos.Add(SpecialMediumInfo.ThiefSuicide); + if (target == Warlock.warlock) infos.Add(SpecialMediumInfo.WarlockSuicide); + } + else + { + if (target == Lovers.lover1 || target == Lovers.lover2) infos.Add(SpecialMediumInfo.ActiveLoverDies); + if (target.Data.Role.IsImpostor && killer.Data.Role.IsImpostor && Thief.formerThief != killer) + infos.Add(SpecialMediumInfo.ImpostorTeamkill); + } + + if (target == Sidekick.sidekick && + (killer == Jackal.jackal || Jackal.formerJackals.Any(x => x.PlayerId == killer.PlayerId))) + infos.Add(SpecialMediumInfo.JackalKillsSidekick); + if (target == Lawyer.lawyer && killer == Lawyer.target) infos.Add(SpecialMediumInfo.LawyerKilledByClient); + if (Medium.target.wasCleaned) infos.Add(SpecialMediumInfo.BodyCleaned); + + if (infos.Count > 0) + { + var selectedInfo = infos[Rnd.Next(infos.Count)]; + switch (selectedInfo) + { + case SpecialMediumInfo.SheriffSuicide: + msg = "Yikes, that Sheriff shot backfired."; + break; + case SpecialMediumInfo.WarlockSuicide: + msg = "MAYBE I cursed the person next to me and killed myself. Oops."; + break; + case SpecialMediumInfo.ThiefSuicide: + msg = "I tried to steal the gun from their pocket, but they were just happy to see me."; + break; + case SpecialMediumInfo.ActiveLoverDies: + msg = "I wanted to get out of this toxic relationship anyways."; + break; + case SpecialMediumInfo.PassiveLoverSuicide: + msg = "The love of my life died, thus with a kiss I die."; + break; + case SpecialMediumInfo.LawyerKilledByClient: + msg = "My client killed me. Do I still get paid?"; + break; + case SpecialMediumInfo.JackalKillsSidekick: + msg = + "First they sidekicked me, then they killed me. At least I don't need to do tasks anymore."; + break; + case SpecialMediumInfo.ImpostorTeamkill: + msg = "I guess they confused me for the Spy, is there even one?"; + break; + case SpecialMediumInfo.BodyCleaned: + msg = "Is my dead body some kind of art now or... aaand it's gone."; + break; + } + } + else + { + int randomNumber = Rnd.Next(4); + string typeOfColor = Helpers.isLighterColor(Medium.target.killerIfExisting.Data.DefaultOutfit.ColorId) + ? "lighter" + : "darker"; + float timeSinceDeath = ((float)(Medium.meetingStartTime - Medium.target.timeOfDeath).TotalMilliseconds); + + if (randomNumber == 0) + msg = "If my role hasn't been saved, there's no " + + RoleInfo.GetRolesString(Medium.target.player, false) + " in the game anymore."; + else if (randomNumber == 1) msg = "I'm not sure, but I guess a " + typeOfColor + " color killed me."; + else if (randomNumber == 2) + msg = "If I counted correctly, I died " + Math.Round(timeSinceDeath / 1000) + + "s before the next meeting started."; + else + msg = "It seems like my killer was the " + + RoleInfo.GetRolesString(Medium.target.killerIfExisting, false, false, true) + "."; + } + + if (Rnd.NextDouble() < chanceAdditionalInfo) + { + int count = 0; + string condition = ""; + var alivePlayersList = PlayerControl.AllPlayerControls.ToArray().Where(pc => !pc.Data.IsDead); + switch (Rnd.Next(3)) + { + case 0: + count = alivePlayersList.Where(pc => + pc.Data.Role.IsImpostor || + new List() + { RoleInfo.jackal, RoleInfo.sidekick, RoleInfo.sheriff, RoleInfo.thief } + .Contains(RoleInfo.getRoleInfoForPlayer(pc, false).FirstOrDefault())).Count(); + condition = "killer" + (count == 1 ? "" : "s"); + break; + case 1: + count = alivePlayersList.Where(Helpers.roleCanUseVents).Count(); + condition = "player" + (count == 1 ? "" : "s") + " who can use vents"; + break; + case 2: + count = alivePlayersList.Where(pc => + Helpers.isNeutral(pc) && pc != Jackal.jackal && pc != Sidekick.sidekick && + pc != Thief.thief).Count(); + condition = "player" + (count == 1 ? "" : "s") + " who " + (count == 1 ? "is" : "are") + + " neutral but cannot kill"; + break; + case 3: + //count = alivePlayersList.Where(pc => + break; + } + + msg += $"\nWhen you asked, {count} " + condition + (count == 1 ? " was" : " were") + " still alive"; + } + + return Medium.target.player.Data.PlayerName + "'s Soul:\n" + msg; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Morphling.cs b/BetterOtherRoles/Roles/Morphling.cs new file mode 100644 index 0000000..2982218 --- /dev/null +++ b/BetterOtherRoles/Roles/Morphling.cs @@ -0,0 +1,54 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +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 = 30f; + public static float duration = 10f; + + public static PlayerControl currentTarget; + public static PlayerControl sampledTarget; + public static PlayerControl morphTarget; + public static float morphTimer = 0f; + + public static void resetMorph() + { + morphTarget = null; + morphTimer = 0f; + if (morphling == null) return; + morphling.setDefaultLook(); + } + + public static void clearAndReload() + { + resetMorph(); + morphling = null; + currentTarget = null; + sampledTarget = null; + morphTarget = null; + morphTimer = 0f; + cooldown = CustomOptionHolder.MorphlingCooldown.GetFloat(); + duration = CustomOptionHolder.MorphlingDuration.GetFloat(); + } + + public static Sprite getSampleSprite() + { + if (sampleSprite) return sampleSprite; + sampleSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SampleButton.png", 115f); + return sampleSprite; + } + + public static Sprite getMorphSprite() + { + if (morphSprite) return morphSprite; + morphSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.MorphButton.png", 115f); + return morphSprite; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Ninja.cs b/BetterOtherRoles/Roles/Ninja.cs new file mode 100644 index 0000000..db1c57e --- /dev/null +++ b/BetterOtherRoles/Roles/Ninja.cs @@ -0,0 +1,54 @@ +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Ninja +{ + public static PlayerControl ninja; + public static Color color = Palette.ImpostorRed; + + public static PlayerControl ninjaMarked; + public static PlayerControl currentTarget; + public static float cooldown = 30f; + public static float traceTime = 1f; + public static bool knowsTargetLocation = false; + public static float invisibleDuration = 5f; + + public static float invisibleTimer = 0f; + public static bool isInvisble = false; + private static Sprite markButtonSprite; + private static Sprite killButtonSprite; + public static Arrow arrow = new Arrow(Color.black); + + public static Sprite getMarkButtonSprite() + { + if (markButtonSprite) return markButtonSprite; + markButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.NinjaMarkButton.png", 115f); + return markButtonSprite; + } + + public static Sprite getKillButtonSprite() + { + if (killButtonSprite) return killButtonSprite; + killButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.NinjaAssassinateButton.png", 115f); + return killButtonSprite; + } + + public static void clearAndReload() + { + ninja = null; + currentTarget = ninjaMarked = null; + cooldown = CustomOptionHolder.NinjaCooldown.GetFloat(); + knowsTargetLocation = CustomOptionHolder.NinjaKnowsTargetLocation.GetBool(); + traceTime = CustomOptionHolder.NinjaTraceTime.GetFloat(); + invisibleDuration = CustomOptionHolder.NinjaInvisibleDuration.GetFloat(); + invisibleTimer = 0f; + isInvisble = false; + if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); + arrow = new Arrow(Color.black); + if (arrow.arrow != null) arrow.arrow.SetActive(false); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Portalmaker.cs b/BetterOtherRoles/Roles/Portalmaker.cs new file mode 100644 index 0000000..b2e1eed --- /dev/null +++ b/BetterOtherRoles/Roles/Portalmaker.cs @@ -0,0 +1,75 @@ +using BetterOtherRoles.Options; +using BetterOtherRoles.Utilities; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Portalmaker + { + public static PlayerControl portalmaker; + public static Color color = new Color32(69, 69, 169, byte.MaxValue); + + public static float cooldown; + public static float usePortalCooldown; + public static bool logOnlyHasColors; + public static bool logShowsTime; + public static bool canPortalFromAnywhere; + + private static Sprite placePortalButtonSprite; + private static Sprite usePortalButtonSprite; + private static Sprite usePortalSpecialButtonSprite1; + private static Sprite usePortalSpecialButtonSprite2; + private static Sprite logSprite; + + public static Sprite getPlacePortalButtonSprite() + { + if (placePortalButtonSprite) return placePortalButtonSprite; + placePortalButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlacePortalButton.png", 115f); + return placePortalButtonSprite; + } + + public static Sprite getUsePortalButtonSprite() + { + if (usePortalButtonSprite) return usePortalButtonSprite; + usePortalButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalButton.png", 115f); + return usePortalButtonSprite; + } + + public static Sprite getUsePortalSpecialButtonSprite(bool first) + { + if (first) + { + if (usePortalSpecialButtonSprite1) return usePortalSpecialButtonSprite1; + usePortalSpecialButtonSprite1 = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalSpecialButton1.png", 115f); + return usePortalSpecialButtonSprite1; + } + else + { + if (usePortalSpecialButtonSprite2) return usePortalSpecialButtonSprite2; + usePortalSpecialButtonSprite2 = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.UsePortalSpecialButton2.png", 115f); + return usePortalSpecialButtonSprite2; + } + } + + public static Sprite getLogSprite() + { + if (logSprite) return logSprite; + logSprite = FastDestroyableSingleton.Instance.UseButton + .fastUseSettings[ImageNames.DoorLogsButton].Image; + return logSprite; + } + + public static void clearAndReload() + { + portalmaker = null; + cooldown = CustomOptionHolder.PortalmakerCooldown.GetFloat(); + usePortalCooldown = CustomOptionHolder.PortalmakerUsePortalCooldown.GetFloat(); + logOnlyHasColors = CustomOptionHolder.PortalmakerLogOnlyColorType.GetBool(); + logShowsTime = CustomOptionHolder.PortalmakerLogHasTime.GetBool(); + canPortalFromAnywhere = CustomOptionHolder.PortalmakerCanPortalFromAnywhere.GetBool(); + } + } \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Pursuer.cs b/BetterOtherRoles/Roles/Pursuer.cs new file mode 100644 index 0000000..eb990bf --- /dev/null +++ b/BetterOtherRoles/Roles/Pursuer.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Pursuer +{ + public static PlayerControl pursuer; + public static PlayerControl target; + public static Color color = Lawyer.color; + public static List blankedList = new List(); + public static int blanks = 0; + public static Sprite blank; + public static bool notAckedExiled = false; + + public static float cooldown = 30f; + public static int blanksNumber = 5; + + public static Sprite getTargetSprite() + { + if (blank) return blank; + blank = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PursuerButton.png", 115f); + return blank; + } + + public static void clearAndReload() + { + pursuer = null; + target = null; + blankedList = new List(); + blanks = 0; + notAckedExiled = false; + + cooldown = CustomOptionHolder.PursuerCooldown.GetFloat(); + blanksNumber = Mathf.RoundToInt(CustomOptionHolder.PursuerBlanksNumber.GetFloat()); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/SecurityGuard.cs b/BetterOtherRoles/Roles/SecurityGuard.cs new file mode 100644 index 0000000..c3d5724 --- /dev/null +++ b/BetterOtherRoles/Roles/SecurityGuard.cs @@ -0,0 +1,133 @@ +using BetterOtherRoles.Options; +using BetterOtherRoles.Utilities; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class SecurityGuard +{ + public static PlayerControl securityGuard; + public static Color color = new Color32(195, 178, 95, byte.MaxValue); + + public static float cooldown = 30f; + public static int remainingScrews = 7; + public static int totalScrews = 7; + public static int ventPrice = 1; + public static int camPrice = 2; + public static int placedCameras = 0; + public static float duration = 10f; + public static int maxCharges = 5; + public static int rechargeTasksNumber = 3; + public static int rechargedTasks = 3; + public static int charges = 1; + public static bool cantMove = true; + public static Vent ventTarget = null; + public static Minigame minigame = null; + + private static Sprite closeVentButtonSprite; + + public static Sprite getCloseVentButtonSprite() + { + if (closeVentButtonSprite) return closeVentButtonSprite; + closeVentButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CloseVentButton.png", 115f); + return closeVentButtonSprite; + } + + private static Sprite placeCameraButtonSprite; + + public static Sprite getPlaceCameraButtonSprite() + { + if (placeCameraButtonSprite) return placeCameraButtonSprite; + placeCameraButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlaceCameraButton.png", 115f); + return placeCameraButtonSprite; + } + + private static Sprite animatedVentSealedSprite; + private static float lastPPU; + + public static Sprite getAnimatedVentSealedSprite() + { + float ppu = 185f; + if (SubmergedCompatibility.IsSubmerged) ppu = 120f; + if (lastPPU != ppu) + { + animatedVentSealedSprite = null; + lastPPU = ppu; + } + + if (animatedVentSealedSprite) return animatedVentSealedSprite; + animatedVentSealedSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.AnimatedVentSealed.png", ppu); + return animatedVentSealedSprite; + } + + private static Sprite staticVentSealedSprite; + + public static Sprite getStaticVentSealedSprite() + { + if (staticVentSealedSprite) return staticVentSealedSprite; + staticVentSealedSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StaticVentSealed.png", 160f); + return staticVentSealedSprite; + } + + private static Sprite submergedCentralUpperVentSealedSprite; + + public static Sprite getSubmergedCentralUpperSealedSprite() + { + if (submergedCentralUpperVentSealedSprite) return submergedCentralUpperVentSealedSprite; + submergedCentralUpperVentSealedSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CentralUpperBlocked.png", 145f); + return submergedCentralUpperVentSealedSprite; + } + + private static Sprite submergedCentralLowerVentSealedSprite; + + public static Sprite getSubmergedCentralLowerSealedSprite() + { + if (submergedCentralLowerVentSealedSprite) return submergedCentralLowerVentSealedSprite; + submergedCentralLowerVentSealedSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CentralLowerBlocked.png", 145f); + return submergedCentralLowerVentSealedSprite; + } + + private static Sprite camSprite; + + public static Sprite getCamSprite() + { + if (camSprite) return camSprite; + camSprite = FastDestroyableSingleton.Instance.UseButton.fastUseSettings[ImageNames.CamsButton] + .Image; + return camSprite; + } + + private static Sprite logSprite; + + public static Sprite getLogSprite() + { + if (logSprite) return logSprite; + logSprite = FastDestroyableSingleton.Instance.UseButton + .fastUseSettings[ImageNames.DoorLogsButton].Image; + return logSprite; + } + + public static void clearAndReload() + { + securityGuard = null; + ventTarget = null; + minigame = null; + duration = CustomOptionHolder.SecurityGuardCamDuration.GetFloat(); + maxCharges = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardCamMaxCharges.GetFloat()); + rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardCamRechargeTasksNumber.GetFloat()); + rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardCamRechargeTasksNumber.GetFloat()); + charges = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardCamMaxCharges.GetFloat()) / 2; + placedCameras = 0; + cooldown = CustomOptionHolder.SecurityGuardCooldown.GetFloat(); + totalScrews = remainingScrews = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardTotalScrews.GetFloat()); + camPrice = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardCamPrice.GetFloat()); + ventPrice = Mathf.RoundToInt(CustomOptionHolder.SecurityGuardVentPrice.GetFloat()); + cantMove = CustomOptionHolder.SecurityGuardNoMove.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Seer.cs b/BetterOtherRoles/Roles/Seer.cs new file mode 100644 index 0000000..5c66b7b --- /dev/null +++ b/BetterOtherRoles/Roles/Seer.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Seer +{ + public static PlayerControl seer; + public static Color color = new Color32(97, 178, 108, byte.MaxValue); + public static List deadBodyPositions = new List(); + + public static float soulDuration = 15f; + public static bool limitSoulDuration = false; + public static int mode = 0; + + private static Sprite soulSprite; + + public static Sprite getSoulSprite() + { + if (soulSprite) return soulSprite; + soulSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Soul.png", 500f); + return soulSprite; + } + + public static void clearAndReload() + { + seer = null; + deadBodyPositions = new List(); + limitSoulDuration = CustomOptionHolder.SeerLimitSoulDuration.GetBool(); + soulDuration = CustomOptionHolder.SeerSoulDuration.GetFloat(); + mode = CustomOptionHolder.SeerMode.CurrentSelection; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Sheriff.cs b/BetterOtherRoles/Roles/Sheriff.cs new file mode 100644 index 0000000..2d20b5a --- /dev/null +++ b/BetterOtherRoles/Roles/Sheriff.cs @@ -0,0 +1,38 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Sheriff +{ + public static PlayerControl sheriff; + public static Color color = new Color32(248, 205, 70, byte.MaxValue); + + public static float cooldown = 30f; + public static bool canKillNeutrals = false; + public static bool spyCanDieToSheriff = false; + + public static PlayerControl currentTarget; + + public static PlayerControl formerDeputy; // Needed for keeping handcuffs + shifting + public static PlayerControl formerSheriff; // When deputy gets promoted... + + public static void replaceCurrentSheriff(PlayerControl deputy) + { + if (!formerSheriff) formerSheriff = sheriff; + sheriff = deputy; + currentTarget = null; + cooldown = CustomOptionHolder.SheriffCooldown.GetFloat(); + } + + public static void clearAndReload() + { + sheriff = null; + currentTarget = null; + formerDeputy = null; + formerSheriff = null; + cooldown = CustomOptionHolder.SheriffCooldown.GetFloat(); + canKillNeutrals = CustomOptionHolder.SheriffCanKillNeutrals.GetBool(); + spyCanDieToSheriff = CustomOptionHolder.SpyCanDieToSheriff.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Sidekick.cs b/BetterOtherRoles/Roles/Sidekick.cs new file mode 100644 index 0000000..3f592e6 --- /dev/null +++ b/BetterOtherRoles/Roles/Sidekick.cs @@ -0,0 +1,34 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Sidekick +{ + public static PlayerControl sidekick; + public static Color color = new Color32(0, 180, 235, byte.MaxValue); + + public static PlayerControl currentTarget; + + public static bool wasTeamRed; + public static bool wasImpostor; + public static bool wasSpy; + + public static float cooldown = 30f; + public static bool canUseVents = true; + public static bool canKill = true; + public static bool promotesToJackal = true; + public static bool hasImpostorVision = false; + + public static void clearAndReload() + { + sidekick = null; + currentTarget = null; + cooldown = CustomOptionHolder.JackalKillCooldown.GetFloat(); + canUseVents = CustomOptionHolder.SidekickCanUseVents.GetBool(); + canKill = CustomOptionHolder.SidekickCanKill.GetBool(); + promotesToJackal = CustomOptionHolder.SidekickPromoteToJackal.GetBool(); + hasImpostorVision = CustomOptionHolder.JackalAndSidekickHaveImpostorVision.GetBool(); + wasTeamRed = wasImpostor = wasSpy = false; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Snitch.cs b/BetterOtherRoles/Roles/Snitch.cs new file mode 100644 index 0000000..eadb38d --- /dev/null +++ b/BetterOtherRoles/Roles/Snitch.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Snitch +{ + public static PlayerControl snitch; + public static Color color = new Color32(184, 251, 79, byte.MaxValue); + + public enum Mode + { + Chat = 0, + Map = 1, + ChatAndMap = 2 + } + + public enum Targets + { + EvilPlayers = 0, + Killers = 1 + } + + public static Mode mode = Mode.Chat; + public static Targets targets = Targets.EvilPlayers; + public static int taskCountForReveal = 1; + + public static bool isRevealed = false; + public static Dictionary playerRoomMap = new Dictionary(); + public static TMPro.TextMeshPro text = null; + public static bool needsUpdate = true; + + public static void clearAndReload() + { + taskCountForReveal = Mathf.RoundToInt(CustomOptionHolder.SnitchLeftTasksForReveal.GetFloat()); + snitch = null; + isRevealed = false; + playerRoomMap = new Dictionary(); + if (text != null) UnityEngine.Object.Destroy(text); + text = null; + needsUpdate = true; + mode = (Mode)CustomOptionHolder.SnitchMode.CurrentSelection; + targets = (Targets)CustomOptionHolder.SnitchTargets.CurrentSelection; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Spy.cs b/BetterOtherRoles/Roles/Spy.cs new file mode 100644 index 0000000..63d3dfb --- /dev/null +++ b/BetterOtherRoles/Roles/Spy.cs @@ -0,0 +1,22 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Spy +{ + public static PlayerControl spy; + public static Color color = Palette.ImpostorRed; + + public static bool impostorsCanKillAnyone = true; + public static bool canEnterVents = false; + public static bool hasImpostorVision = false; + + public static void clearAndReload() + { + spy = null; + impostorsCanKillAnyone = CustomOptionHolder.SpyImpostorsCanKillAnyone.GetBool(); + canEnterVents = CustomOptionHolder.SpyCanEnterVents.GetBool(); + hasImpostorVision = CustomOptionHolder.SpyHasImpostorVision.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/StickyBomber.cs b/BetterOtherRoles/Roles/StickyBomber.cs new file mode 100644 index 0000000..b249030 --- /dev/null +++ b/BetterOtherRoles/Roles/StickyBomber.cs @@ -0,0 +1,135 @@ +using System.Collections; +using BetterOtherRoles.Options; +using BetterOtherRoles.Players; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class StickyBomber +{ + public static PlayerControl Player; + public static Color Color = Palette.ImpostorRed; + + public static PlayerControl StuckPlayer; + public static float RemainingTime; + public static float RemainingDelay; + public static PlayerControl CurrentTarget; + public static PlayerControl CurrentTransferTarget; + + public static float BombCooldown; + public static float FirstDelay; + public static float OtherDelay; + public static float Duration; + public static bool CanReceiveBomb; + public static bool ShieldedPlayerCanReceiveBomb; + public static bool AllowKillButton; + public static bool TriggerBothCooldown; + public static bool ShowRemainingTime; + + public static void ClearAndReload() + { + Player = null; + StuckPlayer = null; + RemainingTime = 0f; + RemainingDelay = 0f; + CurrentTarget = null; + CurrentTransferTarget = null; + + BombCooldown = CustomOptionHolder.StickyBomberCooldown.GetFloat(); + FirstDelay = CustomOptionHolder.StickyBomberFirstDelay.GetFloat(); + OtherDelay = CustomOptionHolder.StickyBomberOtherDelay.GetFloat(); + Duration = CustomOptionHolder.StickyBomberDuration.GetFloat(); + CanReceiveBomb = CustomOptionHolder.StickyBomberCanReceiveBomb.GetBool(); + ShieldedPlayerCanReceiveBomb = CustomOptionHolder.StickyBomberCanGiveBombToShielded.GetBool(); + AllowKillButton = CustomOptionHolder.StickyBomberEnableKillButton.GetBool(); + TriggerBothCooldown = CustomOptionHolder.StickyBomberTriggerAllCooldowns.GetBool(); + ShowRemainingTime = CustomOptionHolder.StickyBomberShowTimer.GetBool(); + } + + public static Sprite StickyButton => + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StickyBombButton.png", 115f); + + public static Sprite StickyTransferButton => + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.StickyBombTransferButton.png", 115f); + + public static void RpcGiveBomb(byte playerId) + { + var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, + (byte)CustomRPC.StickyBomberGiveBomb, Hazel.SendOption.Reliable, -1); + writer.Write(playerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + GiveBomb(playerId); + } + + public static void GiveBomb(byte playerId) + { + if (playerId == byte.MaxValue) + { + StuckPlayer = null; + if (Player != PlayerControl.LocalPlayer) return; + HudManagerStartPatch.stickyBomberButton.HasEffect = false; + HudManagerStartPatch.stickyBomberButton.Timer = HudManagerStartPatch.stickyBomberButton.MaxTimer; + return; + } + + var player = Helpers.playerById(playerId); + if (player == null) return; + RemainingDelay = StuckPlayer == null ? FirstDelay : OtherDelay; + if (StuckPlayer == null) + { + RemainingTime = Duration; + if (TriggerBothCooldown && Player == CachedPlayer.LocalPlayer.PlayerControl) + { + Player.killTimer = Duration + 1f; + } + } + + StuckPlayer = player; + } + + public static IEnumerator CoCreateBomb() + { + var timer = 0f; + while (timer <= Duration) + { + timer += Time.deltaTime; + if (StuckPlayer && StuckPlayer.Data.IsDead) + { + System.Console.WriteLine($"Stuck player is dead"); + RpcGiveBomb(byte.MaxValue); + if (HudManagerStartPatch.stickyBomberButton != null) + { + HudManagerStartPatch.stickyBomberButton.HasEffect = false; + HudManagerStartPatch.stickyBomberButton.Timer = 0.5f; + } + + if (TriggerBothCooldown) + { + Player.killTimer = 0.5f; + } + + break; + } + + yield return new WaitForEndOfFrame(); + } + + if (!Player || !StuckPlayer) yield break; + var killAttempt = Helpers.checkMurderAttemptAndKill(Player, StuckPlayer, showAnimation: false); + if (killAttempt == MurderAttemptResult.PerformKill) + { + var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, + (byte)CustomRPC.ShareGhostInfo, Hazel.SendOption.Reliable, -1); + writer.Write(CachedPlayer.LocalPlayer.PlayerId); + writer.Write((byte)RPCProcedure.GhostInfoTypes.DeathReasonAndKiller); + writer.Write(StuckPlayer.PlayerId); + writer.Write((byte)DeadPlayer.CustomDeathReason.StickyBomb); + writer.Write(Player.PlayerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + GameHistory.overrideDeathReasonAndKiller(StuckPlayer, DeadPlayer.CustomDeathReason.StickyBomb, + killer: StickyBomber.Player); + } + + RpcGiveBomb(byte.MaxValue); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Swapper.cs b/BetterOtherRoles/Roles/Swapper.cs new file mode 100644 index 0000000..5b3f39b --- /dev/null +++ b/BetterOtherRoles/Roles/Swapper.cs @@ -0,0 +1,38 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Swapper +{ + public static PlayerControl swapper; + public static Color color = new Color32(134, 55, 86, byte.MaxValue); + private static Sprite spriteCheck; + public static bool canCallEmergency = false; + public static bool canOnlySwapOthers = false; + public static int charges; + public static float rechargeTasksNumber; + public static float rechargedTasks; + + public static byte playerId1 = byte.MaxValue; + public static byte playerId2 = byte.MaxValue; + + public static Sprite getCheckSprite() + { + if (spriteCheck) return spriteCheck; + spriteCheck = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SwapperCheck.png", 150f); + return spriteCheck; + } + + public static void clearAndReload() + { + swapper = null; + playerId1 = byte.MaxValue; + playerId2 = byte.MaxValue; + canCallEmergency = CustomOptionHolder.SwapperCanCallEmergency.GetBool(); + canOnlySwapOthers = CustomOptionHolder.SwapperCanOnlySwapOther.GetBool(); + charges = Mathf.RoundToInt(CustomOptionHolder.SwapperSwapsNumber.GetFloat()); + rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.SwapperRechargeTasksNumber.GetFloat()); + rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.SwapperRechargeTasksNumber.GetFloat()); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Thief.cs b/BetterOtherRoles/Roles/Thief.cs new file mode 100644 index 0000000..859edc0 --- /dev/null +++ b/BetterOtherRoles/Roles/Thief.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Thief +{ + public static PlayerControl thief; + public static Color color = new Color32(71, 99, 45, byte.MaxValue); + public static PlayerControl currentTarget; + public static PlayerControl formerThief; + + public static float cooldown = 30f; + + public static bool suicideFlag = false; // Used as a flag for suicide + + public static bool hasImpostorVision; + public static bool canUseVents; + public static bool canKillSheriff; + public static bool canStealWithGuess; + + public static void clearAndReload() + { + thief = null; + suicideFlag = false; + currentTarget = null; + formerThief = null; + hasImpostorVision = CustomOptionHolder.ThiefHasImpVision.GetBool(); + cooldown = CustomOptionHolder.ThiefCooldown.GetFloat(); + canUseVents = CustomOptionHolder.ThiefCanUseVents.GetBool(); + canKillSheriff = CustomOptionHolder.ThiefCanKillSheriff.GetBool(); + canStealWithGuess = CustomOptionHolder.ThiefCanStealWithGuess.GetBool(); + } + + public static bool isFailedThiefKill(PlayerControl target, PlayerControl killer, RoleInfo targetRole) + { + return killer == Thief.thief && !target.Data.Role.IsImpostor && !new List + { RoleInfo.jackal, canKillSheriff ? RoleInfo.sheriff : null, RoleInfo.sidekick }.Contains(targetRole); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/TimeMaster.cs b/BetterOtherRoles/Roles/TimeMaster.cs new file mode 100644 index 0000000..7b8ff2a --- /dev/null +++ b/BetterOtherRoles/Roles/TimeMaster.cs @@ -0,0 +1,37 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class TimeMaster +{ + public static PlayerControl timeMaster; + public static Color color = new Color32(112, 142, 239, byte.MaxValue); + + public static bool reviveDuringRewind = false; + public static float rewindTime = 3f; + public static float shieldDuration = 3f; + public static float cooldown = 30f; + + public static bool shieldActive = false; + public static bool isRewinding = false; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TimeShieldButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + timeMaster = null; + isRewinding = false; + shieldActive = false; + rewindTime = CustomOptionHolder.TimeMasterRewindTime.GetFloat(); + shieldDuration = CustomOptionHolder.TimeMasterShieldDuration.GetFloat(); + cooldown = CustomOptionHolder.TimeMasterCooldown.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Tracker.cs b/BetterOtherRoles/Roles/Tracker.cs new file mode 100644 index 0000000..65b3a2c --- /dev/null +++ b/BetterOtherRoles/Roles/Tracker.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Tracker +{ + public static PlayerControl tracker; + public static Color color = new Color32(100, 58, 220, byte.MaxValue); + public static List localArrows = new List(); + + public static float updateIntervall = 5f; + public static bool resetTargetAfterMeeting = false; + public static bool canTrackCorpses = false; + public static float corpsesTrackingCooldown = 30f; + public static float corpsesTrackingDuration = 5f; + public static float corpsesTrackingTimer = 0f; + public static List deadBodyPositions = new List(); + + 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 trackCorpsesButtonSprite; + + public static Sprite getTrackCorpsesButtonSprite() + { + if (trackCorpsesButtonSprite) return trackCorpsesButtonSprite; + trackCorpsesButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PathfindButton.png", 115f); + return trackCorpsesButtonSprite; + } + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TrackerButton.png", 115f); + return buttonSprite; + } + + public static void resetTracked() + { + currentTarget = tracked = null; + usedTracker = false; + if (arrow?.arrow != null) UnityEngine.Object.Destroy(arrow.arrow); + arrow = new Arrow(Color.blue); + if (arrow.arrow != null) arrow.arrow.SetActive(false); + } + + public static void clearAndReload() + { + tracker = null; + resetTracked(); + timeUntilUpdate = 0f; + updateIntervall = CustomOptionHolder.TrackerUpdateInterval.GetFloat(); + resetTargetAfterMeeting = CustomOptionHolder.TrackerResetTargetAfterMeeting.GetBool(); + if (localArrows != null) + { + foreach (Arrow arrow in localArrows) + if (arrow?.arrow != null) + UnityEngine.Object.Destroy(arrow.arrow); + } + + deadBodyPositions = new List(); + corpsesTrackingTimer = 0f; + corpsesTrackingCooldown = CustomOptionHolder.TrackerCorpsesTrackingCooldown.GetFloat(); + corpsesTrackingDuration = CustomOptionHolder.TrackerCorpsesTrackingDuration.GetFloat(); + canTrackCorpses = CustomOptionHolder.TrackerCanTrackCorpses.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Trapper.cs b/BetterOtherRoles/Roles/Trapper.cs new file mode 100644 index 0000000..b73f892 --- /dev/null +++ b/BetterOtherRoles/Roles/Trapper.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Trapper +{ + public static PlayerControl trapper; + public static Color color = new Color32(110, 57, 105, byte.MaxValue); + + public static float cooldown = 30f; + public static int maxCharges = 5; + public static int rechargeTasksNumber = 3; + public static int rechargedTasks = 3; + public static int charges = 1; + public static int trapCountToReveal = 2; + public static List playersOnMap = new List(); + public static bool anonymousMap = false; + public static int infoType = 0; // 0 = Role, 1 = Good/Evil, 2 = Name + public static float trapDuration = 5f; + + private static Sprite trapButtonSprite; + + public static Sprite getButtonSprite() + { + if (trapButtonSprite) return trapButtonSprite; + trapButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.Trapper_Place_Button.png", 115f); + return trapButtonSprite; + } + + public static void clearAndReload() + { + trapper = null; + cooldown = CustomOptionHolder.TrapperCooldown.GetFloat(); + maxCharges = Mathf.RoundToInt(CustomOptionHolder.TrapperMaxCharges.GetFloat()); + rechargeTasksNumber = Mathf.RoundToInt(CustomOptionHolder.TrapperRechargeTasksNumber.GetFloat()); + rechargedTasks = Mathf.RoundToInt(CustomOptionHolder.TrapperRechargeTasksNumber.GetFloat()); + charges = Mathf.RoundToInt(CustomOptionHolder.TrapperMaxCharges.GetFloat()) / 2; + trapCountToReveal = Mathf.RoundToInt(CustomOptionHolder.TrapperTrapNeededTriggerToReveal.GetFloat()); + playersOnMap = new List(); + anonymousMap = CustomOptionHolder.TrapperAnonymousMap.GetBool(); + infoType = CustomOptionHolder.TrapperInfoType.CurrentSelection; + trapDuration = CustomOptionHolder.TrapperTrapDuration.GetFloat(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Trickster.cs b/BetterOtherRoles/Roles/Trickster.cs new file mode 100644 index 0000000..dbdb97c --- /dev/null +++ b/BetterOtherRoles/Roles/Trickster.cs @@ -0,0 +1,53 @@ +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Trickster +{ + public static PlayerControl trickster; + public static Color color = Palette.ImpostorRed; + public static float placeBoxCooldown = 30f; + public static float lightsOutCooldown = 30f; + public static float lightsOutDuration = 10f; + public static float lightsOutTimer = 0f; + + private static Sprite placeBoxButtonSprite; + private static Sprite lightOutButtonSprite; + private static Sprite tricksterVentButtonSprite; + + public static Sprite getPlaceBoxButtonSprite() + { + if (placeBoxButtonSprite) return placeBoxButtonSprite; + placeBoxButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.PlaceJackInTheBoxButton.png", 115f); + return placeBoxButtonSprite; + } + + public static Sprite getLightsOutButtonSprite() + { + if (lightOutButtonSprite) return lightOutButtonSprite; + lightOutButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.LightsOutButton.png", 115f); + return lightOutButtonSprite; + } + + public static Sprite getTricksterVentButtonSprite() + { + if (tricksterVentButtonSprite) return tricksterVentButtonSprite; + tricksterVentButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.TricksterVentButton.png", 115f); + return tricksterVentButtonSprite; + } + + public static void clearAndReload() + { + trickster = null; + lightsOutTimer = 0f; + placeBoxCooldown = CustomOptionHolder.TricksterPlaceBoxCooldown.GetFloat(); + lightsOutCooldown = CustomOptionHolder.TricksterLightsOutCooldown.GetFloat(); + lightsOutDuration = CustomOptionHolder.TricksterLightsOutDuration.GetFloat(); + JackInTheBox.UpdateStates(); // if the role is erased, we might have to update the state of the created objects + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Undertaker.cs b/BetterOtherRoles/Roles/Undertaker.cs new file mode 100644 index 0000000..16eaeb5 --- /dev/null +++ b/BetterOtherRoles/Roles/Undertaker.cs @@ -0,0 +1,65 @@ +using System.Linq; +using BetterOtherRoles.Players; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Undertaker +{ + public static PlayerControl Player; + public static readonly Color Color = Palette.ImpostorRed; + public static DeadBody DraggedBody; + public static DeadBody TargetBody; + public static bool CanDropBody; + + public static Sprite DragButtonSprite => + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DragButton.png", 115f); + + public static Sprite DropButtonSprite => + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.DropButton.png", 115f); + + public static void ClearAndReload() + { + Player = null; + DraggedBody = null; + TargetBody = null; + } + + public static void RpcDropBody(Vector3 position) + { + if (Player == null) return; + var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, + (byte)CustomRPC.UndertakerDropBody, Hazel.SendOption.Reliable, -1); + writer.Write(position.x); + writer.Write(position.y); + writer.Write(position.z); + AmongUsClient.Instance.FinishRpcImmediately(writer); + DropBody(position); + } + + public static void DropBody(Vector3 position) + { + if (!DraggedBody) return; + DraggedBody.transform.position = position; + DraggedBody = null; + TargetBody = null; + } + + public static void RpcDragBody(byte playerId) + { + if (Player == null) return; + var writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, + (byte)CustomRPC.UndertakerDragBody, Hazel.SendOption.Reliable, -1); + writer.Write(playerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + DragBody(playerId); + } + + public static void DragBody(byte playerId) + { + if (Player == null) return; + var body = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(b => b.ParentId == playerId); + if (body == null) return; + DraggedBody = body; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Vampire.cs b/BetterOtherRoles/Roles/Vampire.cs new file mode 100644 index 0000000..4870ada --- /dev/null +++ b/BetterOtherRoles/Roles/Vampire.cs @@ -0,0 +1,51 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Vampire +{ + public static PlayerControl vampire; + public static Color color = Palette.ImpostorRed; + + public static float delay = 10f; + public static float cooldown = 30f; + public static bool canKillNearGarlics = true; + 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("BetterOtherRoles.Resources.VampireButton.png", 115f); + return buttonSprite; + } + + private static Sprite garlicButtonSprite; + + public static Sprite getGarlicButtonSprite() + { + if (garlicButtonSprite) return garlicButtonSprite; + garlicButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.GarlicButton.png", 115f); + return garlicButtonSprite; + } + + public static void clearAndReload() + { + vampire = null; + bitten = null; + targetNearGarlic = false; + localPlacedGarlic = false; + currentTarget = null; + garlicsActive = CustomOptionHolder.VampireSpawnRate.CurrentSelection > 0; + delay = CustomOptionHolder.VampireKillDelay.GetFloat(); + cooldown = CustomOptionHolder.VampireCooldown.GetFloat(); + canKillNearGarlics = CustomOptionHolder.VampireCanKillNearGarlics.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Vulture.cs b/BetterOtherRoles/Roles/Vulture.cs new file mode 100644 index 0000000..faf6da6 --- /dev/null +++ b/BetterOtherRoles/Roles/Vulture.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using BetterOtherRoles.Objects; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Vulture +{ + public static PlayerControl vulture; + public static Color color = new Color32(139, 69, 19, byte.MaxValue); + public static List localArrows = new List(); + public static float cooldown = 30f; + public static int vultureNumberToWin = 4; + public static int eatenBodies = 0; + public static bool triggerVultureWin = false; + public static bool canUseVents = true; + public static bool showArrows = true; + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.VultureButton.png", 115f); + return buttonSprite; + } + + public static void clearAndReload() + { + vulture = null; + vultureNumberToWin = Mathf.RoundToInt(CustomOptionHolder.VultureNumberToWin.GetFloat()); + eatenBodies = 0; + cooldown = CustomOptionHolder.VultureCooldown.GetFloat(); + triggerVultureWin = false; + canUseVents = CustomOptionHolder.VultureCanUseVents.GetBool(); + showArrows = CustomOptionHolder.VultureShowArrow.GetBool(); + if (localArrows != null) + { + foreach (Arrow arrow in localArrows) + if (arrow?.arrow != null) + UnityEngine.Object.Destroy(arrow.arrow); + } + + localArrows = new List(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Warlock.cs b/BetterOtherRoles/Roles/Warlock.cs new file mode 100644 index 0000000..ee9b271 --- /dev/null +++ b/BetterOtherRoles/Roles/Warlock.cs @@ -0,0 +1,55 @@ +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Warlock +{ + public static PlayerControl warlock; + public static Color color = Palette.ImpostorRed; + + public static PlayerControl currentTarget; + public static PlayerControl curseVictim; + public static PlayerControl curseVictimTarget; + + public static float cooldown = 30f; + public static float rootTime = 5f; + + private static Sprite curseButtonSprite; + private static Sprite curseKillButtonSprite; + + public static Sprite getCurseButtonSprite() + { + if (curseButtonSprite) return curseButtonSprite; + curseButtonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CurseButton.png", 115f); + return curseButtonSprite; + } + + public static Sprite getCurseKillButtonSprite() + { + if (curseKillButtonSprite) return curseKillButtonSprite; + curseKillButtonSprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.CurseKillButton.png", 115f); + return curseKillButtonSprite; + } + + public static void clearAndReload() + { + warlock = null; + currentTarget = null; + curseVictim = null; + curseVictimTarget = null; + cooldown = CustomOptionHolder.WarlockCooldown.GetFloat(); + rootTime = CustomOptionHolder.WarlockRootTime.GetFloat(); + } + + public static void resetCurse() + { + HudManagerStartPatch.warlockCurseButton.Timer = HudManagerStartPatch.warlockCurseButton.MaxTimer; + HudManagerStartPatch.warlockCurseButton.Sprite = Warlock.getCurseButtonSprite(); + HudManagerStartPatch.warlockCurseButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + currentTarget = null; + curseVictim = null; + curseVictimTarget = null; + } +} \ No newline at end of file diff --git a/BetterOtherRoles/Roles/Witch.cs b/BetterOtherRoles/Roles/Witch.cs new file mode 100644 index 0000000..e87f530 --- /dev/null +++ b/BetterOtherRoles/Roles/Witch.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using BetterOtherRoles.Options; +using UnityEngine; + +namespace BetterOtherRoles.Roles; + +public static class Witch +{ + public static PlayerControl witch; + public static Color color = Palette.ImpostorRed; + + public static List futureSpelled = new List(); + public static PlayerControl currentTarget; + public static PlayerControl spellCastingTarget; + public static float cooldown = 30f; + public static float spellCastingDuration = 2f; + public static float cooldownAddition = 10f; + public static float currentCooldownAddition = 0f; + public static bool canSpellAnyone = false; + public static bool triggerBothCooldowns = true; + public static bool witchVoteSavesTargets = true; + + private static Sprite buttonSprite; + + public static Sprite getButtonSprite() + { + if (buttonSprite) return buttonSprite; + buttonSprite = Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SpellButton.png", 115f); + return buttonSprite; + } + + private static Sprite spelledOverlaySprite; + + public static Sprite getSpelledOverlaySprite() + { + if (spelledOverlaySprite) return spelledOverlaySprite; + spelledOverlaySprite = + Helpers.loadSpriteFromResources("BetterOtherRoles.Resources.SpellButtonMeeting.png", 225f); + return spelledOverlaySprite; + } + + + public static void clearAndReload() + { + witch = null; + futureSpelled = new List(); + currentTarget = spellCastingTarget = null; + cooldown = CustomOptionHolder.WitchCooldown.GetFloat(); + cooldownAddition = CustomOptionHolder.WitchAdditionalCooldown.GetFloat(); + currentCooldownAddition = 0f; + canSpellAnyone = CustomOptionHolder.WitchCanSpellAnyone.GetBool(); + spellCastingDuration = CustomOptionHolder.WitchSpellCastingDuration.GetFloat(); + triggerBothCooldowns = CustomOptionHolder.WitchTriggerBothCooldown.GetBool(); + witchVoteSavesTargets = CustomOptionHolder.WitchVoteSavesTargets.GetBool(); + } +} \ No newline at end of file diff --git a/BetterOtherRoles/TasksHandler.cs b/BetterOtherRoles/TasksHandler.cs index da61395..2d92bc7 100644 --- a/BetterOtherRoles/TasksHandler.cs +++ b/BetterOtherRoles/TasksHandler.cs @@ -1,5 +1,7 @@ using HarmonyLib; using System; +using BetterOtherRoles.Modifiers; +using BetterOtherRoles.Roles; using BetterOtherRoles.Utilities; namespace BetterOtherRoles { diff --git a/BetterOtherRoles/UI/BetterUIBehaviour.cs b/BetterOtherRoles/UI/BetterUIBehaviour.cs index bf62477..5ea4f03 100644 --- a/BetterOtherRoles/UI/BetterUIBehaviour.cs +++ b/BetterOtherRoles/UI/BetterUIBehaviour.cs @@ -10,10 +10,6 @@ public class BetterUIBehaviour : MonoBehaviour { private void Update() { - if (InputManager.GetKeyDown(KeyCode.F2)) - { - UIManager.CustomOptionsPanel?.Toggle(); - } #if DEBUG if (InputManager.GetKeyDown(KeyCode.F3)) { diff --git a/BetterOtherRoles/UI/Components/CustomOptionViewer.cs b/BetterOtherRoles/UI/Components/CustomOptionViewer.cs deleted file mode 100644 index 391f714..0000000 --- a/BetterOtherRoles/UI/Components/CustomOptionViewer.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using BetterOtherRoles.Modules; -using BetterOtherRoles.UI.Panels; -using UnityEngine; -using UnityEngine.UI; -using UniverseLib.UI; - -namespace BetterOtherRoles.UI.Components; - -public class CustomOptionViewer -{ - public static readonly List Options = new(); - - private readonly CustomOption _option; - private readonly GameObject _container; - private readonly Text _label; - private readonly Text _value; - - public CustomOptionViewer(CustomOptionsPanel panel, GameObject contentRoot, CustomOption option) - { - _option = option; - var depth = Depth; - var group = contentRoot; - - _container = UIFactory.CreateHorizontalGroup(group, "Container", - false, true, true, - true, padding: new Vector4(0f + (_option.isHeader ? 20f : 0f), 0f, 10f, 0f), bgColor: UIPalette.Transparent); - UIFactory.SetLayoutElement(_container, minHeight: 35, flexibleHeight: 9999, minWidth: panel.MinWidth, - flexibleWidth: 0); - - _label = UIFactory.CreateLabel(_container, "Label", string.Empty); - UIFactory.SetLayoutElement(_label.gameObject, 350, 25, 0, 0); - var container = UIFactory.CreateUIObject("EditorValueContainer", _container); - UIFactory.SetLayoutGroup(container, true, false, true, true, 0, - childAlignment: TextAnchor.MiddleRight, padRight: 20, padLeft: 20); - - var valueString = _option.DisplayUIValue; - - var valueContainer = UIFactory.CreateHorizontalGroup(container, "ValueContainer", - true, true, true, true, - padding: new Vector4(0f, 0f, 5f, 5f), childAlignment: TextAnchor.MiddleRight); - UIFactory.SetLayoutElement(valueContainer, 200, 30, flexibleWidth: 0, 0); - _value = UIFactory.CreateLabel(valueContainer, "ValueLabel", valueString, - TextAnchor.MiddleRight, UIPalette.Secondary); - _value.alignment = TextAnchor.MiddleCenter; - _value.fontSize = 18; - - _label.text = _option.name; - _label.color = UIPalette.Secondary; - _label.fontSize = 18; - - Options.Add(this); - SetActive(IsParentActive); - _option.OnChange += UpdateValue; - } - - private void UpdateValue() - { - _value.text = _option.DisplayUIValue; - var subOptions = Options.Where(o => o._option.parent == _option); - foreach (var subOption in subOptions) - { - subOption.UpdateValue(); - } - SetActive(IsParentActive); - } - - public void SetActive(bool active) - { - _container.SetActive(active); - } - - private int Depth - { - get - { - var currentOption = _option; - var depth = 0; - while (currentOption.parent != null) - { - depth++; - currentOption = currentOption.parent; - } - - return depth; - } - } - - private bool IsParentActive - { - get - { - if (_option.parent == null) return true; - var currentOption = _option; - var active = true; - while (currentOption.parent != null && active) - { - currentOption = currentOption.parent; - active = currentOption.selection > 0; - } - - return active; - } - } - - private bool HasChildren => CustomOption.options.Any(o => o.parent == _option); -} \ No newline at end of file diff --git a/BetterOtherRoles/UI/Panels.cs b/BetterOtherRoles/UI/Panels.cs index 8b4a297..abbb888 100644 --- a/BetterOtherRoles/UI/Panels.cs +++ b/BetterOtherRoles/UI/Panels.cs @@ -6,24 +6,18 @@ public static partial class UIManager { private static bool _initialized = false; public static OverlayPanel Overlay { get; private set; } - public static CustomOptionsPanel CustomOptionsPanel { get; private set; } public static LocalOptionsPanel LocalOptionsPanel { get; private set; } public static CreditsPanel CreditsPanel { get; private set; } public static StickyBombPanel StickyBombPanel { get; private set; } - public static VersionHandshakePanel VersionHandshakePanel { get; private set; } - public static UpdatePluginPanel UpdatePluginPanel { get; private set; } private static void InitPanels() { if (UiBase == null) return; Overlay = new OverlayPanel(UiBase); - CustomOptionsPanel = new CustomOptionsPanel(UiBase); LocalOptionsPanel = new LocalOptionsPanel(UiBase); CreditsPanel = new CreditsPanel(UiBase); StickyBombPanel = new StickyBombPanel(UiBase); - VersionHandshakePanel = new VersionHandshakePanel(UiBase); - UpdatePluginPanel = new UpdatePluginPanel(UiBase); _initialized = true; } @@ -31,10 +25,8 @@ private static void InitPanels() public static void CloseAllPanels() { if (!_initialized) return; - CustomOptionsPanel.SetActive(false); LocalOptionsPanel.SetActive(false); CreditsPanel.SetActive(false); StickyBombPanel.SetActive(false); - VersionHandshakePanel.SetActive(false); } } \ No newline at end of file diff --git a/BetterOtherRoles/UI/Panels/CustomOptionsPanel.cs b/BetterOtherRoles/UI/Panels/CustomOptionsPanel.cs deleted file mode 100644 index 4fbe917..0000000 --- a/BetterOtherRoles/UI/Panels/CustomOptionsPanel.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using BetterOtherRoles.Modules; -using BetterOtherRoles.UI.Components; -using UnityEngine; -using UnityEngine.UI; -using UniverseLib; -using UniverseLib.UI; - -namespace BetterOtherRoles.UI.Panels; - -public class CustomOptionsPanel : WrappedPanel -{ - public CustomOptionsPanel(UIBase owner) : base(owner) - { - } - - public override string Name => $"BetterOtherRoles v{BetterOtherRolesPlugin.VersionString}"; - - public override int MinWidth => 600; - public override int MinHeight => Screen.height; - public override bool CanDragAndResize => false; - public override bool ShowByDefault => false; - public override bool DisplayTitleBar => true; - public override Color BackgroundColor => UIPalette.Dark; - public override bool AlwaysOnTop => true; - public override Positions Position => Positions.TopLeft; - - private readonly Dictionary _categoryHolders = new(); - - private readonly Dictionary _categories = new() - { - { CustomOption.CustomOptionType.General, "Mods settings" }, - { CustomOption.CustomOptionType.Guesser, "Guesser Mode Settings" }, - { CustomOption.CustomOptionType.Impostor, "Impostor Roles Settings" }, - { CustomOption.CustomOptionType.Neutral, "Neutral Roles Settings" }, - { CustomOption.CustomOptionType.Crewmate, "Crewmate Roles Settings" }, - { CustomOption.CustomOptionType.Modifier, "Modifier Settings" }, - { CustomOption.CustomOptionType.HideNSeekMain, "Hide 'N Seek Settings" }, - { CustomOption.CustomOptionType.HideNSeekRoles, "Hide 'N Seek Roles Settings" }, - }; - - private List Categories - { - get - { - return TORMapOptions.gameMode switch - { - CustomGamemodes.Classic => new List - { - CustomOption.CustomOptionType.General, - CustomOption.CustomOptionType.Impostor, - CustomOption.CustomOptionType.Neutral, - CustomOption.CustomOptionType.Crewmate, - CustomOption.CustomOptionType.Modifier - }, - CustomGamemodes.Guesser => new List - { - CustomOption.CustomOptionType.General, - CustomOption.CustomOptionType.Guesser, - CustomOption.CustomOptionType.Impostor, - CustomOption.CustomOptionType.Neutral, - CustomOption.CustomOptionType.Crewmate, - CustomOption.CustomOptionType.Modifier - }, - _ => new List - { - CustomOption.CustomOptionType.General, - CustomOption.CustomOptionType.HideNSeekMain, - CustomOption.CustomOptionType.HideNSeekRoles - }, - }; - } - } - - private Text _categoryTitle = null!; - private int _currentIndex; - - protected override void ConstructPanelContent() - { - base.ConstructPanelContent(); - var titleContainer = UIFactory.CreateHorizontalGroup(ContentRoot, "TitleContainer", false, false, true, true, - 0, new Vector4(5f, 5f, 0f, 0f), UIPalette.Transparent); - UIFactory.SetLayoutElement(titleContainer, minHeight: 40, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - - var previousButton = UIFactory.CreateButton(titleContainer, "PreviousButton", "\u27a4", UIPalette.Black); - RuntimeHelper.SetColorBlock(previousButton.Component, UIPalette.Black, UIPalette.Black, - UIPalette.Black, UIPalette.Black); - UIFactory.SetLayoutElement(previousButton.GameObject, 30, 30, 0, 0); - previousButton.ButtonText.transform.Rotate(Vector3.up, 180f); - previousButton.ButtonText.fontSize = 20; - previousButton.OnClick = PreviousCategory; - - _categoryTitle = UIFactory.CreateLabel(titleContainer, "Title", "Custom options", TextAnchor.MiddleCenter, - UIPalette.Secondary, true, 20); - _categoryTitle.fontStyle = FontStyle.Bold; - UIFactory.SetLayoutElement(_categoryTitle.gameObject, minWidth: MinWidth - 66, flexibleWidth: 0, minHeight: 30, - flexibleHeight: 0); - - var nextButton = UIFactory.CreateButton(titleContainer, "NextButton", "\u27a4", UIPalette.Black); - RuntimeHelper.SetColorBlock(nextButton.Component, UIPalette.Black, UIPalette.Black, - UIPalette.Black, UIPalette.Black); - UIFactory.SetLayoutElement(nextButton.GameObject, 30, 30, 0, 0); - nextButton.ButtonText.fontSize = 20; - nextButton.OnClick = NextCategory; - ConstructCustomOptions(); - } - - private void ResetCategories() - { - HideCurrentCategory(); - _currentIndex = 0; - UpdateCurrentCategory(); - } - - public void CheckForUpdate(CustomGamemodes oldGameMode, CustomGamemodes newGameMode) - { - if (oldGameMode == newGameMode) return; - ResetCategories(); - } - - private void ConstructCustomOptions() - { - var i = 0; - foreach (var category in _categories) - { - _categoryHolders[i] = - UIFactory.CreateScrollView(ContentRoot, "CustomOptionsScrollView", out var content, out var _); - UIFactory.SetLayoutElement(_categoryHolders[i], MinWidth, 25, 0, 9999); - UIFactory.SetLayoutElement(content, MinWidth, 25, 0, 9999); - var options = CustomOption.options.Where(o => o.type == category.Key); - foreach (var option in options) - { - _ = new CustomOptionViewer(this, content, option); - } - _categoryHolders[i].SetActive(false); - i++; - } - _currentIndex = 0; - UpdateCurrentCategory(); - } - - private void HideCurrentCategory() - { - CurrentCategoryHolder.SetActive(false); - } - - private void PreviousCategory() - { - HideCurrentCategory(); - _currentIndex--; - if (_currentIndex < 0) - { - _currentIndex = Categories.Count - 1; - } - - UpdateCurrentCategory(); - } - - private void NextCategory() - { - HideCurrentCategory(); - _currentIndex++; - if (_currentIndex >= Categories.Count) - { - _currentIndex = 0; - } - - UpdateCurrentCategory(); - } - - private void UpdateCurrentCategory() - { - CurrentCategoryHolder.SetActive(true); - } - - private GameObject CurrentCategoryHolder - { - get - { - var categories = Categories; - var key = categories[_currentIndex]; - var category = _categories[key]; - _categoryTitle.text = category; - return _categoryHolders[_categories.Keys.ToList().IndexOf(key)]; - } - } - - public override void SetActive(bool active) - { - if (active) - { - // UpdateEditable(); - } - UIManager.Overlay?.SetActive(active); - base.SetActive(active); - Owner.SetOnTop(); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/UI/Panels/StickyBombPanel.cs b/BetterOtherRoles/UI/Panels/StickyBombPanel.cs index 2f9788d..2b0ed65 100644 --- a/BetterOtherRoles/UI/Panels/StickyBombPanel.cs +++ b/BetterOtherRoles/UI/Panels/StickyBombPanel.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using BetterOtherRoles.Roles; +using UnityEngine; using UnityEngine.UI; using UniverseLib.UI; diff --git a/BetterOtherRoles/UI/Panels/UpdatePluginPanel.cs b/BetterOtherRoles/UI/Panels/UpdatePluginPanel.cs deleted file mode 100644 index 8456183..0000000 --- a/BetterOtherRoles/UI/Panels/UpdatePluginPanel.cs +++ /dev/null @@ -1,234 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using BepInEx.Unity.IL2CPP.Utils; -using BetterOtherRoles.Eno; -using BetterOtherRoles.Modules; -using BetterOtherRoles.UI.Components; -using UnityEngine; -using UnityEngine.UI; -using UniverseLib; -using UniverseLib.UI; -using UniverseLib.UI.Models; - -namespace BetterOtherRoles.UI.Panels; - -public class UpdatePluginPanel : WrappedPanel -{ - public UpdatePluginPanel(UIBase owner) : base(owner) - { - } - - public override string Name => $"BetterOtherRoles Updater"; - - public override int MinWidth => 600; - public override int MinHeight => 600; - public override bool CanDragAndResize => false; - public override bool ShowByDefault => false; - public override bool DisplayTitleBar => true; - public override Color BackgroundColor => UIPalette.Dark; - public override bool AlwaysOnTop => true; - public override Positions Position => Positions.MiddleCenter; - - private Text _categoryTitle = null!; - - private GameObject _titleContainer; - private GameObject _dropdownObject; - private Text _releaseName; - private Text _releaseDescription; - private ButtonRef _downloadButton; - private Components.ProgressBar _progressBar; - private Text _progressInfos; - - [HideFromIl2Cpp] - private GithubRelease _selectedRelease { get; set; } - - private readonly Dictionary _githubReleases = new(); - - protected override void ConstructPanelContent() - { - base.ConstructPanelContent(); - _titleContainer = UIFactory.CreateHorizontalGroup(ContentRoot, "TitleContainer", false, false, true, true, - 0, new Vector4(5f, 5f, 5f, 0f), UIPalette.Transparent); - UIFactory.SetLayoutElement(_titleContainer, minHeight: 40, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - - _categoryTitle = UIFactory.CreateLabel(_titleContainer, "Title", "Select a version to install:", TextAnchor.MiddleLeft, - UIPalette.Secondary, true, 18); - _categoryTitle.fontStyle = FontStyle.Bold; - UIFactory.SetLayoutElement(_categoryTitle.gameObject, minWidth: 260, flexibleWidth: 0, minHeight: 40, - flexibleHeight: 0); - - var releaseNameContainer = UIFactory.CreateHorizontalGroup(ContentRoot, "ReleaseNameContainer", false, false, true, true, - 0, new Vector4(5f, 5f, 5f, 0f), UIPalette.Transparent, TextAnchor.MiddleCenter); - UIFactory.SetLayoutElement(releaseNameContainer, minHeight: 60, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - _releaseName = UIFactory.CreateLabel(releaseNameContainer, "ReleaseTitle", string.Empty, TextAnchor.MiddleCenter, fontSize: 30); - UIFactory.SetLayoutElement(_releaseName.gameObject, MinWidth, flexibleWidth: 0, minHeight: 40, flexibleHeight: 0); - - var buttonsContainer = UIFactory.CreateVerticalGroup(ContentRoot, "ButtonsContainer", false, false, true, true, - 0, new Vector4(5f, 5f, 5f, 0f), UIPalette.Transparent, TextAnchor.MiddleCenter); - UIFactory.SetLayoutElement(buttonsContainer, minHeight: 60, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - _downloadButton = UIFactory.CreateButton(buttonsContainer, "DownloadButton", "Download & Install", UIPalette.Success); - UIFactory.SetLayoutElement(_downloadButton.GameObject, 300, flexibleWidth: 0, minHeight: 40, flexibleHeight: 0); - _downloadButton.Component.SetColorsAuto(UIPalette.Success); - _downloadButton.ButtonText.fontSize = 18; - _downloadButton.ButtonText.fontStyle = FontStyle.Bold; - _downloadButton.OnClick = OnDownloadButtonClick; - - _progressBar = new Components.ProgressBar(buttonsContainer, MinWidth - 40, 30); - _progressBar.SetActive(false); - - _progressInfos = UIFactory.CreateLabel(buttonsContainer, "ProgressInfos", string.Empty, TextAnchor.MiddleCenter, UIPalette.Secondary); - UIFactory.SetLayoutElement(_progressInfos.gameObject, MinWidth, flexibleWidth: 0, minHeight: 20, flexibleHeight: 0); - _progressInfos.gameObject.SetActive(false); - - var scrollbarContainer = UIFactory.CreateVerticalGroup(ContentRoot, "ScrollbarContainer", false, false, true, - true, 0, new Vector4(10f, 0f, 0f, 0f), UIPalette.Transparent); - UIFactory.SetLayoutElement(scrollbarContainer, minHeight: 400, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - - var scrollerObject = UIFactory.CreateScrollView(scrollbarContainer, "ReleaseScrollView", out var content, out _); - UIFactory.SetLayoutElement(scrollerObject, MinWidth, 25, 0, 9999); - UIFactory.SetLayoutElement(content, MinWidth, 25, 0, 9999); - - _releaseDescription = UIFactory.CreateLabel(content, "ReleaseDescription", string.Empty, TextAnchor.UpperLeft, fontSize: 18); - UIFactory.SetLayoutElement(_releaseDescription.gameObject, MinWidth, flexibleWidth: 0, minHeight: 40, flexibleHeight: 0); - } - - public void SetProgressInfosText(string text) - { - _progressInfos.text = text; - } - - public void SetProgressBarActive(bool value) - { - _progressInfos.gameObject.SetActive(value); - _progressBar.SetActive(value); - _downloadButton.GameObject.SetActive(!value); - } - - private void OnDownloadButtonClick() - { - if (_selectedRelease == null) return; - var isCompatible = _selectedRelease.Version.Major == BetterOtherRolesPlugin.Version.Major && _selectedRelease.Version.Minor == BetterOtherRolesPlugin.Version.Minor; - if (!isCompatible) return; - PluginUpdater.Instance.StartDownloadRelease(_selectedRelease); - } - - public void SetDownloadProgression(float progression) - { - _progressBar?.SetProgression(progression); - } - - private void RefreshSelectedRelease() - { - if (_selectedRelease == null) return; - var isCompatible = _selectedRelease.Version.Major == BetterOtherRolesPlugin.Version.Major && _selectedRelease.Version.Minor == BetterOtherRolesPlugin.Version.Minor; - var isUpgrade = _selectedRelease.IsNewer(BetterOtherRolesPlugin.Version); - var isReinstall = !isUpgrade && _selectedRelease.Version == BetterOtherRolesPlugin.Version; - var updateType = isUpgrade ? "Upgrade" : isReinstall ? "Reinstall" : "Downgrade"; - var updateTypeColor = isUpgrade ? Color.green : isReinstall ? UIPalette.Info : UIPalette.Warning; - var updateTypeArrow = isUpgrade ? "\u25b2" : isReinstall ? "=" : "\u25bc"; - _releaseName.text = $"{Helpers.cs(updateTypeColor, updateType)}: {Helpers.cs(Color.yellow, $"v{BetterOtherRolesPlugin.VersionString}")} {Helpers.cs(updateTypeColor, updateTypeArrow)} {_selectedRelease.Tag}"; - if (!isCompatible) - { - _releaseDescription.text = _selectedRelease.Description; - _downloadButton.ButtonText.text = "Unsupported game version"; - _downloadButton.Component.SetColorsAuto(UIPalette.Danger); - } - else if (isUpgrade) - { - var releases = _githubReleases.Values.Where(r => r.IsNewer(BetterOtherRolesPlugin.Version) && !r.IsNewer(_selectedRelease.Version)); - _releaseDescription.text = string.Join("\n", releases.Select(r => r.Description)); - _downloadButton.Component.SetColorsAuto(UIPalette.Success); - _downloadButton.ButtonText.text = $"Install {_selectedRelease.Name}"; - } - else - { - _releaseDescription.text = _selectedRelease.Description; - if (isReinstall) - { - _downloadButton.Component.SetColorsAuto(UIPalette.Info); - _downloadButton.ButtonText.text = $"Reinstall {_selectedRelease.Tag}"; - } - else - { - _downloadButton.Component.SetColorsAuto(UIPalette.Warning); - _downloadButton.ButtonText.text = $"Downgrade {_selectedRelease.Tag}"; - } - } - } - - public void RefreshDropdown(GithubRelease latestRelease = null) - { - if (_dropdownObject) UnityEngine.Object.Destroy(_dropdownObject); - var defaultItemText = string.Empty; - _githubReleases.Clear(); - if (PluginUpdater.Instance.Releases != null) - { - foreach (var release in PluginUpdater.Instance.Releases) - { - var isLatest = latestRelease?.Id == release.Id; - var isCompatible = release.Version.Major == BetterOtherRolesPlugin.Version.Major && release.Version.Minor == BetterOtherRolesPlugin.Version.Minor; - var isCurrent = release.Version == BetterOtherRolesPlugin.Version; - var isNewer = release.IsNewer(BetterOtherRolesPlugin.Version); - var color = isCurrent ? UIPalette.Info : !isCompatible ? Color.red : isNewer ? Color.green : UIPalette.Warning; - var text = release.Tag; - if (isCurrent) - { - text += " (current)"; - } - else if (!isCompatible) - { - text += " (incompatible)"; - } - else if (isLatest) - { - text += " (latest)"; - } - - var key = Helpers.cs(color, text); - - _githubReleases[key] = release; - if (isLatest) - { - defaultItemText = key; - } - } - } - _dropdownObject = UIFactory.CreateDropdown( - _titleContainer, - "VersionSelector", - out _, - defaultItemText, - 16, - OnVersionDropdownChanged, - _githubReleases.Keys.ToArray()); - UIFactory.SetLayoutElement(_dropdownObject, minWidth: 275, flexibleWidth: 0, minHeight: 40, flexibleHeight: 0); - if (latestRelease != null) - { - _selectedRelease = latestRelease; - } else if (_githubReleases.Count > 0) - { - _selectedRelease = _githubReleases.First().Value; - } - RefreshSelectedRelease(); - } - - private void OnVersionDropdownChanged(int value) - { - var key = _githubReleases.Keys.ToArray()[value]; - _selectedRelease = _githubReleases[key]; - RefreshSelectedRelease(); - } - - public override void SetActive(bool active) - { - UIManager.Overlay?.SetActive(active); - base.SetActive(active); - Owner.SetOnTop(); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/UI/Panels/VersionHandshakePanel.cs b/BetterOtherRoles/UI/Panels/VersionHandshakePanel.cs deleted file mode 100644 index 5705b37..0000000 --- a/BetterOtherRoles/UI/Panels/VersionHandshakePanel.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System.Text; -using BetterOtherRoles.Eno; -using BetterOtherRoles.Modules; -using BetterOtherRoles.Players; -using InnerNet; -using UnityEngine; -using UnityEngine.UI; -using UniverseLib.UI; - -namespace BetterOtherRoles.UI.Panels; - -public class VersionHandshakePanel : WrappedPanel -{ - public VersionHandshakePanel(UIBase owner) : base(owner) - { - } - - public override string Name => - $"BetterOtherRoles v{BetterOtherRolesPlugin.VersionString}"; - - public override int MinWidth => 250; - public override int MinHeight => 450; - public override bool CanDragAndResize => false; - public override bool ShowByDefault => false; - public override bool DisplayTitleBar => false; - public override bool CanClickThroughPanel => true; - public override Color BackgroundColor => UIPalette.Transparent; - public override bool AlwaysOnTop => false; - public override Positions Position => Positions.MiddleRight; - - private Text _content; - - protected override void ConstructPanelContent() - { - base.ConstructPanelContent(); - var container = UIFactory.CreateVerticalGroup(ContentRoot, "ImageContainer", - false, - false, - true, - true, - childAlignment: TextAnchor.UpperLeft); - container.GetComponent().color = UIPalette.Transparent; - UIFactory.SetLayoutElement(container, minHeight: MinHeight, flexibleHeight: 0, minWidth: MinWidth, - flexibleWidth: 0); - - _content = UIFactory.CreateLabel(container, "TextContent", "", TextAnchor.UpperLeft, - UIPalette.Secondary, true, 18); - UIFactory.SetLayoutElement(_content.gameObject, minWidth: MinWidth, flexibleWidth: 0, minHeight: 40, - flexibleHeight: 0); - } - - public void UpdateChecks() - { - if (AmongUsClient.Instance.GameState != InnerNetClient.GameStates.Joined || CachedPlayer.AllPlayers == null) - { - SetActive(false); - return; - } - SetActive(true); - var text = new StringBuilder(); - foreach (var player in CachedPlayer.AllPlayers) - { - if (player.Data == null) continue; - var clientId = player.PlayerControl.OwnerId; - var symbol = Helpers.cs(Palette.ImpostorRed, "✖"); - var playerName = player.Data.PlayerName; - var errorMessage = string.Empty; - if (AmongUsClient.Instance.HostId == clientId) - { - playerName = Helpers.cs(Color.magenta, playerName); - } - if (!VersionHandshake.Has(clientId)) - { - errorMessage = "missing or bad mod"; - } - else if (!VersionHandshake.Find(clientId).Version.Equals(VersionHandshake.Instance.Version)) - { - errorMessage = $"wrong version (v{VersionHandshake.Find(clientId).Version.ToString()})"; - } - else if (!VersionHandshake.Find(clientId).GuidMatch()) - { - errorMessage = "wrong build"; - } - else - { - symbol = Helpers.cs(Palette.AcceptedGreen, "✔️"); - var version = VersionHandshake.Find(clientId); - if (version.Flags.TryGetValue("LOBBY_NAME_COLOR", out var lobbyNameColor)) - { - try - { - var playerNameText = player.PlayerControl.cosmetics.nameText; - if (lobbyNameColor.ToLower() == "rainbow") - { - playerNameText.color = FirstKillShield.ShieldColor; - } else if (lobbyNameColor.StartsWith("#")) - { - playerNameText.color = Helpers.ColorFromHex(lobbyNameColor); - } - } - catch - { - // ignored - } - } - } - - var line = $"{symbol} {playerName}"; - if (errorMessage != string.Empty) - { - line += $": {Helpers.cs(Palette.ImpostorRed, errorMessage)}"; - } - - text.AppendLine(line); - } - - _content.text = text.ToString(); - } -} \ No newline at end of file diff --git a/BetterOtherRoles/UI/UIManager.cs b/BetterOtherRoles/UI/UIManager.cs index 18f3261..0301ff9 100644 --- a/BetterOtherRoles/UI/UIManager.cs +++ b/BetterOtherRoles/UI/UIManager.cs @@ -1,12 +1,10 @@ using System.Collections.Generic; using System.Linq; -using BetterOtherRoles.Eno; using BetterOtherRoles.Modules; using UnityEngine; using UniverseLib; using UniverseLib.Config; using UniverseLib.UI; -using xCloud; namespace BetterOtherRoles.UI; @@ -61,8 +59,6 @@ internal static void InitUi() panel.SetActive(panel.ShowByDefault); } - BetterOtherRolesPlugin.Instance.AddComponent(); - Initializing = false; } diff --git a/BetterOtherRoles/Utilities/EventUtility.cs b/BetterOtherRoles/Utilities/EventUtility.cs index 150311c..1d3eea7 100644 --- a/BetterOtherRoles/Utilities/EventUtility.cs +++ b/BetterOtherRoles/Utilities/EventUtility.cs @@ -9,6 +9,7 @@ using System.Linq; using InnerNet; using BetterOtherRoles.Modules; +using BetterOtherRoles.Options; namespace BetterOtherRoles.Utilities { public static class EventUtility { @@ -42,8 +43,8 @@ public static void Load() { public static void clearAndReload() { eventQueue = new List(); eventInvert = false; - if (canBeEnabled && CustomOptionHolder.enableCodenameDisableHorses != null) - disableHorses = CustomOptionHolder.enableCodenameDisableHorses.getBool(); + if (canBeEnabled && CustomOptionHolder.EnableCodenameDisableHorses != null) + disableHorses = CustomOptionHolder.EnableCodenameDisableHorses.GetBool(); } public static void Update() { @@ -66,7 +67,7 @@ public static void Update() { public static bool isEventDate => DateTime.Today.Date == enabled; public static bool canBeEnabled => DateTime.Today.Date > enabled && DateTime.Today.Date <= enabled.AddDays(7); // One Week after the EVENT - public static bool isEnabled => isEventDate || canBeEnabled && CustomOptionHolder.enableCodenameHorsemode != null && CustomOptionHolder.enableCodenameHorsemode.getBool(); + public static bool isEnabled => isEventDate || canBeEnabled && CustomOptionHolder.EnableCodenameHorseMode != null && CustomOptionHolder.EnableCodenameHorseMode.GetBool(); public static void AddToQueue(EventTypes newEvent) { if (!isEnabled || eventQueue == null || eventQueue.Contains(newEvent)) return; diff --git a/BetterOtherRoles/Utilities/HandleGuesser.cs b/BetterOtherRoles/Utilities/HandleGuesser.cs index 268dc32..096ac67 100644 --- a/BetterOtherRoles/Utilities/HandleGuesser.cs +++ b/BetterOtherRoles/Utilities/HandleGuesser.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Text; using BetterOtherRoles.CustomGameModes; +using BetterOtherRoles.Options; +using BetterOtherRoles.Roles; using UnityEngine; namespace BetterOtherRoles.Utilities { @@ -39,15 +41,15 @@ public static void clearAndReload() { GuesserGM.clearAndReload(); isGuesserGm = TORMapOptions.gameMode == CustomGamemodes.Guesser; if (isGuesserGm) { - guesserCantGuessSnitch = CustomOptionHolder.guesserGamemodeCantGuessSnitchIfTaksDone.getBool(); - hasMultipleShotsPerMeeting = CustomOptionHolder.guesserGamemodeHasMultipleShotsPerMeeting.getBool(); - killsThroughShield = CustomOptionHolder.guesserGamemodeKillsThroughShield.getBool(); - evilGuesserCanGuessSpy = CustomOptionHolder.guesserGamemodeEvilCanKillSpy.getBool(); + guesserCantGuessSnitch = CustomOptionHolder.GuesserModeCantGuessSnitchIfTasksDone.GetBool(); + hasMultipleShotsPerMeeting = CustomOptionHolder.GuesserModeMultipleShotsPerMeeting.GetBool(); + killsThroughShield = CustomOptionHolder.GuesserModeKillsThroughShield.GetBool(); + evilGuesserCanGuessSpy = CustomOptionHolder.GuesserModeEvilCanKillSpy.GetBool(); } else { - guesserCantGuessSnitch = CustomOptionHolder.guesserCantGuessSnitchIfTaksDone.getBool(); - hasMultipleShotsPerMeeting = CustomOptionHolder.guesserHasMultipleShotsPerMeeting.getBool(); - killsThroughShield = CustomOptionHolder.guesserKillsThroughShield.getBool(); - evilGuesserCanGuessSpy = CustomOptionHolder.guesserEvilCanKillSpy.getBool(); + guesserCantGuessSnitch = CustomOptionHolder.GuesserCantGuessSnitchIfTasksDone.GetBool(); + hasMultipleShotsPerMeeting = CustomOptionHolder.GuesserHasMultipleShotsPerMeeting.GetBool(); + killsThroughShield = CustomOptionHolder.GuesserKillsThroughShield.GetBool(); + evilGuesserCanGuessSpy = CustomOptionHolder.GuesserEvilCanKillSpy.GetBool(); } } diff --git a/BetterOtherRoles/libs/AmongUsSpecimen.dll b/BetterOtherRoles/libs/AmongUsSpecimen.dll new file mode 100644 index 0000000..a226c09 Binary files /dev/null and b/BetterOtherRoles/libs/AmongUsSpecimen.dll differ diff --git a/BetterOtherRoles/packages.lock.json b/BetterOtherRoles/packages.lock.json index cbc79fb..850b9f0 100644 --- a/BetterOtherRoles/packages.lock.json +++ b/BetterOtherRoles/packages.lock.json @@ -4,9 +4,9 @@ "net6.0": { "AmongUs.GameLibs.Steam": { "type": "Direct", - "requested": "[2023.10.24, )", - "resolved": "2023.10.24", - "contentHash": "8N064B27cGIZZk902aCLinazPp5T02KNdAUOLBVc1NIua8vYz4muwNdSI0RDGEY0CWbICK+FVsfGXdzAVTeH9A==" + "requested": "[2023.11.28, )", + "resolved": "2023.11.28", + "contentHash": "EsKrZS4tjTRrY7mtZls3tMy54zije4vleEA9s0UGUr4SF3qm2axR6wMncyIJCk4ACXlN5Bxpsd3/upDe9Gnx6A==" }, "BepInEx.IL2CPP.MSBuild": { "type": "Direct", @@ -16,17 +16,17 @@ }, "BepInEx.Unity.IL2CPP": { "type": "Direct", - "requested": "[6.0.0-be.674, )", - "resolved": "6.0.0-be.674", - "contentHash": "y6b5w0L5jDE8h67swHN3cDJ+FV+MzVcwrVqr9ssO37L9Laj87zYUtQVRTXwi5G/QFqeUQcUqi04gsYYR9yue3Q==", + "requested": "[6.0.0-be.671, )", + "resolved": "6.0.0-be.671", + "contentHash": "XpmrBitEO7pe5YG9VHqn0nuelEF5Dp0Rpkxa2F7PFZF1a00KSsdCL809++HYnGzLumNOCIt7mO7yyDNP5k25mw==", "dependencies": { - "BepInEx.Core": "6.0.0-be.674", - "BepInEx.Unity.Common": "6.0.0-be.674", + "BepInEx.Core": "6.0.0-be.671", + "BepInEx.Unity.Common": "6.0.0-be.671", "HarmonyX": "2.10.1", "Iced": "1.18.0", - "Il2CppInterop.Generator": "1.4.6-ci.389", - "Il2CppInterop.HarmonySupport": "1.4.6-ci.389", - "Il2CppInterop.Runtime": "1.4.6-ci.389", + "Il2CppInterop.Generator": "1.4.6-ci.367", + "Il2CppInterop.HarmonySupport": "1.4.6-ci.367", + "Il2CppInterop.Runtime": "1.4.6-ci.367", "MonoMod.RuntimeDetour": "22.5.1.1", "Samboy063.Cpp2IL.Core": "2022.1.0-development.866" } @@ -68,8 +68,8 @@ }, "BepInEx.Core": { "type": "Transitive", - "resolved": "6.0.0-be.674", - "contentHash": "onhAmi1nB36fVyQ25TRkWfDcYHBmw9pKxx758ut2hWou2gJpRpY2Dxc+GZrXCidPGy65mCi393zIU+07ShHTZw==", + "resolved": "6.0.0-be.671", + "contentHash": "Hp9QsgwtlGuNULFq5tF8YHrVD5R5WA5nMgFTJbcScWsGJDq7KPEhiLNGvKHAxcmMM8GA0CKM+jn8cJPtlMKvNQ==", "dependencies": { "HarmonyX": "2.10.1", "MonoMod.Utils": "22.5.1.1", @@ -78,8 +78,8 @@ }, "BepInEx.Unity.Common": { "type": "Transitive", - "resolved": "6.0.0-be.674", - "contentHash": "CApjIS89Pl7sKsnxOXANWBq3ALrdAQzn/neK6E6sydjYQiiVKwC6Wo65c1wHdcctSylGhh+e59WuxVSlGuJW9w==", + "resolved": "6.0.0-be.671", + "contentHash": "05W7ERsHizZl0MacTAhiGkcihZl2b0DYBP0e6gA1Vzoay+teQ/mHy3zorGu1r8lLWlesH4LXl89HwFjrMA1ZKw==", "dependencies": { "AssetRipper.VersionUtilities": "1.2.1", "MonoMod.Utils": "22.5.1.1" @@ -106,8 +106,8 @@ }, "Il2CppInterop.Common": { "type": "Transitive", - "resolved": "1.4.6-ci.389", - "contentHash": "KTyf2f66Q2mS9a6xhvoPWwD0VzRIoskPMVQehaVMo1dx4Di1FPFsKqukQ+ob6wgP5Rbnx53kiH0PY+IRSb35XA==", + "resolved": "1.4.6-ci.367", + "contentHash": "zviSAk0COGdxx1KLTJlSi6lyvfRjbPO4qhj9RvLAU5zP74hwAkjhim0WsSo9clkkyGS+KXDrjnUEHqfXuMMm9Q==", "dependencies": { "Iced": "1.17.0", "Microsoft.Extensions.Logging.Abstractions": "6.0.1", @@ -116,29 +116,29 @@ }, "Il2CppInterop.Generator": { "type": "Transitive", - "resolved": "1.4.6-ci.389", - "contentHash": "XJX4sn/RzAEBNIZZXuyDcLZrFx5tCoahujDu5aKWjApiMj/nTRQAxZn17daIIvd9aHqLaAfiWWth5QDLIt2bKw==", + "resolved": "1.4.6-ci.367", + "contentHash": "VP/1LX3wEy0/5BCrgggzIm9niyRGp/zjXaxFJip1D2bvM7oIXwK0LR0Rp8BE/uxKW8aQjVYxxwVwsdXPS/1KZw==", "dependencies": { - "Il2CppInterop.Common": "1.4.6-ci.389", + "Il2CppInterop.Common": "1.4.6-ci.367", "Mono.Cecil": "0.11.3" } }, "Il2CppInterop.HarmonySupport": { "type": "Transitive", - "resolved": "1.4.6-ci.389", - "contentHash": "Xd2zK6sLqwA0ReyUy83SWKcALwY99fq6vVL5gFOMN5Ct8OOVhtNIws0ysCWsfx1GL0RJiRYfR4pza/MmWRz4PQ==", + "resolved": "1.4.6-ci.367", + "contentHash": "rKb4Bt4cZQNWtI1L1/n/m5jJelP8pwAcQHwN/gaUAcobnapGZPJvRp8gyLQRvthGm3sxeleIQelEsv6L+21A2g==", "dependencies": { "HarmonyX": "2.10.0", - "Il2CppInterop.Runtime": "1.4.6-ci.389" + "Il2CppInterop.Runtime": "1.4.6-ci.367" } }, "Il2CppInterop.Runtime": { "type": "Transitive", - "resolved": "1.4.6-ci.389", - "contentHash": "nzYjuVzDG/O8+AQ8ax3WVHf+ZVsQKrVtp/yvuW8XoEPLdkbgryIrMo75dvN+tPqxOU3o2MPt9MZ9j25P5aVJMw==", + "resolved": "1.4.6-ci.367", + "contentHash": "Wb4rj/ESlfiYljfVXskndbkYNSX1WxPcsylrYex39QnVzujk6tRQUbHLA7PZn509z6P5wYbqJvhodzJ+w9Kk4A==", "dependencies": { "Iced": "1.17.0", - "Il2CppInterop.Common": "1.4.6-ci.389" + "Il2CppInterop.Common": "1.4.6-ci.367" } }, "js6pak.Gee.External.Capstone": { diff --git a/BetterOtherRolesServer/BetterOtherRolesServer.csproj b/BetterOtherRolesServer/BetterOtherRolesServer.csproj new file mode 100644 index 0000000..9c9ef27 --- /dev/null +++ b/BetterOtherRolesServer/BetterOtherRolesServer.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + diff --git a/BetterOtherRolesServer/Program.cs b/BetterOtherRolesServer/Program.cs new file mode 100644 index 0000000..981c925 --- /dev/null +++ b/BetterOtherRolesServer/Program.cs @@ -0,0 +1,16 @@ +using System.Net.Sockets; +using System.Net; +using System; +using System.Reflection; + +const string address = "127.0.0.1"; +const int port = 80; + +var server = new TcpListener(IPAddress.Parse(address), port); + +server.Start(); +Console.WriteLine("Server has started on 127.0.0.1:80.{0}Waiting for a connection…", Environment.NewLine); + +var client = server.AcceptTcpClient(); + +Console.WriteLine("A client connected."); \ No newline at end of file