]> git.deb.at Git - rhonda/theotherroles.git/commitdiff
Update 4.1.6
authorMallöris <|||||@||.||>
Mon, 11 Jul 2022 16:43:16 +0000 (18:43 +0200)
committerMallöris <|||||@||.||>
Mon, 11 Jul 2022 16:43:16 +0000 (18:43 +0200)
56 files changed:
.github/workflows/build.yml [new file with mode: 0644]
README.md
TheOtherRoles.sln
TheOtherRoles/Buttons.cs
TheOtherRoles/CustomOptionHolder.cs
TheOtherRoles/Helpers.cs
TheOtherRoles/Main.cs
TheOtherRoles/MapOptions.cs
TheOtherRoles/Modules/CustomColors.cs
TheOtherRoles/Patches/ClientOptionsPatch.cs
TheOtherRoles/Patches/CredentialsPatch.cs
TheOtherRoles/Patches/GameStartManagerPatch.cs
TheOtherRoles/Patches/IntroPatch.cs
TheOtherRoles/Patches/LightSourcePatch.cs [deleted file]
TheOtherRoles/Patches/MainMenuPatch.cs
TheOtherRoles/Patches/MapBehaviourPatch.cs
TheOtherRoles/Patches/MeetingPatch.cs
TheOtherRoles/Patches/PlayerControlPatch.cs
TheOtherRoles/Patches/RegionMenuPatch.cs
TheOtherRoles/Patches/RoleAssignmentPatch.cs
TheOtherRoles/Patches/UsablesPatch.cs
TheOtherRoles/RPC.cs
TheOtherRoles/Resources/CreditsButton.png [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/SoundEffectSourcesAndLicenses.md [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/arsonistDouse.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/cleanerClean.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/deputyHandcuff.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/engineerRepair.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/eraserErase.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/fail.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/garlic.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/hackerHack.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/jackalSidekick.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/lighterLight.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/medicShield.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/mediumAsk.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/morphlingMorph.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/morphlingSample.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/portalUse.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/pursuerBlank.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/securityGuardPlaceCam.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/shifterShift.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/timemasterShield.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/trackerTrackCorpses.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/trackerTrackPlayer.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/tricksterPlaceBox.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/tricksterUseBoxVent.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/vampireBite.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/vultureEat.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/warlockCurse.raw [new file with mode: 0644]
TheOtherRoles/Resources/SoundEffects/witchSpell.raw [new file with mode: 0644]
TheOtherRoles/Resources/ThirdParty/Submerged/Submerged.dll
TheOtherRoles/RoleInfo.cs
TheOtherRoles/SoundEffectsManager.cs [new file with mode: 0644]
TheOtherRoles/TheOtherRoles.cs
TheOtherRoles/TheOtherRoles.csproj

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644 (file)
index 0000000..945b5f9
--- /dev/null
@@ -0,0 +1,38 @@
+name: AutoBuild .NET
+
+on:
+  push:
+    branches:
+      - main
+
+jobs:
+  build:
+    runs-on: ubuntu-20.04
+
+    steps:
+      - uses: actions/cache@v2
+        with:
+          path: |
+            ~/.nuget/packages
+            ~/.cache/bepinex
+          key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-nuget-
+
+      - uses: actions/checkout@v2
+        with:
+          submodules: true
+
+      - name: Setup .NET
+        uses: actions/setup-dotnet@v1
+        with:
+          dotnet-version: 6.x
+
+      - name: Build
+        run: dotnet build TheOtherRoles/TheOtherRoles.csproj --configuration Release
+
+      - name: Upload TheOtherRoles
+        uses: actions/upload-artifact@v2
+        with:
+          name: TheOtherRoles.dll
+          path: TheOtherRoles/bin/Release/netstandard2.1/TheOtherRoles.dll
\ No newline at end of file
index 1df8c68f3f2bf2dba59f90fbe758b1eebe8602f6..94c9e58369d61824e889b2985844325599b4a19a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein
 # Releases
 | Among Us - Version| Mod Version | Link |
 |----------|-------------|-----------------|
+| 2022.6.21| v4.1.6| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.1.6/TheOtherRoles.zip)
 | 2022.6.21| v4.1.5| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.1.5/TheOtherRoles.zip)
 | 2022.3.29| v4.1.4| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.1.4/TheOtherRoles.zip)
 | 2022.3.29| v4.1.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.1.3/TheOtherRoles.zip)
@@ -107,6 +108,24 @@ The [Role Assignment](#role-assignment) sections explains how the roles are bein
 <details>
   <summary>Click to show the Changelog</summary>
   
+**Version 4.1.6**  
+- Added Sound Effects: Most buttons / role funcionalities now have a sound!
+- Added a mod option: Enable Sound Effects  
+- Added an option: Hide After Death Modifiers: Modifiers which will have an effect after your death will be hidden while the player is alive so they cant be claimed / called
+- Added lobby timer sync, so that each player can see when the lobby will close on Vanilla Servers
+- Added a credits screen to the main menu
+- Re-Added the player's last position to the map in meetings
+- Changed the custom region ui   
+- Fixed a bug where the Spy's Name appearing in white to the impostors in the intro cutscene
+- Fixed a bug where the zoom function for ghosts would zoom in too far
+- Fixed a bug where custom color names did not work (TOR is now compatible with colorblind mode)
+- Fixed a bug where the ninjas color name did not become invisible in colorblind mode
+- Fixed a bug where Morphling & Camouflager did not work correctly for skins with adaptive color
+- Fixed a bug where the first kill shield was given to the wrong lover
+- Fixed a bug where Pursuer appeared in the GuesserUI even when Lawyer was disabled
+- Fixed a bug where a guessed Guesser could still guess if they had the guesser ui open
+- Fixed a bug where the role assignment did not work properly (fingers crossed)
+
 **Version 4.1.5**
 - Updated to Among Us version 2022.6.21
 - Added Custom servers (Modded EU & Modded NA). Thanks to [miniduikboot](https://github.com/miniduikboot) & GD
@@ -1219,12 +1238,12 @@ Because of the vents the Engineer might not be able to start some tasks using th
 
 ## Sheriff
 ### **Team: Crewmates**
-The Sheriff has the ability to kill Impostors.\
+The Sheriff has the ability to kill Impostors or Neutral roles if enabled.\
 If they try to kill a Crewmate, they die instead.\
 \
 **NOTE:**
 - If the Sheriff shoots the person the Medic shielded, the Sheriff and the shielded person **both remain unharmed**.
-- If the Sheriff shoots a Mini Impostor, the Sheriff dies if the Mini is still growing up. If it's 18, the Mini Impostor dies.
+- If the Sheriff shoots a Mini Impostor while growing up, nothing happens. If it's fully grown, the Mini Impostor dies.
 
 ### Game Options
 | Name | Description |
index 3de367df45de7b3962a25d5bf7512488e0fcfffc..3c00efe92fc7b5a1ea80f1957acdcce663c56def 100644 (file)
@@ -2,6 +2,8 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheOtherRoles", "TheOtherRoles\TheOtherRoles.csproj", "{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TheOtherUpdater", "TheOtherUpdater\TheOtherUpdater.vcxproj", "{73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -12,5 +14,9 @@ Global
                {11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {11FBC798-BAF5-4EE5-9511-BE6DB0592F99}.Release|Any CPU.Build.0 = Release|Any CPU
+               {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Debug|Any CPU.ActiveCfg = Debug|Win32
+               {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Debug|Any CPU.Build.0 = Debug|Win32
+               {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Release|Any CPU.ActiveCfg = Release|Win32
+               {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Release|Any CPU.Build.0 = Release|Win32
        EndGlobalSection
 EndGlobal
index e47eb88710a2a0f6e2f4e0c1f7b8bf4244c64b89..26ee68caadfc636fd11d4ee5532f9e98954a88d2 100644 (file)
@@ -53,8 +53,6 @@ namespace TheOtherRoles
         public static CustomButton zoomOutButton;
 
         public static Dictionary<byte, List<CustomButton>> deputyHandcuffedButtons = null;
-
-        public static bool zoomOutStatus = false;
         public static PoolablePlayer morphTargetDisplay;
 
         public static TMPro.TMP_Text securityGuardButtonScrewsText;
@@ -125,6 +123,7 @@ namespace TheOtherRoles
             timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer;
             timeMasterShieldButton.isEffectActive = false;
             timeMasterShieldButton.actionButton.cooldownTimerText.color = Palette.EnabledColor;
+            SoundEffectsManager.stop("timemasterShield");
         }
 
         private static void addReplacementHandcuffedButton(CustomButton button, Vector3? positionOffset = null, Func<bool> couldUse = null)
@@ -203,7 +202,7 @@ namespace TheOtherRoles
                     MessageWriter usedRepairWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.EngineerUsedRepair, Hazel.SendOption.Reliable, -1);
                     AmongUsClient.Instance.FinishRpcImmediately(usedRepairWriter);
                     RPCProcedure.engineerUsedRepair();
-
+                    SoundEffectsManager.play("engineerRepair");
                     foreach (PlayerTask task in CachedPlayer.LocalPlayer.PlayerControl.myTasks.GetFastEnumerator()) {
                         if (task.TaskType == TaskTypes.FixLights) {
                             MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.EngineerFixLights, Hazel.SendOption.Reliable, -1);
@@ -266,6 +265,7 @@ namespace TheOtherRoles
                                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                                     RPCProcedure.cleanBody(playerInfo.PlayerId);
                                     janitorCleanButton.Timer = janitorCleanButton.MaxTimer;
+                                    SoundEffectsManager.play("cleanerClean");
 
                                     break;
                                 }
@@ -332,6 +332,8 @@ namespace TheOtherRoles
                     RPCProcedure.deputyUsedHandcuffs(targetId);
                     Deputy.currentTarget = null;
                     deputyHandcuffButton.Timer = deputyHandcuffButton.MaxTimer;
+
+                    SoundEffectsManager.play("deputyHandcuff");
                 },
                 () => { return (Deputy.deputy != null && Deputy.deputy == CachedPlayer.LocalPlayer.PlayerControl || Sheriff.sheriff != null && Sheriff.sheriff == CachedPlayer.LocalPlayer.PlayerControl && Sheriff.sheriff == Sheriff.formerDeputy && Deputy.keepsHandcuffsOnPromotion) && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => {
@@ -357,6 +359,7 @@ namespace TheOtherRoles
                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.TimeMasterShield, Hazel.SendOption.Reliable, -1);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.timeMasterShield();
+                    SoundEffectsManager.play("timemasterShield");
                 },
                 () => { return TimeMaster.timeMaster != null && TimeMaster.timeMaster == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -371,7 +374,11 @@ namespace TheOtherRoles
                 KeyCode.F, 
                 true,
                 TimeMaster.shieldDuration,
-                () => { timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer; }
+                () => {
+                    timeMasterShieldButton.Timer = timeMasterShieldButton.MaxTimer;
+                    SoundEffectsManager.stop("timemasterShield");
+
+                }
             );
 
             // Medic Shield
@@ -387,6 +394,8 @@ namespace TheOtherRoles
                     else
                         RPCProcedure.medicSetShielded(Medic.currentTarget.PlayerId);
                     Medic.meetingAfterShielding = false;
+
+                    SoundEffectsManager.play("medicShield");
                 },
                 () => { return Medic.medic != null && Medic.medic == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return !Medic.usedShield && Medic.currentTarget && CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -405,6 +414,7 @@ namespace TheOtherRoles
                     writer.Write(Shifter.currentTarget.PlayerId);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.setFutureShifted(Shifter.currentTarget.PlayerId);
+                    SoundEffectsManager.play("shifterShift");
                 },
                 () => { return Shifter.shifter != null && Shifter.shifter == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return Shifter.currentTarget && Shifter.futureShift == null && CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -426,11 +436,12 @@ namespace TheOtherRoles
                         RPCProcedure.morphlingMorph(Morphling.sampledTarget.PlayerId);
                         Morphling.sampledTarget = null;
                         morphlingButton.EffectDuration = Morphling.duration;
-
+                        SoundEffectsManager.play("morphlingMorph");
                     } else if (Morphling.currentTarget != null) {
                         Morphling.sampledTarget = Morphling.currentTarget;
                         morphlingButton.Sprite = Morphling.getMorphSprite();
                         morphlingButton.EffectDuration = 1f;
+                        SoundEffectsManager.play("morphlingSample");
 
                         // Add poolable player to the button so that the target outfit is shown
                         morphlingButton.actionButton.cooldownTimerText.transform.localPosition = new Vector3(0, 0, -1f);  // Before the poolable player
@@ -471,6 +482,7 @@ namespace TheOtherRoles
                     if (Morphling.sampledTarget == null) {
                         morphlingButton.Timer = morphlingButton.MaxTimer;
                         morphlingButton.Sprite = Morphling.getSampleSprite();
+                        SoundEffectsManager.play("morphlingMorph");
 
                         // Reset the poolable player
                         morphTargetDisplay.gameObject.SetActive(false);
@@ -486,6 +498,7 @@ namespace TheOtherRoles
                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CamouflagerCamouflage, Hazel.SendOption.Reliable, -1);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.camouflagerCamouflage();
+                    SoundEffectsManager.play("morphlingMorph");
                 },
                 () => { return Camouflager.camouflager != null && Camouflager.camouflager == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -500,13 +513,17 @@ namespace TheOtherRoles
                 KeyCode.F,
                 true,
                 Camouflager.duration,
-                () => { camouflagerButton.Timer = camouflagerButton.MaxTimer; }
+                () => {
+                    camouflagerButton.Timer = camouflagerButton.MaxTimer;
+                    SoundEffectsManager.play("morphlingMorph");
+                }
             );
 
             // Hacker button
             hackerButton = new CustomButton(
                 () => {
                     Hacker.hackerTimer = Hacker.duration;
+                    SoundEffectsManager.play("hackerHack");
                 },
                 () => { return Hacker.hacker != null && Hacker.hacker == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return true; },
@@ -636,6 +653,7 @@ namespace TheOtherRoles
                     writer.Write(Tracker.currentTarget.PlayerId);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.trackerUsedTracker(Tracker.currentTarget.PlayerId);
+                    SoundEffectsManager.play("trackerTrackPlayer");
                 },
                 () => { return Tracker.tracker != null && Tracker.tracker == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Tracker.currentTarget != null && !Tracker.usedTracker; },
@@ -647,7 +665,8 @@ namespace TheOtherRoles
             );
 
             trackerTrackCorpsesButton = new CustomButton(
-                () => { Tracker.corpsesTrackingTimer = Tracker.corpsesTrackingDuration; },
+                () => { Tracker.corpsesTrackingTimer = Tracker.corpsesTrackingDuration;
+                            SoundEffectsManager.play("trackerTrackCorpses"); },
                 () => { return Tracker.tracker != null && Tracker.tracker == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead && Tracker.canTrackCorpses; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
                 () => {
@@ -700,6 +719,7 @@ namespace TheOtherRoles
                                     RPCProcedure.vampireSetBitten(byte.MaxValue, byte.MaxValue);
                                 }
                             })));
+                            SoundEffectsManager.play("vampireBite");
 
                             vampireKillButton.HasEffect = true; // Trigger effect on this click
                         }
@@ -749,7 +769,8 @@ namespace TheOtherRoles
                     MessageWriter writer = AmongUsClient.Instance.StartRpc(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.PlaceGarlic, Hazel.SendOption.Reliable);
                     writer.WriteBytesAndSize(buff);
                     writer.EndMessage();
-                    RPCProcedure.placeGarlic(buff); 
+                    RPCProcedure.placeGarlic(buff);
+                    SoundEffectsManager.play("garlic");
                 },
                 () => { return !Vampire.localPlacedGarlic && !CachedPlayer.LocalPlayer.Data.IsDead && Vampire.garlicsActive; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && !Vampire.localPlacedGarlic; },
@@ -774,6 +795,7 @@ namespace TheOtherRoles
                     writer.WriteBytesAndSize(buff);
                     writer.EndMessage();
                     RPCProcedure.placePortal(buff);
+                    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; },
@@ -798,6 +820,7 @@ namespace TheOtherRoles
                     }
                     RPCProcedure.usePortal(CachedPlayer.LocalPlayer.PlayerId);
                     usePortalButton.Timer = usePortalButton.MaxTimer;
+                    SoundEffectsManager.play("portalUse");
                     FastDestroyableSingleton<HudManager>.Instance.StartCoroutine(Effects.Lerp(Portal.teleportDuration, new Action<float>((p) => { // Delayed action
                         CachedPlayer.LocalPlayer.PlayerControl.moveable = false;
                         CachedPlayer.LocalPlayer.NetTransform.Halt();
@@ -830,6 +853,7 @@ namespace TheOtherRoles
                     writer.Write(Jackal.currentTarget.PlayerId);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.jackalCreatesSidekick(Jackal.currentTarget.PlayerId);
+                    SoundEffectsManager.play("jackalSidekick");
                 },
                 () => { return Jackal.canCreateSidekick && Jackal.jackal != null && Jackal.jackal == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return Jackal.canCreateSidekick && Jackal.currentTarget != null && CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -877,6 +901,7 @@ namespace TheOtherRoles
             lighterButton = new CustomButton(
                 () => {
                     Lighter.lighterTimer = Lighter.duration;
+                    SoundEffectsManager.play("lighterLight");
                 },
                 () => { return Lighter.lighter != null && Lighter.lighter == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove; },
@@ -891,7 +916,10 @@ namespace TheOtherRoles
                 KeyCode.F,
                 true,
                 Lighter.duration,
-                () => { lighterButton.Timer = lighterButton.MaxTimer; }
+                () => {
+                    lighterButton.Timer = lighterButton.MaxTimer;
+                    SoundEffectsManager.play("lighterLight");
+                }
             );
 
             // Eraser erase button
@@ -904,6 +932,7 @@ namespace TheOtherRoles
                     writer.Write(Eraser.currentTarget.PlayerId);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.setFutureErased(Eraser.currentTarget.PlayerId);
+                    SoundEffectsManager.play("eraserErase");
                 },
                 () => { return Eraser.eraser != null && Eraser.eraser == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && Eraser.currentTarget != null; },
@@ -926,7 +955,8 @@ namespace TheOtherRoles
                     MessageWriter writer = AmongUsClient.Instance.StartRpc(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.PlaceJackInTheBox, Hazel.SendOption.Reliable);
                     writer.WriteBytesAndSize(buff);
                     writer.EndMessage();
-                    RPCProcedure.placeJackInTheBox(buff); 
+                    RPCProcedure.placeJackInTheBox(buff);
+                    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(); },
@@ -941,7 +971,8 @@ namespace TheOtherRoles
                 () => {
                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.LightsOut, Hazel.SendOption.Reliable, -1);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
-                    RPCProcedure.lightsOut(); 
+                    RPCProcedure.lightsOut();
+                    SoundEffectsManager.play("lighterLight");
                 },
                 () => { return Trickster.trickster != null && Trickster.trickster == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead && JackInTheBox.hasJackInTheBoxLimitReached() && JackInTheBox.boxesConvertedToVents; },
                 () => { return CachedPlayer.LocalPlayer.PlayerControl.CanMove && JackInTheBox.hasJackInTheBoxLimitReached() && JackInTheBox.boxesConvertedToVents; },
@@ -956,7 +987,10 @@ namespace TheOtherRoles
                 KeyCode.F,
                 true,
                 Trickster.lightsOutDuration,
-                () => { lightsOutButton.Timer = lightsOutButton.MaxTimer; }
+                () => {
+                    lightsOutButton.Timer = lightsOutButton.MaxTimer;
+                    SoundEffectsManager.play("lighterLight");
+                }
             );
 
             // Cleaner Clean
@@ -980,6 +1014,7 @@ namespace TheOtherRoles
                                     RPCProcedure.cleanBody(playerInfo.PlayerId);
 
                                     Cleaner.cleaner.killTimer = cleanerCleanButton.Timer = cleanerCleanButton.MaxTimer;
+                                    SoundEffectsManager.play("cleanerClean");
                                     break;
                                 }
                             }
@@ -1003,6 +1038,7 @@ namespace TheOtherRoles
                         Warlock.curseVictim = Warlock.currentTarget;
                         warlockCurseButton.Sprite = Warlock.getCurseKillButtonSprite();
                         warlockCurseButton.Timer = 1f;
+                        SoundEffectsManager.play("warlockCurse");
                     } else if (Warlock.curseVictim != null && Warlock.curseVictimTarget != null) {
                         MurderAttemptResult murder = Helpers.checkMuderAttemptAndKill(Warlock.warlock, Warlock.curseVictimTarget, showAnimation: false);
                         if (murder == MurderAttemptResult.SuppressKill) return; 
@@ -1061,6 +1097,7 @@ namespace TheOtherRoles
                         writer.EndMessage();
                         RPCProcedure.placeCamera(buff); 
                     }
+                    SoundEffectsManager.play("securityGuardPlaceCam");  // Same sound used for both types (cam or vent)!
                     securityGuardButton.Timer = securityGuardButton.MaxTimer;
                 },
                 () => { return SecurityGuard.securityGuard != null && SecurityGuard.securityGuard == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead && SecurityGuard.remainingScrews >= Mathf.Min(SecurityGuard.ventPrice, SecurityGuard.camPrice); },
@@ -1163,7 +1200,8 @@ namespace TheOtherRoles
                         arsonistButton.HasEffect = false;
                     } else if (Arsonist.currentTarget != null) {
                         Arsonist.douseTarget = Arsonist.currentTarget;
-                        arsonistButton.HasEffect = true;              
+                        arsonistButton.HasEffect = true;
+                        SoundEffectsManager.play("arsonistDouse");
                     }
                 },
                 () => { return Arsonist.arsonist != null && Arsonist.arsonist == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
@@ -1222,6 +1260,7 @@ namespace TheOtherRoles
 
                                     Vulture.cooldown = vultureEatButton.Timer = vultureEatButton.MaxTimer;
                                     Vulture.eatenBodies++;
+                                    SoundEffectsManager.play("vultureEat");
                                     break;
                                 }
                             }
@@ -1249,6 +1288,7 @@ namespace TheOtherRoles
                     if (Medium.target != null) {
                         Medium.soulTarget = Medium.target;
                         mediumButton.HasEffect = true;
+                        SoundEffectsManager.play("mediumAsk");
                     }
                 },
                 () => { return Medium.medium != null && Medium.medium == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
@@ -1321,6 +1361,7 @@ namespace TheOtherRoles
 
                         Medium.souls.Remove(target);
                     }
+                    SoundEffectsManager.stop("mediumAsk");
                 }
             );
 
@@ -1338,6 +1379,7 @@ namespace TheOtherRoles
 
                         Pursuer.blanks++;
                         pursuerButton.Timer = pursuerButton.MaxTimer;
+                        SoundEffectsManager.play("pursuerBlank");
                     }
 
                 },
@@ -1367,6 +1409,7 @@ namespace TheOtherRoles
                 () => {
                     if (Witch.currentTarget != null) {
                         Witch.spellCastingTarget = Witch.currentTarget;
+                        SoundEffectsManager.play("witchSpell");
                     }
                 },
                 () => { return Witch.witch != null && Witch.witch == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
@@ -1473,6 +1516,7 @@ namespace TheOtherRoles
                     if (Ninja.currentTarget != null) {
                         Ninja.ninjaMarked = Ninja.currentTarget;
                         ninjaButton.Timer = 5f;
+                        SoundEffectsManager.play("warlockCurse");
                     }
                 },
                 () => { return Ninja.ninja != null && Ninja.ninja == CachedPlayer.LocalPlayer.PlayerControl && !CachedPlayer.LocalPlayer.Data.IsDead; },
index 6571201de6bf024f154f3d26135ff6821dabf673..5cb322fa05accbbfa90bfb6da7f86bf6729492a8 100644 (file)
@@ -225,6 +225,8 @@ namespace TheOtherRoles {
         public static CustomOption pursuerCooldown;
         public static CustomOption pursuerBlanksNumber;
 
+        public static CustomOption modifiersAreHidden;
+
         public static CustomOption modifierBait;
         public static CustomOption modifierBaitQuantity;
         public static CustomOption modifierBaitReportDelayMin;
@@ -510,6 +512,8 @@ namespace TheOtherRoles {
             mediumOneTimeUse = CustomOption.Create(363, Types.Crewmate, "Each Soul Can Only Be Questioned Once", false, mediumSpawnRate);
 
             // Modifier
+            modifiersAreHidden = CustomOption.Create(1009, Types.Modifier, cs(Color.yellow, "Hide After Death Modifiers"), true, null, true);
+
             modifierBloody = CustomOption.Create(1000, Types.Modifier, cs(Color.yellow, "Bloody"), rates, null, true);
             modifierBloodyQuantity = CustomOption.Create(1001, Types.Modifier, cs(Color.yellow, "Bloody Quantity"), ratesModifier, modifierBloody);
             modifierBloodyDuration = CustomOption.Create(1002, Types.Modifier, "Trail Duration", 10f, 3f, 60f, 1f, modifierBloody);
index 1f78ae7c75715d041bce2a2a5fa9cff66b48929b..8c57aeb045cc26b05b933d83a9439a7abd306876 100644 (file)
@@ -67,6 +67,34 @@ namespace TheOtherRoles {
             return null;
         }
 
+        public static AudioClip loadAudioClipFromResources(string path, string clipName = "UNNAMED_TOR_AUDIO_CLIP") {
+            // must be "raw (headerless) 2-channel signed 32 bit pcm (le)" (can e.g. use Audacity® to export)
+            try {
+                Assembly assembly = Assembly.GetExecutingAssembly();
+                Stream stream = assembly.GetManifestResourceStream(path);
+                var byteAudio = new byte[stream.Length];
+                _ = stream.Read(byteAudio, 0, (int)stream.Length);
+                float[] samples = new float[byteAudio.Length / 4]; // 4 bytes per sample
+                int offset;
+                for (int i = 0; i < samples.Length; i++) {
+                    offset = i * 4;
+                    samples[i] = (float)BitConverter.ToInt32(byteAudio, offset) / Int32.MaxValue;
+                }
+                int channels = 2;
+                int sampleRate = 48000;
+                AudioClip audioClip = AudioClip.Create(clipName, samples.Length, channels, sampleRate, false);
+                audioClip.SetData(samples, 0);
+                return audioClip;
+            } catch {
+                System.Console.WriteLine("Error loading AudioClip from resources: " + path);
+            }
+            return null;
+
+            /* Usage example:
+            AudioClip exampleClip = Helpers.loadAudioClipFromResources("TheOtherRoles.Resources.exampleClip.raw");
+            if (Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(exampleClip, false, 0.8f);
+            */
+        }
         public static PlayerControl playerById(byte id)
         {
             foreach (PlayerControl player in CachedPlayer.AllPlayers)
@@ -250,8 +278,8 @@ namespace TheOtherRoles {
             else clip = nextSkin.IdleAnim;
             float progress = playerPhysics.Animator.m_animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
             playerPhysics.myPlayer.cosmetics.skin.skin = nextSkin;
-            if (playerPhysics.myPlayer.cosmetics.skin.layer.material == FastDestroyableSingleton<HatManager>.Instance.PlayerMaterial)
-                target.SetPlayerMaterialColors(playerPhysics.myPlayer.cosmetics.skin.layer);
+            playerPhysics.myPlayer.cosmetics.skin.UpdateMaterial();
+
             spriteAnim.Play(clip, 1f);
             spriteAnim.m_animator.Play("a", 0, progress % 1);
             spriteAnim.m_animator.Update(0f);
@@ -330,6 +358,7 @@ namespace TheOtherRoles {
                 MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1);
                 AmongUsClient.Instance.FinishRpcImmediately(writer);
                 RPCProcedure.shieldedMurderAttempt();
+                SoundEffectsManager.play("fail");
                 return MurderAttemptResult.SuppressKill;
             }
 
@@ -371,6 +400,7 @@ namespace TheOtherRoles {
             writer.Write((byte)TheOtherRolesPlugin.Version.Major);
             writer.Write((byte)TheOtherRolesPlugin.Version.Minor);
             writer.Write((byte)TheOtherRolesPlugin.Version.Build);
+            writer.Write(AmongUsClient.Instance.AmHost ? Patches.GameStartManagerPatch.timer : -1f);
             writer.WritePacked(AmongUsClient.Instance.ClientId);
             writer.Write((byte)(TheOtherRolesPlugin.Version.Revision < 0 ? 0xFF : TheOtherRolesPlugin.Version.Revision));
             writer.Write(Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId.ToByteArray());
@@ -390,19 +420,19 @@ namespace TheOtherRoles {
         }
 
 
+        public static bool zoomOutStatus = false;
         public static void toggleZoom(bool reset=false) {
-            float zoomFactor = 4f;
-            if (HudManagerStartPatch.zoomOutStatus)
-                zoomFactor = 1 / zoomFactor;
-            else if (reset) return; // Dont zoom out if meant to reset.
-            HudManagerStartPatch.zoomOutStatus = !HudManagerStartPatch.zoomOutStatus;
-            Camera.main.orthographicSize *= zoomFactor;
+            TheOtherRolesPlugin.Logger.LogMessage(Camera.main.orthographicSize);
+            float orthographicSize = reset || zoomOutStatus ? 3f : 12f;
+
+            zoomOutStatus = !zoomOutStatus && !reset;
+            Camera.main.orthographicSize = orthographicSize;
             foreach (var cam in Camera.allCameras) {
-                if (cam != null && cam.gameObject.name == "UI Camera") cam.orthographicSize *= zoomFactor;  // The UI is scaled too, else we cant click the buttons. Downside: map is super small.
+                if (cam != null && cam.gameObject.name == "UI Camera") cam.orthographicSize = orthographicSize;  // The UI is scaled too, else we cant click the buttons. Downside: map is super small.
             }
 
-            HudManagerStartPatch.zoomOutButton.Sprite = HudManagerStartPatch.zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.PlusButton.png", 150f / zoomFactor * 2) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.MinusButton.png", 150f);
-            HudManagerStartPatch.zoomOutButton.PositionOffset = HudManagerStartPatch.zoomOutStatus ? new Vector3(0f, 3f, 0) : new Vector3(0.4f, 2.8f, 0);
+            HudManagerStartPatch.zoomOutButton.Sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.PlusButton.png", 75f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.MinusButton.png", 150f);
+            HudManagerStartPatch.zoomOutButton.PositionOffset = zoomOutStatus ? new Vector3(0f, 3f, 0) : new Vector3(0.4f, 2.8f, 0);
             ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height); // This will move button positions to the correct position.
         }
         
index db449b6ea58f442cc492804bdf118d090564b608..4aad1be787e4dad1181623eed032379351840ef3 100644 (file)
@@ -23,7 +23,7 @@ namespace TheOtherRoles
     public class TheOtherRolesPlugin : BasePlugin
     {
         public const string Id = "me.eisbison.theotherroles";
-        public const string VersionString = "4.1.5";
+        public const string VersionString = "4.1.6";
 
         public static Version Version = Version.Parse(VersionString);
         internal static BepInEx.Logging.ManualLogSource Logger;
@@ -40,6 +40,7 @@ namespace TheOtherRoles
         public static ConfigEntry<bool> GhostsSeeVotes{ get; set; }
         public static ConfigEntry<bool> ShowRoleSummary { get; set; }
         public static ConfigEntry<bool> ShowLighterDarker { get; set; }
+        public static ConfigEntry<bool> EnableSoundEffects { get; set; }
         public static ConfigEntry<bool> EnableHorseMode { get; set; }
         public static ConfigEntry<string> Ip { get; set; }
         public static ConfigEntry<ushort> Port { get; set; }
@@ -54,9 +55,9 @@ namespace TheOtherRoles
         public static void UpdateRegions() {
             ServerManager serverManager = FastDestroyableSingleton<ServerManager>.Instance;
             var regions = new IRegionInfo[] {
-                new DnsRegionInfo(Ip.Value, "Custom", StringNames.NoTranslation, Ip.Value, Port.Value, false).CastFast<IRegionInfo>(),
                 new DnsRegionInfo("mods.hopto.org", "Modded NA (MNA)", StringNames.NoTranslation, "mods.hopto.org", 443, false).CastFast<IRegionInfo>(),
-                new DnsRegionInfo("au-eu.duikbo.at", "Modded EU (MEU)", StringNames.NoTranslation, "au-eu.duikbo.at", 22023, false).CastFast<IRegionInfo>()
+                new DnsRegionInfo("au-eu.duikbo.at", "Modded EU (MEU)", StringNames.NoTranslation, "au-eu.duikbo.at", 22023, false).CastFast<IRegionInfo>(),
+                new DnsRegionInfo(Ip.Value, "Custom", StringNames.NoTranslation, Ip.Value, Port.Value, false).CastFast<IRegionInfo>()
             };
             
             IRegionInfo ? currentRegion = serverManager.CurrentRegion;
@@ -89,6 +90,7 @@ namespace TheOtherRoles
             GhostsSeeVotes = Config.Bind("Custom", "Ghosts See Votes", true);
             ShowRoleSummary = Config.Bind("Custom", "Show Role Summary", true);
             ShowLighterDarker = Config.Bind("Custom", "Show Lighter / Darker", true);
+            EnableSoundEffects = Config.Bind("Custom", "Enable Sound Effects", true);
             EnableHorseMode = Config.Bind("Custom", "Enable Horse Mode", false);
             ShowPopUpVersion = Config.Bind("Custom", "Show PopUp", "0");
             
index 06339bada889d0dcc2d2029c0573111cde7fedfd..2ecb05ddecf8b1820ab5d147ebfb291f250e3a57 100644 (file)
@@ -15,6 +15,7 @@ namespace TheOtherRoles{
         public static bool showRoleSummary = true;
         public static bool allowParallelMedBayScans = false;
         public static bool showLighterDarker = true;
+        public static bool enableSoundEffects = true;
         public static bool enableHorseMode = false;
         public static bool shieldFirstKill = false;
 
@@ -48,6 +49,7 @@ namespace TheOtherRoles{
             ghostsSeeVotes = TheOtherRolesPlugin.GhostsSeeVotes.Value;
             showRoleSummary = TheOtherRolesPlugin.ShowRoleSummary.Value;
             showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value;
+            enableSoundEffects = TheOtherRolesPlugin.EnableSoundEffects.Value;
             enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
             Patches.ShouldAlwaysHorseAround.isHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
         }
index 11919d64fd7adea8c45477ecac04189abfc8177a..1c2148628c2f9a6d71521d44a6c212950e47d4ed 100644 (file)
@@ -73,7 +73,7 @@ namespace TheOtherRoles.Modules {
                                         color = new Color32(0xDB, 0xFD, 0x2F, byte.MaxValue), 
                                         shadow = new Color32(0x74, 0xE5, 0x10, byte.MaxValue), 
                                         isLighterColor = true });
-            colors.Add(new CustomColor { longname = "Signal Orange",
+            colors.Add(new CustomColor { longname = "Signal\nOrange",
                                         color = new Color32(0xF7, 0x44, 0x17, byte.MaxValue), 
                                         shadow = new Color32(0x9B, 0x2E, 0x0F, byte.MaxValue),
                                         isLighterColor = true });   
@@ -131,6 +131,7 @@ namespace TheOtherRoles.Modules {
                 typeof(Il2CppReferenceArray<Il2CppSystem.Object>)
             })]
             private class ColorStringPatch {
+                [HarmonyPriority(Priority.Last)]
                 public static bool Prefix(ref string __result, [HarmonyArgument(0)] StringNames name) {
                     if ((int)name >= 50000) {
                         string text = CustomColors.ColorStrings[(int)name];
index 57ab847d83762b3fbdf8fac67ed6b5bf5217c7b4..8aa21edfc1a1ed05fc9193db629807c0a53a1779 100644 (file)
@@ -20,6 +20,7 @@ namespace TheOtherRoles.Patches
             new SelectionBehaviour("Ghosts Can Additionally See Modifier", () => MapOptions.ghostsSeeModifier = TheOtherRolesPlugin.GhostsSeeModifier.Value = !TheOtherRolesPlugin.GhostsSeeModifier.Value, TheOtherRolesPlugin.GhostsSeeModifier.Value),
             new SelectionBehaviour("Show Role Summary", () => MapOptions.showRoleSummary = TheOtherRolesPlugin.ShowRoleSummary.Value = !TheOtherRolesPlugin.ShowRoleSummary.Value, TheOtherRolesPlugin.ShowRoleSummary.Value),
             new SelectionBehaviour("Show Lighter / Darker", () => MapOptions.showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value = !TheOtherRolesPlugin.ShowLighterDarker.Value, TheOtherRolesPlugin.ShowLighterDarker.Value),
+            new SelectionBehaviour("Enable Sound Effects", () => MapOptions.enableSoundEffects = TheOtherRolesPlugin.EnableSoundEffects.Value = !TheOtherRolesPlugin.EnableSoundEffects.Value, TheOtherRolesPlugin.EnableSoundEffects.Value),
         };
         
         private static GameObject popUp;
index 7f61b07333a319ceea1512ddb821be45d9cc5c96..4f593469d6eeaaeed0d7cd76ec24003b0be58373 100644 (file)
@@ -18,8 +18,7 @@ $@"Modded by <color=#FCCE03FF>Eisbison</color>, <color=#FCCE03FF>Thunderstorm584
 Design by <color=#FCCE03FF>Bavari</color>";
 
         public static string contributorsCredentials =
-$@"<size=60%> <color=#FCCE03FF>Special thanks to K3ndo & Smeggy</color> 
-GitHub Contributors: Gendelo, Alex2911, amsyarasyiq, MaximeGillot, Psynomit, probablyadnf, JustASysAdmin</size>";
+$@"<size=60%> <color=#FCCE03FF>Special thanks to K3ndo & Smeggy</color></size>";
 
         [HarmonyPatch(typeof(VersionShower), nameof(VersionShower.Start))]
         private static class VersionShowerPatch
index c2e0a5423769af6713146294be99e1a8f7e18622..91e2818b3cf4dbb46adf5586692ca246607a943b 100644 (file)
@@ -11,7 +11,7 @@ using TheOtherRoles.Utilities;
 namespace TheOtherRoles.Patches {
     public class GameStartManagerPatch  {
         public static Dictionary<int, PlayerVersion> playerVersions = new Dictionary<int, PlayerVersion>();
-        private static float timer = 600f;
+        public static float timer = 600f;
         private static float kickingTimer = 0f;
         private static bool versionSent = false;
         private static string lobbyCodeText = "";
@@ -47,7 +47,7 @@ namespace TheOtherRoles.Patches {
             private static string currentText = "";
         
             public static void Prefix(GameStartManager __instance) {
-                if (!AmongUsClient.Instance.AmHost  || !GameData.Instance ) return; // Not host or no instance
+                if (!GameData.Instance ) return; // No instance
                 update = GameData.Instance.PlayerCount != __instance.LastPlayerCount;
             }
 
@@ -122,7 +122,7 @@ namespace TheOtherRoles.Patches {
                 }
 
                 // Lobby timer
-                if (!AmongUsClient.Instance.AmHost || !GameData.Instance) return; // Not host or no instance
+                if (!GameData.Instance) return; // No instance
 
                 if (update) currentText = __instance.PlayerCounter.text;
 
index 4e22adab7f6dcdaeb861b261c2cbaed6f6acac52..bc47d42f505d591a1e42006414a11f394a8d3985 100644 (file)
@@ -55,7 +55,10 @@ namespace TheOtherRoles.Patches {
                     BountyHunter.cooldownText.transform.localPosition = bottomLeft + new Vector3(0f, -1f, -1f);
                     BountyHunter.cooldownText.gameObject.SetActive(true);
                 }
-            } 
+            }
+
+            // Force Reload of SoundEffectHolder
+            SoundEffectsManager.Load();
 
             // First kill
             if (AmongUsClient.Instance.AmHost && MapOptions.shieldFirstKill && MapOptions.firstKillName != "") {
@@ -115,6 +118,14 @@ namespace TheOtherRoles.Patches {
            
         }
 
+        [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.CreatePlayer))]
+        class CreatePlayerPatch {
+            public static void Postfix(IntroCutscene __instance, bool impostorPositioning, ref PoolablePlayer __result) {
+                if (impostorPositioning) __result.SetNameColor(Palette.ImpostorRed);
+            }
+        }
+
+
         [HarmonyPatch(typeof(IntroCutscene), nameof(IntroCutscene.ShowRole))]
         class SetUpRoleTextPatch {
             static public void SetRoleTexts(IntroCutscene __instance) {
diff --git a/TheOtherRoles/Patches/LightSourcePatch.cs b/TheOtherRoles/Patches/LightSourcePatch.cs
deleted file mode 100644 (file)
index a388421..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-using HarmonyLib;
-using UnityEngine;
-
-
-namespace TheOtherRoles.Patches {
-
-       [HarmonyPatch(typeof(LightSource), nameof(LightSource.Start))]
-
-       class LightSourceStartPatch {
-               static void Postfix(LightSource __instance) {
-                       __instance.transform.position += Vector3.down * 0.095f;  // Fixes Polus Rock / Garbage / Boxes reducing vision to 0
-                       return;
-               }
-       }
-}
\ No newline at end of file
index 7418c956813b1559c0c1bca7aee0e1c405ef2c78..4fbe205ec8060e5738f48f71d70c0c9bcfbdcc37 100644 (file)
@@ -1,4 +1,6 @@
-using HarmonyLib;
+using System;
+using System.Collections.Generic;
+using HarmonyLib;
 using UnityEngine;
 using UnityEngine.UI;
 using static UnityEngine.UI.Button;
@@ -11,6 +13,8 @@ namespace TheOtherRoles.Modules {
         private static bool horseButtonState = MapOptions.enableHorseMode;
         private static Sprite horseModeOffSprite = null;
         private static Sprite horseModeOnSprite = null;
+        private static GameObject bottomTemplate;
+        private static AnnouncementPopUp popUp;
 
         private static void Prefix(MainMenuManager __instance) {
             CustomHatLoader.LaunchHatFetcher();
@@ -41,7 +45,7 @@ namespace TheOtherRoles.Modules {
             // Horse mode stuff
             var horseModeSelectionBehavior = new ClientOptionsPatch.SelectionBehaviour("Enable Horse Mode", () => MapOptions.enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value = !TheOtherRolesPlugin.EnableHorseMode.Value, TheOtherRolesPlugin.EnableHorseMode.Value);
 
-            var bottomTemplate = GameObject.Find("InventoryButton");
+            bottomTemplate = GameObject.Find("InventoryButton");
             if (bottomTemplate == null) return;
             var horseButton = Object.Instantiate(bottomTemplate, bottomTemplate.transform.parent);
             var passiveHorseButton = horseButton.GetComponent<PassiveButton>();
@@ -59,19 +63,83 @@ namespace TheOtherRoles.Modules {
                 if (horseButtonState) {
                     if (horseModeOnSprite == null) horseModeOnSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOn.png", 75f);
                     spriteHorseButton.sprite = horseModeOnSprite;
-                }
-                else {
+                } else {
                     if (horseModeOffSprite == null) horseModeOffSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.HorseModeButtonOff.png", 75f);
                     spriteHorseButton.sprite = horseModeOffSprite;
                 }
                 CredentialsPatch.LogoPatch.updateSprite();
                 // Avoid wrong Player Particles floating around in the background
-                var particles = GameObject.FindObjectOfType<PlayerParticles>(); 
+                var particles = GameObject.FindObjectOfType<PlayerParticles>();
                 if (particles != null) {
                     particles.pool.ReclaimAll();
                     particles.Start();
                 }
             });
+
+            // TOR credits button
+            if (bottomTemplate == null) return;
+            var creditsButton = Object.Instantiate(bottomTemplate, bottomTemplate.transform.parent);
+            var passiveCreditsButton = creditsButton.GetComponent<PassiveButton>();
+            var spriteCreditsButton = creditsButton.GetComponent<SpriteRenderer>();
+
+            spriteCreditsButton.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CreditsButton.png", 75f);
+
+            passiveCreditsButton.OnClick = new ButtonClickedEvent();
+
+            passiveCreditsButton.OnClick.AddListener((System.Action)delegate {
+                // do stuff
+                if (popUp != null) Object.Destroy(popUp);
+                popUp = Object.Instantiate(Object.FindObjectOfType<AnnouncementPopUp>(true));
+                popUp.gameObject.SetActive(true);
+                popUp.Init();
+                //SelectableHyperLinkHelper.DestroyGOs(popUp.selectableHyperLinks, "test");
+                string creditsString = @$"<align=""center"">Github Contributors:
+Gendelo
+Alex2911    amsyarasyiq    MaximeGillot
+Psynomit    probablyadnf    JustASysAdmin
+
+";
+                creditsString += $@"<size=60%> Other Credits & Resources:
+OxygenFilter - For all the version v2.3.0 to v2.6.1, we were using the OxygenFilter for automatic deobfuscation
+Reactor - The framework used for all version before v2.0.0
+BepInEx - Used to hook game functions
+Essentials - Custom game options by DorCoMaNdO:
+
+Before v1.6: We used the default Essentials release
+v1.6-v1.8: We slightly changed the default Essentials. The changes can be found on this branch of our fork.
+v2.0.0 and later: As we're not using Reactor anymore, we are using our own implementation, inspired by the one from DorCoMaNdO
+Jackal and Sidekick - Original idea for the Jackal and Sidekick comes from Dhalucard
+Among-Us-Love-Couple-Mod - Idea for the Lovers role comes from Woodi-dev
+Jester - Idea for the Jester role comes from Maartii
+ExtraRolesAmongUs - Idea for the Engineer and Medic role comes from NotHunter101. Also some code snippets come of the implementation were used.
+Among-Us-Sheriff-Mod - Idea for the Sheriff role comes from Woodi-dev
+TooManyRolesMods - Idea for the Detective and Time Master roles comes from Hardel-DW. Also some code snippets of the implementation were used.
+TownOfUs - Idea for the Swapper, Shifter, Arsonist and a similar Mayor role come from Slushiegoose
+Ottomated - Idea for the Morphling, Snitch and Camouflager role come from Ottomated
+Crowded-Mod - Our implementation for 10+ player lobbies is inspired by the one from the Crowded Mod Team
+Goose-Goose-Duck - Idea for the Vulture role come from Slushygoose</size>";
+                creditsString += "</align>";
+                popUp.AnnounceTextMeshPro.text = creditsString;
+                __instance.StartCoroutine(Effects.Lerp(0.01f, new Action<float>((p) => {
+                    if (p == 1) {
+                        var titleText = GameObject.Find("Title_Text").GetComponent<TMPro.TextMeshPro>();
+                        if (titleText != null) titleText.text = "Credits and Contributors";
+                    }
+                })));
+            });
+            
+        }
+
+        public static void Postfix(MainMenuManager __instance) {
+            __instance.StartCoroutine(Effects.Lerp(0.01f, new Action<float>((p) => {
+                if (p == 1) {
+                    bottomTemplate = GameObject.Find("InventoryButton");
+                    foreach (Transform tf in bottomTemplate.transform.parent.GetComponentsInChildren<Transform>()) {
+                        tf.localPosition = new Vector2(tf.localPosition.x * 0.8f, tf.localPosition.y);
+                    }
+                }
+            })));
+
         }
     }
 
index 70fb5b7a83acf31dfe91c61fe3d03a905960be3c..47ac6c622151b1f5b9e83de641ef7eb611c3d9f0 100644 (file)
@@ -1,11 +1,11 @@
-using HarmonyLib;
+using HarmonyLib;
 using TheOtherRoles.Players;
 using TheOtherRoles.Utilities;
 using UnityEngine;
 
 
 namespace TheOtherRoles.Patches {
-       
+
        [HarmonyPatch(typeof(MapBehaviour))]
        class MapBehaviourPatch {
 
@@ -15,26 +15,14 @@ namespace TheOtherRoles.Patches {
                        if (!MapUtilities.CachedShipStatus) {
                                return false;
                        }
-                       Vector3 vector = AntiTeleport.position != null? AntiTeleport.position : CachedPlayer.LocalPlayer.transform.position;
+                       Vector3 vector = AntiTeleport.position != null ? AntiTeleport.position : CachedPlayer.LocalPlayer.transform.position;
                        vector /= MapUtilities.CachedShipStatus.MapScale;
                        vector.x *= Mathf.Sign(MapUtilities.CachedShipStatus.transform.localScale.x);
                        vector.z = -1f;
                        __instance.HerePoint.transform.localPosition = vector;
                        CachedPlayer.LocalPlayer.PlayerControl.SetPlayerMaterialColors(__instance.HerePoint);
-                       return false;
-               }
 
-               [HarmonyPrefix]
-               [HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.ShowNormalMap))]
-               static bool Prefix3(MapBehaviour __instance) {
-                       if (!MeetingHud.Instance || __instance.IsOpen) return true;  // Only run in meetings and when the map is closed
-
-                       CachedPlayer.LocalPlayer.PlayerControl.SetPlayerMaterialColors(__instance.HerePoint);
-                       __instance.GenericShow();
-                       __instance.taskOverlay.Show();
-                       __instance.ColorControl.SetColor(new Color(0.05f, 0.2f, 1f, 1f));
-                       FastDestroyableSingleton<HudManager>.Instance.SetHudActive(false);
                        return false;
                }
        }
-}
\ No newline at end of file
+}
index 5e7d40179a2f0d4b023d7108c922e86e59311408..3c95bb840a5734c6c40cab7b77360119dd79ce20 100644 (file)
@@ -274,7 +274,8 @@ namespace TheOtherRoles.Patches {
             }
         }
 
-        private static GameObject guesserUI;
+        public static GameObject guesserUI;
+        public static PassiveButton guesserUIExitButton;
         static void guesserOnClick(int buttonTarget, MeetingHud __instance) {
             if (guesserUI != null || !(__instance.state == MeetingHud.VoteStates.Voted || __instance.state == MeetingHud.VoteStates.NotVoted)) return;
             __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(false));
@@ -296,9 +297,13 @@ namespace TheOtherRoles.Patches {
             exitButton.gameObject.GetComponent<SpriteRenderer>().sprite = smallButtonTemplate.GetComponent<SpriteRenderer>().sprite;
             exitButtonParent.transform.localPosition = new Vector3(2.725f, 2.1f, -5);
             exitButtonParent.transform.localScale = new Vector3(0.217f, 0.9f, 1);
-            exitButton.GetComponent<PassiveButton>().OnClick.RemoveAllListeners();
-            exitButton.GetComponent<PassiveButton>().OnClick.AddListener((System.Action)(() => {
-                __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true));
+            guesserUIExitButton = exitButton.GetComponent<PassiveButton>();
+            guesserUIExitButton.OnClick.RemoveAllListeners();
+            guesserUIExitButton.OnClick.AddListener((System.Action)(() => {
+                __instance.playerStates.ToList().ForEach(x => {
+                    x.gameObject.SetActive(true);
+                    if (CachedPlayer.LocalPlayer.Data.IsDead && x.transform.FindChild("ShootButton") != null) UnityEngine.Object.Destroy(x.transform.FindChild("ShootButton").gameObject);
+                });
                 UnityEngine.Object.Destroy(container.gameObject);
             }));
 
@@ -316,6 +321,7 @@ namespace TheOtherRoles.Patches {
                 else if (new List<RoleId>() { RoleId.Janitor, RoleId.Godfather, RoleId.Mafioso }.Contains(roleInfo.roleId) && CustomOptionHolder.mafiaSpawnRate.getSelection() == 0) continue;
                 else if (roleInfo.roleId == RoleId.Sidekick && (!CustomOptionHolder.jackalCanCreateSidekick.getBool() || CustomOptionHolder.jackalSpawnRate.getSelection() == 0)) continue;
                 if (roleInfo.roleId == RoleId.Deputy && (CustomOptionHolder.deputySpawnRate.getSelection() == 0 || CustomOptionHolder.sheriffSpawnRate.getSelection() == 0)) continue;
+                if (roleInfo.roleId == RoleId.Pursuer && CustomOptionHolder.lawyerSpawnRate.getSelection() == 0) continue;
                 if (roleInfo.roleId == RoleId.Spy && roleData.impostors.Count <= 1) continue;
 
                 if (Guesser.guesserCantGuessSnitch && Snitch.snitch != null) {
@@ -356,6 +362,7 @@ namespace TheOtherRoles.Patches {
                             MessageWriter murderAttemptWriter = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1);
                             AmongUsClient.Instance.FinishRpcImmediately(murderAttemptWriter);
                             RPCProcedure.shieldedMurderAttempt();
+                            SoundEffectsManager.play("fail");
                             return;
                         }
 
@@ -559,6 +566,9 @@ namespace TheOtherRoles.Patches {
                 
                 // Reset zoomed out ghosts
                 Helpers.toggleZoom(reset: true);
+
+                // Stop all playing sounds
+                SoundEffectsManager.stopAll();
             }
         }
 
index 5835a4dab7252ea673fb67f8dbc6e439612c5281..f71a8001bd78dedbc811c3604250f183309a9278 100644 (file)
@@ -1028,6 +1028,9 @@ namespace TheOtherRoles.Patches {
             if (target.hasFakeTasks())
                 target.clearAllTasks();
 
+            // First kill (set before lover suicide)
+            if (MapOptions.firstKillName == "") MapOptions.firstKillName = target.Data.PlayerName;
+
             // Lover suicide trigger on murder
             if ((Lovers.lover1 != null && target == Lovers.lover1) || (Lovers.lover2 != null && target == Lovers.lover2)) {
                 PlayerControl otherLover = target == Lovers.lover1 ? Lovers.lover2 : Lovers.lover1;
@@ -1127,9 +1130,6 @@ namespace TheOtherRoles.Patches {
                 }
                 Helpers.showFlash(color, 1.5f);
             }
-
-            // First kill
-            if (MapOptions.firstKillName == "") MapOptions.firstKillName = target.Data.PlayerName;
         }
     }
 
index bfa7be8a29764e6cb0454cf1cbb19b8e0e5766b1..1dfd7149dbd2779c160cfc1542188bf1958b1ac3 100644 (file)
@@ -39,6 +39,28 @@ namespace TheOtherRoles.Patches {
 
         public static void Postfix(RegionMenu __instance) {
             if (!__instance.TryCast<RegionMenu>()) return;
+            bool isCustomRegion = FastDestroyableSingleton<ServerManager>.Instance.CurrentRegion.Name == "Custom";
+            if (!isCustomRegion)
+            {
+                if (ipField != null && ipField.gameObject != null) {
+                    ipField.gameObject.SetActive(false);
+
+                }
+                if (portField != null && portField.gameObject != null) {
+                    portField.gameObject.SetActive(false);
+                }
+            } else
+            {
+                if (ipField != null && ipField.gameObject != null)
+                {
+                    ipField.gameObject.SetActive(true);
+
+                }
+                if (portField != null && portField.gameObject != null)
+                {
+                    portField.gameObject.SetActive(true);
+                }
+            }
             var template = FastDestroyableSingleton<JoinGameButton>.Instance;
             var joinGameButtons = GameObject.FindObjectsOfType<JoinGameButton>();
             foreach (var t in joinGameButtons) {  // The correct button has a background, the other 2 dont
@@ -71,6 +93,7 @@ namespace TheOtherRoles.Patches {
                 ipField.OnFocusLost = new Button.ButtonClickedEvent();
                 ipField.OnChange.AddListener((UnityAction)onEnterOrIpChange);
                 ipField.OnFocusLost.AddListener((UnityAction)onFocusLost);
+                ipField.gameObject.SetActive(isCustomRegion);
 
                 void onEnterOrIpChange() {
                     TheOtherRolesPlugin.Ip.Value = ipField.text;
@@ -103,6 +126,7 @@ namespace TheOtherRoles.Patches {
                 portField.OnFocusLost = new Button.ButtonClickedEvent();
                 portField.OnChange.AddListener((UnityAction)onEnterOrPortFieldChange);
                 portField.OnFocusLost.AddListener((UnityAction)onFocusLost);
+                portField.gameObject.SetActive(isCustomRegion);
 
                 void onEnterOrPortFieldChange() {
                     ushort port = 0;
index 0f82bef72c57c0a9ee4fa5b9de5a0ebbe9bb0793..f870b43446a37c509468af0b24dd760819462248 100644 (file)
@@ -21,6 +21,7 @@ namespace TheOtherRoles.Patches {
         private static int crewValues;
         private static int impValues;
         private static bool isEvilGuesser;
+        private static List<Tuple<byte, byte>> playerRoleMap = new List<Tuple<byte, byte>>();
         public static void Postfix() {
             MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ResetVaribles, Hazel.SendOption.Reliable, -1);
             AmongUsClient.Instance.FinishRpcImmediately(writer);
@@ -39,6 +40,7 @@ namespace TheOtherRoles.Patches {
             assignChanceRoles(data); // Assign roles that may or may not be in the game last
             assignRoleTargets(data);
             assignModifiers();
+            setRolesAgain();
         }
 
         public static RoleAssignmentData getRoleAssignmentData() {
@@ -421,6 +423,8 @@ namespace TheOtherRoles.Patches {
             byte playerId = playerList[index].PlayerId;
             if (removePlayer) playerList.RemoveAt(index);
 
+            playerRoleMap.Add(new Tuple<byte, byte>(playerId, roleId));
+
             MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.Reliable, -1);
             writer.Write(roleId);
             writer.Write(playerId);
@@ -510,6 +514,25 @@ namespace TheOtherRoles.Patches {
             return selection;
         }
 
+        private static void setRolesAgain()
+        {
+
+            while (playerRoleMap.Any())
+            {
+                byte amount = (byte)Math.Min(playerRoleMap.Count, 20);
+                var writer = AmongUsClient.Instance!.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.WorkaroundSetRoles, SendOption.Reliable, -1);
+                writer.Write(amount);
+                for (int i = 0; i < amount; i++)
+                {
+                    var option = playerRoleMap[0];
+                    playerRoleMap.RemoveAt(0);
+                    writer.WritePacked((uint)option.Item1);
+                    writer.WritePacked((uint)option.Item2);
+                }
+                AmongUsClient.Instance.FinishRpcImmediately(writer);
+            }
+        }
+
 
         public class RoleAssignmentData {
             public List<PlayerControl> crewmates {get;set;}
index 0970d130b7583b5febcc1088e176c68d9c6e4616..9314eaee1ca12d23d03e2aa84fdbd1ebf9a007cc 100644 (file)
@@ -116,6 +116,7 @@ namespace TheOtherRoles.Patches {
                 writer.Write(isEnter ? byte.MaxValue : (byte)0);
                 writer.EndMessage();
                 RPCProcedure.useUncheckedVent(__instance.Id, CachedPlayer.LocalPlayer.PlayerId, isEnter ? byte.MaxValue : (byte)0);
+                SoundEffectsManager.play("tricksterUseBoxVent");
                 return false;
             }
 
index a56ee34eab1dc7075b70d768a2e951258a7b8bc1..9f0246df0fb6fe6fcb265f92eabcc2f1d6821136 100644 (file)
@@ -77,6 +77,7 @@ namespace TheOtherRoles
         ResetVaribles = 60,
         ShareOptions,
         ForceEnd,
+        WorkaroundSetRoles,
         SetRole,
         SetModifier,
         VersionHandshake,
@@ -147,6 +148,7 @@ namespace TheOtherRoles
             clearAndReloadRoles();
             clearGameHistory();
             setCustomButtonCooldowns();
+            Helpers.toggleZoom(reset : true);
         }
 
         public static void HandleShareOptions(byte numberOfOptions, MessageReader reader) {            
@@ -174,6 +176,21 @@ namespace TheOtherRoles
             }
         }
 
+        public static void workaroundSetRoles(byte numberOfRoles, MessageReader reader)
+        {
+                for (int i = 0; i < numberOfRoles; i++)
+                {                   
+                    byte playerId = (byte) reader.ReadPackedUInt32();
+                    byte roleId = (byte) reader.ReadPackedUInt32();
+                    try {
+                        setRole(roleId, playerId);
+                    } catch (Exception e) {
+                        TheOtherRolesPlugin.Logger.LogError("Error while deserializing roles: " + e.Message);
+                    }
+            }
+            
+        }
+
         public static void setRole(byte roleId, byte playerId) {
             foreach (PlayerControl player in CachedPlayer.AllPlayers)
                 if (player.PlayerId == playerId) {
@@ -410,6 +427,7 @@ namespace TheOtherRoles
 
         public static void timeMasterRewindTime() {
             TimeMaster.shieldActive = false; // Shield is no longer active when rewinding
+            SoundEffectsManager.stop("timemasterShield");  // Shield sound stopped when rewinding
             if(TimeMaster.timeMaster != null && TimeMaster.timeMaster == CachedPlayer.LocalPlayer.PlayerControl) {
                 resetTimeMasterButton();
             }
@@ -622,6 +640,7 @@ namespace TheOtherRoles
                 if (wasSpy || wasImpostor) Sidekick.wasTeamRed = true;
                 Sidekick.wasSpy = wasSpy;
                 Sidekick.wasImpostor = wasImpostor;
+                if (player == CachedPlayer.LocalPlayer.PlayerControl) SoundEffectsManager.play("jackalSidekick");
             }
             Jackal.canCreateSidekick = false;
         }
@@ -748,6 +767,7 @@ namespace TheOtherRoles
             if (flag == byte.MaxValue)
             {
                 target.cosmetics.currentBodySprite.BodySprite.color = Color.white;
+                target.cosmetics.colorBlindText.gameObject.SetActive(SaveManager.colorblindMode);
                 if (Camouflager.camouflageTimer <= 0) target.setDefaultLook();
                 Ninja.isInvisble = false;
                 return;
@@ -757,6 +777,7 @@ namespace TheOtherRoles
             Color color = Color.clear;           
             if (CachedPlayer.LocalPlayer.Data.Role.IsImpostor || CachedPlayer.LocalPlayer.Data.IsDead) color.a = 0.1f;
             target.cosmetics.currentBodySprite.BodySprite.color = color;
+            target.cosmetics.colorBlindText.gameObject.SetActive(false);
             Ninja.invisibleTimer = Ninja.invisibleDuration;
             Ninja.isInvisble = true;
         }
@@ -905,10 +926,13 @@ namespace TheOtherRoles
             }
             PlayerControl guesser = Helpers.playerById(killerId);
             if (FastDestroyableSingleton<HudManager>.Instance != null && guesser != null)
-                if (CachedPlayer.LocalPlayer.PlayerControl == dyingTarget) 
+                if (CachedPlayer.LocalPlayer.PlayerControl == dyingTarget) {
                     FastDestroyableSingleton<HudManager>.Instance.KillOverlay.ShowKillAnimation(guesser.Data, dyingTarget.Data);
-                else if (dyingLoverPartner != null && CachedPlayer.LocalPlayer.PlayerControl == dyingLoverPartner) 
+                    if (MeetingHudPatch.guesserUI != null) MeetingHudPatch.guesserUIExitButton.OnClick.Invoke();
+                } else if (dyingLoverPartner != null && CachedPlayer.LocalPlayer.PlayerControl == dyingLoverPartner) {
                     FastDestroyableSingleton<HudManager>.Instance.KillOverlay.ShowKillAnimation(dyingLoverPartner.Data, dyingLoverPartner.Data);
+                    if (MeetingHudPatch.guesserUI != null) MeetingHudPatch.guesserUIExitButton.OnClick.Invoke();
+                }
             
             PlayerControl guessedTarget = Helpers.playerById(guessedTargetId);
             if (Guesser.showInfoInGhostChat && CachedPlayer.LocalPlayer.Data.IsDead && guessedTarget != null) {
@@ -965,6 +989,9 @@ namespace TheOtherRoles
                 case (byte)CustomRPC.ForceEnd:
                     RPCProcedure.forceEnd();
                     break; 
+                case (byte)CustomRPC.WorkaroundSetRoles:
+                    RPCProcedure.workaroundSetRoles(reader.ReadByte(), reader);
+                    break;
                 case (byte)CustomRPC.SetRole:
                     byte roleId = reader.ReadByte();
                     byte playerId = reader.ReadByte();
@@ -980,6 +1007,8 @@ namespace TheOtherRoles
                     byte major = reader.ReadByte();
                     byte minor = reader.ReadByte();
                     byte patch = reader.ReadByte();
+                    float timer = reader.ReadSingle();
+                    if (!AmongUsClient.Instance.AmHost && timer >= 0f) GameStartManagerPatch.timer = timer;
                     int versionOwnerId = reader.ReadPackedInt32();
                     byte revision = 0xFF;
                     Guid guid;
diff --git a/TheOtherRoles/Resources/CreditsButton.png b/TheOtherRoles/Resources/CreditsButton.png
new file mode 100644 (file)
index 0000000..dd8f59f
Binary files /dev/null and b/TheOtherRoles/Resources/CreditsButton.png differ
diff --git a/TheOtherRoles/Resources/SoundEffects/SoundEffectSourcesAndLicenses.md b/TheOtherRoles/Resources/SoundEffects/SoundEffectSourcesAndLicenses.md
new file mode 100644 (file)
index 0000000..5cc3a56
--- /dev/null
@@ -0,0 +1,41 @@
+#### Custom Button Sound credits, sources and licenses:
+
+| Name | Comment | Url | License |
+|---|---|---|---|
+|engineerRepair| | [Repair_metal.wav](https://freesound.org/people/zbig77/sounds/244985/ ) | CC0 1.0|
+|janitorClean + cleanerClean | combined, shortened + fade out | [Vacuum cleaner.wav](https://freesound.org/people/Accorman/sounds/573797/ ) + [Windowcleaner Spray](https://freesound.org/people/Rudmer_Rotteveel/sounds/536409/ )| CC0 1.0 both|
+|sheriffKill | (already has a sound)  |-|-|
+|deputyHandcuff | | [Ratchet close long.wav](https://freesound.org/people/jameswrowles/sounds/437230/ ) | CC0 1.0|
+|timeMasterShield  | | [Mechanical alarm clock is ticking (SLAVA).wav](https://freesound.org/people/ST303/sounds/171043/ ) | CC0 1.0|
+|medicShield | | [energy](https://freesound.org/people/Leszek_Szary/sounds/146727/ )| CC0 1.0 |
+|shifterShift | recorded by gendelo3 | - | GPLv3 |
+|morphlingSample |Combined and cut |[Scanner 03.wav](https://freesound.org/people/Glitchedtones/sounds/375942/ ) + [ scanner epson V600](https://freesound.org/people/gecop/sounds/521298/ )| CC0 1.0 both|
+|morphlingMorph | | [Whoosh](https://freesound.org/people/qubodup/sounds/60013/) | CC0 1.0 |
+|camouflagerCamo | same as morphlingMorph | - | - |
+|hackerHack | recorded by gendelo3 | - | GPLv3 |
+|hackerVitals  | (already has a sound) |-|-|
+|hackerAdmin  | (already has a sound) |-|-|
+|trackerTrackPlayer | | [CASHIER-REGISTER-KEYBOARD-BEEP-CALC.wav](https://freesound.org/people/newagesoup/sounds/348240/ ) | CC0 1.0 |
+|trackerTrackCorpses |sniffing sound|[Male_Breath_Sniff_Stereo_NT4.wav](https://freesound.org/people/Nox_Sound/sounds/554905/ ) | CC0 1.0 |
+|vampireKill |combined |[Gore Rend](https://freesound.org/people/magnuswaker/sounds/563491/ ) +  [R15-53-Blood Sucking.wav](https://freesound.org/people/craigsmith/sounds/487070/ ) | CC0 1.0 both|
+|garlic | | [Garlic cloves](https://freesound.org/people/Aemyn/sounds/512453/ )| CC0 1.0 |
+|jackalKill | (already has a sound) |-|-|
+|jackalSidekick | | [Snare - Nice.wav]( https://freesound.org/people/molodiaz/sounds/593550/ )| CC0 1.0 |
+|lighterLight | |[Torch Click 2](https://freesound.org/people/BenjaminNelan/sounds/410360/ ) | CC0 1.0 |
+|eraserErase | | [Pencil Eraser Erasing](https://freesound.org/people/deleted_user_7146007/sounds/383861/ ) | CC0 1.0 |
+|tricksterPlaceBox | |[Carton_impact_5.wav](https://freesound.org/people/andresix/sounds/245617/ ) | CC0 1.0 |
+|tricksterLight | same as lighterLight |-|-|
+|tricksterUseBoxVent | |[rubber duck -CsG-.wav](https://freesound.org/people/csaszi/sounds/350917/) | CC0 1.0 |
+|warlockCurse | | [Buffer Spell](https://freesound.org/people/deleted_user_3277771/sounds/176741/ ) | CC0 1.0 |
+|warlockKill | (already has a sound) |-|-|
+|securityGuardPlaceCam | combined | [drilling a screw into wood.wav](https://freesound.org/people/chewiesmissus/sounds/244242/ ) + [hammer v3.wav](https://freesound.org/people/blukotek/sounds/337814/ ) | CC0 1.0 both|
+|securityGuardSealVent | same as securityGuardPlaceCam |-|-|
+|securityGuardCam | (already has a sound) |-|-|
+|arsonistDouse | | [Water Pouring Out of Bucket](https://freesound.org/people/Breviceps/sounds/508178/ )| CC0 1.0 |
+|vultureEat | combined | [Vulture](https://freesound.org/people/AntumDeluge/sounds/188041/ ) + [Eating Crisps](https://freesound.org/people/Sethroph/sounds/334209/ )| CC0 1.0 both| |
+|mediumAsk| |[ghost_sounds.wav](https://freesound.org/people/fishwithfeathers/sounds/177768/ )| CC0 1.0|
+|pursuerBlank | | [gun load.wav](https://freesound.org/people/Shelby_Wideman/sounds/178141/ )| CC0 1.0 |
+|witchSpell | | [witch's laugh](https://freesound.org/people/Yogoorth/sounds/589144/ ) | CC0 1.0 |
+|portalmakerPlacePortal | same as tricksterPlaceBox| - | - |
+|portalUse | | [Static electronic noise - Xbox 360](https://freesound.org/people/scenes/sounds/431654/ ) + [Teleport Slurp](https://freesound.org/people/GameAudio/sounds/220163/  ) | CC0 1.0 both |
+|fail | | [twitch: SmeggyTV: Mein Auge](https://www.twitch.tv/smeggytv/clip/KindQuaintEndiveDancingBanana-Zoc-bXUnqNCoqQD5 )  | License granted for use in TOR |
\ No newline at end of file
diff --git a/TheOtherRoles/Resources/SoundEffects/arsonistDouse.raw b/TheOtherRoles/Resources/SoundEffects/arsonistDouse.raw
new file mode 100644 (file)
index 0000000..297efad
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/arsonistDouse.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/cleanerClean.raw b/TheOtherRoles/Resources/SoundEffects/cleanerClean.raw
new file mode 100644 (file)
index 0000000..70bfed1
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/cleanerClean.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/deputyHandcuff.raw b/TheOtherRoles/Resources/SoundEffects/deputyHandcuff.raw
new file mode 100644 (file)
index 0000000..5af1a9d
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/deputyHandcuff.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/engineerRepair.raw b/TheOtherRoles/Resources/SoundEffects/engineerRepair.raw
new file mode 100644 (file)
index 0000000..e4f5ace
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/engineerRepair.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/eraserErase.raw b/TheOtherRoles/Resources/SoundEffects/eraserErase.raw
new file mode 100644 (file)
index 0000000..bf95d80
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/eraserErase.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/fail.raw b/TheOtherRoles/Resources/SoundEffects/fail.raw
new file mode 100644 (file)
index 0000000..514c79b
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/fail.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/garlic.raw b/TheOtherRoles/Resources/SoundEffects/garlic.raw
new file mode 100644 (file)
index 0000000..d907a38
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/garlic.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/hackerHack.raw b/TheOtherRoles/Resources/SoundEffects/hackerHack.raw
new file mode 100644 (file)
index 0000000..93684f5
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/hackerHack.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/jackalSidekick.raw b/TheOtherRoles/Resources/SoundEffects/jackalSidekick.raw
new file mode 100644 (file)
index 0000000..e4ec042
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/jackalSidekick.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/lighterLight.raw b/TheOtherRoles/Resources/SoundEffects/lighterLight.raw
new file mode 100644 (file)
index 0000000..8bb44c3
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/lighterLight.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/medicShield.raw b/TheOtherRoles/Resources/SoundEffects/medicShield.raw
new file mode 100644 (file)
index 0000000..16a93bb
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/medicShield.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/mediumAsk.raw b/TheOtherRoles/Resources/SoundEffects/mediumAsk.raw
new file mode 100644 (file)
index 0000000..12fe798
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/mediumAsk.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/morphlingMorph.raw b/TheOtherRoles/Resources/SoundEffects/morphlingMorph.raw
new file mode 100644 (file)
index 0000000..7fff361
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/morphlingMorph.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/morphlingSample.raw b/TheOtherRoles/Resources/SoundEffects/morphlingSample.raw
new file mode 100644 (file)
index 0000000..fe77442
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/morphlingSample.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/portalUse.raw b/TheOtherRoles/Resources/SoundEffects/portalUse.raw
new file mode 100644 (file)
index 0000000..a5fdcdb
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/portalUse.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/pursuerBlank.raw b/TheOtherRoles/Resources/SoundEffects/pursuerBlank.raw
new file mode 100644 (file)
index 0000000..c94e197
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/pursuerBlank.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/securityGuardPlaceCam.raw b/TheOtherRoles/Resources/SoundEffects/securityGuardPlaceCam.raw
new file mode 100644 (file)
index 0000000..8be0b1a
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/securityGuardPlaceCam.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/shifterShift.raw b/TheOtherRoles/Resources/SoundEffects/shifterShift.raw
new file mode 100644 (file)
index 0000000..58d2097
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/shifterShift.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/timemasterShield.raw b/TheOtherRoles/Resources/SoundEffects/timemasterShield.raw
new file mode 100644 (file)
index 0000000..9322eec
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/timemasterShield.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/trackerTrackCorpses.raw b/TheOtherRoles/Resources/SoundEffects/trackerTrackCorpses.raw
new file mode 100644 (file)
index 0000000..9bf310c
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/trackerTrackCorpses.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/trackerTrackPlayer.raw b/TheOtherRoles/Resources/SoundEffects/trackerTrackPlayer.raw
new file mode 100644 (file)
index 0000000..a58eb25
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/trackerTrackPlayer.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/tricksterPlaceBox.raw b/TheOtherRoles/Resources/SoundEffects/tricksterPlaceBox.raw
new file mode 100644 (file)
index 0000000..9dfe036
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/tricksterPlaceBox.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/tricksterUseBoxVent.raw b/TheOtherRoles/Resources/SoundEffects/tricksterUseBoxVent.raw
new file mode 100644 (file)
index 0000000..1aa46f2
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/tricksterUseBoxVent.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/vampireBite.raw b/TheOtherRoles/Resources/SoundEffects/vampireBite.raw
new file mode 100644 (file)
index 0000000..a2c9403
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/vampireBite.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/vultureEat.raw b/TheOtherRoles/Resources/SoundEffects/vultureEat.raw
new file mode 100644 (file)
index 0000000..774911a
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/vultureEat.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/warlockCurse.raw b/TheOtherRoles/Resources/SoundEffects/warlockCurse.raw
new file mode 100644 (file)
index 0000000..04baa45
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/warlockCurse.raw differ
diff --git a/TheOtherRoles/Resources/SoundEffects/witchSpell.raw b/TheOtherRoles/Resources/SoundEffects/witchSpell.raw
new file mode 100644 (file)
index 0000000..5ac52e9
Binary files /dev/null and b/TheOtherRoles/Resources/SoundEffects/witchSpell.raw differ
index dc85f5119688a37329264fd1e22c75b6316eecd5..4be122568116db2e0095789c8071a0f07dc677b9 100644 (file)
Binary files a/TheOtherRoles/Resources/ThirdParty/Submerged/Submerged.dll and b/TheOtherRoles/Resources/ThirdParty/Submerged/Submerged.dll differ
index 6924b6d1ba654a51ef74598dcd98d1d4ea4f2995..827986f49aee8f8de5907135446b17cb0c7db490 100644 (file)
@@ -143,14 +143,18 @@ namespace TheOtherRoles
 
             // Modifier
             if (showModifier) {
+                // after dead modifier
+                if (!CustomOptionHolder.modifiersAreHidden.getBool() || PlayerControl.LocalPlayer.Data.IsDead)
+                {
+                    if (Bait.bait.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bait);
+                    if (Bloody.bloody.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bloody);
+                    if (Vip.vip.Any(x => x.PlayerId == p.PlayerId)) infos.Add(vip);
+                }
                 if (p == Lovers.lover1 || p == Lovers.lover2) infos.Add(lover);
                 if (p == Tiebreaker.tiebreaker) infos.Add(tiebreaker);
-                if (Bait.bait.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bait);
-                if (Bloody.bloody.Any(x => x.PlayerId == p.PlayerId)) infos.Add(bloody);
                 if (AntiTeleport.antiTeleport.Any(x => x.PlayerId == p.PlayerId)) infos.Add(antiTeleport);
                 if (Sunglasses.sunglasses.Any(x => x.PlayerId == p.PlayerId)) infos.Add(sunglasses);
                 if (p == Mini.mini) infos.Add(mini);
-                if (Vip.vip.Any(x => x.PlayerId == p.PlayerId)) infos.Add(vip);
                 if (Invert.invert.Any(x => x.PlayerId == p.PlayerId)) infos.Add(invert);
             }
 
diff --git a/TheOtherRoles/SoundEffectsManager.cs b/TheOtherRoles/SoundEffectsManager.cs
new file mode 100644 (file)
index 0000000..eb047d9
--- /dev/null
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Text;
+using UnityEngine;
+using System.Linq;
+
+namespace TheOtherRoles
+{
+    // Class to preload all audio/sound effects that are contained in the embedded resources.
+    // The effects are made available through the soundEffects Dict / the get and the play methods.
+    public static class SoundEffectsManager
+        
+    {
+        private static Dictionary<string, AudioClip> soundEffects;
+
+        public static void Load()
+        {
+            soundEffects = new Dictionary<string, AudioClip>();
+            Assembly assembly = Assembly.GetExecutingAssembly();
+            string[] resourceNames = assembly.GetManifestResourceNames();
+            foreach (string resourceName in resourceNames)
+            {
+                if (resourceName.Contains("TheOtherRoles.Resources.SoundEffects.") && resourceName.Contains(".raw"))
+                {
+                    soundEffects.Add(resourceName, Helpers.loadAudioClipFromResources(resourceName));
+                }
+            }
+        }
+
+        public static AudioClip get(string path)
+        {
+            // Convenience: As as SoundEffects are stored in the same folder, allow using just the name as well
+            if (!path.Contains(".")) path = "TheOtherRoles.Resources.SoundEffects." + path + ".raw";
+            AudioClip returnValue;
+            return soundEffects.TryGetValue(path, out returnValue) ? returnValue : null;
+        }
+
+
+        public static void play(string path, float volume=0.8f)
+        {
+            if (!MapOptions.enableSoundEffects) return;
+            AudioClip clipToPlay = get(path);
+            // if (false) clipToPlay = get("exampleClip"); for april fools?
+            stop(path);
+            if (Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(clipToPlay, false, volume);
+        }
+
+        public static void stop(string path) {
+            if (Constants.ShouldPlaySfx()) SoundManager.Instance.StopSound(get(path));
+        }
+
+        public static void stopAll() {
+            foreach (var path in soundEffects.Keys) stop(path);
+        }
+    }
+}
index db9b5ae6030facbc9afab32e5d8c79b4f4331e7d..7ec73dbd89b04583c4c321abc39de5a0e0055da3 100644 (file)
@@ -286,6 +286,7 @@ namespace TheOtherRoles
                     byte localPlayerId = CachedPlayer.LocalPlayer.PlayerId;
                     handcuffedKnows.Add(localPlayerId, handcuffDuration);
                     handcuffedPlayers.RemoveAll(x => x == localPlayerId);
+                    SoundEffectsManager.play("deputyHandcuff");
                 }
 
                 HudManagerStartPatch.setAllButtonsHandcuffedStatus(active);
index 6133669af8622ae7deea85cad66f85260685f6c8..05ad58b05a3e2d3f5ac53772f7e19cb785574a65 100644 (file)
@@ -1,7 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <TargetFramework>netstandard2.1</TargetFramework>
-        <Version>4.1.4</Version>
+        <Version>4.1.6</Version>
         <Description>TheOtherRoles</Description>
         <Authors>Eisbison</Authors>
                <LangVersion>latest</LangVersion>