diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd61d495..f9ade134 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/cache@v2 + - uses: actions/cache@v4 with: path: | ~/.nuget/packages @@ -18,13 +18,12 @@ jobs: key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} restore-keys: | ${{ runner.os }}-nuget- - - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v4 with: dotnet-version: 6.x @@ -32,8 +31,7 @@ jobs: run: dotnet build TheOtherRoles/TheOtherRoles.csproj --configuration Release - name: Upload TheOtherRoles - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: TheOtherRoles.dll - path: TheOtherRoles/bin/Release/net6.0/TheOtherRoles.dll - + path: TheOtherRoles/bin/Release/net6.0/TheOtherRoles.dll \ No newline at end of file diff --git a/Strings.xlsx b/Strings.xlsx index 2e670bfb..5855d3b3 100644 Binary files a/Strings.xlsx and b/Strings.xlsx differ diff --git a/TheOtherRoles/Buttons.cs b/TheOtherRoles/Buttons.cs index 872e6c03..820d7493 100644 --- a/TheOtherRoles/Buttons.cs +++ b/TheOtherRoles/Buttons.cs @@ -11,7 +11,9 @@ using TheOtherRoles.CustomGameModes; using TheOtherRoles.Patches; using TheOtherRoles.Modules; - +using TheOtherRoles.MetaContext; +using Reactor.Utilities; + namespace TheOtherRoles { [HarmonyPatch(typeof(HudManager), nameof(HudManager.Start))] @@ -88,7 +90,9 @@ static class HudManagerStartPatch public static CustomButton jekyllAndHydeDrugButton; public static CustomButton jekyllAndHydeSuicideButton; public static CustomButton teleporterTeleportButton; - public static CustomButton teleporterSampleButton; + public static CustomButton kataomoiButton; + public static CustomButton kataomoiStalkingButton; + public static CustomButton kataomoiSearchButton; public static CustomButton cupidArrowButton; public static CustomButton cupidShieldButton; public static CustomButton foxStealthButton; @@ -120,6 +124,10 @@ static class HudManagerStartPatch public static TMPro.TMP_Text securityGuardButtonScrewsText; public static TMPro.TMP_Text securityGuardChargesText; public static TMPro.TMP_Text deputyButtonHandcuffsText; + public static TMPro.TMP_Text tricksterBoxesText; + public static TMPro.TMP_Text engineerRepairText; + public static TMPro.TMP_Text foxRepairText; + public static TMPro.TMP_Text vultureRemainingText; public static TMPro.TMP_Text pursuerButtonBlanksText; public static TMPro.TMP_Text veteranButtonAlertText; public static TMPro.TMP_Text hackerAdminTableChargesText; @@ -130,17 +138,18 @@ static class HudManagerStartPatch public static TMPro.TMP_Text jekyllAndHydeKillCounterText; public static TMPro.TMP_Text jekyllAndHydeDrugText; public static TMPro.TMP_Text akujoTimeRemainingText; + public static TMPro.TMP_Text akujoHonmeiText; public static TMPro.TMP_Text akujoBackupLeftText; public static TMPro.TMP_Text cupidTimeRemainingText; + public static TMPro.TMP_Text cupidLoversText; public static TMPro.TMP_Text plagueDoctornumInfectionsText; public static TMPro.TMP_Text teleporterNumLeftText; - public static TMPro.TMP_Text teleporterTarget1Text; - public static TMPro.TMP_Text teleporterTarget2Text; public static TMPro.TMP_Text prophetButtonText; public static TMPro.TMP_Text noisemakerButtonText; //public static TMPro.TMP_Text trapperChargesText; public static TMPro.TMP_Text portalmakerButtonText1; public static TMPro.TMP_Text portalmakerButtonText2; + public static TMPro.TMP_Text portalmakerButtonNumText; public static TMPro.TMP_Text huntedShieldCountText; public static Props.Proptip accelAttributePropTip; @@ -185,6 +194,9 @@ public static void setCustomButtonCooldowns() { securityGuardButton.MaxTimer = SecurityGuard.cooldown; securityGuardCamButton.MaxTimer = SecurityGuard.cooldown; arsonistButton.MaxTimer = Arsonist.cooldown; + kataomoiButton.MaxTimer = Kataomoi.stareCooldown; + kataomoiStalkingButton.MaxTimer = Kataomoi.stalkingCooldown; + kataomoiSearchButton.MaxTimer = Kataomoi.searchCooldown; vultureEatButton.MaxTimer = Vulture.cooldown; mediumButton.MaxTimer = Medium.cooldown; pursuerButton.MaxTimer = Pursuer.cooldown; @@ -210,7 +222,6 @@ public static void setCustomButtonCooldowns() { sprintButton.MaxTimer = Sprinter.sprintCooldown; veteranAlertButton.MaxTimer = Veteran.cooldown; plagueDoctorButton.MaxTimer = PlagueDoctor.infectCooldown; - teleporterSampleButton.MaxTimer = Teleporter.sampleCooldown; teleporterTeleportButton.MaxTimer = Teleporter.teleportCooldown; undertakerDragButton.MaxTimer = 0f; mimicAAdminButton.MaxTimer = 0f; @@ -277,6 +288,10 @@ public static void setCustomButtonCooldowns() { witchSpellButton.EffectDuration = Witch.spellCastingDuration; securityGuardCamButton.EffectDuration = SecurityGuard.duration; ninjaButton.EffectDuration = Ninja.stealthDuration; + sprintButton.EffectDuration = Sprinter.sprintDuration; + kataomoiButton.EffectDuration = Kataomoi.stareDuration; + kataomoiStalkingButton.EffectDuration = Kataomoi.stalkingDuration; + kataomoiSearchButton.EffectDuration = Kataomoi.searchDuration; bomberAPlantBombButton.EffectDuration = BomberA.duration; bomberBPlantBombButton.EffectDuration = BomberA.duration; //serialKillerButton.EffectDuration = SerialKiller.suicideTimer; @@ -449,7 +464,7 @@ public static void createButtonsPostfix(HudManager __instance) { engineerRepairButton = new CustomButton( () => { engineerRepairButton.Timer = 0f; - Engineer.acTokenCommon ??= new("engineer.common1"); + _ = new StaticAchievementToken("engineer.common1"); MessageWriter usedRepairWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.EngineerUsedRepair, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(usedRepairWriter); RPCProcedure.engineerUsedRepair(); @@ -482,6 +497,7 @@ public static void createButtonsPostfix(HudManager __instance) { }, () => { return Engineer.engineer != null && Engineer.engineer == CachedPlayer.LocalPlayer.PlayerControl && Engineer.remainingFixes > 0 && !CachedPlayer.LocalPlayer.Data.IsDead; }, () => { + if (engineerRepairText != null) engineerRepairText.text = Engineer.remainingFixes.ToString(); bool sabotageActive = false; foreach (PlayerTask task in CachedPlayer.LocalPlayer.PlayerControl.myTasks.GetFastEnumerator()) if (task.TaskType == TaskTypes.FixLights || task.TaskType == TaskTypes.RestoreOxy || task.TaskType == TaskTypes.ResetReactor || task.TaskType == TaskTypes.ResetSeismic || task.TaskType == TaskTypes.FixComms || task.TaskType == TaskTypes.StopCharles @@ -495,8 +511,9 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("RepairText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); + engineerRepairText = engineerRepairButton.ShowUsesIcon(3); // Janitor Clean janitorCleanButton = new CustomButton( @@ -513,7 +530,7 @@ public static void createButtonsPostfix(HudManager __instance) { { NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId); - Janitor.acTokenCommon ??= new("janitor.common1"); + _ = new StaticAchievementToken("janitor.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CleanBody, Hazel.SendOption.Reliable, -1); writer.Write(playerInfo.PlayerId); writer.Write(Janitor.janitor.PlayerId); @@ -541,31 +558,24 @@ public static void createButtonsPostfix(HudManager __instance) { // Sheriff Kill sheriffKillButton = new CustomButton( () => { - if (Sheriff.currentTarget == Veteran.veteran && Veteran.alertActive) - { - Sheriff.acTokenAnother ??= new("sheriff.another1"); - Helpers.checkMurderAttemptAndKill(Sheriff.sheriff, Sheriff.sheriff); - return; - } - MurderAttemptResult murderAttemptResult = Helpers.checkMuderAttempt(Sheriff.sheriff, Sheriff.currentTarget); if (murderAttemptResult == MurderAttemptResult.SuppressKill) return; - if (murderAttemptResult == MurderAttemptResult.PerformKill) { + if (murderAttemptResult is MurderAttemptResult.PerformKill or MurderAttemptResult.ReverseKill) { byte targetId = 0; if (((Sheriff.currentTarget.Data.Role.IsImpostor && (Sheriff.currentTarget != Mini.mini || Mini.isGrownUp())) || (Sheriff.spyCanDieToSheriff && Spy.spy == Sheriff.currentTarget) || (Sheriff.canKillNeutrals && Helpers.isNeutral(Sheriff.currentTarget)) || - (Jackal.jackal == Sheriff.currentTarget || Sidekick.sidekick == Sheriff.currentTarget) || + Jackal.jackal == Sheriff.currentTarget || Sidekick.sidekick == Sheriff.currentTarget || (CreatedMadmate.createdMadmate == Sheriff.currentTarget && CreatedMadmate.canDieToSheriff) || (Madmate.canDieToSheriff && Madmate.madmate.Any(x => x.PlayerId == Sheriff.currentTarget.PlayerId))) && !Madmate.madmate.Any(y => y.PlayerId == Sheriff.sheriff.PlayerId)) { - Sheriff.acTokenCommon ??= new("sheriff.common1"); + _ = new StaticAchievementToken("sheriff.common1"); targetId = Sheriff.currentTarget.PlayerId; } else { - Sheriff.acTokenAnother ??= new("sheriff.another1"); + _= new StaticAchievementToken("sheriff.another1"); targetId = CachedPlayer.LocalPlayer.PlayerId; } @@ -597,7 +607,7 @@ public static void createButtonsPostfix(HudManager __instance) { targetId = Sheriff.sheriff == CachedPlayer.LocalPlayer.PlayerControl ? Sheriff.currentTarget.PlayerId : Deputy.currentTarget.PlayerId; // If the deputy is now the sheriff, sheriffs target, else deputies target if (Helpers.isEvil(Helpers.playerById(targetId))) - Deputy.acTokenCommon ??= new("deputy.common1"); + _ = new StaticAchievementToken("deputy.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.DeputyUsedHandcuffs, Hazel.SendOption.Reliable, -1); writer.Write(targetId); @@ -619,14 +629,10 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("HandcuffText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); // Deputy Handcuff button handcuff counter - deputyButtonHandcuffsText = GameObject.Instantiate(deputyHandcuffButton.actionButton.cooldownTimerText, deputyHandcuffButton.actionButton.cooldownTimerText.transform.parent); - deputyButtonHandcuffsText.text = ""; - deputyButtonHandcuffsText.enableWordWrapping = false; - deputyButtonHandcuffsText.transform.localScale = Vector3.one * 0.5f; - deputyButtonHandcuffsText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + deputyButtonHandcuffsText = deputyHandcuffButton.ShowUsesIcon(3); jackalAndSidekickSabotageLightsButton = new CustomButton( () => { @@ -679,7 +685,7 @@ public static void createButtonsPostfix(HudManager __instance) { }, buttonText: ModTranslation.getString("TimeShieldText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); // Medic Shield @@ -688,7 +694,7 @@ public static void createButtonsPostfix(HudManager __instance) { medicShieldButton.Timer = 0f; if (!Helpers.isEvil(Medic.currentTarget)) - Medic.acTokenCommon ??= new("medic.common1"); + _ = new StaticAchievementToken("medic.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, Medic.setShieldAfterMeeting ? (byte)CustomRPC.SetFutureShielded : (byte)CustomRPC.MedicSetShielded, Hazel.SendOption.Reliable, -1); writer.Write(Medic.currentTarget.PlayerId); @@ -709,7 +715,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("ShieldText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); @@ -736,7 +742,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("ShiftText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); // Morphling morph @@ -744,7 +750,7 @@ public static void createButtonsPostfix(HudManager __instance) { morphlingButton = new CustomButton( () => { if (Morphling.sampledTarget != null) { - Morphling.acTokenCommon ??= new("morphling.common1"); + _ = new StaticAchievementToken("morphling.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.MorphlingMorph, Hazel.SendOption.Reliable, -1); writer.Write(Morphling.sampledTarget.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer); @@ -809,7 +815,7 @@ public static void createButtonsPostfix(HudManager __instance) { // Camouflager camouflage camouflagerButton = new CustomButton( () => { - Camouflager.acTokenCommon ??= new("camouflager.common1"); + _ = new StaticAchievementToken("camouflager.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CamouflagerCamouflage, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.camouflagerCamouflage(); @@ -856,12 +862,12 @@ public static void createButtonsPostfix(HudManager __instance) { 0f, () => { hackerButton.Timer = hackerButton.MaxTimer;}, buttonText: ModTranslation.getString("HackerText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); hackerAdminTableButton = new CustomButton( () => { - Hacker.acTokenAdmin ??= new("hacker.common1"); + _ = new StaticAchievementToken("hacker.common1"); if (!MapBehaviour.Instance || !MapBehaviour.Instance.isActiveAndEnabled) { HudManager __instance = FastDestroyableSingleton.Instance; __instance.InitMap(); @@ -894,7 +900,7 @@ public static void createButtonsPostfix(HudManager __instance) { }, GameOptionsManager.Instance.currentNormalGameOptions.MapId == 3, FastDestroyableSingleton.Instance.GetString(StringNames.Admin), - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.AdminButton, FastDestroyableSingleton.Instance.GetString(StringNames.Admin).camelString() ); @@ -908,7 +914,7 @@ public static void createButtonsPostfix(HudManager __instance) { hackerVitalsButton = new CustomButton( () => { if (GameOptionsManager.Instance.currentNormalGameOptions.MapId != 1) { - Hacker.acTokenVitals ??= new("hacker.common2"); + _ = new StaticAchievementToken("hacker.common2"); if (Hacker.vitals == null) { var e = UnityEngine.Object.FindObjectsOfType().FirstOrDefault(x => x.gameObject.name.Contains("panel_vitals") || x.gameObject.name.Contains("Vitals")); if (e == null || Camera.main == null) return; @@ -965,7 +971,7 @@ public static void createButtonsPostfix(HudManager __instance) { Helpers.isMira() ? TranslationController.Instance.GetString(StringNames.DoorlogLabel) : TranslationController.Instance.GetString(StringNames.VitalsLabel), - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.AdminButton, Helpers.isMira() ? TranslationController.Instance.GetString(StringNames.DoorlogLabel).camelString() : TranslationController.Instance.GetString(StringNames.VitalsLabel).camelString() @@ -982,7 +988,7 @@ public static void createButtonsPostfix(HudManager __instance) { trackerTrackPlayerButton = new CustomButton( () => { if (Tracker.currentTarget.Data.Role.IsImpostor) - Tracker.acTokenCommon ??= new("tracker.common1"); + _ = new StaticAchievementToken("tracker.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.TrackerUsedTracker, Hazel.SendOption.Reliable, -1); writer.Write(Tracker.currentTarget.PlayerId); @@ -998,7 +1004,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("TrackerText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); trackerTrackCorpsesButton = new CustomButton( @@ -1021,7 +1027,7 @@ public static void createButtonsPostfix(HudManager __instance) { trackerTrackCorpsesButton.Timer = trackerTrackCorpsesButton.MaxTimer; }, buttonText: ModTranslation.getString("PathfindText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); vampireKillButton = new CustomButton( @@ -1044,7 +1050,7 @@ public static void createButtonsPostfix(HudManager __instance) { vampireKillButton.HasEffect = false; // Block effect on this click vampireKillButton.Timer = vampireKillButton.MaxTimer; } else { - Vampire.acTokenCommon ??= new("vampire.common1"); + _ = new StaticAchievementToken("vampire.common1"); Vampire.bitten = Vampire.currentTarget; // Notify players about bitten MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.VampireSetBitten, Hazel.SendOption.Reliable, -1); @@ -1147,7 +1153,7 @@ public static void createButtonsPostfix(HudManager __instance) { null, true, ModTranslation.getString("GarlicText"), - true + CustomButton.ButtonLabelType.UseButton ); portalmakerPlacePortalButton = new CustomButton( @@ -1166,15 +1172,20 @@ public static void createButtonsPostfix(HudManager __instance) { SoundEffectsManager.play("tricksterPlaceBox"); }, () => { return Portalmaker.portalmaker != null && Portalmaker.portalmaker == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead && Portal.secondPortal == null; }, - () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Portal.secondPortal == null; }, + () => + { + if (portalmakerButtonNumText != null) portalmakerButtonNumText.text = $"{(Portal.firstPortal == null ? 2 : 1)}"; + return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Portal.secondPortal == null; + }, () => { portalmakerPlacePortalButton.Timer = portalmakerPlacePortalButton.MaxTimer; }, Portalmaker.getPlacePortalButtonSprite(), CustomButton.ButtonPositions.lowerRowRight, __instance, KeyCode.F, buttonText: ModTranslation.getString("PlacePortalText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); + portalmakerButtonNumText = portalmakerPlacePortalButton.ShowUsesIcon(3); usePortalButton = new CustomButton( () => { @@ -1184,7 +1195,7 @@ public static void createButtonsPostfix(HudManager __instance) { bool portalMakerSoloTeleport = !Portal.locationNearEntry(CachedPlayer.LocalPlayer.transform.position); if (portalMakerSoloTeleport) { - Portalmaker.acTokenAnother ??= new("portalmaker.another1"); + _ = new StaticAchievementToken("portalmaker.another1"); exit = Portal.firstPortal.portalGameObject.transform.position; entry = CachedPlayer.LocalPlayer.transform.position; } @@ -1228,12 +1239,12 @@ public static void createButtonsPostfix(HudManager __instance) { KeyCode.H, mirror: true, ModTranslation.getString("PortalTeleportText"), - true + CustomButton.ButtonLabelType.UseButton ); portalmakerMoveToPortalButton = new CustomButton( () => { - Portalmaker.acTokenAnother ??= new("portalmaker.another1"); + _ = new StaticAchievementToken("portalmaker.another1"); bool didTeleport = false; Vector3 exit = Portal.secondPortal.portalGameObject.transform.position; @@ -1272,7 +1283,7 @@ public static void createButtonsPostfix(HudManager __instance) { KeyCode.J, mirror: true, ModTranslation.getString("PortalTeleportText"), - true + CustomButton.ButtonLabelType.UseButton ); @@ -1298,6 +1309,7 @@ public static void createButtonsPostfix(HudManager __instance) { Helpers.checkMurderAttemptAndKill(Veteran.veteran, Jackal.jackal); return; } + _ = new StaticAchievementToken("jackal.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.JackalCreatesSidekick, Hazel.SendOption.Reliable, -1); writer.Write(Jackal.currentTarget.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer); @@ -1392,13 +1404,14 @@ public static void createButtonsPostfix(HudManager __instance) { AmongUsClient.Instance.FinishRpcImmediately(killWriter); RPCProcedure.serialKillerSuicide(targetId); }, - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ) { showButtonText = true, buttonText = ModTranslation.getString("serialKillerSuicideText"), isEffectActive = true }; + ButtonEffect.SetMouseActionIcon(jekyllAndHydeSuicideButton.actionButtonGameObject, true, ModTranslation.getString("buttonsNormalSuicide"), false, ButtonEffect.ActionIconType.InfoAction); jekyllAndHydeDrugButton = new CustomButton( // OnClick @@ -1435,7 +1448,7 @@ public static void createButtonsPostfix(HudManager __instance) { KeyCode.F, false, ModTranslation.getString("DrugText"), - true + CustomButton.ButtonLabelType.UseButton ); jekyllAndHydeDrugText = GameObject.Instantiate(jekyllAndHydeDrugButton.actionButton.cooldownTimerText, jekyllAndHydeDrugButton.actionButton.cooldownTimerText.transform.parent); jekyllAndHydeDrugText.text = ""; @@ -1443,69 +1456,35 @@ public static void createButtonsPostfix(HudManager __instance) { jekyllAndHydeDrugText.transform.localScale = Vector3.one * 0.5f; jekyllAndHydeDrugText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); - teleporterSampleButton = new CustomButton( - () => - { - if (Teleporter.target1 == null) Teleporter.target1 = Teleporter.currentTarget; - else Teleporter.target2 = Teleporter.currentTarget; - Teleporter.currentTarget = null; - teleporterSampleButton.Timer = teleporterSampleButton.MaxTimer; - SoundEffectsManager.play("teleporterSample"); - }, - () => { return Teleporter.teleporter != null && CachedPlayer.LocalPlayer.PlayerControl == Teleporter.teleporter && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, - () => - { - if (teleporterTarget1Text != null) teleporterTarget1Text.text = Teleporter.target1 != null ? $"1. {Teleporter.target1.Data.PlayerName}" : ""; - if (teleporterTarget2Text != null) teleporterTarget2Text.text = Teleporter.target2 != null ? $"2. {Teleporter.target2.Data.PlayerName}" : ""; - return Teleporter.currentTarget != null && (Teleporter.target1 == null || Teleporter.target2 == null) && Teleporter.teleportNumber > 0 && CachedPlayer.LocalPlayer.PlayerControl.CanMove; - }, - () => - { - Teleporter.target1 = null; - Teleporter.target2 = null; - teleporterSampleButton.Timer = teleporterSampleButton.MaxTimer; - }, - Morphling.getSampleSprite(), - CustomButton.ButtonPositions.lowerRowRight, - __instance, - KeyCode.K, - buttonText: ModTranslation.getString("TeleporterSampleText"), - abilityTexture: true - ); - teleporterTarget1Text = GameObject.Instantiate(teleporterSampleButton.actionButton.cooldownTimerText, teleporterSampleButton.actionButton.cooldownTimerText.transform.parent); - teleporterTarget1Text.text = ""; - teleporterTarget1Text.enableWordWrapping = false; - teleporterTarget1Text.transform.localScale = Vector3.one * 0.5f; - teleporterTarget1Text.transform.localPosition += new Vector3(-0.05f, 1.0f, 0); - - teleporterTarget2Text = GameObject.Instantiate(teleporterSampleButton.actionButton.cooldownTimerText, teleporterSampleButton.actionButton.cooldownTimerText.transform.parent); - teleporterTarget2Text.text = ""; - teleporterTarget2Text.enableWordWrapping = false; - teleporterTarget2Text.transform.localScale = Vector3.one * 0.5f; - teleporterTarget2Text.transform.localPosition += new Vector3(-0.05f, 0.7f, 0) ; - teleporterTeleportButton = new CustomButton( () => - { - if (Teleporter.target1 != null && Teleporter.target2 != null && !Teleporter.target1.Data.IsDead && !Teleporter.target2.Data.IsDead && - Teleporter.target1.CanMove && Teleporter.target2.CanMove) + { + List transportTargets = new(); + foreach (var player in PlayerControl.AllPlayerControls) { - Teleporter.acTokenCommon ??= new("teleporter.common1"); - Teleporter.acTokenChallenge.Value.swapTime = DateTime.UtcNow; - Teleporter.acTokenChallenge.Value.target1 = Teleporter.target1.PlayerId; - Teleporter.acTokenChallenge.Value.target2 = Teleporter.target2.PlayerId; - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.TeleporterTeleport, Hazel.SendOption.Reliable, -1); - writer.Write(Teleporter.target1.PlayerId); - writer.Write(Teleporter.target2.PlayerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.teleporterTeleport(Teleporter.target1.PlayerId, Teleporter.target2.PlayerId); + if (!player.Data.Disconnected) + { + if (!player.Data.IsDead) transportTargets.Add(player.PlayerId); + else + { + foreach (var body in UnityEngine.Object.FindObjectsOfType()) + { + if (body.ParentId == player.PlayerId) transportTargets.Add(player.PlayerId); + } + } + } } - Teleporter.target1 = null; - Teleporter.target2 = null; - teleporterSampleButton.Timer = teleporterSampleButton.MaxTimer; - teleporterTeleportButton.Timer = teleporterTeleportButton.MaxTimer; - Teleporter.teleportNumber--; - SoundEffectsManager.play("teleporterTeleport"); + byte[] transporttargetIDs = transportTargets.ToArray(); + var pk = new Teleporter.PlayerMenu((x) => + { + Teleporter.target1 = x; + Teleporter.SwappingMenus = true; + Coroutines.Start(Teleporter.OpenSecondMenu()); + }, (y) => + { + return transporttargetIDs.Contains(y.PlayerId); + }); + Coroutines.Start(pk.Open(0f, true)); }, () => { return Teleporter.teleporter != null && CachedPlayer.LocalPlayer.PlayerControl == Teleporter.teleporter && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, () => @@ -1514,23 +1493,18 @@ public static void createButtonsPostfix(HudManager __instance) { { teleporterNumLeftText.text = $"{Teleporter.teleportNumber}"; } - return Teleporter.target1 != null && Teleporter.target2 != null && Teleporter.teleportNumber > 0 && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !TransportationToolPatches.isUsingTransportation(Teleporter.target1) - && !TransportationToolPatches.isUsingTransportation(Teleporter.target2); + return Teleporter.teleportNumber > 0 && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !Teleporter.SwappingMenus; }, () => { teleporterTeleportButton.Timer = teleporterTeleportButton.MaxTimer; }, Teleporter.getButtonSprite(), - CustomButton.ButtonPositions.upperRowRight, + CustomButton.ButtonPositions.lowerRowRight, __instance, KeyCode.F, false, ModTranslation.getString("TeleporterTeleportText"), - true + CustomButton.ButtonLabelType.UseButton ); - teleporterNumLeftText = GameObject.Instantiate(teleporterTeleportButton.actionButton.cooldownTimerText, teleporterTeleportButton.actionButton.cooldownTimerText.transform.parent); - teleporterNumLeftText.text = ""; - teleporterNumLeftText.enableWordWrapping = false; - teleporterNumLeftText.transform.localScale = Vector3.one * 0.5f; - teleporterNumLeftText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + teleporterNumLeftText = teleporterTeleportButton.ShowUsesIcon(3); plagueDoctorButton = new CustomButton( () => @@ -1570,14 +1544,9 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("InfectText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - - plagueDoctornumInfectionsText = GameObject.Instantiate(plagueDoctorButton.actionButton.cooldownTimerText, plagueDoctorButton.actionButton.cooldownTimerText.transform.parent); - plagueDoctornumInfectionsText.text = ""; - plagueDoctornumInfectionsText.enableWordWrapping = false; - plagueDoctornumInfectionsText.transform.localScale = Vector3.one * 0.5f; - plagueDoctornumInfectionsText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + plagueDoctornumInfectionsText = plagueDoctorButton.ShowUsesIcon(2); // EvilHacker creates madmate button evilHackerCreatesMadmateButton = new CustomButton( @@ -1624,7 +1593,7 @@ public static void createButtonsPostfix(HudManager __instance) { writer.Write(Prophet.currentTarget.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.prophetExamine(Prophet.currentTarget.PlayerId); - if (Prophet.examinesLeft == 0) Prophet.acTokenUse ??= new("prophet.challenge1"); + if (Prophet.examinesLeft == 0) _ = new StaticAchievementToken("prophet.challenge1"); prophetButton.Timer = prophetButton.MaxTimer; } }, @@ -1646,14 +1615,9 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("ProphetText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - - prophetButtonText = GameObject.Instantiate(prophetButton.actionButton.cooldownTimerText, prophetButton.actionButton.cooldownTimerText.transform.parent); - prophetButtonText.text = ""; - prophetButtonText.enableWordWrapping = false; - prophetButtonText.transform.localScale = Vector3.one * 0.5f; - prophetButtonText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + prophetButtonText = prophetButton.ShowUsesIcon(3); blackmailerButton = new CustomButton( () => { // Action when Pressed @@ -1665,7 +1629,7 @@ public static void createButtonsPostfix(HudManager __instance) { return; } - Blackmailer.acTokenCommon ??= new("blackmailer.common1"); + _ = new StaticAchievementToken("blackmailer.common1"); Blackmailer.acTokenChallenge.Value.cleared |= Blackmailer.acTokenChallenge.Value.witness.Any(x => x == Blackmailer.currentTarget.PlayerId); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.BlackmailPlayer, Hazel.SendOption.Reliable, -1); @@ -1718,8 +1682,8 @@ public static void createButtonsPostfix(HudManager __instance) { eraserButton.MaxTimer += 10; eraserButton.Timer = eraserButton.MaxTimer; - Eraser.acTokenCommon ??= new("eraser.common1"); - if (Eraser.currentTarget.Data.Role.IsImpostor) Eraser.acTokenAnother ??= new("eraser.another1"); + _ = new StaticAchievementToken("eraser.common1"); + if (Eraser.currentTarget.Data.Role.IsImpostor) _ = new StaticAchievementToken("eraser.another1"); Eraser.acTokenChallenge.Value++; MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetFutureErased, Hazel.SendOption.Reliable, -1); @@ -1762,7 +1726,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("PlaceTrapText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); moriartyBrainwashButton = new CustomButton( @@ -1829,7 +1793,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("BrainwashText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); moriartyKillButton = new CustomButton( @@ -1837,7 +1801,7 @@ public static void createButtonsPostfix(HudManager __instance) { { MurderAttemptResult murder = Helpers.checkMurderAttemptAndKill(CachedPlayer.LocalPlayer.PlayerControl, Moriarty.killTarget, showAnimation: false); - if (murder != MurderAttemptResult.BlankKill) + if (murder == MurderAttemptResult.PerformKill) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.MoriartyKill, Hazel.SendOption.Reliable, -1); writer.Write(Moriarty.killTarget.PlayerId); @@ -1893,18 +1857,23 @@ public static void createButtonsPostfix(HudManager __instance) { SoundEffectsManager.play("tricksterPlaceBox"); }, () => { return Trickster.trickster != null && Trickster.trickster == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead && !JackInTheBox.hasJackInTheBoxLimitReached(); }, - () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && !JackInTheBox.hasJackInTheBoxLimitReached(); }, + () => + { + if (tricksterBoxesText != null) tricksterBoxesText.text = (JackInTheBox.JackInTheBoxLimit - JackInTheBox.AllJackInTheBoxes.Count).ToString(); + return CachedPlayer.LocalPlayer.PlayerControl.CanMove && !JackInTheBox.hasJackInTheBoxLimitReached(); + }, () => { placeJackInTheBoxButton.Timer = placeJackInTheBoxButton.MaxTimer;}, Trickster.getPlaceBoxButtonSprite(), CustomButton.ButtonPositions.upperRowLeft, __instance, KeyCode.F, buttonText: ModTranslation.getString("PlaceJackInTheBoxText") - ); + ); + tricksterBoxesText = placeJackInTheBoxButton.ShowUsesIcon(0); lightsOutButton = new CustomButton( () => { - Trickster.acTokenCommon2 ??= new("trickster.common2"); + _ = new StaticAchievementToken("trickster.common2"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.LightsOut, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.lightsOut(); @@ -1945,7 +1914,7 @@ public static void createButtonsPostfix(HudManager __instance) { Vector2 truePosition2 = component.TruePosition; if (Vector2.Distance(truePosition2, truePosition) <= CachedPlayer.LocalPlayer.PlayerControl.MaxReportDistance && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !PhysicsHelpers.AnythingBetween(truePosition, truePosition2, Constants.ShipAndObjectsMask, false)) { - Cleaner.acTokenCommon ??= new("cleaner.common1"); + _ = new StaticAchievementToken("cleaner.common1"); Cleaner.acTokenChallenge.Value++; NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId); @@ -2003,10 +1972,10 @@ public static void createButtonsPostfix(HudManager __instance) { MurderAttemptResult murder = Helpers.checkMurderAttemptAndKill(Warlock.warlock, Warlock.curseVictimTarget, showAnimation: false); if (murder == MurderAttemptResult.SuppressKill) return; if (murder == MurderAttemptResult.PerformKill) { - Warlock.acTokenCommon ??= new("warlock.common1"); + _ = new StaticAchievementToken("warlock.common1"); Warlock.acTokenChallenge.Value++; if (Warlock.curseVictimTarget == CachedPlayer.LocalPlayer.PlayerControl) - Warlock.acTokenAnother ??= new("warlock.another1"); + _ = new StaticAchievementToken("warlock.another1"); } warlockCurseButton.buttonText = ModTranslation.getString("CurseText"); @@ -2105,7 +2074,7 @@ public static void createButtonsPostfix(HudManager __instance) { CustomButton.ButtonPositions.lowerRowRight, __instance, KeyCode.F, - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.UseButton, buttonText: ModTranslation.getString("PlaceCameraText") ); @@ -2180,7 +2149,7 @@ public static void createButtonsPostfix(HudManager __instance) { Helpers.isMira() ? TranslationController.Instance.GetString(StringNames.SecurityLogsSystem) : ModTranslation.getString("securityGuardCamButton"), - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.AdminButton, Helpers.isMira() ? TranslationController.Instance.GetString(StringNames.SecurityLogsSystem).camelString() : ModTranslation.getString("securityGuardCamButton").camelString() @@ -2198,6 +2167,7 @@ public static void createButtonsPostfix(HudManager __instance) { () => { bool dousedEveryoneAlive = Arsonist.dousedEveryoneAlive(); if (dousedEveryoneAlive) { + _ = new StaticAchievementToken("arsonist.challenge"); MessageWriter winWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ArsonistWin, Hazel.SendOption.Reliable, -1); AmongUsClient.Instance.FinishRpcImmediately(winWriter); RPCProcedure.arsonistWin(); @@ -2244,7 +2214,7 @@ public static void createButtonsPostfix(HudManager __instance) { Arsonist.duration, () => { if (Arsonist.douseTarget != null) Arsonist.dousedPlayers.Add(Arsonist.douseTarget); - + _ = new StaticAchievementToken("arsonist.common1"); arsonistButton.Timer = Arsonist.dousedEveryoneAlive() ? 0 : arsonistButton.MaxTimer; foreach (PlayerControl p in Arsonist.dousedPlayers) { @@ -2294,14 +2264,9 @@ public static void createButtonsPostfix(HudManager __instance) { Veteran.alertDuration, () => { veteranAlertButton.Timer = veteranAlertButton.MaxTimer; }, buttonText: ModTranslation.getString("AlertText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - - veteranButtonAlertText = GameObject.Instantiate(veteranAlertButton.actionButton.cooldownTimerText, veteranAlertButton.actionButton.cooldownTimerText.transform.parent); - veteranButtonAlertText.text = ""; - veteranButtonAlertText.enableWordWrapping = false; - veteranButtonAlertText.transform.localScale = Vector3.one * 0.5f; - veteranButtonAlertText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + veteranButtonAlertText = veteranAlertButton.ShowUsesIcon(3); //createRoleSummaryButton(__instance); @@ -2596,7 +2561,7 @@ public static void createButtonsPostfix(HudManager __instance) { undertakerDragButton = new CustomButton( () => { - Undertaker.acTokenCommon ??= new("undertaker.common1"); + _ = new StaticAchievementToken("undertaker.common1"); var bodyComponent = Undertaker.TargetBody; if (Undertaker.DraggedBody == null && bodyComponent != null) { @@ -2656,9 +2621,8 @@ public static void createButtonsPostfix(HudManager __instance) { writer.Write(CachedPlayer.LocalPlayer.PlayerControl.PlayerId); writer.Write(false); writer.Write(false); + AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.buskerPseudocide(CachedPlayer.LocalPlayer.PlayerControl.PlayerId, false, false); - AmongUsClient.Instance.FinishRpcImmediately(writer); - Busker.pseudocideFlag = true; }, () => { return Busker.busker != null && CachedPlayer.LocalPlayer.PlayerControl == Busker.busker && (!CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead || Busker.checkPseudocide()); }, () => @@ -2688,25 +2652,24 @@ public static void createButtonsPostfix(HudManager __instance) { () => { if (Busker.buttonInterrupted) - { - Busker.acTokenCommon ??= new("busker.common1"); + { + Busker.buttonInterrupted = false; + _ = new StaticAchievementToken("busker.common1"); Busker.acTokenChallenge.Value.pseudocide = DateTime.UtcNow; - buskerButton.Timer = buskerButton.MaxTimer = Busker.cooldown; MessageWriter writer1 = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.BuskerRevive, SendOption.Reliable, -1); - writer1.Write(CachedPlayer.LocalPlayer.PlayerControl.PlayerId); - RPCProcedure.buskerRevive(CachedPlayer.LocalPlayer.PlayerControl.PlayerId); + writer1.Write(CachedPlayer.LocalPlayer.PlayerControl.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer1); - Busker.pseudocideFlag = false; - Busker.buttonInterrupted = false; + RPCProcedure.buskerRevive(CachedPlayer.LocalPlayer.PlayerControl.PlayerId); + buskerButton.Timer = buskerButton.MaxTimer = Busker.cooldown; } else { - Busker.acTokenAnother ??= new("busker.another1"); + _ = new StaticAchievementToken("busker.another1"); Busker.dieBusker(); } }, buttonText: ModTranslation.getString("PseudocideText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ) { effectCancellable = true @@ -2739,14 +2702,9 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("NoisemakerText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - - noisemakerButtonText = GameObject.Instantiate(noisemakerButton.actionButton.cooldownTimerText, noisemakerButton.actionButton.cooldownTimerText.transform.parent); - noisemakerButtonText.text = ""; - noisemakerButtonText.enableWordWrapping = false; - noisemakerButtonText.transform.localScale = Vector3.one * 0.5f; - noisemakerButtonText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + noisemakerButtonText = noisemakerButton.ShowUsesIcon(3); schrodingersCatKillButton = new CustomButton( () => @@ -2785,29 +2743,39 @@ public static void createButtonsPostfix(HudManager __instance) { () => { if (Sherlock.killPopup == null) Sherlock.killPopup = GameManagerCreator.Instance.HideAndSeekManagerPrefab.DeathPopupPrefab; - int count = 0; + int count = 0; + string msg = ""; foreach (var item in Sherlock.killLog) { float distance = Vector3.Distance(item.Item2.Item2, CachedPlayer.LocalPlayer.PlayerControl.transform.position); if (distance < Sherlock.investigateDistance) { var newPopUp = UnityEngine.Object.Instantiate(Sherlock.killPopup, __instance.transform.parent); - PlayerControl killer = Helpers.playerById(item.Item1); - PlayerControl target = Helpers.playerById(item.Item2.Item1); + PlayerControl killer = Helpers.getPlayerById(item.Item1); + PlayerControl target = Helpers.getPlayerById(item.Item2.Item1); string killerTeam = RoleInfo.GetRolesString(killer, useColors: true, showModifier: false, includeHidden: true); newPopUp.gameObject.transform.GetChild(0).GetComponent().enabled = false; newPopUp.gameObject.transform.GetChild(0).GetComponent().text = string.Format(ModTranslation.getString("sherlockMessage2"), killerTeam); newPopUp.gameObject.transform.position += (count % 4) * new Vector3(0, -1.2f, 0) + new Vector3(3f - (int)(count / 4) * 3.8f, -0.25f, __instance.MapButton.transform.localPosition.z - 600f); newPopUp.ModShow(target, 0); - count++; + count++; + msg += $"{string.Format(ModTranslation.getString("sherlockMeeting"), target?.Data?.PlayerName, killerTeam)}\n"; } + } + if (!string.IsNullOrEmpty(msg)) + { + msg = msg.TrimEnd('\n'); + MeetingOverlayHolder.RegisterOverlay(TORGUIContextEngine.API.VerticalHolder(GUIAlignment.Left, + new TORGUIText(GUIAlignment.Left, TORGUIContextEngine.API.GetAttribute(AttributeAsset.OverlayTitle), new TranslateTextComponent("sherlockInfo")), + new TORGUIText(GUIAlignment.Left, TORGUIContextEngine.API.GetAttribute(AttributeAsset.OverlayContent), new RawTextComponent(msg))) + , MeetingOverlayHolder.IconsSprite[2], Sherlock.color); } if (count == 0) { Sherlock.investigateMessage(ModTranslation.getString("sherlockMessage1"), 7f, Color.white); } if (count >= 3) - Sherlock.acTokenCommon ??= new("sherlock.common1"); + _ = new StaticAchievementToken("sherlock.common1"); Sherlock.numUsed += 1; sherlockInvestigateButton.Timer = sherlockInvestigateButton.MaxTimer; SoundEffectsManager.play("sherlockInvestigate"); @@ -2828,7 +2796,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("InvestigateText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); sherlockNumInvestigateText = GameObject.Instantiate(sherlockInvestigateButton.actionButton.cooldownTimerText, sherlockInvestigateButton.actionButton.cooldownTimerText.transform.parent); sherlockNumInvestigateText.text = ""; @@ -2900,20 +2868,26 @@ public static void createButtonsPostfix(HudManager __instance) { } }, () => { return Cupid.cupid != null && CachedPlayer.LocalPlayer.PlayerControl == Cupid.cupid && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && Cupid.lovers2 == null && Cupid.timeLeft > 0; }, - () => { return Cupid.cupid != null && CachedPlayer.LocalPlayer.PlayerControl == Cupid.cupid && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && Cupid.currentTarget != null && Cupid.lovers2 == null && Cupid.timeLeft > 0; }, + () => + { + if (cupidLoversText != null) cupidLoversText.text = Cupid.lovers1 == null ? "2" : "1"; + return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Cupid.currentTarget != null; + }, () => { cupidArrowButton.Timer = cupidArrowButton.MaxTimer; }, Cupid.getArrowSprite(), CustomButton.ButtonPositions.upperRowRight, __instance, KeyCode.F, buttonText: ModTranslation.getString("CupidArrowText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); cupidTimeRemainingText = GameObject.Instantiate(cupidArrowButton.actionButton.cooldownTimerText, __instance.transform); cupidTimeRemainingText.text = ""; cupidTimeRemainingText.enableWordWrapping = false; cupidTimeRemainingText.transform.localScale = Vector3.one * 0.45f; cupidTimeRemainingText.transform.localPosition = cupidArrowButton.actionButton.cooldownTimerText.transform.parent.localPosition + new Vector3(-0.1f, 0.35f, 0f); + ButtonEffect.SetMouseActionIcon(cupidArrowButton.actionButtonGameObject, true, ModTranslation.getString("buttonsCupidSuicide"), true, ButtonEffect.ActionIconType.InfoAction); + cupidLoversText = cupidArrowButton.ShowUsesIcon(4); cupidShieldButton = new CustomButton( () => @@ -2938,7 +2912,7 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.G, buttonText: ModTranslation.getString("ShieldText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); // Akujo Honmei @@ -2968,13 +2942,16 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.F, buttonText: ModTranslation.getString("AkujoHonmeiText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); + akujoHonmeiText = akujoHonmeiButton.ShowUsesIcon(4); + akujoHonmeiText.text = "1"; akujoTimeRemainingText = GameObject.Instantiate(akujoHonmeiButton.actionButton.cooldownTimerText, __instance.transform); akujoTimeRemainingText.text = ""; akujoTimeRemainingText.enableWordWrapping = false; akujoTimeRemainingText.transform.localScale = Vector3.one * 0.45f; akujoTimeRemainingText.transform.localPosition = akujoHonmeiButton.actionButton.cooldownTimerText.transform.parent.localPosition + new Vector3(-0.1f, 0.35f, 0f); + ButtonEffect.SetMouseActionIcon(akujoHonmeiButton.actionButtonGameObject, true, ModTranslation.getString("buttonsAkujoSuicide"), true, ButtonEffect.ActionIconType.InfoAction); // Akujo Keep akujoBackupButton = new CustomButton( @@ -3010,13 +2987,9 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.K, buttonText: ModTranslation.getString("AkujoBackupText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - akujoBackupLeftText = GameObject.Instantiate(akujoBackupButton.actionButton.cooldownTimerText, akujoBackupButton.actionButton.cooldownTimerText.transform.parent); - akujoBackupLeftText.text = ""; - akujoBackupLeftText.enableWordWrapping = false; - akujoBackupLeftText.transform.localScale = Vector3.one * 0.5f; - akujoBackupLeftText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + akujoBackupLeftText = akujoBackupButton.ShowUsesIcon(4); // Mimic(Assistant) Morph mimicAMorphButton = new CustomButton( @@ -3085,7 +3058,7 @@ public static void createButtonsPostfix(HudManager __instance) { return; } - Ninja.acTokenCommon ??= new("ninja.common1"); + _ = new StaticAchievementToken("ninja.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.NinjaStealth, Hazel.SendOption.Reliable, -1); writer.Write(CachedPlayer.LocalPlayer.PlayerId); writer.Write(true); @@ -3141,6 +3114,135 @@ public static void createButtonsPostfix(HudManager __instance) { effectCancellable = true }; + // Kataomoi button + kataomoiButton = new CustomButton( + () => { + if (Kataomoi.canLove()) + { + var murderAttemptResult = Helpers.checkMuderAttempt(Kataomoi.kataomoi, Kataomoi.currentTarget); + if (murderAttemptResult == MurderAttemptResult.SuppressKill) return; + + MessageWriter winWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.KataomoiWin, Hazel.SendOption.Reliable, -1); + AmongUsClient.Instance.FinishRpcImmediately(winWriter); + RPCProcedure.kataomoiWin(); + + if (murderAttemptResult == MurderAttemptResult.PerformKill) + { + byte targetId = Kataomoi.currentTarget.PlayerId; + MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.UncheckedMurderPlayer, Hazel.SendOption.Reliable, -1); + killWriter.Write(Kataomoi.kataomoi.Data.PlayerId); + killWriter.Write(targetId); + killWriter.Write(byte.MaxValue); + AmongUsClient.Instance.FinishRpcImmediately(killWriter); + RPCProcedure.uncheckedMurderPlayer(Kataomoi.kataomoi.Data.PlayerId, targetId, Byte.MaxValue); + } + + kataomoiButton.HasEffect = false; + } + else if (Kataomoi.currentTarget != null) + { + kataomoiButton.HasEffect = true; + } + }, + () => { return Kataomoi.kataomoi != null && Kataomoi.kataomoi == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, + () => { + if (Kataomoi.canLove()) { + kataomoiButton.actionButton.graphic.sprite = Kataomoi.getLoveSprite(); + kataomoiButton.buttonText = ModTranslation.getString("KataomoiLoveText"); + kataomoiButton.resetKeyBind(); + } + + if (kataomoiButton.isEffectActive && Kataomoi.target != null && Kataomoi.target != Kataomoi.currentTarget) + { + kataomoiButton.Timer = 0f; + kataomoiButton.isEffectActive = false; + } + + return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Kataomoi.currentTarget != null; + }, + () => { + kataomoiButton.Timer = kataomoiButton.MaxTimer; + kataomoiButton.isEffectActive = false; + kataomoiButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + }, + Kataomoi.getStareSprite(), + CustomButton.ButtonPositions.lowerRowRight, + __instance, + KeyCode.H, + true, + Kataomoi.stareDuration, + () => { + Kataomoi.doStare(); + kataomoiButton.Timer = Kataomoi.canLove() ? 0 : kataomoiButton.MaxTimer; + }, + buttonText: ModTranslation.getString("KataomoiStareText"), + abilityTexture: CustomButton.ButtonLabelType.UseButton, + shakeOnEnd: false + ); + + // Kataomoi search button + kataomoiSearchButton = new CustomButton( + () => { + if (Kataomoi.kataomoi == null) return; + Kataomoi.doSearch(); + }, + () => { return Kataomoi.kataomoi != null && Kataomoi.kataomoi == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, + () => { + return CachedPlayer.LocalPlayer.PlayerControl.CanMove; + }, + () => { + kataomoiSearchButton.Timer = kataomoiSearchButton.MaxTimer; + kataomoiSearchButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + kataomoiSearchButton.isEffectActive = false; + Kataomoi.resetSearch(); + }, + Kataomoi.getSearchSprite(), + CustomButton.ButtonPositions.upperRowRight, + __instance, + KeyCode.G, + true, + Kataomoi.searchDuration, + () => { + kataomoiSearchButton.Timer = kataomoiSearchButton.MaxTimer; + Kataomoi.resetSearch(); + }, + buttonText: ModTranslation.getString("KataomoiSearchText") + ); + + // Kataomoi stalking button + kataomoiStalkingButton = new CustomButton( + () => { + if (Kataomoi.kataomoi == null) return; + + byte playerId = Kataomoi.kataomoi.Data.PlayerId; + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.KataomoiStalking, Hazel.SendOption.Reliable, -1); + writer.Write(playerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + + RPCProcedure.kataomoiStalking(playerId); + }, + () => { return Kataomoi.kataomoi != null && Kataomoi.kataomoi == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, + () => { + return CachedPlayer.LocalPlayer.PlayerControl.CanMove; + }, + () => { + kataomoiStalkingButton.Timer = kataomoiStalkingButton.MaxTimer; + kataomoiStalkingButton.actionButton.cooldownTimerText.color = Palette.EnabledColor; + kataomoiStalkingButton.isEffectActive = false; + }, + Kataomoi.getStalkingSprite(), + CustomButton.ButtonPositions.upperRowCenter, + __instance, + KeyCode.F, + true, + Kataomoi.stalkingDuration, + () => { + kataomoiStalkingButton.Timer = kataomoiStalkingButton.MaxTimer; + }, + buttonText: ModTranslation.getString("KataomoiStalkText"), + abilityTexture: CustomButton.ButtonLabelType.UseButton + ); + foxStealthButton = new CustomButton( () => { @@ -3192,7 +3294,7 @@ public static void createButtonsPostfix(HudManager __instance) { RPCProcedure.foxStealth(false); }, buttonText: ModTranslation.getString("FoxStealthText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ) { effectCancellable = true @@ -3244,6 +3346,7 @@ public static void createButtonsPostfix(HudManager __instance) { () => { return CachedPlayer.LocalPlayer.PlayerControl == Fox.fox && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && Fox.numRepair > 0; }, () => { + if (foxRepairText != null) foxRepairText.text = Fox.numRepair.ToString(); bool sabotageActive = false; foreach (PlayerTask task in CachedPlayer.LocalPlayer.PlayerControl.myTasks) if (task.TaskType is TaskTypes.FixLights or TaskTypes.RestoreOxy or TaskTypes.ResetReactor or TaskTypes.ResetSeismic or TaskTypes.FixComms or TaskTypes.StopCharles) @@ -3255,9 +3358,10 @@ public static void createButtonsPostfix(HudManager __instance) { CustomButton.ButtonPositions.upperRowRight, __instance, KeyCode.G, - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.UseButton, buttonText: ModTranslation.getString("RepairText") ); + foxRepairText = foxRepairButton.ShowUsesIcon(4); foxImmoralistButton = new CustomButton( () => @@ -3279,7 +3383,7 @@ public static void createButtonsPostfix(HudManager __instance) { CustomButton.ButtonPositions.lowerRowRight, __instance, KeyCode.I, - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.UseButton, buttonText: ModTranslation.getString("FoxImmoralistText") ); @@ -3328,14 +3432,14 @@ public static void createButtonsPostfix(HudManager __instance) { SerialKiller.suicideTimer, () => { - SerialKiller.acTokenAnother ??= new("serialKiller.another1"); + _ = new StaticAchievementToken("serialKiller.another1"); byte targetId = SerialKiller.serialKiller.PlayerId; MessageWriter killWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SerialKillerSuicide, Hazel.SendOption.Reliable, -1); killWriter.Write(targetId); killWriter.Write(targetId); AmongUsClient.Instance.FinishRpcImmediately(killWriter); RPCProcedure.serialKillerSuicide(targetId); }, - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ) { //UnityEngine.Object.Destroy(serialKillerButton.actionButton.buttonLabelText); @@ -3343,7 +3447,8 @@ public static void createButtonsPostfix(HudManager __instance) { showButtonText = true, buttonText = ModTranslation.getString("serialKillerSuicideText"), isEffectActive = true - }; + }; + ButtonEffect.SetMouseActionIcon(serialKillerButton.actionButtonGameObject, true, ModTranslation.getString("buttonsNormalSuicide"), false, ButtonEffect.ActionIconType.InfoAction); // Evil Tracker track evilTrackerButton = new CustomButton( @@ -3353,7 +3458,7 @@ public static void createButtonsPostfix(HudManager __instance) { Helpers.checkMurderAttemptAndKill(Veteran.veteran, EvilTracker.evilTracker); return; } - EvilTracker.acTokenCommon1 ??= new("evilTracker.common1"); + _ = new StaticAchievementToken("evilTracker.common1"); EvilTracker.target = EvilTracker.currentTarget; }, () => { return EvilTracker.target == null && CachedPlayer.LocalPlayer.PlayerControl == EvilTracker.evilTracker && !CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead; }, @@ -3383,7 +3488,7 @@ public static void createButtonsPostfix(HudManager __instance) { Vector2 truePosition2 = component.TruePosition; if (Vector2.Distance(truePosition2, truePosition) <= CachedPlayer.LocalPlayer.PlayerControl.MaxReportDistance && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !PhysicsHelpers.AnythingBetween(truePosition, truePosition2, Constants.ShipAndObjectsMask, false)) { NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId); - + _ = new StaticAchievementToken("vulture.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CleanBody, Hazel.SendOption.Reliable, -1); writer.Write(playerInfo.PlayerId); writer.Write(Vulture.vulture.PlayerId); @@ -3399,7 +3504,11 @@ public static void createButtonsPostfix(HudManager __instance) { } }, () => { return Vulture.vulture != null && Vulture.vulture == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; }, - () => { return __instance.ReportButton.graphic.color == Palette.EnabledColor && CachedPlayer.LocalPlayer.PlayerControl.CanMove; }, + () => + { + if (vultureRemainingText != null) vultureRemainingText.text = (Vulture.vultureNumberToWin - Vulture.eatenBodies).ToString(); + return __instance.ReportButton.graphic.color == Palette.EnabledColor && CachedPlayer.LocalPlayer.PlayerControl.CanMove; + }, () => { vultureEatButton.Timer = vultureEatButton.MaxTimer; }, Vulture.getButtonSprite(), CustomButton.ButtonPositions.lowerRowCenter, @@ -3407,6 +3516,7 @@ public static void createButtonsPostfix(HudManager __instance) { KeyCode.F, buttonText: ModTranslation.getString("VultureText") ); + vultureRemainingText = vultureEatButton.ShowUsesIcon(2); // EvilHacker button evilHackerButton = new CustomButton( @@ -3440,7 +3550,8 @@ public static void createButtonsPostfix(HudManager __instance) { __instance, KeyCode.H, false, - FastDestroyableSingleton.Instance.GetString(StringNames.Admin), + FastDestroyableSingleton.Instance.GetString(StringNames.Admin), + abilityTexture: CustomButton.ButtonLabelType.AdminButton, actionName: FastDestroyableSingleton.Instance.GetString(StringNames.Admin).camelString() ); @@ -3522,7 +3633,7 @@ public static void createButtonsPostfix(HudManager __instance) { SoundEffectsManager.stop("mediumAsk"); }, buttonText: ModTranslation.getString("MediumText"), - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.UseButton, shakeOnEnd: false ); @@ -3649,7 +3760,7 @@ Func fortuneTellerCouldUse(byte index) // keyboard shortcut KeyCode.None, true, - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ) { Timer = 0.0f, @@ -3712,6 +3823,7 @@ Func fortuneTellerCouldUse(byte index) Helpers.checkMurderAttemptAndKill(Veteran.veteran, Pursuer.pursuer); return; } + if (Pursuer.target.Data.Role.IsImpostor) _ = new StaticAchievementToken("pursuer.common1"); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetBlanked, Hazel.SendOption.Reliable, -1); writer.Write(Pursuer.target.PlayerId); writer.Write(Byte.MaxValue); @@ -3738,15 +3850,11 @@ Func fortuneTellerCouldUse(byte index) __instance, KeyCode.F, buttonText: ModTranslation.getString("PursuerText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); // Pursuer button blanks left - pursuerButtonBlanksText = GameObject.Instantiate(pursuerButton.actionButton.cooldownTimerText, pursuerButton.actionButton.cooldownTimerText.transform.parent); - pursuerButtonBlanksText.text = ""; - pursuerButtonBlanksText.enableWordWrapping = false; - pursuerButtonBlanksText.transform.localScale = Vector3.one * 0.5f; - pursuerButtonBlanksText.transform.localPosition += new Vector3(-0.05f, 0.7f, 0); + pursuerButtonBlanksText = pursuerButton.ShowUsesIcon(1); // Witch Spell button @@ -3786,7 +3894,7 @@ Func fortuneTellerCouldUse(byte index) if (Witch.spellCastingTarget == null) return; MurderAttemptResult attempt = Helpers.checkMuderAttempt(Witch.witch, Witch.spellCastingTarget); if (attempt == MurderAttemptResult.PerformKill) { - Witch.acTokenCommon ??= new("witch.common1"); + _ = new StaticAchievementToken("witch.common1"); Witch.acTokenChallenge.Value++; MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetFutureSpelled, Hazel.SendOption.Reliable, -1); writer.Write(Witch.currentTarget.PlayerId); @@ -3820,7 +3928,7 @@ Func fortuneTellerCouldUse(byte index) return; } - Sprinter.acTokenSprint ??= new("sprinter.common1"); + _ = new StaticAchievementToken("sprinter.common1"); if (Sprinter.acTokenMove != null) Sprinter.acTokenMove.Value.pos = CachedPlayer.LocalPlayer.PlayerControl.GetTruePosition(); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SprinterSprint, Hazel.SendOption.Reliable, -1); @@ -3868,7 +3976,7 @@ Func fortuneTellerCouldUse(byte index) AmongUsClient.Instance.FinishRpcImmediately(writer); RPCProcedure.sprinterSprint(PlayerControl.LocalPlayer.PlayerId, false); }, - abilityTexture: true, + abilityTexture: CustomButton.ButtonLabelType.UseButton, buttonText: ModTranslation.getString("SprintText") ) { @@ -3888,7 +3996,7 @@ Func fortuneTellerCouldUse(byte index) return; } if (attempt == MurderAttemptResult.PerformKill) { - Assassin.acTokenCommon ??= new("assassin.common1"); + _ = new StaticAchievementToken("assassin.common1"); Assassin.acTokenChallenge.Value.markKill = true; // Create first trace before killing var pos = CachedPlayer.LocalPlayer.transform.position; @@ -3979,7 +4087,7 @@ Func fortuneTellerCouldUse(byte index) Mayor.remoteMeetingsLeft--; if (Mathf.RoundToInt(CustomOptionHolder.mayorMaxRemoteMeetings.getFloat()) - Mayor.remoteMeetingsLeft >= 3) - Mayor.acTokenAnother ??= new("mayor.another1"); + _ = new StaticAchievementToken("mayor.another1"); Helpers.handleVampireBiteOnBodyReport(); // Manually call Vampire handling, since the CmdReportDeadBody Prefix won't be called Helpers.HandleUndertakerDropOnBodyReport(); @@ -4129,7 +4237,7 @@ Func fortuneTellerCouldUse(byte index) KeyCode.Z, true, buttonText: ModTranslation.getString("FreePlayOperateText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); freePlayReviveButton = new CustomButton( @@ -4157,7 +4265,7 @@ Func fortuneTellerCouldUse(byte index) KeyCode.Y, true, buttonText: ModTranslation.getString("FreePlayReviveText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); freePlaySuicideButton = new CustomButton( @@ -4186,7 +4294,7 @@ Func fortuneTellerCouldUse(byte index) KeyCode.X, true, buttonText: ModTranslation.getString("FreePlaySuicideText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); thiefKillButton = new CustomButton( @@ -4297,7 +4405,7 @@ Func fortuneTellerCouldUse(byte index) SoundEffectsManager.play("lighterLight"); }, buttonText: ModTranslation.getString("LighterText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); hunterAdminTableButton = new CustomButton( @@ -4366,7 +4474,7 @@ Func fortuneTellerCouldUse(byte index) SoundEffectsManager.play("trackerTrackPlayer"); }, buttonText: ModTranslation.getString("HunterArrowText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); huntedShieldButton = new CustomButton( @@ -4401,14 +4509,9 @@ Func fortuneTellerCouldUse(byte index) }, buttonText: ModTranslation.getString("TimeShieldText"), - abilityTexture: true + abilityTexture: CustomButton.ButtonLabelType.UseButton ); - - huntedShieldCountText = GameObject.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); + huntedShieldCountText = huntedShieldButton.ShowUsesIcon(3); // Set the default (or settings from the previous game) timers / durations when spawning the buttons initialized = true; diff --git a/TheOtherRoles/CustomGameModes/FreePlayGM.cs b/TheOtherRoles/CustomGameModes/FreePlayGM.cs index 9ef7bfff..a8d9af99 100644 --- a/TheOtherRoles/CustomGameModes/FreePlayGM.cs +++ b/TheOtherRoles/CustomGameModes/FreePlayGM.cs @@ -72,6 +72,7 @@ void SetWidget(int tab) RPCProcedure.setRole((byte)r.roleId, PlayerControl.LocalPlayer.PlayerId); if (r.roleId == RoleId.Fox) { + CachedPlayer.LocalPlayer.PlayerControl.clearAllTasks(); if (Shrine.allShrine?.FirstOrDefault() == null){ Shrine.activateShrines(GameOptionsManager.Instance.currentNormalGameOptions.MapId); } @@ -113,7 +114,7 @@ void SetWidget(int tab) SetWidget(0); } - private static void FastSetRole(this PlayerControl targetPlayer, RoleTypes roleType) + public static void FastSetRole(this PlayerControl targetPlayer, RoleTypes roleType) { NetworkedPlayerInfo data = targetPlayer.Data; RoleBehaviour roleBehaviour = UnityEngine.Object.Instantiate(RoleManager.Instance.AllRoles.First(r => r.Role == roleType), data.gameObject.transform); diff --git a/TheOtherRoles/CustomOptionHolder.cs b/TheOtherRoles/CustomOptionHolder.cs index b90e5f38..25e06409 100644 --- a/TheOtherRoles/CustomOptionHolder.cs +++ b/TheOtherRoles/CustomOptionHolder.cs @@ -7,7 +7,7 @@ namespace TheOtherRoles { 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[] ratesModifier = new string[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" }; public static string[] presets = new string[]{ "preset1", "preset2", "Random Preset Skeld", "Random Preset Mira HQ", "Random Preset Polus", "Random Preset Airship", "Random Preset Submerged" }; public static CustomOption presetSelection; @@ -305,7 +305,6 @@ public class CustomOptionHolder { public static CustomOption teleporterSpawnRate; public static CustomOption teleporterCooldown; - public static CustomOption teleporterSampleCooldown; public static CustomOption teleporterTeleportNumber; public static CustomOption tricksterSpawnRate; @@ -409,6 +408,16 @@ public class CustomOptionHolder { public static CustomOption schrodingersCatHideRole; public static CustomOption schrodingersCatCanChooseImpostor; + public static CustomOption kataomoiSpawnRate; + public static CustomOption kataomoiStareCooldown; + public static CustomOption kataomoiStareDuration; + public static CustomOption kataomoiStareCount; + public static CustomOption kataomoiStalkingCooldown; + public static CustomOption kataomoiStalkingDuration; + public static CustomOption kataomoiStalkingFadeTime; + public static CustomOption kataomoiSearchCooldown; + public static CustomOption kataomoiSearchDuration; + public static CustomOption moriartySpawnRate; public static CustomOption moriartyBrainwashTime; public static CustomOption moriartyBrainwashCooldown; @@ -849,6 +858,16 @@ public static void Load() { plagueDoctorImmunityTime = CustomOption.Create(6005, Types.Neutral, "plagueDoctorImmunityTime", 10f, 1f, 30f, 1f, plagueDoctorSpawnRate, false, "unitSeconds"); plagueDoctorInfectKiller = CustomOption.Create(6006, Types.Neutral, "plagueDoctorInfectKiller", true, plagueDoctorSpawnRate); plagueDoctorWinDead = CustomOption.Create(5999, Types.Neutral, "plagueDoctorWinDead", true, plagueDoctorSpawnRate); + + kataomoiSpawnRate = CustomOption.Create(8300, Types.Neutral, cs(Kataomoi.color, "kataomoi"), rates, null, true); + kataomoiStareCooldown = CustomOption.Create(8301, Types.Neutral, "kataomoiStareCooldown", 20f, 2.5f, 60f, 2.5f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiStareDuration = CustomOption.Create(8302, Types.Neutral, "kataomoiStareDuration", 3f, 1f, 10f, 1f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiStareCount = CustomOption.Create(8303, Types.Neutral, "kataomoiStareCount", 5f, 1f, 100f, 1f, kataomoiSpawnRate, false, "unitShots"); + kataomoiStalkingCooldown = CustomOption.Create(8304, Types.Neutral, "kataomoiStalkingCooldown", 20f, 2.5f, 60f, 2.5f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiStalkingDuration = CustomOption.Create(8305, Types.Neutral, "kataomoiStalkingDuration", 10f, 1f, 30f, 1f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiStalkingFadeTime = CustomOption.Create(8306, Types.Neutral, "kataomoiStalkingFadeTime", 0.5f, 0.0f, 2.5f, 0.5f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiSearchCooldown = CustomOption.Create(8307, Types.Neutral, "kataomoiSearchCooldown", 10f, 2.5f, 60f, 2.5f, kataomoiSpawnRate, false, "unitSeconds"); + kataomoiSearchDuration = CustomOption.Create(8308, Types.Neutral, "kataomoiSearchDuration", 10f, 1f, 30f, 1f, kataomoiSpawnRate, false, "unitSeconds"); schrodingersCatSpawnRate = CustomOption.Create(8400, Types.Neutral, cs(SchrodingersCat.color, "schrodingersCat"), rates, null, true); schrodingersCatKillCooldown = CustomOption.Create(971, Types.Neutral, "schrodingersCatKillCooldown", 20f, 1f, 60f, 0.5f, schrodingersCatSpawnRate, format: "unitSeconds"); @@ -992,7 +1011,6 @@ public static void Load() { prophetPowerCrewAsRed = CustomOption.Create(9010, Types.Crewmate, "prophetPowerCrewAsRed", false, prophetSpawnRate); teleporterSpawnRate = CustomOption.Create(9000, Types.Crewmate, cs(Teleporter.color, "teleporter"), rates, null, true); - teleporterSampleCooldown = CustomOption.Create(9004, Types.Crewmate, "teleporterSampleCooldown", 30f, 5f, 60f, 5f, teleporterSpawnRate, false, "unitSeconds"); teleporterCooldown = CustomOption.Create(9001, Types.Crewmate, "teleporterCooldown", 30f, 5f, 120f, 5f, teleporterSpawnRate, false, "unitSeconds"); teleporterTeleportNumber = CustomOption.Create(9003, Types.Crewmate, "teleporterTeleportNumber", 3f, 1f, 10f, 1f, teleporterSpawnRate, false, "unitScrews"); diff --git a/TheOtherRoles/GameHistory.cs b/TheOtherRoles/GameHistory.cs index 9a45e1ec..c8775c9f 100644 --- a/TheOtherRoles/GameHistory.cs +++ b/TheOtherRoles/GameHistory.cs @@ -14,6 +14,7 @@ public enum CustomDeathReason { Shift, //LawyerSuicide, LoverSuicide, // not necessary + KataomoiStare, WitchExile, Revenge, Suicide, @@ -67,4 +68,4 @@ public static void overrideDeathReasonAndKiller(PlayerControl player, DeadPlayer } } } -} \ No newline at end of file +} diff --git a/TheOtherRoles/Helpers.cs b/TheOtherRoles/Helpers.cs index c86a591d..bfa05137 100644 --- a/TheOtherRoles/Helpers.cs +++ b/TheOtherRoles/Helpers.cs @@ -268,7 +268,7 @@ public static void refreshRoleDescription(PlayerControl player) { foreach (var roleInfo in infos) { - taskTexts.Add(getRoleString(roleInfo)); + taskTexts.Add(getRoleString(roleInfo, Husk.husk.Any(x => x.PlayerId == player.PlayerId))); } var toRemove = new List(); @@ -306,12 +306,13 @@ public static void refreshRoleDescription(PlayerControl player) { } } - internal static string getRoleString(RoleInfo roleInfo) + internal static string getRoleString(RoleInfo roleInfo, bool isHusk) { + bool addHusk = isHusk && !roleInfo.isModifier; if (roleInfo.roleId == RoleId.Jackal) { var getSidekickText = Jackal.canCreateSidekick ? ModTranslation.getString("jackalWithSidekick") : ModTranslation.getString("jackalShortDesc"); - return cs(roleInfo.color, $"{roleInfo.name}: {getSidekickText}"); + return cs(roleInfo.color, $"{roleInfo.name}{(addHusk ? $" ({ModTranslation.getString("husk")})" : "")}: {getSidekickText}"); } if (roleInfo.roleId == RoleId.Invert) @@ -319,7 +320,7 @@ internal static string getRoleString(RoleInfo roleInfo) return cs(roleInfo.color, $"{roleInfo.name}: {roleInfo.shortDescription} ({Invert.meetings})"); } - return cs(roleInfo.color, $"{roleInfo.name}: {roleInfo.shortDescription}"); + return cs(roleInfo.color, $"{roleInfo.name}{(addHusk ? $" ({ModTranslation.getString("husk")})" : "")}: {roleInfo.shortDescription}"); } public static bool isLighterColor(int colorId) { @@ -373,7 +374,7 @@ public static int GetDisplayType(int players) public static bool hasFakeTasks(this PlayerControl player) { return (player == Jester.jester || player == Jackal.jackal || player == Sidekick.sidekick || player == Arsonist.arsonist || player == Opportunist.opportunist || player == Vulture.vulture || Jackal.formerJackals.Any(x => x == player) || player == Moriarty.moriarty || player == Moriarty.formerMoriarty || (Madmate.madmate.Any(x => x.PlayerId == player.PlayerId) && !Madmate.hasTasks) || - (player == CreatedMadmate.createdMadmate && !CreatedMadmate.hasTasks) || player == Akujo.akujo || player == PlagueDoctor.plagueDoctor || player == JekyllAndHyde.formerJekyllAndHyde || player == Cupid.cupid || (player == SchrodingersCat.schrodingersCat && !SchrodingersCat.hideRole)); + (player == CreatedMadmate.createdMadmate && !CreatedMadmate.hasTasks) || player == Akujo.akujo || player == Kataomoi.kataomoi || player == PlagueDoctor.plagueDoctor || player == JekyllAndHyde.formerJekyllAndHyde || player == Cupid.cupid || (player == SchrodingersCat.schrodingersCat && !SchrodingersCat.hideRole)); } public static bool canBeErased(this PlayerControl player) { @@ -425,6 +426,16 @@ public static bool MushroomSabotageActive() return CachedPlayer.LocalPlayer.PlayerControl.myTasks.ToArray().Any((x) => x.TaskType == TaskTypes.MushroomMixupSabotage); } + public static bool ShowButtons + { + get + { + return !(MapBehaviour.Instance && MapBehaviour.Instance.IsOpen) && + !MeetingHud.Instance && + !ExileController.Instance; + } + } + public static List removeLineFeed(string line) { var lines = line.Split("\n", StringSplitOptions.None); @@ -645,6 +656,113 @@ static public bool AnyNonTriggersBetween(Vector2 pos1, Vector2 pos2, out Vector2 return PhysicsHelpers.AnyNonTriggersBetween(pos1, vector.normalized, vector.magnitude, layerMask!.Value); } + public static bool destroyGameObjects(GameObject root, DestroyInfo[] excludeInfos = null, GameObject obj = null) + { + if (obj == null) + obj = root; + + DestroyInfo findInfo = null; + if (excludeInfos != null) + findInfo = Array.Find(excludeInfos, (info) => info.searchName == obj.name); + if (obj != root && findInfo == null) + { + UnityEngine.Object.DestroyImmediate(obj); + return true; + } + + if (findInfo == null || findInfo.isDestroyChild) + { + for (int i = 0; i < obj.transform.GetChildCount(); ++i) + { + if (destroyGameObjects(root, excludeInfos, obj.transform.GetChild(i).gameObject)) + --i; + } + } + return false; + } + + public class DestroyInfo + { + public DestroyInfo(string searchName, bool isFindChild = true) + { + this.searchName = searchName; + this.isDestroyChild = isFindChild; + } + + public string searchName = ""; + public bool isDestroyChild = true; + } + + public static bool hideGameObjects(GameObject root, DestroyInfo[] excludeInfos = null, GameObject obj = null) + { + if (obj == null) + obj = root; + + DestroyInfo findInfo = null; + if (excludeInfos != null) + findInfo = Array.Find(excludeInfos, (info) => info.searchName == obj.name); + if (obj != root && findInfo == null) + { + obj.SetActive(false); + return true; + } + + if (findInfo == null || findInfo.isDestroyChild) + { + for (int i = 0; i < obj.transform.GetChildCount(); ++i) + { + if (destroyGameObjects(root, excludeInfos, obj.transform.GetChild(i).gameObject)) + --i; + } + } + return false; + } + + public static PlayerControl getPlayerById(byte playerId) + { + return PlayerControl.AllPlayerControls.GetFastEnumerator().ToArray().Where(p => p.PlayerId == playerId).FirstOrDefault(); + } + + public static MeshFilter CreateRectMesh(this MeshFilter filter, Vector2 size, Vector3? center = null) + { + center ??= Vector3.zero; + + var mesh = filter.mesh; + + float x = size.x * 0.5f; + float y = size.y * 0.5f; + mesh.SetVertices(new Vector3[] { + new Vector3(-x, -y) + center.Value, + new Vector3(x, -y) + center.Value, + new Vector3(-x, y) + center.Value, + new Vector3(x, y) + center.Value}); + mesh.SetTriangles(new int[] { 0, 2, 1, 2, 3, 1 }, 0); + mesh.SetUVs(0, new Vector2[] { new(0, 0), new(1, 0), new(0, 1), new(1, 1) }); + var color = new Color32(255, 255, 255, 255); + mesh.SetColors(new Color32[] { color, color, color, color }); + + return filter; + } + + public static RenderTexture SetCameraRenderTexture(this Camera camera, int textureX, int textureY) + { + if (camera.targetTexture) GameObject.Destroy(camera.targetTexture); + camera.targetTexture = new RenderTexture(textureX, textureY, 32, RenderTextureFormat.ARGB32); + + return camera.targetTexture; + } + + public static (MeshRenderer renderer, MeshFilter filter) CreateMeshRenderer(string objName, Transform parent, Vector3 localPosition, int? layer, Color? color = null) + { + var meshFilter = CreateObject("mesh", parent, localPosition, layer); + var meshRenderer = meshFilter.gameObject.AddComponent(); + meshRenderer.material = new Material(Shader.Find(color.HasValue ? "Unlit/Color" : "Unlit/Texture")); + if (color.HasValue) meshRenderer.sharedMaterial.color = color.Value; + meshFilter.mesh = new Mesh(); + + return (meshRenderer, meshFilter); + } + public static void setSemiTransparent(this PoolablePlayer player, bool value) { float alpha = value ? 0.25f : 1f; foreach (SpriteRenderer r in player.gameObject.GetComponentsInChildren()) @@ -826,6 +944,7 @@ public static bool hidePlayerName(PlayerControl source, PlayerControl target) { if (!source.Data.Role.IsImpostor && Ninja.isStealthed(target) && Ninja.ninja == target) return true; // Hide Ninja nametags from non-impostors if (Sprinter.sprinting && Sprinter.sprinter == target && source != Sprinter.sprinter) return true; // Hide Sprinter nametags if (Fox.stealthed && Fox.fox == target && source != Fox.fox) return true; // Hide Fox nametags + if (source != target && Kataomoi.isStalking(target)) return true; // Hide Kataomoi nametags if (Patches.SurveillanceMinigamePatch.nightVisionIsActive) return true; //else if (Assassin.isInvisble && Assassin.assassin == target) return true; else if (!TORMapOptions.hidePlayerNames) return false; // All names are visible @@ -1102,6 +1221,21 @@ public static PlainShipRoom getPlainShipRoom(PlayerControl p) return null; } + public static bool roleCanUseSabotage(this PlayerControl player) { + bool roleCouldUse = false; + if (Madmate.madmate.Any(x => x.PlayerId == player?.PlayerId) && Madmate.canSabotage) + roleCouldUse = true; + else if (CreatedMadmate.createdMadmate != null && CachedPlayer.LocalPlayer.PlayerControl == CreatedMadmate.createdMadmate && CreatedMadmate.canSabotage) + roleCouldUse = true; + else if (Janitor.janitor != null && Janitor.janitor == CachedPlayer.LocalPlayer.PlayerControl) + roleCouldUse = false; + else if (Mafioso.mafioso != null && Mafioso.mafioso == CachedPlayer.LocalPlayer.PlayerControl && Godfather.godfather != null && !Godfather.godfather.Data.IsDead) + roleCouldUse = false; + else if (player?.Data?.Role?.IsImpostor == true) + roleCouldUse = true; + return roleCouldUse; + } + public static bool roleCanUseVents(this PlayerControl player) { bool roleCouldUse = false; if (Engineer.engineer != null && Engineer.engineer == player) @@ -1134,13 +1268,9 @@ public static bool roleCanUseVents(this PlayerControl player) { else if (Mafioso.mafioso != null && Mafioso.mafioso == CachedPlayer.LocalPlayer.PlayerControl && Godfather.godfather != null && !Godfather.godfather.Data.IsDead) roleCouldUse = false; else if (Ninja.ninja != null && Ninja.ninja == CachedPlayer.LocalPlayer.PlayerControl && Ninja.canUseVents == false) - { - roleCouldUse = false; - } - else if (Undertaker.undertaker != null && Undertaker.undertaker == CachedPlayer.LocalPlayer.PlayerControl && Undertaker.DraggedBody != null && Undertaker.disableVent) - { - roleCouldUse = false; - } + roleCouldUse = false; + else if (Undertaker.undertaker != null && Undertaker.undertaker == CachedPlayer.LocalPlayer.PlayerControl && Undertaker.DraggedBody != null && Undertaker.disableVent) + roleCouldUse = false; else roleCouldUse = true; } @@ -1350,14 +1480,26 @@ public static void toggleZoom(bool reset=false) { { var rend = tzGO.transform.Find("Inactive").GetComponent(); var rendActive = tzGO.transform.Find("Active").GetComponent(); - rend.sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Plus_Button.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_Button.png", 100f); - rendActive.sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Plus_ButtonActive.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_ButtonActive.png", 100f); + rend.sprite = zoomOutStatus ? loadSpriteFromResources("TheOtherRoles.Resources.Plus_Button.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_Button.png", 100f); + rendActive.sprite = zoomOutStatus ? loadSpriteFromResources("TheOtherRoles.Resources.Plus_ButtonActive.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_ButtonActive.png", 100f); tzGO.transform.localScale = new Vector3(1.2f, 1.2f, 1f) * (zoomOutStatus ? 4 : 1); } ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); // This will move button positions to the correct position. } + public static float GetShadowSize() + { + var shadowCollab = Camera.main.GetComponentInChildren(); + return shadowCollab.ShadowCamera.orthographicSize; + } + public static void ChangeShadowSize(float orthographicSize = 3f) + { + var shadowCollab = Camera.main.GetComponentInChildren(); + shadowCollab.ShadowCamera.orthographicSize = orthographicSize; + shadowCollab.ShadowQuad.transform.localScale = new Vector3(orthographicSize * Camera.main.aspect, orthographicSize) * 2f; + } + public static void AddModSettingsChangeMessage(this NotificationPopper popper, StringNames key, string value, string option, bool playSound = true) { string str = DestroyableSingleton.Instance.GetString(StringNames.LobbyChangeSettingNotification, "" + option + "", "" + value + ""); diff --git a/TheOtherRoles/Main.cs b/TheOtherRoles/Main.cs index b377f528..315602f8 100644 --- a/TheOtherRoles/Main.cs +++ b/TheOtherRoles/Main.cs @@ -35,7 +35,7 @@ namespace TheOtherRoles public class TheOtherRolesPlugin : BasePlugin { public const string Id = "me.eisbison.theotherroles"; - public const string VersionString = "1.2.9"; + public const string VersionString = "1.3.0"; public static uint betaDays = 0; // amount of days for the build to be usable (0 for infinite!) public static Version Version = Version.Parse(VersionString); diff --git a/TheOtherRoles/MetaContext/MetaContext.cs b/TheOtherRoles/MetaContext/MetaContext.cs index ded2f54c..59a94956 100644 --- a/TheOtherRoles/MetaContext/MetaContext.cs +++ b/TheOtherRoles/MetaContext/MetaContext.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using TheOtherRoles.Modules; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; @@ -478,6 +479,7 @@ public TextAttributes GetAttribute(AttributeAsset attribute) AttributeAsset.StandardMediumMasked => new TextAttributes(TextAlignment.Center, GetFont(FontAsset.Gothic), FontStyle.Bold, new(1.6f, 0.8f, 1.6f), new(1.45f, 0.3f), new(255, 255, 255), false), AttributeAsset.StandardLargeWideMasked => new TextAttributes(TextAlignment.Center, GetFont(FontAsset.Gothic), FontStyle.Bold, new(1.7f, 1f, 1.7f), new(2.9f, 0.45f), new(255, 255, 255), false), AttributeAsset.OverlayContent => new TextAttributes(Instance.GetAttribute(AttributeParams.StandardBaredLeft)) { FontSize = new(1.5f, 1.1f, 1.5f), Size = new(5f, 6f) }, + AttributeAsset.OverlayTitle => new TextAttributes(Instance.GetAttribute(AttributeParams.StandardBaredBoldLeft)) { FontSize = new(1.8f) }, AttributeAsset.MetaRoleButton => new TextAttributes(TextAlignment.Center, GetFont(FontAsset.GothicMasked), FontStyle.Bold, new(1.8f, 1f, 2f), new(1.4f, 0.26f), new(255, 255, 255), false), AttributeAsset.DocumentTitle => new TextAttributes(Instance.GetAttribute(AttributeParams.StandardBoldLeft)) { FontSize = new(2.2f, 0.6f, 2.2f), Size = new(5f, 6f) }, AttributeAsset.DocumentStandard => new TextAttributes(Instance.GetAttribute(AttributeParams.StandardLeft)) { FontSize = new(1.2f, 0.6f, 1.2f), Size = new(7f, 6f) }, diff --git a/TheOtherRoles/MetaContext/MetaText.cs b/TheOtherRoles/MetaContext/MetaText.cs index ebece3ce..78285c6e 100644 --- a/TheOtherRoles/MetaContext/MetaText.cs +++ b/TheOtherRoles/MetaContext/MetaText.cs @@ -119,6 +119,11 @@ public enum AttributeAsset /// MetaRoleButton, + /// + /// 主にオーバーレイ向けの見出し用可変サイズテキスト属性です。 + /// + OverlayTitle, + /// /// SerializableDocumentのTextStyle"Title"で提供されているテキスト属性です。 /// diff --git a/TheOtherRoles/MetaContext/SpriteLoader.cs b/TheOtherRoles/MetaContext/SpriteLoader.cs index 4f774d41..221893e1 100644 --- a/TheOtherRoles/MetaContext/SpriteLoader.cs +++ b/TheOtherRoles/MetaContext/SpriteLoader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -136,8 +136,71 @@ public Texture2D GetTexture() } return texture; } - } + } + public class XOnlyDividedSpriteLoader : Image, IDividedSpriteLoader + { + float pixelsPerUnit; + Sprite[] sprites; + ITextureLoader texture; + int? division, size; + public Vector2 Pivot = new(0.5f, 0.5f); + + public XOnlyDividedSpriteLoader(ITextureLoader textureLoader, float pixelsPerUnit, int x, bool isSize = false) + { + this.pixelsPerUnit = pixelsPerUnit; + if (isSize) + { + this.size = x; + this.division = null; + } + else + { + this.division = x; + this.size = null; + } + sprites = null!; + texture = textureLoader; + } + + public Sprite GetSprite(int index) + { + if (!size.HasValue || !division.HasValue || sprites == null) + { + var texture2D = texture.GetTexture(); + if (size == null) + size = texture2D.width / division; + else if (division == null) + division = texture2D.width / size!; + sprites = new Sprite[division!.Value]; + } + + if (!sprites[index]) + { + var texture2D = texture.GetTexture(); + sprites[index] = texture2D.ToSprite(new Rect(index * size!.Value, 0, size!.Value, texture2D.height), Pivot, pixelsPerUnit); + } + return sprites[index]; + } + + public Sprite GetSprite() => GetSprite(0); + + public int Length + { + get + { + if (!division.HasValue) GetSprite(0); + return division!.Value; + } + } + + public Image WrapLoader(int index) => new WrapSpriteLoader(() => GetSprite(index)); + + static public XOnlyDividedSpriteLoader FromResource(string address, float pixelsPerUnit, int x, bool isSize = false) + => new(new ResourceTextureLoader(address), pixelsPerUnit, x, isSize); + static public XOnlyDividedSpriteLoader FromDisk(string address, float pixelsPerUnit, int x, bool isSize = false) + => new(new DiskTextureLoader(address), pixelsPerUnit, x, isSize); + } public class DividedSpriteLoader : Image, IDividedSpriteLoader { diff --git a/TheOtherRoles/MetaContext/TextField.cs b/TheOtherRoles/MetaContext/TextField.cs index b1ea5d89..d3839703 100644 --- a/TheOtherRoles/MetaContext/TextField.cs +++ b/TheOtherRoles/MetaContext/TextField.cs @@ -1,4 +1,4 @@ -using HarmonyLib; +using HarmonyLib; using System; using System.Collections; using System.Collections.Generic; @@ -587,7 +587,9 @@ static public void LoadAssetsOnTitle() StandardTextPrefab.gameObject.hideFlags = HideFlags.HideAndDontSave; UnityEngine.Object.Destroy(StandardTextPrefab.spriteAnimator); UnityEngine.Object.DontDestroyOnLoad(StandardTextPrefab.gameObject); - } + } + + public static void PlayHoverSE() => SoundManager.Instance.PlaySound(HoverClip, false, 0.8f); static public void LoadAssetAtInitialize() { diff --git a/TheOtherRoles/Modules/Achievement.cs b/TheOtherRoles/Modules/Achievement.cs index ff78ef07..62d1eb18 100644 --- a/TheOtherRoles/Modules/Achievement.cs +++ b/TheOtherRoles/Modules/Achievement.cs @@ -1,4 +1,4 @@ -using BepInEx.Unity.IL2CPP.Utils; +using BepInEx.Unity.IL2CPP.Utils; using BepInEx.Unity.IL2CPP.Utils.Collections; using Innersloth.IO; using System; diff --git a/TheOtherRoles/Modules/AssetLoader.cs b/TheOtherRoles/Modules/AssetLoader.cs index be0aef4b..3a75ded6 100644 --- a/TheOtherRoles/Modules/AssetLoader.cs +++ b/TheOtherRoles/Modules/AssetLoader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/TheOtherRoles/Modules/BepInExUpdater.cs b/TheOtherRoles/Modules/BepInExUpdater.cs index 9702678d..4cef9a28 100644 --- a/TheOtherRoles/Modules/BepInExUpdater.cs +++ b/TheOtherRoles/Modules/BepInExUpdater.cs @@ -58,9 +58,11 @@ public IEnumerator CoUpdate() resource!.CopyTo(file); } } - - var startInfo = new ProcessStartInfo(tempPath, $"--game-path \"{Paths.GameRootPath}\" --zip \"{zipPath}\""); - startInfo.UseShellExecute = false; + + var startInfo = new ProcessStartInfo(tempPath, $"--game-path \"{Paths.GameRootPath}\" --zip \"{zipPath}\"") + { + UseShellExecute = false + }; Process.Start(startInfo); Application.Quit(); } @@ -80,4 +82,4 @@ public static bool Prefix() { return !BepInExUpdater.UpdateRequired; } -} \ No newline at end of file +} diff --git a/TheOtherRoles/Modules/ButtonEffect.cs b/TheOtherRoles/Modules/ButtonEffect.cs index 94ff758c..a9c59526 100644 --- a/TheOtherRoles/Modules/ButtonEffect.cs +++ b/TheOtherRoles/Modules/ButtonEffect.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -68,7 +68,14 @@ static KeyCodeInfo() } static Image keyBindBackgroundSprite = SpriteLoader.FromResource("TheOtherRoles.Resources.KeyBindBackground.png", 100f); - static Image mouseDisableActionSprite = SpriteLoader.FromResource("TheOtherRoles.Resources.MouseActionDisableIcon.png", 100f); + static Image mouseDisableActionSprite = SpriteLoader.FromResource("TheOtherRoles.Resources.MouseActionDisableIcon.png", 100f); + static Image infoActionSprite = SpriteLoader.FromResource("TheOtherRoles.Resources.ButtonInfoIcon.png", 100f); + + public enum ActionIconType + { + NonClickAction, + InfoAction + } static public GameObject AddKeyGuide(GameObject button, KeyCode key, UnityEngine.Vector2 pos, bool removeExistingGuide, string action = null) { @@ -78,16 +85,20 @@ static public GameObject AddKeyGuide(GameObject button, KeyCode key, UnityEngine if (KeyCodeInfo.AllKeyInfo.ContainsKey(key)) numSprite = KeyCodeInfo.AllKeyInfo[key].Sprite; if (numSprite == null) return null; - GameObject obj = new(); - obj.name = "HotKeyGuide"; + GameObject obj = new() + { + name = "HotKeyGuide" + }; obj.transform.SetParent(button.transform); obj.layer = button.layer; SpriteRenderer renderer = obj.AddComponent(); renderer.transform.localPosition = (UnityEngine.Vector3)pos + new UnityEngine.Vector3(0f, 0f, -10f); renderer.sprite = keyBindBackgroundSprite.GetSprite(); - GameObject numObj = new(); - numObj.name = "HotKeyText"; + GameObject numObj = new() + { + name = "HotKeyText" + }; numObj.transform.SetParent(obj.transform); numObj.layer = button.layer; renderer = numObj.AddComponent(); @@ -117,7 +128,7 @@ public static void SetHintOverlay(GameObject gameObj, KeyCode keyCode, string ac button.OnMouseOut.AddListener((Action)(() => TORGUIManager.Instance.HideHelpContextIf(button))); } - static public GameObject SetMouseActionIcon(GameObject button, bool show, string action = "mouseClick", bool atBottom = true) + static public GameObject SetMouseActionIcon(GameObject button, bool show, string action = "mouseClick", bool atBottom = true, ActionIconType actionType = ActionIconType.NonClickAction) { if (!show) { @@ -126,18 +137,40 @@ static public GameObject SetMouseActionIcon(GameObject button, bool show, string } else { - GameObject obj = new(); - obj.name = "MouseAction"; + GameObject obj = new() + { + name = "MouseAction" + }; obj.transform.SetParent(button.transform); obj.layer = button.layer; SpriteRenderer renderer = obj.AddComponent(); renderer.transform.localPosition = new(0.48f, atBottom ? -0.29f : 0.48f, -10f); - renderer.sprite = mouseDisableActionSprite.GetSprite(); + renderer.sprite = actionType == ActionIconType.NonClickAction ? mouseDisableActionSprite.GetSprite() : infoActionSprite.GetSprite(); if (action != null) SetHintOverlay(obj, KeyCode.None, action); return obj; } + } + + private static IDividedSpriteLoader textureUsesIconsSprite = XOnlyDividedSpriteLoader.FromResource("TheOtherRoles.Resources.UsesIcon.png", 120f, 10); + static public GameObject ShowUsesIcon(this ActionButton button) + { + Transform template = HudManager.Instance.AbilityButton.transform.GetChild(2); + var usesObject = GameObject.Instantiate(template.gameObject); + usesObject.transform.SetParent(button.gameObject.transform); + usesObject.transform.localScale = template.localScale; + usesObject.transform.localPosition = template.localPosition * 1.2f; + return usesObject; + } + + static public GameObject ShowUsesIcon(this ActionButton button, int iconVariation, out TMPro.TextMeshPro text) + { + GameObject result = ShowUsesIcon(button); + var renderer = result.GetComponent(); + renderer.sprite = textureUsesIconsSprite.GetSprite(iconVariation); + text = result.transform.GetChild(0).GetComponent(); + return result; } static public void ShowVanillaKeyGuide(this HudManager manager) diff --git a/TheOtherRoles/Modules/CustomOverlay.cs b/TheOtherRoles/Modules/CustomOverlay.cs index 283aaf3f..70d2e47e 100644 --- a/TheOtherRoles/Modules/CustomOverlay.cs +++ b/TheOtherRoles/Modules/CustomOverlay.cs @@ -133,8 +133,9 @@ public static void showInfoOverlay() (roleDesc != "" ? $"\n{r.fullDescription}" : "") + "\n\n"; } - var rows = rolesText.Count(c => c == '\n'); - var maxY = Mathf.Max(1.15f, (2 * rows - 24) * 0.04f + 1.16f); + var rows = rolesText.Count(c => c == '\n'); + var infoCount = RoleInfo.getRoleInfoForPlayer(CachedPlayer.LocalPlayer.PlayerControl).Count; + var maxY = Mathf.Max(1.15f, (infoCount * 2.2f + rows - 18f) * (AmongUs.Data.DataManager.Settings.Language.CurrentLanguage == SupportedLangs.English ? 0.06f : 0.09f) + 1.165f); scroller.enabled = true; scroller.ContentYBounds = new FloatRange(1.15f, maxY); scroller.ScrollToTop(); diff --git a/TheOtherRoles/Modules/GameStatistics.cs b/TheOtherRoles/Modules/GameStatistics.cs index 3a326ad0..4ea489a4 100644 --- a/TheOtherRoles/Modules/GameStatistics.cs +++ b/TheOtherRoles/Modules/GameStatistics.cs @@ -1,4 +1,4 @@ -using BepInEx.Unity.IL2CPP.Utils.Collections; +using BepInEx.Unity.IL2CPP.Utils.Collections; using HarmonyLib; using Hazel; using System; @@ -104,24 +104,27 @@ public class RoleHistory public RoleInfo roleInfo = null; public float historyTime = 0f; public NetworkedPlayerInfo.PlayerOutfit playerOutfit = null; - public bool isMadmate = false; + public bool isMadmate = false; + public Color32 defaultColor = default; - public RoleHistory(string playerName, RoleInfo roleInfo, float historyTime, NetworkedPlayerInfo.PlayerOutfit playerOutfit, bool isMadmate) + public RoleHistory(string playerName, RoleInfo roleInfo, float historyTime, NetworkedPlayerInfo.PlayerOutfit playerOutfit, bool isMadmate, Color32 color) { this.playerName = playerName; this.roleInfo = roleInfo; this.historyTime = historyTime; this.playerOutfit = playerOutfit; - this.isMadmate = isMadmate; + this.isMadmate = isMadmate; + defaultColor = color; } } public static void recordRoleHistory(PlayerControl player) { - if (player == null) return; + if (player == null) return; + var info = RoleInfo.getRoleInfoForPlayer(player, false, true).FirstOrDefault(); if (roleHistory.ContainsKey(player.PlayerId)) - roleHistory[player.PlayerId].Add(new(player.Data.PlayerName, RoleInfo.getRoleInfoForPlayer(player, false, true).FirstOrDefault(), currentTime, player.Data.DefaultOutfit, Madmate.madmate.Any(x => - x.PlayerId == player.PlayerId) || CreatedMadmate.createdMadmate == player)); + roleHistory[player.PlayerId].Add(new(player.Data.PlayerName, info, currentTime, player.Data.DefaultOutfit, Madmate.madmate.Any(x => + x.PlayerId == player.PlayerId) || CreatedMadmate.createdMadmate == player, info.color)); } public class StatisticsEvent @@ -621,10 +624,9 @@ public void Show(GameStatistics.Event statisticsEvent) var history = GameStatistics.roleHistory[near.Item1].Where(x => x.historyTime <= statisticsEvent.Time).LastOrDefault(); var role = history.roleInfo; bool isMadmate = history.isMadmate; - var roleText = Helpers.cs(isMadmate ? Madmate.color : role.color, isMadmate ? (role == RoleInfo.crewmate ? Madmate.fullName : Madmate.prefix + role.name) : role.name); + var roleText = Helpers.cs(isMadmate ? Madmate.color : history.defaultColor, isMadmate ? (role == RoleInfo.crewmate ? Madmate.fullName : Madmate.prefix + role.name) : role.name); context.Append(new MetaContextOld.Text(TextAttribute.BoldAttrLeft) { RawText = GameStatistics.roleHistory[near.Item1].FirstOrDefault().playerName }); context.Append(new MetaContextOld.VariableText(new TextAttribute(TextAttribute.BoldAttrLeft) { Alignment = TMPro.TextAlignmentOptions.TopLeft }.EditFontSize(1.35f)) { RawText = roleText }); - } TORGUIManager.Instance.SetHelpContext(button, context); @@ -738,4 +740,4 @@ public static implicit operator Il2CppArgument(T value) return new Il2CppArgument(value); } } -} \ No newline at end of file +} diff --git a/TheOtherRoles/Modules/MeetingOverlayHolder.cs b/TheOtherRoles/Modules/MeetingOverlayHolder.cs new file mode 100644 index 00000000..d9ab9a09 --- /dev/null +++ b/TheOtherRoles/Modules/MeetingOverlayHolder.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BepInEx.Unity.IL2CPP.Utils.Collections; +using TheOtherRoles.MetaContext; +using UnityEngine; + +namespace TheOtherRoles.Modules +{ + internal class MeetingOverlayHolder + { + static IDividedSpriteLoader IconSprite = DividedSpriteLoader.FromResource("TheOtherRoles.Resources.MeetingNotification.png", 100f, 4, 1); + static Image NotificationSprite = SpriteLoader.FromResource("TheOtherRoles.Resources.MeetingNotificationDot.png", 135f); + static public Image[] IconsSprite = Helpers.Sequential(IconSprite.Length).Select(num => new WrapSpriteLoader(() => IconSprite.GetSprite(num))).ToArray(); + + static List<(GUIContextSupplier overlay, Image icon, UnityEngine.Color color, Reference isNew)> icons = new(); + static Transform shower; + + public static void clearAndReload() => icons.Clear(); + + public static void RegisterOverlay(GUIContextSupplier overlay, Image icon, UnityEngine.Color color) + { + icons.Add((overlay, icon, color, new Reference() { Value = true })); + Generate(icons.Count - 1); + } + + static void Generate(int index) + { + if (!shower) return; + + if (icons.Count <= index) return; + var icon = icons[index]; + + var renderer = Helpers.CreateObject("Icon", shower, new(-3.6f + index * 0.48f, 0f, 0f)); + renderer.sprite = IconSprite.GetSprite(0); + renderer.color = Color.Lerp(icon.color, Color.white, 0.3f); + + var iconInner = Helpers.CreateObject("Inner", renderer.transform, new(0f, 0f, -1f)); + iconInner.sprite = icon.icon.GetSprite(); + + var notification = Helpers.CreateObject("Notification", renderer.transform, new(0.19f, 0.19f, -1.5f)); + notification.sprite = NotificationSprite.GetSprite(); + notification.gameObject.SetActive(icon.isNew.Value); + + IEnumerator CoAppear() + { + float p = 0f; + while (true) + { + p += Time.deltaTime * 2.4f; + if (p > 1f) break; + + //曲線(0<=x<=1): x\ +\ \left(\cos0.5x\pi\ \right)^{1.5}\cdot x^{0.3}\cdot2.5 + if (p > 0f) + renderer.transform.localScale = Vector3.one * (p + Mathf.Pow(Mathf.Cos(0.5f * p * Mathf.PI), 1.5f) * Mathf.Pow(p, 0.3f) * 2.5f); + else + renderer.transform.localScale = Vector3.zero; + yield return null; + } + renderer.transform.localScale = Vector3.one; + } + + if (icon.isNew.Value) TORGUIManager.Instance.StartCoroutine(CoAppear().WrapToIl2Cpp()); + + var collider = renderer.gameObject.AddComponent(); + collider.isTrigger = true; + collider.size = new(0.4f, 0.4f); + + var button = renderer.gameObject.SetUpButton(false, renderer, icon.color); + button.OnMouseOver.AddListener((Action)(() => { VanillaAsset.PlayHoverSE(); TORGUIManager.Instance.SetHelpContext(button, icon.overlay.Invoke()); notification.gameObject.SetActive(false); icon.isNew.Set(false); })); + button.OnMouseOut.AddListener((Action)(() => TORGUIManager.Instance.HideHelpContextIf(button))); + } + + public static void OnMeetingStart() + { + shower = Helpers.CreateObject("OverlayHolder", MeetingHud.Instance.transform, new(0f, 2.7f, -20f)).transform; + for (int i = 0; i < icons.Count; i++) Generate(i); + } + } +} diff --git a/TheOtherRoles/Objects/Arrow.cs b/TheOtherRoles/Objects/Arrow.cs index d0077bb5..aa83bc8d 100644 --- a/TheOtherRoles/Objects/Arrow.cs +++ b/TheOtherRoles/Objects/Arrow.cs @@ -17,8 +17,10 @@ public static Sprite getSprite() { public Arrow(Color color) { - arrow = new GameObject("Arrow"); - arrow.layer = 5; + arrow = new GameObject("Arrow") + { + layer = 5 + }; image = arrow.AddComponent(); image.sprite = getSprite(); image.color = color; @@ -79,4 +81,4 @@ public static void UpdateProximity(Vector3 position) Tracker.Meter.SetDangerValue(dangerLevel1, dangerLevel2); } } -} \ No newline at end of file +} diff --git a/TheOtherRoles/Objects/CustomButton.cs b/TheOtherRoles/Objects/CustomButton.cs index f3131967..d9799284 100644 --- a/TheOtherRoles/Objects/CustomButton.cs +++ b/TheOtherRoles/Objects/CustomButton.cs @@ -1,3 +1,4 @@ +using AmongUs.GameOptions; using Il2CppSystem.Runtime.ExceptionServices; using System; using System.Collections.Generic; @@ -52,7 +53,15 @@ public static class ButtonPositions { public static readonly Vector3 upperRowFarLeft = new(-3f, 1f, 0f); } - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool HasEffect, float EffectDuration, Action OnEffectEnds, bool mirror = false, string buttonText = "", bool abilityTexture = false, string actionName = "", bool shakeOnEnd = true) + public enum ButtonLabelType + { + UseButton, + AdminButton, + KillButton, + HauntButton + } + + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool HasEffect, float EffectDuration, Action OnEffectEnds, bool mirror = false, string buttonText = "", ButtonLabelType abilityTexture = ButtonLabelType.KillButton, string actionName = "", bool shakeOnEnd = true) { this.hudManager = hudManager; this.OnClick = OnClick; @@ -76,21 +85,17 @@ public CustomButton(Action OnClick, Func HasButton, Func CouldUse, A actionButtonGameObject = actionButton.gameObject; actionButtonRenderer = actionButton.graphic; actionButtonMat = actionButtonRenderer.material; - if (abilityTexture) - { - UnityEngine.Object.Destroy(actionButton.buttonLabelText); - actionButton.buttonLabelText = UnityEngine.Object.Instantiate(hudManager.UseButton.buttonLabelText, actionButton.transform); - } + setLabelType(abilityTexture); actionButtonLabelText = actionButton.buttonLabelText; PassiveButton button = actionButton.GetComponent(); - this.showButtonText = (actionButtonRenderer.sprite == Sprite || buttonText != ""); + showButtonText = actionButtonRenderer.sprite == Sprite || buttonText != ""; button.OnClick = new Button.ButtonClickedEvent(); button.OnClick.AddListener((UnityEngine.Events.UnityAction)onClickEvent); setKeyBind(); setActive(false); } - public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool mirror = false, string buttonText = "", bool abilityTexture = false, string actionName = "", bool shakeOnEnd = true) + public CustomButton(Action OnClick, Func HasButton, Func CouldUse, Action OnMeetingEnds, Sprite Sprite, Vector3 PositionOffset, HudManager hudManager, KeyCode? hotkey, bool mirror = false, string buttonText = "", ButtonLabelType abilityTexture = ButtonLabelType.KillButton, string actionName = "", bool shakeOnEnd = true) : this(OnClick, HasButton, CouldUse, OnMeetingEnds, Sprite, PositionOffset, hudManager, hotkey, false, 0f, () => {}, mirror, buttonText, abilityTexture, actionName, shakeOnEnd) { } public void onClickEvent() @@ -255,9 +260,34 @@ public void Update() } } + internal GameObject UsesIcon = null!; + public TMPro.TextMeshPro ShowUsesIcon(int iconVariation) + { + if (UsesIcon) GameObject.Destroy(UsesIcon); + UsesIcon = ButtonEffect.ShowUsesIcon(actionButton, iconVariation, out var text); + return text; + } + + public void setLabelType(ButtonLabelType labelType) + { + Material mat = null; + switch (labelType) + { + case ButtonLabelType.UseButton: + mat = hudManager.UseButton.fastUseSettings[ImageNames.UseButton].FontMaterial; break; + case ButtonLabelType.AdminButton: + mat = hudManager.UseButton.fastUseSettings[ImageNames.PolusAdminButton].FontMaterial; break; + case ButtonLabelType.KillButton: + mat = RoleManager.Instance.GetRole(RoleTypes.Shapeshifter).Ability.FontMaterial; break; + case ButtonLabelType.HauntButton: + mat = RoleManager.Instance.GetRole(RoleTypes.Engineer).Ability.FontMaterial; break; + } + if (mat != null) actionButton.buttonLabelText.SetSharedMaterial(mat); + } + public void setKeyBind() { - if (hotkey != null && hotkey != KeyCode.None && hotkey != KeyCode.KeypadPlus) + if (hotkey is not null and not KeyCode.None and not KeyCode.KeypadPlus) { actionButtonGameObject.ForEachChild((Il2CppSystem.Action)((c) => { if (c.name.Equals("HotKeyGuide")) GameObject.Destroy(c); })); ButtonEffect.SetKeyGuide(actionButtonGameObject, (KeyCode)hotkey, action: actionName != "" ? actionName : (showButtonText && buttonText != "" ? buttonText : ModTranslation.getString("buttonsActionButton"))); @@ -275,4 +305,4 @@ public void resetKeyBind() setKeyBind(); } } -} \ No newline at end of file +} diff --git a/TheOtherRoles/Objects/CustomNormalPlayerTask.cs b/TheOtherRoles/Objects/CustomNormalPlayerTask.cs index de92c0e9..bc2a334a 100644 --- a/TheOtherRoles/Objects/CustomNormalPlayerTask.cs +++ b/TheOtherRoles/Objects/CustomNormalPlayerTask.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -18,7 +18,7 @@ public class CustomNormalPlayerTask public static List allTasks = new(); public static List completedConsoles = new(); public static uint counter = 0; - public static NormalPlayerTask npt; + NormalPlayerTask npt; public CustomNormalPlayerTask(string name, Il2CppSystem.Type taskType, int maxStep, byte[] Data, SystemTypes startAt, bool showTaskStep) { @@ -53,10 +53,13 @@ public CustomNormalPlayerTask(string name, Il2CppSystem.Type taskType, int maxSt public void addTaskToPlayer(byte playerId) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.FoxSetTask, SendOption.Reliable, -1); - writer.Write(playerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - RPCProcedure.foxSetTasks(playerId); + Helpers.getPlayerById(playerId).myTasks.Add(npt); + NetworkedPlayerInfo pi = GameData.Instance.GetPlayerById(playerId); + var taskinfo = new NetworkedPlayerInfo.TaskInfo((byte)npt.Id, npt.Id) + { + Complete = false + }; + pi.Tasks.Add(taskinfo); } public static void reset() diff --git a/TheOtherRoles/Objects/FoxTask.cs b/TheOtherRoles/Objects/FoxTask.cs index 7056bc3e..27ffa5b4 100644 --- a/TheOtherRoles/Objects/FoxTask.cs +++ b/TheOtherRoles/Objects/FoxTask.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; @@ -6,7 +6,7 @@ using TheOtherRoles.Modules; using TheOtherRoles; using static TheOtherRoles.TheOtherRoles; - +using System; namespace TheOtherRoles.Objects { @@ -23,20 +23,19 @@ public sealed class FoxTask : Minigame public void Awake() { - if (obj != null) - { - GameObject.Destroy(obj); + if (obj != null) { + Destroy(obj); } - obj = GameObject.Instantiate(prefab, this.transform); + obj = Instantiate(prefab, transform); List texts = obj.GetComponentsInChildren().ToList(); RemainingTime = texts.FirstOrDefault(x => x.name == "RemainingTime"); TaskText = texts.FirstOrDefault(x => x.name == "TaskText"); TaskText.text = ModTranslation.getString("foxTaskPray"); closeButton = obj.GetComponentsInChildren