diff --git a/Strings.xlsx b/Strings.xlsx index ba6e162..2e670bf 100644 Binary files a/Strings.xlsx and b/Strings.xlsx differ diff --git a/TheOtherRoles/CustomGameModes/FreePlayGM.cs b/TheOtherRoles/CustomGameModes/FreePlayGM.cs index df6e09c..9ef7bff 100644 --- a/TheOtherRoles/CustomGameModes/FreePlayGM.cs +++ b/TheOtherRoles/CustomGameModes/FreePlayGM.cs @@ -52,7 +52,7 @@ void SetWidget(int tab) guis ); - GUIContext inner = GUIEmptyWidget.Default; + GUIContext inner = GUIEmptyContext.Default; if (tab == 0) { @@ -107,7 +107,7 @@ void SetWidget(int tab) })), 4)} ); } - roleScreen.SetContext(gui.VerticalHolder(GUIAlignment.Center, new List() { holder, gui.ScrollView(GUIAlignment.Center, new(7.4f, 3.5f), null, inner, out _) }), out _); + roleScreen.SetContext(gui.VerticalHolder(GUIAlignment.Center, new List() { holder, TORGUIContextEngine.API.VerticalMargin(0.15f), gui.ScrollView(GUIAlignment.Center, new(7.4f, 3.5f), null, inner, out _) }), out _); } SetWidget(0); diff --git a/TheOtherRoles/Helpers.cs b/TheOtherRoles/Helpers.cs index 27bd007..c86a591 100644 --- a/TheOtherRoles/Helpers.cs +++ b/TheOtherRoles/Helpers.cs @@ -441,6 +441,9 @@ public static string camelString(this string input) return firstLetter + remainingLetters; } + public static string HeadLower(this string text) => char.ToLower(text[0]) + text[1..]; + public static string HeadUpper(this string text) => char.ToUpper(text[0]) + text[1..]; + public static IEnumerator CoGush(this PlayerControl player) { @@ -606,6 +609,12 @@ private static IEnumerator AnimateCoroutine(HideAndSeekDeathPopup __instance) UnityEngine.Object.Destroy(andSeekDeathPopup.gameObject); } + static public IEnumerator Action(Action action) + { + action.Invoke(); + yield break; + } + public static PassiveButton SetUpButton(this GameObject gameObject, bool withSound = false, SpriteRenderer buttonRenderer = null, Color? defaultColor = null, Color? selectedColor = null) { var button = gameObject.AddComponent(); diff --git a/TheOtherRoles/Main.cs b/TheOtherRoles/Main.cs index e112c88..b377f52 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.8"; + public const string VersionString = "1.2.9"; 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 ef2cb5a..ded2f54 100644 --- a/TheOtherRoles/MetaContext/MetaContext.cs +++ b/TheOtherRoles/MetaContext/MetaContext.cs @@ -179,8 +179,8 @@ public void Update() public abstract class AbstractGUIContext : GUIContext { - public GUIAlignment Alignment { get; private init; } - public GameObject Instantiate(Anchor anchor, Size size, out Size actualSize) + internal override GUIAlignment Alignment { get; init; } + internal override GameObject Instantiate(Anchor anchor, Size size, out Size actualSize) { var obj = Instantiate(size, out actualSize); @@ -198,8 +198,6 @@ public GameObject Instantiate(Anchor anchor, Size size, out Size actualSize) return obj; } - public abstract GameObject Instantiate(Size size, out Size actualSize); - public AbstractGUIContext(GUIAlignment alignment) { Alignment = alignment; @@ -299,7 +297,7 @@ public GUIScrollView(GUIAlignment alignment, UnityEngine.Vector2 size, GUIContex } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { var view = Helpers.CreateObject("ScrollView", null, new UnityEngine.Vector3(0f, 0f, 0f), LayerMask.NameToLayer("UI")); var inner = Helpers.CreateObject("Inner", view.transform, new UnityEngine.Vector3(-0.2f, 0f, -0.1f)); @@ -351,7 +349,7 @@ public class VerticalContextsHolder : ContextsHolder public VerticalContextsHolder(GUIAlignment alignment, IEnumerable contexts) : base(alignment, contexts) { } public VerticalContextsHolder(GUIAlignment alignment, params GUIContext[] contexts) : base(alignment, contexts) { } public float? FixedWidth { get; init; } = null; - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { var results = contexts.Select(c => (c.Instantiate(size, out var acSize), acSize, c)).ToArray(); (float maxWidth, float sumHeight) = results.Aggregate((0f, 0f), (r, current) => (Math.Max(r.Item1, current.acSize.Width), r.Item2 + current.acSize.Height)); @@ -383,7 +381,7 @@ public HorizontalContextsHolder(GUIAlignment alignment, IEnumerable public HorizontalContextsHolder(GUIAlignment alignment, params GUIContext[] contexts) : base(alignment, contexts) { } public float? FixedHeight { get; init; } = null; - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { var results = contexts.Select(c => (c.Instantiate(size, out var acSize), acSize, c)).ToArray(); (float sumWidth, float maxHeight) = results.Aggregate((0f, 0f), (r, current) => (r.Item1 + current.acSize.Width, Math.Max(r.Item2, current.acSize.Height))); @@ -447,10 +445,13 @@ public void SetHelpContext(PassiveUiElement related, string rawText) public class TORGUIContextEngine : GUI { - public static TORGUIContextEngine Instance { get; private set; } = new(); + public static TORGUIContextEngine Instance { get; private set; } = new(); + public static GUI API => Instance; private Dictionary allAttr = new(); private Dictionary allAttrAsset = new(); + + public GUIContext EmptyContext => GUIEmptyContext.Default; public TextAttributes GetAttribute(AttributeParams attribute) { @@ -477,7 +478,9 @@ 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.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.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) }, _ => null! }; } @@ -582,15 +585,15 @@ public GUIContext Button(GUIAlignment alignment, TextAttributes attribute, TextC } - public class GUIEmptyWidget : AbstractGUIContext + public class GUIEmptyContext : AbstractGUIContext { - static public GUIEmptyWidget Default = new(); + static public GUIEmptyContext Default = new(); - public GUIEmptyWidget(GUIAlignment alignment = GUIAlignment.Left) : base(alignment) + public GUIEmptyContext(GUIAlignment alignment = GUIAlignment.Left) : base(alignment) { } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { actualSize = new(0f, 0f); return null; @@ -611,7 +614,7 @@ public TORGUIImage(GUIAlignment alignment, Image image, FuzzySize size, Color? c this.Color = color; } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { var renderer = Helpers.CreateObject("Image", null, UnityEngine.Vector3.zero, LayerMask.NameToLayer("UI")); renderer.sprite = Image.GetSprite(); @@ -654,7 +657,7 @@ public GUIButton(GUIAlignment alignment, TextAttributes attribute, TextComponent } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { var inner = base.Instantiate(size, out actualSize)!; @@ -720,7 +723,7 @@ public TORGUIMargin(GUIAlignment alignment, UnityEngine.Vector2 margin) : base(a this.margin = margin; } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { actualSize = new(margin); return null; @@ -758,7 +761,7 @@ private void ReflectMyAttribute(TMPro.TextMeshPro text, float width) } } - public override GameObject Instantiate(Size size, out Size actualSize) + internal override GameObject Instantiate(Size size, out Size actualSize) { if (Text == null) { diff --git a/TheOtherRoles/MetaContext/MetaGUI.cs b/TheOtherRoles/MetaContext/MetaGUI.cs index 90d6712..7f80b6a 100644 --- a/TheOtherRoles/MetaContext/MetaGUI.cs +++ b/TheOtherRoles/MetaContext/MetaGUI.cs @@ -116,22 +116,31 @@ public GeneralizedArtifact(Artifact inner) public IEnumerator GetEnumerator() => Inner.Select(v => v as T).GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => Inner.Select(v => v as T).GetEnumerator(); } + + public delegate GUIContext GUIContextSupplier(); /// /// GUI上に表示できるオブジェクトの定義を表します。 /// - public interface GUIContext + public abstract class GUIContext { - internal GUIAlignment Alignment { get; } - internal GameObject Instantiate(Size size, out Size actualSize); - internal GameObject Instantiate(Anchor anchor, Size size, out Size actualSize); + internal abstract GUIAlignment Alignment { get; init; } + internal abstract GameObject Instantiate(Size size, out Size actualSize); + internal abstract GameObject Instantiate(Anchor anchor, Size size, out Size actualSize); + + public static implicit operator GUIContextSupplier(GUIContext widget) => () => widget ?? TORGUIContextEngine.Instance.EmptyContext; } /// /// GUI上に表示する各種オブジェクトの定義や関連するオブジェクトを生成できます。 /// public interface GUI - { + { + /// + /// 何も表示しないウィジェットです。 + /// + GUIContext EmptyContext { get; } + /// /// 生文字列のコンテキストです。 /// Textメソッドの呼び出しを簡素化した冗長なメソッドです。 diff --git a/TheOtherRoles/MetaContext/MetaHint.cs b/TheOtherRoles/MetaContext/MetaHint.cs new file mode 100644 index 0000000..61f5244 --- /dev/null +++ b/TheOtherRoles/MetaContext/MetaHint.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Rendering; +using UnityEngine; +using System.Collections; + +namespace TheOtherRoles.MetaContext +{ + public interface Hint + { + public GUIContextSupplier GUI { get; } + } + + public class HintWithImage : Hint + { + private Image Image { get; init; } + private TextComponent Title { get; init; } + private TextComponent Detail { get; init; } + + GUIContextSupplier Hint.GUI => () => + { + return TORGUIContextEngine.API.VerticalHolder(GUIAlignment.Center, + TORGUIContextEngine.API.Margin(new(null, 0.5f)), + TORGUIContextEngine.API.Image(GUIAlignment.Center, Image, new(4f, 2.1f)), + TORGUIContextEngine.API.Margin(new(null, 0.6f)), + TORGUIContextEngine.API.Text(GUIAlignment.Left, TORGUIContextEngine.API.GetAttribute(AttributeAsset.DocumentTitle), Title), + TORGUIContextEngine.API.Margin(new(null, 0.1f)), + TORGUIContextEngine.API.HorizontalHolder(GUIAlignment.Center, TORGUIContextEngine.API.HorizontalMargin(0.16f), TORGUIContextEngine.API.Text(GUIAlignment.Left, TORGUIContextEngine.API.GetAttribute(AttributeAsset.DocumentStandard), Detail)) + ); + }; + + public HintWithImage(Image image, TextComponent title, TextComponent detail) + { + Image = image; + Title = title; + Detail = detail; + } + } + + public class HintManager + { + internal static List AllHints = new(); + + static private Hint WithImage(string id) => new HintWithImage(SpriteLoader.FromResource("TheOtherRoles.Resources.Hints." + id.HeadUpper() + ".png", 100f), new TranslateTextComponent("hint" + id.HeadUpper() + "Title"), new TranslateTextComponent("hint" + id.HeadUpper() + "Detail")); + static HintManager() + { + RegisterHint(WithImage("HelpInGame")); + RegisterHint(WithImage("Busker")); + RegisterHint(WithImage("Sherlock")); + RegisterHint(WithImage("Achievement")); + RegisterHint(WithImage("FreePlay")); + RegisterHint(WithImage("AboutSection")); + } + + public static void RegisterHint(Hint hint) => AllHints.Add(hint); + + public static IEnumerator CoShowHint(float delay = 0.5f) + { + yield return Effects.Wait(delay); + + var overlay = GameObject.Instantiate(TransitionFade.Instance.overlay, null); + overlay.transform.position = TransitionFade.Instance.overlay.transform.position + new Vector3(0, 0, -100f); + overlay.color = Color.black; + overlay.gameObject.layer = LayerMask.NameToLayer("UI"); + overlay.gameObject.AddComponent().sortingOrder = 150; + + var mask = Helpers.CreateObject("Mask", overlay.transform, new Vector3(0, 0, 5f)); + mask.sprite = overlay.sprite; + mask.transform.localScale = overlay.size; + + var hint = AllHints[System.Random.Shared.Next(AllHints.Count)].GUI.Invoke().Instantiate(new(new(0.5f, 0.5f), new(0f, 0f, 0f)), new(6f, 4f), out _); + hint?.transform.SetParent(overlay.transform); + if (hint) hint!.transform.localPosition = new(0f, 0f, 10f); + + yield return Effects.ColorFade(overlay, Color.black, Color.clear, 0.5f); + } + + } +} diff --git a/TheOtherRoles/MetaContext/MetaText.cs b/TheOtherRoles/MetaContext/MetaText.cs index c4c2a78..ebece3c 100644 --- a/TheOtherRoles/MetaContext/MetaText.cs +++ b/TheOtherRoles/MetaContext/MetaText.cs @@ -118,6 +118,16 @@ public enum AttributeAsset /// フリープレイの役職選択ボタンで使用されているテキスト属性です。 /// MetaRoleButton, + + /// + /// SerializableDocumentのTextStyle"Title"で提供されているテキスト属性です。 + /// + DocumentTitle, + + /// + /// SerializableDocumentのTextStyle"Standard"で提供されているテキスト属性です。 + /// + DocumentStandard, } [Flags] diff --git a/TheOtherRoles/Modules/ChatCommands.cs b/TheOtherRoles/Modules/ChatCommands.cs index 6904813..5d1009a 100644 --- a/TheOtherRoles/Modules/ChatCommands.cs +++ b/TheOtherRoles/Modules/ChatCommands.cs @@ -123,8 +123,8 @@ public static bool Prefix(ChatController __instance, [HarmonyArgument(0)] Player if (__instance != FastDestroyableSingleton.Instance.Chat) return true; PlayerControl localPlayer = CachedPlayer.LocalPlayer.PlayerControl; - return localPlayer == null || (MeetingHud.Instance != null || LobbyBehaviour.Instance != null || (localPlayer.Data.IsDead || (localPlayer.isLover() && Lovers.enableChat) || (Cupid.lovers1 != null - && Cupid.lovers2 != null && (CachedPlayer.LocalPlayer.PlayerControl == Cupid.lovers1 || CachedPlayer.LocalPlayer.PlayerControl == Cupid.lovers2))) || (int)sourcePlayer.PlayerId == (int)CachedPlayer.LocalPlayer.PlayerId); + return localPlayer == null || MeetingHud.Instance != null || LobbyBehaviour.Instance != null || (localPlayer.Data.IsDead && !(localPlayer == Busker.busker && Busker.pseudocideFlag)) || (localPlayer.isLover() && Lovers.enableChat && + sourcePlayer == localPlayer.getPartner()) || (localPlayer.isCupidLover() && sourcePlayer == localPlayer.getCupidLover()) || sourcePlayer.PlayerId == CachedPlayer.LocalPlayer.PlayerId; } } diff --git a/TheOtherRoles/Modules/CustomOptions.cs b/TheOtherRoles/Modules/CustomOptions.cs index 2597735..bf26c80 100644 --- a/TheOtherRoles/Modules/CustomOptions.cs +++ b/TheOtherRoles/Modules/CustomOptions.cs @@ -502,6 +502,8 @@ public static void drawTab(LobbyViewSettingsPane __instance, CustomOptionType op if (TORMapOptions.gameMode == CustomGamemodes.Guesser) // Exclude guesser options in neutral mode relevantOptions = relevantOptions.Where(x => !(new List { 310, 311, 312, 313, 314, 315, 316, 317, 318 }).Contains(x.id)).ToList(); + if (TORMapOptions.gameMode != CustomGamemodes.FreePlay) + relevantOptions = relevantOptions.Where(x => x.id != 10424).ToList(); for (int j = 0; j < __instance.settingsInfo.Count; j++) { diff --git a/TheOtherRoles/Patches/GameStartManagerPatch.cs b/TheOtherRoles/Patches/GameStartManagerPatch.cs index 9d0edfd..463ac05 100644 --- a/TheOtherRoles/Patches/GameStartManagerPatch.cs +++ b/TheOtherRoles/Patches/GameStartManagerPatch.cs @@ -8,6 +8,8 @@ using TheOtherRoles.Utilities; using System.Linq; using Reactor.Utilities.Extensions; +using BepInEx.Unity.IL2CPP.Utils.Collections; +using TheOtherRoles.MetaContext; namespace TheOtherRoles.Patches { [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Update))] @@ -36,6 +38,41 @@ public static void Postfix(AmongUsClient __instance) { } } + [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CoJoinOnlineGameFromCode))] + public class JoinGameLoadingPatch + { + public static void Postfix(AmongUsClient __instance, ref Il2CppSystem.Collections.IEnumerator __result) + { + var overlay = GameObject.Instantiate(TransitionFade.Instance.overlay, null); + overlay.transform.position = TransitionFade.Instance.overlay.transform.position; + + System.Collections.IEnumerator CoFadeInIf() + { + if (AmongUsClient.Instance.ClientId < 0) + { + yield return Effects.ColorFade(overlay, Color.black, Color.clear, 0.2f); + GameObject.Destroy(overlay.gameObject); + } + } + + __result = Effects.Sequence( + Effects.ColorFade(overlay, Color.clear, Color.black, 0.2f), + Helpers.Action(() => TORGUIManager.Instance.StartCoroutine(HintManager.CoShowHint(0.6f).WrapToIl2Cpp())).WrapToIl2Cpp(), + __result, + CoFadeInIf().WrapToIl2Cpp() + ); + } + } + + [HarmonyPatch(typeof(CreateGameOptions), nameof(CreateGameOptions.Confirm))] + public class CreateGameOptionsLoadingPatch + { + public static void Postfix(CreateGameOptions __instance) + { + TORGUIManager.Instance.StartCoroutine(HintManager.CoShowHint(0.6f + 0.2f).WrapToIl2Cpp()); + } + } + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Start))] public class GameStartManagerStartPatch { public static void Postfix(GameStartManager __instance) { diff --git a/TheOtherRoles/Patches/MeetingPatch.cs b/TheOtherRoles/Patches/MeetingPatch.cs index f9a6418..4d3a6be 100644 --- a/TheOtherRoles/Patches/MeetingPatch.cs +++ b/TheOtherRoles/Patches/MeetingPatch.cs @@ -447,11 +447,11 @@ public static void swapperCheckAndReturnSwap(MeetingHud __instance, byte dyingPl PlayerVoteArea playerVoteArea = __instance.playerStates[i]; if (playerVoteArea.AmDead || (playerVoteArea.TargetPlayerId == Swapper.swapper.PlayerId && Swapper.canOnlySwapOthers)) continue; renderers[i].color = Color.red; - Swapper.charges++; int copyI = i; swapperButtonList[i].OnClick.RemoveAllListeners(); swapperButtonList[i].OnClick.AddListener((System.Action)(() => swapperOnClick(copyI, __instance))); } + Swapper.charges++; meetingExtraButtonText.text = string.Format(ModTranslation.getString("swapperRemainingSwaps"), Swapper.charges); meetingExtraButtonLabel.text = Helpers.cs(Color.red, ModTranslation.getString("swapperConfirmSwap")); @@ -903,12 +903,12 @@ not MeetingHud.VoteStates.NotVoted and meetingInfoText.getFirst().text = string.Format(ModTranslation.getString("yasunaSpecialVotes"), numSpecialVotes); } - if (!CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && CachedPlayer.LocalPlayer.PlayerControl == Akujo.akujo && Akujo.timeLeft > 0) + if (!CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && CachedPlayer.LocalPlayer.PlayerControl == Akujo.akujo && Akujo.timeLeft > 0 && Akujo.honmei == null) { meetingInfoText.getFirst().text = string.Format(ModTranslation.getString("akujoTimeRemaining"), $"{TimeSpan.FromSeconds(Akujo.timeLeft):mm\\:ss}"); } - if (!CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && CachedPlayer.LocalPlayer.PlayerControl == Cupid.cupid && Cupid.timeLeft > 0) + if (!CachedPlayer.LocalPlayer.PlayerControl.Data.IsDead && CachedPlayer.LocalPlayer.PlayerControl == Cupid.cupid && Cupid.timeLeft > 0 && Cupid.lovers1 == null && Cupid.lovers2 == null) { meetingInfoText.getFirst().text = string.Format(ModTranslation.getString("akujoTimeRemaining"), $"{TimeSpan.FromSeconds(Cupid.timeLeft):mm\\:ss}"); } diff --git a/TheOtherRoles/Patches/PlayerControlPatch.cs b/TheOtherRoles/Patches/PlayerControlPatch.cs index 5b2d3cb..15fe400 100644 --- a/TheOtherRoles/Patches/PlayerControlPatch.cs +++ b/TheOtherRoles/Patches/PlayerControlPatch.cs @@ -3141,9 +3141,10 @@ public static void Postfix(PlayerControl __instance) { PlayerControl akujoPartner = __instance == Akujo.akujo ? Akujo.honmei : Akujo.akujo; if (akujoPartner != null && !akujoPartner.Data.IsDead) - { + { + if (NekoKabocha.nekoKabocha != null && akujoPartner == NekoKabocha.nekoKabocha) NekoKabocha.otherKiller = akujoPartner; akujoPartner.Exiled(); - GameHistory.overrideDeathReasonAndKiller(akujoPartner, DeadPlayer.CustomDeathReason.Suicide); + GameHistory.overrideDeathReasonAndKiller(akujoPartner, DeadPlayer.CustomDeathReason.LoverSuicide); } if (MeetingHud.Instance && akujoPartner != null) diff --git a/TheOtherRoles/RPC.cs b/TheOtherRoles/RPC.cs index 9766796..a21c4de 100644 --- a/TheOtherRoles/RPC.cs +++ b/TheOtherRoles/RPC.cs @@ -1133,7 +1133,12 @@ public static void shifterShift(byte targetId) if (player == Pursuer.pursuer) Pursuer.pursuer = oldShifter; if (player == Vulture.vulture) Vulture.vulture = oldShifter; if (player == Jackal.jackal) Jackal.jackal = oldShifter; - if (player == Sidekick.sidekick) Sidekick.sidekick = oldShifter; + if (player == Sidekick.sidekick) Sidekick.sidekick = oldShifter; + if (Jackal.formerJackals.Contains(player)) + { + Jackal.formerJackals.Add(oldShifter); + Jackal.formerJackals.RemoveAll(x => x.PlayerId == targetId); + } if (player == Lawyer.lawyer) Lawyer.lawyer = oldShifter; if (player == Fox.fox) Fox.fox = oldShifter; if (player == Immoralist.immoralist) Immoralist.immoralist = oldShifter; diff --git a/TheOtherRoles/Resources/Hints/AboutSection.png b/TheOtherRoles/Resources/Hints/AboutSection.png new file mode 100644 index 0000000..6b768c3 Binary files /dev/null and b/TheOtherRoles/Resources/Hints/AboutSection.png differ diff --git a/TheOtherRoles/Resources/Hints/Achievement.png b/TheOtherRoles/Resources/Hints/Achievement.png new file mode 100644 index 0000000..479cd3f Binary files /dev/null and b/TheOtherRoles/Resources/Hints/Achievement.png differ diff --git a/TheOtherRoles/Resources/Hints/Busker.png b/TheOtherRoles/Resources/Hints/Busker.png new file mode 100644 index 0000000..e203ee8 Binary files /dev/null and b/TheOtherRoles/Resources/Hints/Busker.png differ diff --git a/TheOtherRoles/Resources/Hints/FreePlay.png b/TheOtherRoles/Resources/Hints/FreePlay.png new file mode 100644 index 0000000..3895af3 Binary files /dev/null and b/TheOtherRoles/Resources/Hints/FreePlay.png differ diff --git a/TheOtherRoles/Resources/Hints/HelpInGame.png b/TheOtherRoles/Resources/Hints/HelpInGame.png new file mode 100644 index 0000000..cfdc56f Binary files /dev/null and b/TheOtherRoles/Resources/Hints/HelpInGame.png differ diff --git a/TheOtherRoles/Resources/Hints/Sherlock.png b/TheOtherRoles/Resources/Hints/Sherlock.png new file mode 100644 index 0000000..a9bbd2d Binary files /dev/null and b/TheOtherRoles/Resources/Hints/Sherlock.png differ diff --git a/TheOtherRoles/Resources/stringData.json b/TheOtherRoles/Resources/stringData.json index 545adfd..d3b09c9 100644 --- a/TheOtherRoles/Resources/stringData.json +++ b/TheOtherRoles/Resources/stringData.json @@ -8902,5 +8902,53 @@ "0": "Retrive Your Votes!", "11": "\u52d8\u306e\u3044\u3044\u30af\u30eb\u30fc\u306f\u5acc\u3044\u3060\u3088", "13": "\u4f60\u4eec\u7684\u7968\u90fd\u4e0d\u7b97\u6570\uff01" + }, + "hintHelpInGameTitle": { + "0": "Role Help", + "13": "\u89d2\u8272\u89e3\u91ca" + }, + "hintBuskerTitle": { + "0": "Roles: Busker", + "13": "\u89d2\u8272\uff1a\u7075\u5316\u4f7f" + }, + "hintSherlockTitle": { + "0": "Roles: Sherlock", + "13": "\u89d2\u8272\uff1a\u798f\u5c14\u6469\u65af" + }, + "hintAchievementTitle": { + "0": "Achievements", + "13": "\u6210\u5c31" + }, + "hintFreePlayTitle": { + "0": "Free Play", + "13": "\u81ea\u7531\u6a21\u5f0f" + }, + "hintAboutSectionTitle": { + "0": "About Section", + "13": "\u5173\u4e8e\u672c\u6a21\u7ec4" + }, + "hintHelpInGameDetail": { + "0": "You can press key H to view the descriptions of your role in the game.\nYou may also use your scroller if your description is too long.", + "13": "\u4f60\u53ef\u4ee5\u901a\u8fc7\u5728\u6e38\u620f\u4e2d\u6309H\u952e\u6765\u67e5\u770b\u81ea\u5df1\u89d2\u8272\u7684\u529f\u80fd\n\u5982\u679c\u4f60\u7684\u804c\u4e1a\u4ecb\u7ecd\u592a\u957f\uff0c\u4f60\u8fd8\u53ef\u4ee5\u4f7f\u7528\u6eda\u8f6e\u6765\u7ffb\u9875" + }, + "hintBuskerDetail": { + "0": "The Busker can fake their death while the skill is still active.\nBe careful! You will commit suicide if you don't come alive within a certain amount of time.", + "13": "\u7075\u5316\u4f7f\u53ef\u4ee5\u901a\u8fc7\u5047\u6b7b\u6765\u89c2\u5bdf\u5468\u56f4\u7684\u4e8b\u7269\n\u5f53\u5fc3\uff01\u5982\u679c\u4f60\u5047\u6b7b\u65f6\u95f4\u592a\u957f\uff0c\u4f60\u4f1a\u76f4\u63a5\u81ea\u6bd9\u800c\u4ea1" + }, + "hintSherlockDetail": { + "0": "The Sherlock can investigate the killers of the crimes.\nThey have to complete a certain amount of tasks before using their skills.\nThe popup will remain for 7 seconds, so please record them in time!", + "13": "\u798f\u5c14\u6469\u65af\u62e5\u6709\u4fa6\u67e5\u51f6\u624b\u8eab\u4efd\u7684\u80fd\u529b\n\u4ed6\u4eec\u9700\u8981\u5b8c\u6210\u4e00\u5b9a\u6570\u91cf\u7684\u4efb\u52a1\u6765\u4f7f\u7528\u4fa6\u67e5\u6280\u80fd\n\u6b7b\u4ea1\u63d0\u793a\u4f1a\u6301\u7eed7\u79d2\u949f\uff0c\u6240\u4ee5\u8bf7\u53ca\u65f6\u628a\u663e\u793a\u7684\u4fe1\u606f\u8bb0\u5f55\u4e0b\u6765\uff01" + }, + "hintAchievementDetail": { + "0": "You can earn the achievements by completing certain missions in the game.\nYou can view the achievements by pressing the Achievements button under the GMIA button.\nAs some achievements require you to do things that are against your role, \nplease do not complete the Secret achievements on purpose!", + "13": "\u4f60\u53ef\u4ee5\u901a\u8fc7\u8fbe\u6210\u67d0\u4e00\u7279\u6b8a\u4efb\u52a1\u6765\u83b7\u53d6\u6210\u5c31\n\u6240\u6709\u6210\u5c31\u5c06\u4f1a\u88ab\u653e\u5728GMIA\u6309\u94ae\u4e0b\u7684\u6210\u5c31\u6309\u94ae\n\u6709\u4e9b\u6210\u5c31\u8981\u6c42\u4f60\u5728\u8fdd\u80cc\u89d2\u8272\u6216\u9635\u8425\u7684\u521d\u8877\u4e0b\u5b8c\u6210\uff0c\u6240\u4ee5\u8bf7\u4e0d\u8981\u6709\u610f\u5b8c\u6210\u9690\u85cf\u6210\u5c31\uff01" + }, + "hintFreePlayDetail": { + "0": "The Free Play gamemode can only be activated in a local lobby.\nIn the Free Play, you can choose whatever role you want to be and test them out!", + "13": "\u81ea\u7531\u6a21\u5f0f\u53ea\u80fd\u5728\u672c\u5730\u5927\u5385\u4e2d\u5f00\u542f\n\u5728\u81ea\u7531\u6a21\u5f0f\u4e2d\uff0c\u4f60\u53ef\u4ee5\u968f\u610f\u9009\u62e9\u81ea\u5df1\u7684\u89d2\u8272\u5e76\u6d4b\u8bd5\u4ed6\u4eec\u7684\u529f\u80fd" + }, + "hintAboutSectionDetail": { + "0": "The About Section is located under the GMIA button.\nYou can see what our contributors and developers have to say and join us!", + "13": "\u5173\u4e8e\u672c\u6a21\u7ec4\u5185\u5bb9\u5728GMIA\u6309\u94ae\u4e0b\n\u4f60\u53ef\u4ee5\u67e5\u770b\u5f00\u53d1\u8005\u548c\u8d21\u732e\u8005\u60f3\u8bf4\u7684\u8bdd\u5e76\u52a0\u5165\u6211\u4eec\uff01" } } \ No newline at end of file diff --git a/TheOtherRoles/TheOtherRoles.cs b/TheOtherRoles/TheOtherRoles.cs index 4698c87..4042db2 100644 --- a/TheOtherRoles/TheOtherRoles.cs +++ b/TheOtherRoles/TheOtherRoles.cs @@ -4505,6 +4505,15 @@ public static Sprite getArrowSprite() if (arrowSprite) return arrowSprite; arrowSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CupidButton.png", 115f); return arrowSprite; + } + + public static bool isCupidLover(this PlayerControl p) => (p == lovers1 && lovers2 != null) || (p == lovers2 && lovers1 != null); + public static PlayerControl getCupidLover(this PlayerControl p) + { + if (p == null) return null; + if (p == lovers1) return lovers2; + if (p == lovers2) return lovers1; + return null; } public static void breakLovers(PlayerControl lover) diff --git a/TheOtherRoles/TheOtherRoles.csproj b/TheOtherRoles/TheOtherRoles.csproj index e005f62..d249fde 100644 --- a/TheOtherRoles/TheOtherRoles.csproj +++ b/TheOtherRoles/TheOtherRoles.csproj @@ -1,7 +1,7 @@  net6.0 - 1.2.8 + 1.2.9 TheOtherRolesGMIA Imp11 latest