├── .gitignore ├── LICENSE ├── LethalThings.sln ├── LethalThings ├── Content.cs ├── Extensions │ ├── Assembly.cs │ └── PlayerControllerB.cs ├── InputCompat.cs ├── LethalThings.csproj ├── MonoBehaviours │ ├── Arson.cs │ ├── ConfigManager.cs.fuckthis │ ├── Cookie.cs │ ├── CustomNetworkTransform.cs │ ├── Dart.cs │ ├── DartboardInit.cs │ ├── DecalRandomizer.cs │ ├── DecorPlacementDebug.cs │ ├── DevMenu.cs │ ├── Dingus.cs │ ├── FakeItem.cs │ ├── FatalitiesSign.cs │ ├── FishFriend.cs │ ├── FlareController.cs │ ├── ForcedPing.cs │ ├── GrabbableRigidbody.cs │ ├── GremlinEnergy.cs │ ├── HackingTool.cs │ ├── HandheldRadar.cs │ ├── Maggie.cs │ ├── MaggieSpawner.cs │ ├── Missile.cs │ ├── Pinger.cs │ ├── PouchyBelt.cs │ ├── PowerOutletStun.cs │ ├── ProjectileWeapon.cs │ ├── RobotAI.cs │ ├── RocketLauncher.cs │ ├── RoombaAI.cs │ ├── RootMarker.cs │ ├── SaveableNetworkBehaviour.cs │ ├── SaveableObject.cs │ ├── SeasonalHandler.cs │ ├── TeleporterTrap.cs │ ├── TestBehaviour.cs │ ├── ThrowableItem.cs │ ├── ThrowableNoisemaker.cs │ ├── ToyGun.cs │ └── ToyHammer.cs ├── NetworkConfig.cs ├── NuGet.Config ├── Patches │ ├── Debug.cs │ ├── Miscellaneous.cs │ ├── Patches.cs │ ├── PowerOutletStun.cs │ └── SaveData.cs ├── Plugin.cs ├── Thunderstore │ ├── CHANGELOG.md │ ├── README.md │ ├── Thunderstore.zip │ ├── icon.png │ ├── manifest.json │ └── plugins │ │ └── LethalThings │ │ ├── LethalThings.dll │ │ └── lethalthings └── Utilities.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Recordings can get excessive in size 18 | /[Rr]ecordings/ 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.unityproj 36 | *.suo 37 | *.tmp 38 | *.user 39 | *.userprefs 40 | *.pidb 41 | *.booproj 42 | *.svd 43 | *.pdb 44 | *.mdb 45 | *.opendb 46 | *.VC.db 47 | 48 | # Unity3D generated meta files 49 | *.pidb.meta 50 | *.pdb.meta 51 | *.mdb.meta 52 | 53 | # Unity3D generated file on crash reports 54 | sysinfo.txt 55 | 56 | # Builds 57 | *.apk 58 | *.aab 59 | *.unitypackage 60 | *.app 61 | 62 | # Crashlytics generated file 63 | crashlytics-build.properties 64 | 65 | # Packed Addressables 66 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 67 | 68 | # Temporary auto-generated Android Assets 69 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 70 | /[Aa]ssets/[Ss]treamingAssets/aa/* 71 | 72 | /Unity 73 | 74 | /LethalThings/bin 75 | /LethalThings/obj 76 | /LTInputUtilsCompat/bin 77 | /LTInputUtilsCompat/obj 78 | 79 | /LethalThings/DynamicBone/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lethal Company Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LethalThings.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34309.116 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LethalThings", "LethalThings\LethalThings.csproj", "{2DC60A9D-F44B-4B06-8A37-9B05D6D2CAC8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {2DC60A9D-F44B-4B06-8A37-9B05D6D2CAC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {2DC60A9D-F44B-4B06-8A37-9B05D6D2CAC8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {2DC60A9D-F44B-4B06-8A37-9B05D6D2CAC8}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {2DC60A9D-F44B-4B06-8A37-9B05D6D2CAC8}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {187ED89A-15D5-434F-B56B-7D1192890D1D} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /LethalThings/Content.cs: -------------------------------------------------------------------------------- 1 | using LethalLib.Extras; 2 | using LethalLib.Modules; 3 | using LethalThings.Extensions; 4 | using LethalThings.MonoBehaviours; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Text; 11 | using Unity.Netcode.Components; 12 | using Unity.Netcode.Samples; 13 | using UnityEngine; 14 | using static LethalLib.Modules.ContentLoader; 15 | 16 | namespace LethalThings 17 | { 18 | public class Content 19 | { 20 | public static AssetBundle MainAssets; 21 | public static Dictionary Prefabs = new Dictionary(); 22 | public static ContentLoader ContentLoader; 23 | public static GameObject devMenuPrefab; 24 | public static GameObject configManagerPrefab; 25 | 26 | public static void Init() 27 | { 28 | MainAssets = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "lethalthings")); 29 | 30 | configManagerPrefab = MainAssets.LoadAsset("Assets/Custom/LethalThings/LTNetworkConfig.prefab"); 31 | 32 | NetworkPrefabs.RegisterNetworkPrefab(configManagerPrefab); 33 | 34 | ContentLoader = new ContentLoader(Plugin.pluginInfo, MainAssets, (content, prefab) => { 35 | Prefabs.Add(content.ID, prefab); 36 | }); 37 | 38 | CustomContent[] content = 39 | [ 40 | // scrap 41 | new ScrapItem("Arson", "Assets/Custom/LethalThings/Scrap/Arson/ArsonPlush.asset", NetworkConfig.arsonSpawnChance.Value, Levels.LevelTypes.All), 42 | new ScrapItem("Cookie", "Assets/Custom/LethalThings/Scrap/Cookie/CookieFumo.asset", NetworkConfig.cookieSpawnChance.Value, Levels.LevelTypes.All), 43 | new ScrapItem("Bilka", "Assets/Custom/LethalThings/Scrap/Toimari/ToimariPlush.asset", NetworkConfig.toimariSpawnChance.Value, Levels.LevelTypes.All), 44 | new ScrapItem("Hamis", "Assets/Custom/LethalThings/Scrap/Hamis/HamisPlush.asset", NetworkConfig.hamisSpawnChance.Value, Levels.LevelTypes.All), 45 | new ScrapItem("ArsonDirty", "Assets/Custom/LethalThings/Scrap/Arson/ArsonPlushDirty.asset", NetworkConfig.dirtyArsonSpawnChance.Value, Levels.LevelTypes.All), 46 | new ScrapItem("Maxwell", "Assets/Custom/LethalThings/Scrap/Maxwell/Dingus.asset", NetworkConfig.maxwellSpawnChance.Value, Levels.LevelTypes.All), 47 | new ScrapItem("Glizzy", "Assets/Custom/LethalThings/Scrap/glizzy/glizzy.asset", NetworkConfig.glizzySpawnChance.Value, Levels.LevelTypes.All), 48 | new ScrapItem("Revolver", "Assets/Custom/LethalThings/Scrap/Flaggun/Toygun.asset", NetworkConfig.revolverSpawnChance.Value, Levels.LevelTypes.All), 49 | new ScrapItem("GremlinEnergy", "Assets/Custom/LethalThings/Scrap/GremlinEnergy/GremlinEnergy.asset", NetworkConfig.gremlinSodaSpawnChance.Value, Levels.LevelTypes.All), 50 | new ScrapItem("ToyHammerScrap", "Assets/Custom/LethalThings/Items/ToyHammer/ToyHammer.asset", NetworkConfig.toyHammerScrapSpawnChance.Value, Levels.LevelTypes.All), 51 | new ScrapItem("Gnarpy", "Assets/Custom/LethalThings/Scrap/Gnarpy/GnarpyPlush.asset", NetworkConfig.gnarpySpawnChance.Value, Levels.LevelTypes.All), 52 | // shop 53 | new ShopItem("RocketLauncher", "Assets/Custom/LethalThings/Items/RocketLauncher/RocketLauncher.asset", NetworkConfig.rocketLauncherPrice.Value, null, null, "Assets/Custom/LethalThings/Items/RocketLauncher/RocketLauncherInfo.asset", (item) => { 54 | NetworkPrefabs.RegisterNetworkPrefab(item.spawnPrefab.GetComponent().missilePrefab); 55 | }), 56 | new ShopItem("Flaregun", "Assets/Custom/LethalThings/Items/Flaregun/Flaregun.asset", NetworkConfig.flareGunPrice.Value, null, null, "Assets/Custom/LethalThings/Items/Flaregun/FlaregunInfo.asset", (item) => { 57 | NetworkPrefabs.RegisterNetworkPrefab(item.spawnPrefab.GetComponent().projectilePrefab); 58 | }), 59 | new ShopItem("FlaregunAmmo", "Assets/Custom/LethalThings/Items/Flaregun/FlaregunAmmo.asset", NetworkConfig.flareGunAmmoPrice.Value, null, null, "Assets/Custom/LethalThings/Items/Flaregun/FlaregunAmmoInfo.asset"), 60 | new ShopItem("ToyHammerShop", "Assets/Custom/LethalThings/Items/ToyHammer/ToyHammer.asset", NetworkConfig.toyHammerPrice.Value, null, null, "Assets/Custom/LethalThings/Items/ToyHammer/ToyHammerInfo.asset"), 61 | new ShopItem("RemoteRadar", "Assets/Custom/LethalThings/Items/Radar/HandheldRadar.asset", NetworkConfig.remoteRadarPrice.Value, null, null, "Assets/Custom/LethalThings/Items/Radar/HandheldRadarInfo.asset"), 62 | new ShopItem("PouchyBelt", "Assets/Custom/LethalThings/Items/Pouch/Pouch.asset", NetworkConfig.pouchyBeltPrice.Value, null, null, "Assets/Custom/LethalThings/Items/Pouch/PouchInfo.asset"), 63 | new ShopItem("HackingTool", "Assets/Custom/LethalThings/Items/HackingTool/HackingTool.asset", NetworkConfig.hackingToolPrice.Value, null, null, "Assets/Custom/LethalThings/Items/HackingTool/HackingToolInfo.asset"), 64 | new ShopItem("Pinger", "Assets/Custom/LethalThings/Items/PingingTool/PingTool.asset", NetworkConfig.pingerPrice.Value, null, null, "Assets/Custom/LethalThings/Items/PingingTool/PingToolInfo.asset", (item) => { 65 | NetworkPrefabs.RegisterNetworkPrefab(item.spawnPrefab.GetComponent().pingMarkerPrefab); 66 | }), 67 | 68 | 69 | // plain items 70 | new CustomItem("Dart", "Assets/Custom/LethalThings/Unlockables/dartboard/Dart.asset"), 71 | 72 | // unlockables 73 | new Unlockable("SmallRug", "Assets/Custom/LethalThings/Unlockables/Rug/SmallRug.asset", NetworkConfig.smallRugPrice.Value, null, null, "Assets/Custom/LethalThings/Unlockables/Rug/RugInfo.asset", StoreType.Decor), 74 | new Unlockable("LargeRug", "Assets/Custom/LethalThings/Unlockables/Rug/LargeRug.asset", NetworkConfig.largeRugPrice.Value, null, null, "Assets/Custom/LethalThings/Unlockables/Rug/RugInfo.asset", StoreType.Decor), 75 | new Unlockable("FatalitiesSign", "Assets/Custom/LethalThings/Unlockables/Sign/Sign.asset", NetworkConfig.fatalitiesSignPrice.Value, null, null, "Assets/Custom/LethalThings/Unlockables/Sign/SignInfo.asset", StoreType.Decor), 76 | new Unlockable("Dartboard", "Assets/Custom/LethalThings/Unlockables/dartboard/Dartboard.asset", NetworkConfig.dartBoardPrice.Value, null, null, "Assets/Custom/LethalThings/Unlockables/dartboard/DartboardInfo.asset", StoreType.Decor), 77 | //new Unlockable("DeliveryRover", "Assets/Custom/LethalThings/Unlockables/Dog/Dog.asset", NetworkConfig.deliveryRoverPrice.Value, null, null, "Assets/Custom/LethalThings/Unlockables/Dog/DogInfo.asset", StoreType.ShipUpgrade), 78 | 79 | // enemies 80 | new CustomEnemy("Boomba", "Assets/Custom/LethalThings/Enemies/Roomba/Boomba.asset", NetworkConfig.boombaSpawnWeight.Value, Levels.LevelTypes.All, Enemies.SpawnType.Default, null, "Assets/Custom/LethalThings/Enemies/Roomba/BoombaFile.asset"), 81 | 82 | 83 | new CustomEnemy("Maggie", "Assets/Custom/LethalThings/Enemies/Maggie/Maggie.asset", NetworkConfig.maggieSpawnWeight.Value, Levels.LevelTypes.All, Enemies.SpawnType.Default, null, "Assets/Custom/LethalThings/Enemies/Maggie/MaggieFile.asset", null, (enemyType) => { 84 | var goopRagdoll = MainAssets.LoadAsset("Assets/Custom/LethalThings/Enemies/Maggie/PlayerRagdollGoop.prefab"); 85 | Player.RegisterPlayerRagdoll("LTGoopRagdoll", goopRagdoll); 86 | }), 87 | new CustomEnemy("CrystalRay", "Assets/Custom/LethalThings/Enemies/CrystalRay/CrystalRay.asset", NetworkConfig.crystalRaySpawnWeight.Value, Levels.LevelTypes.All, Enemies.SpawnType.Default, null, "Assets/Custom/LethalThings/Enemies/CrystalRay/CrystalRayFile.asset"), 88 | 89 | 90 | // map objects 91 | new MapHazard("TeleporterTrap", "Assets/Custom/LethalThings/hazards/TeleporterTrap/TeleporterTrap.asset", Levels.LevelTypes.All, null, (level) => { 92 | // spawn curve that ensures a maximum of 4 per level 93 | return new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 4)); 94 | }) 95 | ]; 96 | 97 | ContentLoader.RegisterAll(content); 98 | 99 | 100 | // loop through prefabs 101 | foreach (var prefabSet in Prefabs) 102 | { 103 | var prefab = prefabSet.Value; 104 | 105 | // get prefab name 106 | var prefabName = prefabSet.Key; 107 | 108 | 109 | // get all AudioSources 110 | var audioSources = prefab.GetComponentsInChildren(); 111 | 112 | // if has any AudioSources 113 | 114 | if (audioSources.Length > 0) 115 | { 116 | var configValue = NetworkConfig.VolumeConfig.Bind("Volume", $"{prefabName}", 100f, $"Audio volume for {prefabName} (0 - 100)"); 117 | 118 | // loop through AudioSources, adjust volume by multiplier 119 | foreach (var audioSource in audioSources) 120 | { 121 | audioSource.volume *= (configValue.Value / 100); 122 | } 123 | } 124 | } 125 | 126 | 127 | var devMenu = MainAssets.LoadAsset("Assets/Custom/LethalThings/DevMenu.prefab"); 128 | 129 | NetworkPrefabs.RegisterNetworkPrefab(devMenu); 130 | 131 | devMenuPrefab = devMenu; 132 | 133 | try 134 | { 135 | var types = Assembly.GetExecutingAssembly().GetLoadableTypes(); 136 | foreach (var type in types) 137 | { 138 | var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); 139 | foreach (var method in methods) 140 | { 141 | var attributes = method.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), false); 142 | if (attributes.Length > 0) 143 | { 144 | method.Invoke(null, null); 145 | } 146 | } 147 | } 148 | } 149 | catch (Exception e) 150 | { 151 | 152 | } 153 | } 154 | 155 | 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /LethalThings/Extensions/Assembly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace LethalThings.Extensions 8 | { 9 | public static class AssemblyExtensions 10 | { 11 | public static IEnumerable GetLoadableTypes(this Assembly assembly) 12 | { 13 | try 14 | { 15 | return assembly.GetTypes(); 16 | } 17 | catch (ReflectionTypeLoadException e) 18 | { 19 | return e.Types.Where(t => t != null); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LethalThings/Extensions/PlayerControllerB.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.Extensions 9 | { 10 | public static class PlayerControllerExtensions 11 | { 12 | 13 | public static bool SwitchItemSlots(this PlayerControllerB self, int requestedSlot) 14 | { 15 | if (!self.IsItemSwitchPossible() || 16 | self.currentItemSlot == requestedSlot) 17 | { 18 | return false; 19 | } 20 | 21 | var distance = self.currentItemSlot - requestedSlot; 22 | var requestedSlotIsLowerThanCurrent = (distance > 0); 23 | 24 | if (Math.Abs(distance) == self.ItemSlots.Length - 1) 25 | { 26 | self.SwitchItemSlotsServerRpc(requestedSlotIsLowerThanCurrent ? true : false); 27 | } 28 | else 29 | { 30 | do 31 | { 32 | self.SwitchItemSlotsServerRpc(requestedSlotIsLowerThanCurrent ? true : false); 33 | distance += requestedSlotIsLowerThanCurrent ? -1 : 1; 34 | } while (distance != 0); 35 | } 36 | 37 | ShipBuildModeManager.Instance.CancelBuildMode(); 38 | self.playerBodyAnimator.SetBool("GrabValidated", false); 39 | 40 | self.SwitchToItemSlot(requestedSlot); 41 | 42 | if (self.currentlyHeldObjectServer != null) 43 | { 44 | self.currentlyHeldObjectServer.gameObject.GetComponent().PlayOneShot(self.currentlyHeldObjectServer.itemProperties.grabSFX, 0.6f); 45 | } 46 | 47 | return true; 48 | } 49 | 50 | public static bool IsItemSwitchPossible(this PlayerControllerB self) 51 | { 52 | return !(self.timeSinceSwitchingSlots < 0.01 || self.inTerminalMenu || self.isGrabbingObjectAnimation || 53 | self.inSpecialInteractAnimation || self.throwingObject || self.isTypingChat || 54 | self.twoHanded || self.activatingItem || self.jetpackControls || 55 | self.disablingJetpackControls); 56 | } 57 | 58 | public static void DropItem(this PlayerControllerB self, GrabbableObject grabbableObject, int slotIndex = 0, bool itemsFall = true) 59 | { 60 | 61 | 62 | if (itemsFall) 63 | { 64 | grabbableObject.parentObject = null; 65 | grabbableObject.heldByPlayerOnServer = false; 66 | if (self.isInElevator) 67 | { 68 | grabbableObject.transform.SetParent(self.playersManager.elevatorTransform, worldPositionStays: true); 69 | } 70 | else 71 | { 72 | grabbableObject.transform.SetParent(self.playersManager.propsContainer, worldPositionStays: true); 73 | } 74 | self.SetItemInElevator(self.isInHangarShipRoom, self.isInElevator, grabbableObject); 75 | grabbableObject.EnablePhysics(enable: true); 76 | grabbableObject.EnableItemMeshes(enable: true); 77 | grabbableObject.transform.localScale = grabbableObject.originalScale; 78 | grabbableObject.isHeld = false; 79 | grabbableObject.isPocketed = false; 80 | 81 | grabbableObject.transform.position = self.serverItemHolder.position; 82 | 83 | grabbableObject.startFallingPosition = grabbableObject.transform.parent.InverseTransformPoint(self.serverItemHolder.position); 84 | 85 | /* 86 | // spawn a debug sphere at startFallingPosition 87 | GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); 88 | sphere.transform.parent = grabbableObject.transform.parent; 89 | sphere.transform.localPosition = grabbableObject.startFallingPosition; 90 | sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); 91 | 92 | // spawn another debug sphere at the grabbableObject's position 93 | GameObject sphere2 = GameObject.CreatePrimitive(PrimitiveType.Sphere); 94 | sphere2.transform.parent = grabbableObject.transform.parent; 95 | sphere2.transform.localPosition = grabbableObject.transform.localPosition; 96 | sphere2.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); 97 | */ 98 | 99 | grabbableObject.FallToGround(true); 100 | grabbableObject.fallTime = UnityEngine.Random.Range(-0.3f, 0.05f); 101 | if (self.IsOwner) 102 | { 103 | grabbableObject.DiscardItemOnClient(); 104 | } 105 | else if (!grabbableObject.itemProperties.syncDiscardFunction) 106 | { 107 | grabbableObject.playerHeldBy = null; 108 | } 109 | 110 | self.SetObjectAsNoLongerHeld(self.isInElevator, self.isInHangarShipRoom, grabbableObject.targetFloorPosition, grabbableObject); 111 | } 112 | if (self.IsOwner) 113 | { 114 | // if player was holding this item in their hands 115 | if(self.currentlyHeldObject != null && self.currentlyHeldObject == grabbableObject) 116 | { 117 | HUDManager.Instance.holdingTwoHandedItem.enabled = false; 118 | HUDManager.Instance.ClearControlTips(); 119 | self.activatingItem = false; 120 | } 121 | 122 | HUDManager.Instance.itemSlotIcons[slotIndex].enabled = false; 123 | 124 | 125 | } 126 | self.ItemSlots[slotIndex] = null; 127 | } 128 | 129 | 130 | 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /LethalThings/InputCompat.cs: -------------------------------------------------------------------------------- 1 | using LethalCompanyInputUtils.Api; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Text; 7 | using UnityEngine; 8 | using UnityEngine.InputSystem; 9 | 10 | namespace LethalThings 11 | { 12 | public static class InputCompat 13 | { 14 | public static bool Enabled => BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils"); 15 | 16 | public static InputActionAsset Asset; 17 | 18 | public static void Init() 19 | { 20 | Keybinds.Instance = new Keybinds(); 21 | Asset = Keybinds.Instance.GetAsset(); 22 | 23 | } 24 | 25 | public static InputAction LTUtilityBeltQuick1 => Keybinds.Instance.LTUtilityBeltQuick1; 26 | 27 | public static InputAction LTUtilityBeltQuick2 => Keybinds.Instance.LTUtilityBeltQuick2; 28 | 29 | public static InputAction LTUtilityBeltQuick3 => Keybinds.Instance.LTUtilityBeltQuick3; 30 | 31 | public static InputAction LTUtilityBeltQuick4 => Keybinds.Instance.LTUtilityBeltQuick4; 32 | 33 | 34 | } 35 | 36 | 37 | public class Keybinds : LcInputActions 38 | { 39 | [InputAction("", Name = "[LT] Utility Belt Quick 1")] 40 | public InputAction LTUtilityBeltQuick1 { get; set; } 41 | [InputAction("", Name = "[LT] Utility Belt Quick 2")] 42 | public InputAction LTUtilityBeltQuick2 { get; set; } 43 | [InputAction("", Name = "[LT] Utility Belt Quick 3")] 44 | public InputAction LTUtilityBeltQuick3 { get; set; } 45 | [InputAction("", Name = "[LT] Utility Belt Quick 4")] 46 | public InputAction LTUtilityBeltQuick4 { get; set; } 47 | 48 | public static Keybinds Instance; 49 | 50 | public InputActionAsset GetAsset() => Asset; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /LethalThings/LethalThings.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | LethalThings 6 | Mod for Lethal Company 7 | 1.0.0 8 | true 9 | latest 10 | 11 | https://api.nuget.org/v3/index.json; 12 | https://nuget.bepinex.dev/v3/index.json; 13 | 14 | 15 | 16 | 17 | portable 18 | 19 | 20 | 21 | portable 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | all 35 | runtime; build; native; contentfiles; analyzers; buildtransitive 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | C:\Users\mail\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\modding\BepInEx\plugins\Rune580-LethalCompany_InputUtils\LethalCompanyInputUtils\LethalCompanyInputUtils.dll 48 | 49 | 50 | C:\Users\mail\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\modding\BepInEx\plugins\MMHOOK\MMHOOK_Assembly-CSharp.dll 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/Arson.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode; 5 | using UnityEngine; 6 | using UnityEngine.UIElements; 7 | using Random = UnityEngine.Random; 8 | 9 | namespace LethalThings.MonoBehaviours 10 | { 11 | public class Arson : GrabbableObject 12 | { 13 | 14 | public AudioSource noiseAudio; 15 | 16 | public AudioSource noiseAudioFar; 17 | 18 | [Space(3f)] 19 | public AudioClip[] noiseSFX; 20 | 21 | public AudioClip[] noiseSFXFar; 22 | 23 | [Space(3f)] 24 | public float noiseRange; 25 | 26 | public float maxLoudness; 27 | 28 | public float minLoudness; 29 | 30 | public float minPitch; 31 | 32 | public float maxPitch; 33 | 34 | private System.Random noisemakerRandom; 35 | 36 | public Animator triggerAnimator; 37 | 38 | public bool isCleanable; 39 | 40 | public Item cleanArson; 41 | 42 | public bool arsonBeingShowered = false; 43 | 44 | public float showerTime = 0f; 45 | 46 | public float totalShowerTime = 5f; 47 | 48 | public static List allArsonList = new List(); 49 | 50 | public bool canBeShowered = false; 51 | 52 | public ShowerTrigger currentShower = null; 53 | 54 | public static void Init() 55 | { 56 | On.ShowerTrigger.CheckBoundsForPlayers += ShowerTrigger_CheckBoundsForPlayers; 57 | } 58 | 59 | 60 | private static void ShowerTrigger_CheckBoundsForPlayers(On.ShowerTrigger.orig_CheckBoundsForPlayers orig, ShowerTrigger self) 61 | { 62 | 63 | 64 | if (Time.realtimeSinceStartup - self.cleanInterval < 1.5f) 65 | { 66 | return; 67 | } 68 | 69 | var collider = self.showerCollider; 70 | var bounds = collider.bounds; 71 | 72 | for (int i = 0; i < allArsonList.Count; i++) 73 | { 74 | var arson = allArsonList[i]; 75 | 76 | if (arson.arsonBeingShowered || !arson.isCleanable) 77 | { 78 | continue; 79 | } 80 | 81 | Plugin.logger.LogMessage("Checking arson " + arson.gameObject.name); 82 | 83 | var arsonCollider = arson.GetComponent(); 84 | 85 | if (collider.bounds.Intersects(arsonCollider.bounds)) 86 | { 87 | arson.arsonBeingShowered = true; 88 | arson.currentShower = self; 89 | Plugin.logger.LogMessage("Eww!! stinky arson."); 90 | } 91 | else 92 | { 93 | arson.arsonBeingShowered = false; 94 | arson.showerTime = 0f; 95 | } 96 | } 97 | 98 | orig(self); 99 | 100 | 101 | } 102 | 103 | public override void Update() 104 | { 105 | base.Update(); 106 | if (arsonBeingShowered) 107 | { 108 | if(currentShower == null || !currentShower.showerOn) 109 | { 110 | arsonBeingShowered = false; 111 | return; 112 | } 113 | 114 | showerTime += Time.deltaTime; 115 | 116 | if (showerTime >= totalShowerTime) 117 | { 118 | arsonBeingShowered = false; 119 | showerTime = 0f; 120 | 121 | if (IsHost) 122 | { 123 | var gameObject = UnityEngine.Object.Instantiate(cleanArson.spawnPrefab, transform.position, transform.rotation); 124 | gameObject.GetComponent().Spawn(); 125 | 126 | gameObject.transform.rotation = transform.rotation; 127 | 128 | var grabbable = gameObject.GetComponent(); 129 | 130 | if (grabbable && grabbable.itemProperties && grabbable.itemProperties.isScrap && RoundManager.Instance) 131 | { 132 | int price = (int)(Random.Range(grabbable.itemProperties.minValue, grabbable.itemProperties.maxValue) * RoundManager.Instance.scrapValueMultiplier); 133 | 134 | grabbable.SetScrapValue(price); 135 | 136 | syncScrapValueClientRpc(grabbable.GetComponent(), price, isInElevator, isInShipRoom); 137 | 138 | } 139 | 140 | GetComponent().Despawn(true); 141 | } 142 | } 143 | } 144 | } 145 | 146 | 147 | [ClientRpc] 148 | public void syncScrapValueClientRpc(NetworkObjectReference obj, int scrapValue, bool itemIsInElevator, bool itemIsInShipRoom) 149 | { 150 | if (obj.TryGet(out NetworkObject targetObject)) 151 | { 152 | var grabbable = targetObject.GetComponent(); 153 | 154 | if (grabbable) 155 | { 156 | grabbable.SetScrapValue(scrapValue); 157 | 158 | StartOfRound.Instance.localPlayerController.SetItemInElevator(itemIsInShipRoom, itemIsInElevator, grabbable); 159 | } 160 | } 161 | } 162 | 163 | public void Awake() 164 | { 165 | allArsonList.Add(this); 166 | } 167 | 168 | public override void OnDestroy() 169 | { 170 | base.OnDestroy(); 171 | allArsonList.Remove(this); 172 | } 173 | 174 | public override void Start() 175 | { 176 | base.Start(); 177 | noisemakerRandom = new System.Random(StartOfRound.Instance.randomMapSeed + 85); 178 | } 179 | 180 | public override void ItemActivate(bool used, bool buttonDown = true) 181 | { 182 | base.ItemActivate(used, buttonDown); 183 | if (!(GameNetworkManager.Instance.localPlayerController == null)) 184 | { 185 | int num = noisemakerRandom.Next(0, noiseSFX.Length); 186 | float num2 = (float)noisemakerRandom.Next((int)(minLoudness * 100f), (int)(maxLoudness * 100f)) / 100f; 187 | float pitch = (float)noisemakerRandom.Next((int)(minPitch * 100f), (int)(maxPitch * 100f)) / 100f; 188 | noiseAudio.pitch = pitch; 189 | noiseAudio.PlayOneShot(noiseSFX[num], num2); 190 | if (noiseAudioFar != null) 191 | { 192 | noiseAudioFar.pitch = pitch; 193 | noiseAudioFar.PlayOneShot(noiseSFXFar[num], num2); 194 | } 195 | if (triggerAnimator != null) 196 | { 197 | triggerAnimator.SetTrigger("playAnim"); 198 | } 199 | WalkieTalkie.TransmitOneShotAudio(noiseAudio, noiseSFX[num], num2); 200 | RoundManager.Instance.PlayAudibleNoise(base.transform.position, noiseRange, num2, 0, isInElevator && StartOfRound.Instance.hangarDoorsClosed); 201 | 202 | if(noiseSFX[num].name.Contains("chomp")) 203 | { 204 | if (IsOwner) 205 | { 206 | playerHeldBy.DamagePlayer(30, causeOfDeath: CauseOfDeath.Mauling); 207 | 208 | // drop item 209 | playerHeldBy.DiscardHeldObject(); 210 | } 211 | } 212 | } 213 | } 214 | 215 | 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ConfigManager.cs.fuckthis: -------------------------------------------------------------------------------- 1 | using BepInEx.Configuration; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | // THIS IS THE WORST FUCKING THING I HAVE EVER WRITTEN AND I WANT TO CRY 11 | // I TRIED TO MAKE IT GENERIC BUT I FAILED MISERABLY. 12 | // IF SOMEONE KNOWS HOW TO REWRITE IT IN A WAY WHERE I DO NOT HAVE TO HAVE THE SAME VARIABLE IN 3 DIFFERENT PLACES PLEASE DO TELL. 13 | public class ConfigManager : NetworkBehaviour 14 | { 15 | 16 | public static ConfigManager Instance; 17 | 18 | public class Config 19 | { 20 | public static ConfigEntry arsonSpawnWeight; 21 | public static ConfigEntry dirtyArsonSpawnWeight; 22 | public static ConfigEntry toimariSpawnWeight; 23 | public static ConfigEntry hamisSpawnWeight; 24 | public static ConfigEntry cookieSpawnWeight; 25 | public static ConfigEntry maxwellSpawnWeight; 26 | public static ConfigEntry maxwellPlayMusicDefault; 27 | 28 | public static ConfigEntry toyHammerEnabled; 29 | public static ConfigEntry toyHammerPrice; 30 | public static ConfigEntry pouchyBeltEnabled; 31 | public static ConfigEntry pouchyBeltPrice; 32 | public static ConfigEntry remoteRadarEnabled; 33 | public static ConfigEntry remoteRadarPrice; 34 | public static ConfigEntry rocketLauncherEnabled; 35 | public static ConfigEntry rocketLauncherPrice; 36 | 37 | public static ConfigEntry boombaEnabled; 38 | public static ConfigEntry boombaSpawnWeight; 39 | 40 | public static ConfigEntry rugsEnabled; 41 | 42 | public static ConfigEntry enableItemChargerElectrocution; 43 | public static ConfigEntry disableOverlappingModContent; 44 | 45 | public static void Load() 46 | { 47 | arsonSpawnWeight = Plugin.config.Bind("Scrap", "Arson", 10, "How much does Arson spawn, higher = more common"); 48 | dirtyArsonSpawnWeight = Plugin.config.Bind("Scrap", "DirtyArson", 10, "How much does Arson (Dirty) spawn, higher = more common"); 49 | toimariSpawnWeight = Plugin.config.Bind("Scrap", "Toimari", 20, "How much does Toimari spawn, higher = more common"); 50 | hamisSpawnWeight = Plugin.config.Bind("Scrap", "Hamis", 20, "How much does Hamis spawn, higher = more common"); 51 | cookieSpawnWeight = Plugin.config.Bind("Scrap", "Cookie", 20, "How much does Cookie spawn, higher = more common"); 52 | maxwellSpawnWeight = Plugin.config.Bind("Scrap", "Maxwell", 3, "How much does Maxwell spawn, higher = more common"); 53 | maxwellPlayMusicDefault = Plugin.config.Bind("Scrap", "MaxwellPlayMusicDefault", true, "Does Maxwell play music by default?"); 54 | 55 | 56 | toyHammerEnabled = Plugin.config.Bind("Items", "ToyHammer", true, "Is Toy Hammer enabled?"); 57 | toyHammerPrice = Plugin.config.Bind("Items", "ToyHammerPrice", 80, "How much does Toy Hammer cost?"); 58 | pouchyBeltEnabled = Plugin.config.Bind("Items", "PouchyBelt", true, "Is Pouchy Belt enabled?"); 59 | pouchyBeltPrice = Plugin.config.Bind("Items", "PouchyBeltPrice", 290, "How much does Pouchy Belt cost?"); 60 | remoteRadarEnabled = Plugin.config.Bind("Items", "RemoteRadar", true, "Is Remote Radar enabled?"); 61 | remoteRadarPrice = Plugin.config.Bind("Items", "RemoteRadarPrice", 240, "How much does Remote Radar cost?"); 62 | rocketLauncherEnabled = Plugin.config.Bind("Items", "RocketLauncher", true, "Is Rocket Launcher enabled?"); 63 | rocketLauncherPrice = Plugin.config.Bind("Items", "RocketLauncherPrice", 500, "How much does Rocket Launcher cost?"); 64 | 65 | boombaEnabled = Plugin.config.Bind("Enemies", "Boomba", true, "Is Boomba allowed to spawn?"); 66 | boombaSpawnWeight = Plugin.config.Bind("Enemies", "BoombaSpawnWeight", 20, "How much do Boombas spawn, higher = more common"); 67 | 68 | rugsEnabled = Plugin.config.Bind("Decor", "Rugs", true, "Are rugs enabled?"); 69 | 70 | enableItemChargerElectrocution = Plugin.config.Bind("Misc", "EnableItemChargerElectrocution", true, "Do players get electrocuted when stuffing conductive objects in the item charger."); 71 | disableOverlappingModContent = Plugin.config.Bind("Misc", "DisableOverlappingModContent", true, "Disable content from other mods which exists in this one (e.g. maxwell)."); 72 | 73 | 74 | 75 | } 76 | } 77 | 78 | 79 | public NetworkVariable arsonSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 80 | public NetworkVariable dirtyArsonSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 81 | public NetworkVariable toimariSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 82 | public NetworkVariable hamisSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 83 | public NetworkVariable cookieSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 84 | public NetworkVariable maxwellSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 85 | public NetworkVariable maxwellPlayMusicDefault = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 86 | 87 | public NetworkVariable toyHammerEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 88 | public NetworkVariable toyHammerPrice = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 89 | public NetworkVariable pouchyBeltEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 90 | public NetworkVariable pouchyBeltPrice = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 91 | public NetworkVariable remoteRadarEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 92 | public NetworkVariable remoteRadarPrice = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 93 | public NetworkVariable rocketLauncherEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 94 | public NetworkVariable rocketLauncherPrice = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 95 | 96 | public NetworkVariable boombaEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 97 | public NetworkVariable boombaSpawnWeight = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 98 | 99 | public NetworkVariable rugsEnabled = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 100 | 101 | public NetworkVariable enableItemChargerElectrocution = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 102 | public NetworkVariable disableOverlappingModContent = new NetworkVariable(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 103 | 104 | public static void Load() 105 | { 106 | Config.Load(); 107 | On.GameNetworkManager.Awake += GameNetworkManager_Awake; 108 | On.GameNetworkManager.Start += GameNetworkManager_Start; 109 | } 110 | 111 | 112 | 113 | public void WriteVariables() 114 | { 115 | arsonSpawnWeight.Value = Config.arsonSpawnWeight.Value; 116 | dirtyArsonSpawnWeight.Value = Config.dirtyArsonSpawnWeight.Value; 117 | toimariSpawnWeight.Value = Config.toimariSpawnWeight.Value; 118 | hamisSpawnWeight.Value = Config.hamisSpawnWeight.Value; 119 | cookieSpawnWeight.Value = Config.cookieSpawnWeight.Value; 120 | maxwellSpawnWeight.Value = Config.maxwellSpawnWeight.Value; 121 | maxwellPlayMusicDefault.Value = Config.maxwellPlayMusicDefault.Value; 122 | 123 | toyHammerEnabled.Value = Config.toyHammerEnabled.Value; 124 | toyHammerPrice.Value = Config.toyHammerPrice.Value; 125 | pouchyBeltEnabled.Value = Config.pouchyBeltEnabled.Value; 126 | pouchyBeltPrice.Value = Config.pouchyBeltPrice.Value; 127 | remoteRadarEnabled.Value = Config.remoteRadarEnabled.Value; 128 | remoteRadarPrice.Value = Config.remoteRadarPrice.Value; 129 | rocketLauncherEnabled.Value = Config.rocketLauncherEnabled.Value; 130 | rocketLauncherPrice.Value = Config.rocketLauncherPrice.Value; 131 | 132 | boombaEnabled.Value = Config.boombaEnabled.Value; 133 | boombaSpawnWeight.Value = Config.boombaSpawnWeight.Value; 134 | 135 | rugsEnabled.Value = Config.rugsEnabled.Value; 136 | 137 | enableItemChargerElectrocution.Value = Config.enableItemChargerElectrocution.Value; 138 | disableOverlappingModContent.Value = Config.disableOverlappingModContent.Value; 139 | } 140 | 141 | private static void GameNetworkManager_Awake(On.GameNetworkManager.orig_Awake orig, GameNetworkManager self) 142 | { 143 | orig(self); 144 | Debug.Log("ConfigManager Awake WAAAAH"); 145 | var prefab = Content.ConfigManagerPrefab; 146 | if(prefab == null) 147 | { 148 | self.GetComponent().AddNetworkPrefab(prefab); 149 | } 150 | 151 | } 152 | 153 | private static void GameNetworkManager_Start(On.GameNetworkManager.orig_Start orig, GameNetworkManager self) 154 | { 155 | orig(self); 156 | var prefab = Content.ConfigManagerPrefab; 157 | if (Instance == null) 158 | { 159 | // instantiate 160 | var obj = UnityEngine.Object.Instantiate(prefab); 161 | obj.GetComponent().Spawn(false); 162 | obj.GetComponent().WriteVariables(); 163 | Instance = obj.GetComponent(); 164 | } 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/Cookie.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | public class Cookie : ThrowableNoisemaker 11 | { 12 | public AudioClip[] cookieSpecialAudio; 13 | private float explodePercentage = 0.04f; 14 | private float oooPennyPercentage = 0.2f; 15 | public bool wasThrown = false; 16 | public override void ItemInteractLeftRight(bool right) 17 | { 18 | base.ItemInteractLeftRight(right); 19 | 20 | //Plugin.logger.LogInfo($"Attempted to throw cookie!!"); 21 | 22 | if (!IsOwner) 23 | { 24 | return; 25 | } 26 | 27 | //Plugin.logger.LogInfo($"Cookie thrown with right: {right} - {throwWithRight}"); 28 | 29 | if ((throwWithRight && right) || !right) 30 | { 31 | wasThrown = true; 32 | 33 | PlayCookieAudioServerRpc(0); 34 | 35 | } 36 | } 37 | 38 | [ServerRpc] 39 | public void PlayCookieAudioServerRpc(int index) 40 | { 41 | PlayCookieAudioClientRpc(index); 42 | } 43 | 44 | [ClientRpc] 45 | public void PlayCookieAudioClientRpc(int index) 46 | { 47 | noiseAudio.PlayOneShot(cookieSpecialAudio[index]); 48 | if (noiseAudioFar != null) 49 | { 50 | noiseAudioFar.PlayOneShot(cookieSpecialAudio[index]); 51 | } 52 | 53 | WalkieTalkie.TransmitOneShotAudio(noiseAudio, cookieSpecialAudio[index], 0.5f); 54 | RoundManager.Instance.PlayAudibleNoise(base.transform.position, noiseRange, 0.5f, 0, isInElevator && StartOfRound.Instance.hangarDoorsClosed); 55 | } 56 | 57 | [ServerRpc] 58 | public void StopPlayingCookieAudioServerRpc() 59 | { 60 | StopPlayingCookieAudioClientRpc(); 61 | } 62 | 63 | [ClientRpc] 64 | public void StopPlayingCookieAudioClientRpc() 65 | { 66 | noiseAudio.Stop(); 67 | if (noiseAudioFar != null) 68 | { 69 | noiseAudioFar.Stop(); 70 | } 71 | } 72 | 73 | 74 | [ClientRpc] 75 | public void BoomClientRpc() 76 | { 77 | Boom(); 78 | } 79 | 80 | [ServerRpc] 81 | public void BoomServerRpc() 82 | { 83 | Boom(); 84 | BoomClientRpc(); 85 | } 86 | 87 | 88 | public void CreateExplosion() 89 | { 90 | var player = StartOfRound.Instance.allPlayerScripts.FirstOrDefault(x => x.OwnerClientId == OwnerClientId); 91 | Utilities.CreateExplosion(transform.position, true, 20, 0, 4, 10, CauseOfDeath.Blast, player); 92 | } 93 | 94 | public void Boom() 95 | { 96 | CreateExplosion(); 97 | 98 | if (IsHost) 99 | { 100 | Destroy(gameObject); 101 | } 102 | } 103 | 104 | public override void OnHitGround() 105 | { 106 | if (wasThrown) 107 | { 108 | wasThrown = false; 109 | 110 | if (IsOwner) 111 | { 112 | if ((UnityEngine.Random.Range(0f, 1000f) / 1000f) <= explodePercentage) 113 | { 114 | Boom(); 115 | BoomServerRpc(); 116 | } 117 | else 118 | { 119 | 120 | // if random chance 121 | if ((UnityEngine.Random.Range(0f, 1000f) / 1000f) <= oooPennyPercentage) 122 | { 123 | StopPlayingCookieAudioServerRpc(); 124 | PlayCookieAudioServerRpc(1); 125 | } 126 | } 127 | } 128 | 129 | } 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/CustomNetworkTransform.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode; 5 | using UnityEngine; 6 | 7 | namespace LethalThings.MonoBehaviours 8 | { 9 | public class CustomNetworkTransform : NetworkBehaviour 10 | { 11 | public bool syncPosition = true; 12 | public bool syncRotation = true; 13 | public bool syncScale = true; 14 | // required magnitude difference to send an update 15 | public float positionDiffLimit = 0.10f; 16 | 17 | // required angle difference to send an update 18 | public float rotationDiffLimit = 0.10f; 19 | 20 | // required scale difference to send an update 21 | public float scaleDiffLimit = 0.10f; 22 | 23 | // interpolation settings 24 | public bool lerpPosition = true; 25 | public bool lerpRotation = true; 26 | public bool lerpScale = true; 27 | public float positionLerpSpeed = 10f; 28 | public float rotationLerpSpeed = 10f; 29 | public float scaleLerpSpeed = 10f; 30 | 31 | // last sent position 32 | private Vector3 _lastPosition; 33 | private Vector3 _lastRotation; 34 | private Vector3 _lastScale; 35 | 36 | private Vector3 _targetPosition; 37 | private Quaternion _targetRotation; 38 | private Vector3 _targetScale; 39 | 40 | public void FixedUpdate() 41 | { 42 | if (IsServer) 43 | { 44 | if (syncPosition) 45 | { 46 | if (Vector3.Distance(transform.position, _lastPosition) > positionDiffLimit) 47 | { 48 | _lastPosition = transform.position; 49 | UpdatePositionClientRpc(transform.position); 50 | } 51 | } 52 | 53 | if (syncRotation) 54 | { 55 | if (Quaternion.Angle(Quaternion.Euler(transform.eulerAngles), Quaternion.Euler(_lastRotation)) > rotationDiffLimit) 56 | { 57 | _lastRotation = transform.eulerAngles; 58 | UpdateRotationClientRpc(transform.eulerAngles); 59 | } 60 | } 61 | 62 | if (syncScale) 63 | { 64 | if (Vector3.Distance(transform.localScale, _lastScale) > scaleDiffLimit) 65 | { 66 | _lastScale = transform.localScale; 67 | UpdateScaleClientRpc(transform.localScale); 68 | } 69 | } 70 | } 71 | else 72 | { 73 | if (lerpPosition) 74 | { 75 | transform.position = Vector3.Lerp(transform.position, _targetPosition, Time.fixedDeltaTime * positionLerpSpeed); 76 | } 77 | 78 | if (lerpRotation) 79 | { 80 | transform.rotation = Quaternion.Slerp(transform.rotation, _targetRotation, Time.fixedDeltaTime * rotationLerpSpeed); 81 | } 82 | 83 | if (lerpScale) 84 | { 85 | transform.localScale = Vector3.Lerp(transform.localScale, _targetScale, Time.fixedDeltaTime * scaleLerpSpeed); 86 | } 87 | } 88 | } 89 | 90 | 91 | [ClientRpc] 92 | public void UpdatePositionClientRpc(Vector3 position) 93 | { 94 | if (!IsServer && syncPosition) 95 | { 96 | if(lerpPosition) { 97 | _targetPosition = position; 98 | } 99 | else 100 | { 101 | transform.position = position; 102 | 103 | } 104 | } 105 | } 106 | 107 | 108 | [ClientRpc] 109 | public void UpdateRotationClientRpc(Vector3 rotation) 110 | { 111 | if (!IsServer && syncRotation) 112 | { 113 | if (lerpRotation) 114 | { 115 | _targetRotation = Quaternion.Euler(rotation); 116 | } 117 | else 118 | { 119 | transform.rotation = Quaternion.Euler(rotation); 120 | } 121 | } 122 | } 123 | 124 | 125 | [ClientRpc] 126 | public void UpdateScaleClientRpc(Vector3 scale) 127 | { 128 | if (!IsServer && syncScale) 129 | { 130 | if (lerpScale) 131 | { 132 | _targetScale = scale; 133 | } 134 | else 135 | { 136 | transform.localScale = scale; 137 | } 138 | } 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/DartboardInit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode; 5 | using UnityEngine; 6 | 7 | namespace LethalThings.MonoBehaviours 8 | { 9 | public class DartboardInit : NetworkBehaviour 10 | { 11 | public Transform[] dartSpawns; 12 | 13 | public GameObject dartPrefab; 14 | 15 | public List dartInstances = new List(); 16 | 17 | public int dartsToSpawn = 3; 18 | 19 | private float dartInitTimer = 0.6f; 20 | private float dartInitTimerCurrent = 0f; 21 | 22 | public bool initialized = false; 23 | public bool networkSpawned = false; 24 | 25 | public override void OnNetworkSpawn() 26 | { 27 | base.OnNetworkSpawn(); 28 | networkSpawned = true; 29 | } 30 | 31 | 32 | 33 | 34 | public void Update() 35 | { 36 | if(!IsHost) 37 | { 38 | return; 39 | } 40 | 41 | if (!initialized && networkSpawned) 42 | { 43 | //check if time has passed 44 | if (dartInitTimerCurrent >= dartInitTimer) 45 | { 46 | initialized = true; 47 | 48 | Plugin.logger.LogInfo("Attempting to spawn darts!!"); 49 | 50 | // check if there are darts in the scene already 51 | var darts = FindObjectsOfType(); 52 | 53 | // add darts to list 54 | foreach (Dart dart in darts) 55 | { 56 | dartInstances.Add(dart.gameObject); 57 | } 58 | 59 | // pick random dart spawns, no repeats 60 | List dartSpawnsList = new List(dartSpawns); 61 | List dartSpawnPositions = new List(); 62 | for (int i = darts.Length; i < dartsToSpawn; i++) 63 | { 64 | int randomIndex = UnityEngine.Random.Range(0, dartSpawnsList.Count); 65 | dartSpawnPositions.Add(dartSpawnsList[randomIndex]); 66 | dartSpawnsList.RemoveAt(randomIndex); 67 | } 68 | 69 | foreach (Transform dartSpawn in dartSpawnPositions) 70 | { 71 | GameObject dart = Instantiate(dartPrefab, dartSpawn.position, dartSpawn.rotation, transform); 72 | 73 | //Plugin.logger.LogInfo("Spawned dart!!"); 74 | 75 | var dartScript = dart.GetComponent(); 76 | 77 | // offset backwards so the dart tip is at the spawn point 78 | dart.transform.position -= dart.transform.forward * Vector3.Distance(dartScript.dartTip.position, dartSpawn.position); 79 | 80 | dartInstances.Add(dart); 81 | 82 | dart.GetComponent().Spawn(); 83 | } 84 | 85 | } 86 | 87 | dartInitTimerCurrent += Time.deltaTime; 88 | return; 89 | } 90 | else if(!networkSpawned) 91 | { 92 | return; 93 | } 94 | 95 | 96 | 97 | // if any darts are lost, respawn them 98 | // do every 2 seconds 99 | if (Time.frameCount % 120 != 0) 100 | { 101 | return; 102 | } 103 | List newDartInstances = new List(); 104 | 105 | var dartsChanged = false; 106 | 107 | foreach (GameObject dart in dartInstances) 108 | { 109 | if (dart == null) 110 | { 111 | // pick random dart spawn 112 | 113 | dartsChanged = true; 114 | 115 | int randomIndex = UnityEngine.Random.Range(0, dartSpawns.Length); 116 | 117 | Transform dartSpawn = dartSpawns[randomIndex]; 118 | 119 | 120 | GameObject newDart = Instantiate(dartPrefab, dartSpawn.position, dartSpawn.rotation, transform); 121 | 122 | var dartScript = newDart.GetComponent(); 123 | 124 | // offset backwards so the dart tip is at the spawn point 125 | newDart.transform.position -= newDart.transform.forward * Vector3.Distance(dartScript.dartTip.position, dartSpawn.position); 126 | 127 | 128 | newDartInstances.Add(newDart); 129 | newDart.GetComponent().Spawn(); 130 | } 131 | else 132 | { 133 | newDartInstances.Add(dart); 134 | } 135 | } 136 | 137 | if(dartsChanged) 138 | { 139 | dartInstances = newDartInstances; 140 | 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/DecalRandomizer.cs: -------------------------------------------------------------------------------- 1 | using LethalLib.Modules; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | using UnityEngine.Rendering.HighDefinition; 8 | 9 | namespace LethalThings.MonoBehaviours 10 | { 11 | public class DecalRandomizer : SaveableNetworkBehaviour 12 | { 13 | public List decalProjectors = new List(); 14 | [HideInInspector] 15 | private NetworkList decalIndexes = new NetworkList(new List(), NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 16 | 17 | public List decalMaterials = new List(); 18 | 19 | /* 20 | public override object SaveObjectData() 21 | { 22 | // convert networklist to list 23 | List decalIndexesList = new List(); 24 | 25 | for (int i = 0; i < decalIndexes.Count; i++) 26 | { 27 | decalIndexesList.Add(decalIndexes[i]); 28 | } 29 | 30 | return decalIndexesList; 31 | } 32 | 33 | public override void LoadObjectData(object data) 34 | { 35 | if (IsHost) 36 | { 37 | decalIndexes.Clear(); 38 | var decalIndexesList = (List)data; 39 | 40 | for (int i = 0; i < decalIndexesList.Count; i++) 41 | { 42 | decalIndexes.Add(decalIndexesList[i]); 43 | } 44 | } 45 | 46 | }*/ 47 | 48 | public override void SaveObjectData() 49 | { 50 | List decalIndexesList = new List(); 51 | 52 | for (int i = 0; i < decalIndexes.Count; i++) 53 | { 54 | decalIndexesList.Add(decalIndexes[i]); 55 | } 56 | 57 | SaveData.SaveObjectData>("decalData", decalIndexesList, uniqueId); 58 | } 59 | 60 | public void ToggleDecals(bool enabled) 61 | { 62 | // loop decalrenderers and toggle 63 | for (int i = 0; i < decalProjectors.Count; i++) 64 | { 65 | decalProjectors[i].enabled = enabled; 66 | } 67 | } 68 | 69 | public override void LoadObjectData() 70 | { 71 | if (IsHost) 72 | { 73 | decalIndexes.Clear(); 74 | var decalIndexesList = SaveData.LoadObjectData>("decalData", uniqueId); 75 | 76 | if(decalIndexesList == null) 77 | { 78 | decalIndexesList = new List(); 79 | } 80 | 81 | for (int i = 0; i < decalIndexesList.Count; i++) 82 | { 83 | decalIndexes.Add(decalIndexesList[i]); 84 | } 85 | } 86 | } 87 | 88 | public override void OnNetworkSpawn() 89 | { 90 | base.OnNetworkSpawn(); 91 | if (IsHost) 92 | { 93 | for (int i = 0; i < decalProjectors.Count; i++) 94 | { 95 | decalIndexes.Add(UnityEngine.Random.Range(0, decalMaterials.Count)); 96 | } 97 | } 98 | } 99 | 100 | public void Start() 101 | { 102 | if (IsServer) 103 | { 104 | for (int i = 0; i < decalProjectors.Count; i++) 105 | { 106 | decalIndexes[i] = UnityEngine.Random.Range(0, decalMaterials.Count); 107 | } 108 | } 109 | 110 | for (int i = 0; i < decalProjectors.Count; i++) 111 | { 112 | decalProjectors[i].material = decalMaterials[decalIndexes[i]]; 113 | } 114 | } 115 | 116 | public static void Init() 117 | { 118 | On.GrabbableObject.EnableItemMeshes += GrabbableObject_EnableItemMeshes; 119 | } 120 | 121 | private static void GrabbableObject_EnableItemMeshes(On.GrabbableObject.orig_EnableItemMeshes orig, GrabbableObject self, bool enable) 122 | { 123 | orig(self, enable); 124 | 125 | if(self.GetComponentsInChildren() == null) 126 | { 127 | return; 128 | } 129 | 130 | var decalRandomizers = self.GetComponentsInChildren(); 131 | 132 | 133 | for (int i = 0; i < decalRandomizers.Length; i++) 134 | { 135 | decalRandomizers[i].ToggleDecals(enable); 136 | } 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/DecorPlacementDebug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace LethalThings.MonoBehaviours 7 | { 8 | [ExecuteAlways] 9 | public class DecorPlacementDebug : MonoBehaviour 10 | { 11 | private int placementMaskAndBlockers = 605030721; 12 | 13 | public PlaceableShipObject placeableShipObject; 14 | 15 | 16 | void OnDrawGizmos() 17 | { 18 | if (placeableShipObject == null) 19 | { 20 | return; 21 | } 22 | 23 | var currentCollider = placeableShipObject.placeObjectCollider as BoxCollider; 24 | var ghostObject = placeableShipObject.transform; 25 | 26 | //bool flag = Physics.CheckBox(ghostObject.position, currentCollider.size * 0.5f * 0.57f, Quaternion.Euler(ghostObject.eulerAngles), placementMaskAndBlockers, QueryTriggerInteraction.Ignore); 27 | 28 | Gizmos.color = Color.red; 29 | //Gizmos.DrawWireCube(placeableShipObject.transform.position, placeableShipObject.transform.localScale); 30 | 31 | // draw gizmo that matches check box 32 | Gizmos.DrawWireCube(transform.position, currentCollider.size * 0.5f * 0.57f); 33 | 34 | var layerString = ""; 35 | // print out all the layer numbers from placementMaskAndBlockers 36 | for (int i = 0; i < 32; i++) 37 | { 38 | if ((placementMaskAndBlockers & (1 << i)) != 0) 39 | { 40 | layerString += LayerMask.LayerToName(i) + ", "; 41 | } 42 | } 43 | 44 | Debug.Log(layerString); 45 | 46 | } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/FakeItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace LethalThings.MonoBehaviours 6 | { 7 | public class FakeItem : GrabbableObject 8 | { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/FatalitiesSign.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using TMPro; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | public class FatalitiesSign : NetworkBehaviour 11 | { 12 | public static int DaysSinceLastFatality = 0; 13 | public static int lastDeathCount = 0; 14 | public static int daysSpent = 0; 15 | private static bool wasJustUpdated = false; 16 | 17 | public TextMeshProUGUI textMesh; 18 | public TextMeshProUGUI textMeshBack; 19 | [HideInInspector] 20 | public NetworkVariable daysSinceLastFatality = new NetworkVariable(0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 21 | 22 | public static void Init() 23 | { 24 | On.GameNetworkManager.SaveGameValues += GameNetworkManager_SaveGameValues; 25 | On.GameNetworkManager.ResetSavedGameValues += GameNetworkManager_ResetSavedGameValues; 26 | On.StartOfRound.SetTimeAndPlanetToSavedSettings += StartOfRound_SetTimeAndPlanetToSavedSettings; 27 | 28 | On.HUDManager.ApplyPenalty += HUDManager_ApplyPenalty; 29 | On.StartOfRound.PassTimeToNextDay += StartOfRound_PassTimeToNextDay; 30 | } 31 | 32 | private static void StartOfRound_PassTimeToNextDay(On.StartOfRound.orig_PassTimeToNextDay orig, StartOfRound self, int connectedPlayersOnServer) 33 | { 34 | orig(self, connectedPlayersOnServer); 35 | if (!wasJustUpdated) 36 | { 37 | DaysSinceLastFatality++; 38 | } 39 | wasJustUpdated = false; 40 | } 41 | 42 | 43 | private static void HUDManager_ApplyPenalty(On.HUDManager.orig_ApplyPenalty orig, HUDManager self, int playersDead, int bodiesInsured) 44 | { 45 | Plugin.logger.LogInfo($"Dead players: {playersDead}"); 46 | if(playersDead > 0) 47 | { 48 | DaysSinceLastFatality = 0; 49 | wasJustUpdated = true; 50 | } 51 | orig(self, playersDead, bodiesInsured); 52 | } 53 | 54 | 55 | 56 | private static void StartOfRound_SetTimeAndPlanetToSavedSettings(On.StartOfRound.orig_SetTimeAndPlanetToSavedSettings orig, StartOfRound self) 57 | { 58 | orig(self); 59 | string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; 60 | DaysSinceLastFatality = ES3.Load("LethalThings_DaysSinceLastFatality", currentSaveFileName, 0); 61 | } 62 | 63 | private static void GameNetworkManager_ResetSavedGameValues(On.GameNetworkManager.orig_ResetSavedGameValues orig, GameNetworkManager self) 64 | { 65 | orig(self); 66 | DaysSinceLastFatality = 0; 67 | ES3.Save("LethalThings_DaysSinceLastFatality", DaysSinceLastFatality, self.currentSaveFileName); 68 | } 69 | 70 | private static void GameNetworkManager_SaveGameValues(On.GameNetworkManager.orig_SaveGameValues orig, GameNetworkManager self) 71 | { 72 | orig(self); 73 | ES3.Save("LethalThings_DaysSinceLastFatality", DaysSinceLastFatality, self.currentSaveFileName); 74 | } 75 | 76 | 77 | 78 | public void Awake() 79 | { 80 | if (lastDeathCount == 0) 81 | { 82 | lastDeathCount = StartOfRound.Instance.gameStats.deaths; 83 | daysSpent = StartOfRound.Instance.gameStats.daysSpent; 84 | } 85 | } 86 | 87 | public void Update() 88 | { 89 | 90 | // if host update the network variable 91 | if (IsServer && daysSinceLastFatality.Value != DaysSinceLastFatality) 92 | { 93 | daysSinceLastFatality.Value = DaysSinceLastFatality; 94 | } 95 | 96 | if (textMesh.text != daysSinceLastFatality.Value.ToString()) 97 | { 98 | textMesh.text = daysSinceLastFatality.Value.ToString(); 99 | textMeshBack.text = daysSinceLastFatality.Value.ToString(); 100 | } 101 | 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ForcedPing.cs: -------------------------------------------------------------------------------- 1 | using DunGen; 2 | using GameNetcodeStuff; 3 | using HarmonyLib; 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.ComponentModel; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Numerics; 11 | using System.Text; 12 | using TMPro; 13 | using Unity.Netcode; 14 | using UnityEngine; 15 | using UnityEngine.Rendering.HighDefinition.Attributes; 16 | using Vector3 = UnityEngine.Vector3; 17 | 18 | namespace LethalThings.MonoBehaviours 19 | { 20 | public class ForcedPing : NetworkBehaviour 21 | { 22 | public float pingDuration = 20f; 23 | public float currentPingTime = 0; 24 | [HideInInspector] 25 | public NetworkVariable isActive = new NetworkVariable(true, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 26 | public ScanNodeProperties scanNodeProperties; 27 | private HUDManager hudManager; 28 | public bool destroyAfterPing = false; 29 | 30 | public static void Init() 31 | { 32 | On.HUDManager.NodeIsNotVisible += HUDManager_NodeIsNotVisible; 33 | } 34 | 35 | private static bool HUDManager_NodeIsNotVisible(On.HUDManager.orig_NodeIsNotVisible orig, HUDManager self, ScanNodeProperties node, int elementIndex) 36 | { 37 | if (node != null && node.transform != null && node.transform.parent != null && node.transform.parent.GetComponent() != null) 38 | { 39 | var player = GameNetworkManager.Instance.localPlayerController; 40 | 41 | // check if scan node is in field of view of the player 42 | var camera = player.gameplayCamera; 43 | 44 | var viewPos = camera.WorldToViewportPoint(node.transform.position); 45 | 46 | //UnityEngine.Debug.Log($"View pos: {viewPos}"); 47 | 48 | // if node is not in field of view, return false 49 | if (Vector3.Distance(node.transform.position, camera.transform.position) > node.maxRange || (viewPos.x < 0 || viewPos.x > 1 || viewPos.y < 0 || viewPos.y > 1 || viewPos.z <= 0)) 50 | { 51 | //Plugin.logger.LogInfo($"[1] Node {node.name} not valid"); 52 | return orig(self, node, elementIndex); 53 | } 54 | 55 | var flareController = node.transform.parent.GetComponent(); 56 | // Debug.Log($"Burnt out? {flareController.burntOut}"); 57 | if (flareController.isActive.Value) 58 | { 59 | if (!self.nodesOnScreen.Contains(node)) 60 | { 61 | self.nodesOnScreen.Add(node); 62 | } 63 | return false; 64 | } 65 | } 66 | return orig(self, node, elementIndex); 67 | } 68 | 69 | 70 | public void Awake() 71 | { 72 | hudManager = HUDManager.Instance; 73 | 74 | scanNodeProperties = GetComponentInChildren(); 75 | 76 | //hudManager.AttemptScanNode(scanNodeProperties, 0, GameNetworkManager.Instance.localPlayerController); 77 | 78 | if(Vector3.Distance(scanNodeProperties.transform.position, GameNetworkManager.Instance.localPlayerController.transform.position) < scanNodeProperties.maxRange) 79 | { 80 | if (!hudManager.nodesOnScreen.Contains(scanNodeProperties)) 81 | { 82 | hudManager.nodesOnScreen.Add(scanNodeProperties); 83 | } 84 | hudManager.AssignNodeToUIElement(scanNodeProperties); 85 | } 86 | 87 | 88 | 89 | } 90 | 91 | public override void OnNetworkSpawn() 92 | { 93 | base.OnNetworkSpawn(); 94 | 95 | if (IsServer) 96 | { 97 | isActive.Value = true; 98 | currentPingTime = 0; 99 | } 100 | 101 | 102 | } 103 | 104 | [ClientRpc] 105 | public void RemovePingClientRpc() 106 | { 107 | //Plugin.logger.LogInfo("Removing ping"); 108 | Dictionary scanNodes = hudManager.scanNodes; 109 | RectTransform rectTransform = null; 110 | foreach (var scanNode in scanNodes) 111 | { 112 | if (scanNode.Value == scanNodeProperties) 113 | { 114 | rectTransform = scanNode.Key; 115 | } 116 | } 117 | 118 | if (rectTransform != null) 119 | { 120 | scanNodes.Remove(rectTransform); 121 | rectTransform.gameObject.SetActive(false); 122 | } 123 | } 124 | 125 | public void Update() 126 | { 127 | if (IsServer) 128 | { 129 | if (currentPingTime <= pingDuration) 130 | { 131 | currentPingTime += Time.deltaTime; 132 | } 133 | else 134 | { 135 | // no longer active 136 | isActive.Value = false; 137 | RemovePingClientRpc(); 138 | 139 | if (destroyAfterPing) 140 | { 141 | GetComponent().Despawn(true); 142 | } 143 | } 144 | } 145 | 146 | if (isActive.Value && !HUDManager.Instance.nodesOnScreen.Contains(scanNodeProperties)) 147 | { 148 | var player = GameNetworkManager.Instance.localPlayerController; 149 | 150 | var camera = player.gameplayCamera; 151 | 152 | var viewPos = camera.WorldToViewportPoint(scanNodeProperties.transform.position); 153 | 154 | if (Vector3.Distance(scanNodeProperties.transform.position, camera.transform.position) < scanNodeProperties.maxRange && (viewPos.x < 1 && viewPos.x > 0 && viewPos.y < 1 && viewPos.y > 0 && viewPos.z >= 0)) 155 | { 156 | //Plugin.logger.LogInfo($"[2] Node {scanNodeProperties.name} not valid"); 157 | if (!hudManager.nodesOnScreen.Contains(scanNodeProperties)) 158 | { 159 | hudManager.nodesOnScreen.Add(scanNodeProperties); 160 | } 161 | hudManager.AssignNodeToUIElement(scanNodeProperties); 162 | } 163 | } 164 | 165 | 166 | } 167 | 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/GrabbableRigidbody.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode.Components; 5 | using UnityEngine; 6 | 7 | namespace LethalThings.MonoBehaviours 8 | { 9 | // grabbable object which uses unity rigidbody physics 10 | [RequireComponent(typeof(Rigidbody))] 11 | public class GrabbableRigidbody : GrabbableObject 12 | { 13 | public float gravity = 9.8f; 14 | internal Rigidbody rb; 15 | public override void Start() 16 | { 17 | rb = GetComponent(); 18 | rb.useGravity = false; 19 | // force some properties which might be missconfigured 20 | itemProperties.itemSpawnsOnGround = false; 21 | base.Start(); 22 | EnablePhysics(true); 23 | } 24 | 25 | public new void EnablePhysics(bool enable) 26 | { 27 | for (int i = 0; i < propColliders.Length; i++) 28 | { 29 | if (!(propColliders[i] == null) && !propColliders[i].gameObject.CompareTag("InteractTrigger") && !propColliders[i].gameObject.CompareTag("DoNotSet")) 30 | { 31 | propColliders[i].enabled = enable; 32 | } 33 | } 34 | 35 | // enable rigidbody 36 | rb.isKinematic = !enable; 37 | } 38 | 39 | public override void Update() 40 | { 41 | // hax 42 | fallTime = 1.0f; 43 | reachedFloorTarget = true; 44 | var wasHeld = isHeld; 45 | // hella hax 46 | isHeld = true; 47 | base.Update(); 48 | isHeld = wasHeld; 49 | } 50 | 51 | 52 | public void FixedUpdate() 53 | { 54 | // handle gravity if rigidbody is enabled 55 | if (IsHost) { 56 | if (!rb.isKinematic && !isHeld) 57 | { 58 | rb.useGravity = false; 59 | 60 | rb.AddForce(Vector3.down * gravity, ForceMode.Acceleration); 61 | 62 | // Plugin.logger.LogMessage("Velocity: " + rb.velocity.ToString()); 63 | } 64 | else 65 | { 66 | rb.AddForce(Vector3.zero, ForceMode.VelocityChange); 67 | } 68 | } 69 | } 70 | 71 | public override void LateUpdate() 72 | { 73 | if (parentObject != null && isHeld) 74 | { 75 | base.transform.rotation = parentObject.rotation; 76 | base.transform.Rotate(itemProperties.rotationOffset); 77 | base.transform.position = parentObject.position; 78 | Vector3 positionOffset = itemProperties.positionOffset; 79 | positionOffset = parentObject.rotation * positionOffset; 80 | base.transform.position += positionOffset; 81 | } 82 | if (radarIcon != null) 83 | { 84 | radarIcon.position = base.transform.position; 85 | } 86 | } 87 | 88 | public override void FallWithCurve() 89 | { 90 | // stub, we do not need this. 91 | } 92 | 93 | public new void FallToGround(bool randomizePosition = false) 94 | { 95 | // stub, we do not need this. 96 | } 97 | 98 | public override void EquipItem() 99 | { 100 | // remove parent object 101 | base.EquipItem(); 102 | transform.SetParent(null, true); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/GremlinEnergy.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Unity.Netcode; 7 | using UnityEngine; 8 | 9 | namespace LethalThings.MonoBehaviours 10 | { 11 | public class GremlinEnergy : GrabbableObject 12 | { 13 | public AudioSource audioSource; 14 | public AudioClip[] drinkClips; 15 | private float transformChance = 1f; 16 | private float timeToDeathMin = 5f; 17 | private float timeToDeathMax = 10f; 18 | 19 | public static void Init() 20 | { 21 | On.GameNetworkManager.Start += GameNetworkManager_Start; 22 | } 23 | 24 | public static GameObject blobPrefab = null; 25 | 26 | private static void GameNetworkManager_Start(On.GameNetworkManager.orig_Start orig, GameNetworkManager self) 27 | { 28 | orig(self); 29 | 30 | List prefabs = self?.GetComponent()?.NetworkConfig?.Prefabs?.m_Prefabs; 31 | if (prefabs == null) return; 32 | 33 | foreach (var prefabContainer in prefabs) 34 | { 35 | GameObject prefab = prefabContainer?.Prefab; 36 | if (prefab?.GetComponent()?.enemyType?.enemyName != "Blob") continue; 37 | 38 | blobPrefab = prefab; 39 | 40 | //Plugin.logger.LogMessage("Found blob prefab!"); 41 | 42 | break; 43 | } 44 | } 45 | 46 | public override void ItemActivate(bool used, bool buttonDown = true) 47 | { 48 | base.ItemActivate(used, buttonDown); 49 | 50 | 51 | int num = UnityEngine.Random.Range(0, drinkClips.Length); 52 | audioSource.PlayOneShot(drinkClips[num]); 53 | 54 | 55 | WalkieTalkie.TransmitOneShotAudio(audioSource, drinkClips[num], 1f); 56 | RoundManager.Instance.PlayAudibleNoise(base.transform.position, 20, 1f, 0, isInElevator && StartOfRound.Instance.hangarDoorsClosed); 57 | 58 | /* 59 | if(StartOfRound.Instance && !StartOfRound.Instance.inShipPhase && UnityEngine.Random.Range(0f, 1f) < transformChance) 60 | { 61 | // transform into a slime 62 | if (IsOwner) 63 | { 64 | DelayedDeathServerRpc(UnityEngine.Random.Range(timeToDeathMin, timeToDeathMax)); 65 | //HUDManager.Instance.DisplayTip("Anomaly detected in vital signs.", ""); 66 | } 67 | }*/ 68 | 69 | if (base.IsOwner) 70 | { 71 | playerHeldBy.activatingItem = buttonDown; 72 | playerHeldBy.playerBodyAnimator.SetBool("useTZPItem", buttonDown); 73 | } 74 | StartCoroutine(undoAnimation()); 75 | 76 | 77 | } 78 | 79 | public IEnumerator undoAnimation() 80 | { 81 | yield return new WaitForSeconds(3); 82 | if (base.IsOwner) 83 | { 84 | playerHeldBy.playerBodyAnimator.SetBool("useTZPItem", false); 85 | playerHeldBy.activatingItem = false; 86 | 87 | // damage player 88 | playerHeldBy.DamagePlayer(50, causeOfDeath: CauseOfDeath.Unknown, deathAnimation: 1); 89 | 90 | } 91 | } 92 | 93 | 94 | /* 95 | 96 | [ServerRpc] 97 | public void DelayedDeathServerRpc(float timeToDeath) 98 | { 99 | DelayedDeathClientRpc(timeToDeath); 100 | } 101 | 102 | [ClientRpc] 103 | public void DelayedDeathClientRpc(float timeToDeath) 104 | { 105 | StartCoroutine(DelayedDeath(timeToDeath)); 106 | } 107 | 108 | public override void DiscardItem() 109 | { 110 | base.DiscardItem(); 111 | lastPlayerUsedBy.activatingItem = false; 112 | lastPlayerUsedBy.playerBodyAnimator.SetBool("useTZPItem", false); 113 | } 114 | */ 115 | /* 116 | [ServerRpc] 117 | public void HandleKillSpawnServerRpc() 118 | { 119 | var blob = Instantiate(blobPrefab, playerHeldBy.transform.position, Quaternion.identity); 120 | blob.GetComponent().Spawn(); 121 | } 122 | 123 | public IEnumerator DelayedDeath(float timeToDeath) 124 | { 125 | 126 | 127 | yield return new WaitForSeconds(timeToDeath); 128 | 129 | lastPlayerUsedBy.activatingItem = false; 130 | lastPlayerUsedBy.playerBodyAnimator.SetBool("useTZPItem", false); 131 | 132 | 133 | lastPlayerUsedBy.movementAudio.PlayOneShot(StartOfRound.Instance.bloodGoreSFX); 134 | WalkieTalkie.TransmitOneShotAudio(lastPlayerUsedBy.movementAudio, StartOfRound.Instance.bloodGoreSFX); 135 | 136 | 137 | 138 | 139 | if (IsOwner) 140 | { 141 | lastPlayerUsedBy.DiscardHeldObject(); 142 | 143 | lastPlayerUsedBy.DropBlood(); 144 | 145 | 146 | lastPlayerUsedBy.KillPlayer(Vector3.zero, spawnBody: true, CauseOfDeath.Unknown, 1); 147 | lastPlayerUsedBy.inSpecialInteractAnimation = false; 148 | lastPlayerUsedBy.inAnimationWithEnemy = null; 149 | 150 | 151 | } 152 | }*/ 153 | 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/HandheldRadar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using Unity.Netcode; 7 | using UnityEngine; 8 | 9 | namespace LethalThings.MonoBehaviours 10 | { 11 | public class HandheldRadar : GrabbableObject 12 | { 13 | private NetworkVariable turnedOn = new NetworkVariable(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner); 14 | private Material screenOffMat; 15 | private Material screenOnMat; 16 | 17 | public AudioSource audioSource; 18 | public AudioSource audioSourceFar; 19 | 20 | [Space(3f)] 21 | 22 | public AudioClip turnOnSound; 23 | public AudioClip turnOffSound; 24 | public AudioClip switchTargetSound; 25 | 26 | [Space(3f)] 27 | 28 | public int noiseRange = 45; 29 | 30 | 31 | public static void Load() 32 | { 33 | On.ManualCameraRenderer.Update += ManualCameraRenderer_Update; 34 | } 35 | 36 | private static void ManualCameraRenderer_Update(On.ManualCameraRenderer.orig_Update orig, ManualCameraRenderer self) 37 | { 38 | orig(self); 39 | if (NetworkConfig.Instance.remoteRadarEnabledNetVar.Value) 40 | { 41 | var anyPlayerHoldingRadar = false; 42 | foreach (var player in StartOfRound.Instance.allPlayerScripts) 43 | { 44 | if (player?.currentlyHeldObjectServer is HandheldRadar) 45 | { 46 | var radar = (HandheldRadar)player.currentlyHeldObjectServer; 47 | if (radar && radar.turnedOn.Value) 48 | { 49 | anyPlayerHoldingRadar = true; 50 | break; 51 | } 52 | } 53 | } 54 | 55 | if (anyPlayerHoldingRadar) 56 | { 57 | if (self.mapCamera != null) 58 | { 59 | self.mapCamera.enabled = true; 60 | } 61 | } 62 | } 63 | } 64 | 65 | public override void Start() 66 | { 67 | base.Start(); 68 | mainObjectRenderer = transform.GetChild(0).GetChild(0).GetComponent(); 69 | screenOffMat = mainObjectRenderer.materials[1]; 70 | screenOnMat = StartOfRound.Instance.mapScreen.onScreenMat; 71 | } 72 | 73 | public override void Update() 74 | { 75 | isBeingUsed = turnedOn.Value; 76 | 77 | // if battery is dead, turn off 78 | if (turnedOn.Value && insertedBattery.charge <= 0) 79 | { 80 | SwitchScreen(false); 81 | } 82 | 83 | base.Update(); 84 | } 85 | 86 | [ServerRpc] 87 | public void SwitchScreenServerRpc(bool on) 88 | { 89 | SwitchScreenClientRpc(on); 90 | SwitchScreen(on); 91 | } 92 | 93 | [ClientRpc] 94 | public void SwitchScreenClientRpc(bool on) 95 | { 96 | SwitchScreen(on); 97 | } 98 | 99 | public void SwitchScreen(bool on) 100 | { 101 | UnityEngine.Debug.Log("Switching screen: "+on); 102 | 103 | if (IsOwner) 104 | { 105 | turnedOn.Value = on; 106 | } 107 | 108 | 109 | var sound = on ? turnOnSound : turnOffSound; 110 | 111 | audioSource.PlayOneShot(sound, 1); 112 | if (audioSourceFar != null) 113 | { 114 | audioSourceFar.PlayOneShot(sound, 1); 115 | } 116 | WalkieTalkie.TransmitOneShotAudio(audioSource, sound, 1); 117 | RoundManager.Instance.PlayAudibleNoise(transform.position, noiseRange, 1, 0, isInElevator && StartOfRound.Instance.hangarDoorsClosed); 118 | 119 | if (on) 120 | { 121 | mainObjectRenderer.SetMaterials(new List() { mainObjectRenderer.materials[0], screenOnMat }); 122 | } 123 | else 124 | { 125 | mainObjectRenderer.SetMaterials(new List() { mainObjectRenderer.materials[0], screenOffMat }); 126 | } 127 | } 128 | 129 | [ServerRpc] 130 | public void PlayTargetSwitchSoundServerRpc() 131 | { 132 | PlayTargetSwitchSoundClientRpc(); 133 | } 134 | 135 | [ClientRpc] 136 | public void PlayTargetSwitchSoundClientRpc() 137 | { 138 | PlayTargetSwitchSound(); 139 | } 140 | 141 | public void PlayTargetSwitchSound() 142 | { 143 | UnityEngine.Debug.Log("Playing target switch sound"); 144 | 145 | var sound = switchTargetSound; 146 | 147 | audioSource.PlayOneShot(sound, 1); 148 | if (audioSourceFar != null) 149 | { 150 | audioSourceFar.PlayOneShot(sound, 1); 151 | } 152 | WalkieTalkie.TransmitOneShotAudio(audioSource, sound, 1); 153 | RoundManager.Instance.PlayAudibleNoise(transform.position, noiseRange, 1, 0, isInElevator && StartOfRound.Instance.hangarDoorsClosed); 154 | } 155 | 156 | 157 | public override void DiscardItem() 158 | { 159 | if (playerHeldBy != null) 160 | { 161 | playerHeldBy.equippedUsableItemQE = false; 162 | } 163 | base.DiscardItem(); 164 | } 165 | 166 | public override void EquipItem() 167 | { 168 | base.EquipItem(); 169 | playerHeldBy.equippedUsableItemQE = true; 170 | } 171 | 172 | public override void ItemActivate(bool used, bool buttonDown = true) 173 | { 174 | base.ItemActivate(used, buttonDown); 175 | 176 | if (!IsOwner || !turnedOn.Value) 177 | { 178 | return; 179 | } 180 | 181 | StartOfRound.Instance.mapScreen.SwitchRadarTargetForward(true); 182 | if (IsHost) 183 | { 184 | PlayTargetSwitchSoundClientRpc(); 185 | } 186 | else 187 | { 188 | PlayTargetSwitchSoundServerRpc(); 189 | } 190 | 191 | } 192 | 193 | public override void ItemInteractLeftRight(bool right) 194 | { 195 | base.ItemInteractLeftRight(right); 196 | 197 | UnityEngine.Debug.Log("Interacting with handheld radar"); 198 | 199 | if(!IsOwner) 200 | { 201 | return; 202 | } 203 | 204 | if (!right) 205 | { 206 | turnedOn.Value = !turnedOn.Value; 207 | if (IsHost) 208 | { 209 | SwitchScreenClientRpc(turnedOn.Value); 210 | } 211 | else 212 | { 213 | SwitchScreenServerRpc(turnedOn.Value); 214 | } 215 | 216 | } 217 | 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/MaggieSpawner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine.AI; 7 | using UnityEngine; 8 | using Vector3 = UnityEngine.Vector3; 9 | using GameNetcodeStuff; 10 | 11 | namespace LethalThings.MonoBehaviours 12 | { 13 | public class MaggieSpawner : NetworkBehaviour 14 | { 15 | public static GameObject maggieSpawner; 16 | 17 | public static void Init() 18 | { 19 | maggieSpawner = Content.MainAssets.LoadAsset("Assets/Custom/LethalThings/Enemies/Maggie/MaggieSpawner.prefab"); 20 | 21 | LethalLib.Modules.NetworkPrefabs.RegisterNetworkPrefab(maggieSpawner); 22 | 23 | On.CentipedeAI.OnPlayerTeleport += CentipedeAI_OnPlayerTeleport; 24 | On.GameNetcodeStuff.PlayerControllerB.TeleportPlayer += PlayerControllerB_TeleportPlayer; 25 | On.GameNetcodeStuff.PlayerControllerB.Start += PlayerControllerB_Start; 26 | } 27 | 28 | private static void PlayerControllerB_Start(On.GameNetcodeStuff.PlayerControllerB.orig_Start orig, PlayerControllerB self) 29 | { 30 | orig(self); 31 | 32 | if (NetworkManager.Singleton.IsHost) 33 | { 34 | MaggieSpawner maggieSpawner = self.GetComponentInChildren(); 35 | if(maggieSpawner == null) 36 | { 37 | var mS = Instantiate(MaggieSpawner.maggieSpawner, self.transform); 38 | mS.GetComponent().Spawn(); 39 | 40 | mS.GetComponent().TrySetParent(self.GetComponent()); 41 | 42 | mS.GetComponent().MaggieSpawnerMadeClientRpc(); 43 | 44 | mS.GetComponent().ChangeOwnership(self.OwnerClientId); 45 | 46 | //Plugin.logger.LogInfo("MaggieSpawner spawned on " + self.gameObject.name); 47 | } 48 | } 49 | } 50 | 51 | [ClientRpc] 52 | public void MaggieSpawnerMadeClientRpc() 53 | { 54 | //Plugin.logger.LogInfo("MaggieSpawner spawned, parent: " + transform.parent); 55 | 56 | } 57 | 58 | private static void PlayerControllerB_TeleportPlayer(On.GameNetcodeStuff.PlayerControllerB.orig_TeleportPlayer orig, GameNetcodeStuff.PlayerControllerB self, UnityEngine.Vector3 pos, bool withRotation, float rot, bool allowInteractTrigger, bool enableController) 59 | { 60 | orig(self, pos, withRotation, rot, allowInteractTrigger, enableController); 61 | //Plugin.logger.LogInfo("Teleported wawa"); 62 | MaggieSpawner maggieSpawner = self.GetComponentInChildren(); 63 | if (maggieSpawner != null && maggieSpawner.isSpawning) 64 | { 65 | //Plugin.logger.LogInfo("Maggie spawning!!"); 66 | maggieSpawner.isSpawning = false; 67 | maggieSpawner.SpawnMaggieServerRpc(pos, (int)self.playerClientId); 68 | // kill player 69 | self.KillPlayer(Vector3.zero, false, CauseOfDeath.Unknown); 70 | } 71 | } 72 | 73 | private static void CentipedeAI_OnPlayerTeleport(On.CentipedeAI.orig_OnPlayerTeleport orig, CentipedeAI self, GameNetcodeStuff.PlayerControllerB playerTeleported) 74 | { 75 | // if chance is met, spawn maggie 76 | /* 77 | if (NetworkConfig.Instance != null && UnityEngine.Random.Range(0f, 100f) <= NetworkConfig.Instance.maggieTeleporterChanceNetVar.Value) 78 | { 79 | if (self.clingingToPlayer == playerTeleported && playerTeleported.IsOwner) 80 | { 81 | //Plugin.logger.LogInfo("attempt spawn stuff maggie wah"); 82 | self.KillEnemyServerRpc(true); 83 | // get MaggieSpawner on teleporting player 84 | MaggieSpawner maggieSpawner = playerTeleported.GetComponentInChildren(); 85 | if (maggieSpawner != null) 86 | { 87 | maggieSpawner.isSpawning = true; 88 | //Plugin.logger.LogInfo("Allowing maggie spawn!!"); 89 | } 90 | 91 | return; 92 | } 93 | }*/ 94 | 95 | orig(self, playerTeleported); 96 | } 97 | 98 | public EnemyType enemyType; 99 | public bool isSpawning = false; 100 | 101 | [ServerRpc (RequireOwnership = false)] 102 | public void SpawnMaggieServerRpc(Vector3 pos, int playerKilled) 103 | { 104 | PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerKilled]; 105 | bool flag = pos.y < -80f; 106 | NetworkObjectReference netObjectRef = RoundManager.Instance.SpawnEnemyGameObject(RoundManager.Instance.GetNavMeshPosition(pos, default(NavMeshHit), 10f), 0, -1, enemyType); 107 | if (netObjectRef.TryGet(out var networkObject)) 108 | { 109 | Maggie component = networkObject.GetComponent(); 110 | component.SetSuit(player.currentSuitID); 111 | component.mimickingPlayer = player; 112 | component.SetEnemyOutside(!flag); 113 | player.redirectToEnemy = component; 114 | if (player.deadBody != null) 115 | { 116 | player.deadBody.DeactivateBody(setActive: false); 117 | } 118 | } 119 | SpawnMaggieClientRpc(netObjectRef, flag, playerKilled); 120 | } 121 | 122 | [ClientRpc] 123 | public void SpawnMaggieClientRpc(NetworkObjectReference netObjectRef, bool inFactory, int playerKilled) 124 | { 125 | PlayerControllerB player = StartOfRound.Instance.allPlayerScripts[playerKilled]; 126 | if (netObjectRef.TryGet(out var networkObject)) 127 | { 128 | Maggie component = networkObject.GetComponent(); 129 | component.SetSuit(player.currentSuitID); 130 | component.mimickingPlayer = player; 131 | component.SetEnemyOutside(!inFactory); 132 | player.redirectToEnemy = component; 133 | } 134 | } 135 | 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/Missile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Linq; 4 | using System.Numerics; 5 | using System.Reflection; 6 | using DigitalRuby.ThunderAndLightning; 7 | using DunGen; 8 | using GameNetcodeStuff; 9 | using Unity.Netcode; 10 | using UnityEngine; 11 | using Vector3 = UnityEngine.Vector3; 12 | 13 | namespace LethalThings 14 | { 15 | public class Missile : NetworkBehaviour 16 | { 17 | public int damage = 50; 18 | public float maxDistance = 10f; 19 | public float minDistance = 0f; 20 | public float gravity = 2.4f; 21 | public float flightDelay = 0.5f; 22 | public float flightForce = 150f; 23 | public float flightTime = 2f; 24 | public float autoDestroyTime = 3f; 25 | private float timeAlive = 0f; 26 | public float LobForce = 100f; 27 | public ParticleSystem particleSystem; 28 | void OnCollisionEnter(Collision collision) 29 | { 30 | if (IsHost) 31 | { 32 | Boom(); 33 | BoomClientRpc(); 34 | } 35 | else 36 | { 37 | BoomServerRpc(); 38 | } 39 | } 40 | 41 | void Start() 42 | { 43 | GetComponent().useGravity = false; 44 | if (IsHost) 45 | { 46 | GetComponent().AddForce(transform.forward * LobForce, ForceMode.Impulse); 47 | } 48 | } 49 | 50 | [ClientRpc] 51 | public void BoomClientRpc() 52 | { 53 | Boom(); 54 | } 55 | 56 | [ServerRpc] 57 | public void BoomServerRpc() 58 | { 59 | Boom(); 60 | BoomClientRpc(); 61 | } 62 | 63 | 64 | public void CreateExplosion() 65 | { 66 | 67 | var player = StartOfRound.Instance.allPlayerScripts.FirstOrDefault(x => x.OwnerClientId == OwnerClientId); 68 | Utilities.CreateExplosion(transform.position, true, damage, minDistance, maxDistance, 10, CauseOfDeath.Blast, player); 69 | } 70 | 71 | public void Boom() 72 | { 73 | if (particleSystem == null) 74 | { 75 | Debug.LogError("No particle system set on missile, destruction time!!"); 76 | CreateExplosion(); 77 | 78 | if (IsHost) 79 | { 80 | Destroy(gameObject); 81 | } 82 | 83 | return; 84 | } 85 | particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmitting); 86 | particleSystem.transform.SetParent(null); 87 | particleSystem.transform.localScale = Vector3.one; 88 | 89 | // kill system once all particles are dead 90 | Destroy(particleSystem.gameObject, particleSystem.main.duration + particleSystem.main.startLifetime.constant); 91 | 92 | CreateExplosion(); 93 | 94 | if (IsHost) 95 | { 96 | Destroy(gameObject); 97 | } 98 | } 99 | 100 | void FixedUpdate() 101 | { 102 | if (IsHost) 103 | { 104 | GetComponent().useGravity = false; 105 | // apply downwards force, gravity. 106 | GetComponent().AddForce(Vector3.down * gravity); 107 | 108 | // apply forward force, flightForce, calculate using acceleration and stuff 109 | 110 | if (timeAlive <= flightTime && timeAlive >= flightDelay) 111 | { 112 | GetComponent().AddForce(transform.forward * flightForce); 113 | } 114 | 115 | 116 | timeAlive += Time.fixedDeltaTime; 117 | 118 | 119 | 120 | // if time is passt autoDestroyTime, destroy 121 | if (timeAlive > autoDestroyTime) 122 | { 123 | if (IsHost) 124 | { 125 | Boom(); 126 | BoomClientRpc(); 127 | } 128 | else 129 | { 130 | BoomServerRpc(); 131 | } 132 | } 133 | else 134 | { 135 | Debug.Log("Time alive: " + timeAlive + " / " + autoDestroyTime); 136 | } 137 | } 138 | 139 | } 140 | 141 | } 142 | 143 | } -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/PowerOutletStun.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using Unity.Netcode; 3 | using GameNetcodeStuff; 4 | using System.Security; 5 | using System.Security.Permissions; 6 | using System.Collections; 7 | 8 | [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] 9 | namespace LethalThings 10 | { 11 | public class PowerOutletStun : NetworkBehaviour 12 | { 13 | private Coroutine electrocutionCoroutine; 14 | public void Electrocute(ItemCharger socket) 15 | { 16 | Debug.Log("Attempting electrocution"); 17 | if (electrocutionCoroutine != null) 18 | { 19 | StopCoroutine(electrocutionCoroutine); 20 | } 21 | electrocutionCoroutine = StartCoroutine(electrocutionDelayed(socket)); 22 | } 23 | 24 | public AudioSource strikeAudio; 25 | public ParticleSystem strikeParticle; 26 | 27 | [HideInInspector] 28 | private NetworkVariable damage = new NetworkVariable(20, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 29 | 30 | public void Awake() 31 | { 32 | var stormyWeather = FindObjectOfType(true); 33 | GameObject audioSource = stormyWeather.targetedStrikeAudio.gameObject; 34 | // copy gameobject and add to this object as a child 35 | strikeAudio = Instantiate(audioSource, transform).GetComponent(); 36 | strikeAudio.transform.localPosition = Vector3.zero; 37 | strikeAudio.gameObject.SetActive(true); 38 | strikeParticle = Instantiate(stormyWeather.explosionEffectParticle.gameObject, transform).GetComponent(); 39 | strikeParticle.transform.localPosition = Vector3.zero; 40 | strikeParticle.gameObject.SetActive(true); 41 | 42 | 43 | } 44 | 45 | public override void OnNetworkSpawn() 46 | { 47 | base.OnNetworkSpawn(); 48 | if (IsHost) 49 | { 50 | damage.Value = (NetworkConfig.itemChargerElectrocutionDamage.Value); 51 | } 52 | } 53 | 54 | private IEnumerator electrocutionDelayed(ItemCharger socket) 55 | { 56 | Debug.Log("Electrocution started"); 57 | socket.zapAudio.Play(); 58 | yield return new WaitForSeconds(0.75f); 59 | socket.chargeStationAnimator.SetTrigger("zap"); 60 | 61 | 62 | Debug.Log("Electrocution finished"); 63 | if (NetworkObject.IsOwner && !NetworkObject.IsOwnedByServer) 64 | { 65 | Debug.Log("Sending stun to server!!"); 66 | ElectrocutedServerRpc(transform.position); 67 | } 68 | else if (NetworkObject.IsOwner && NetworkObject.IsOwnedByServer) 69 | { 70 | Debug.Log("Sending stun to clients!!"); 71 | ElectrocutedClientRpc(transform.position); 72 | Electrocuted(transform.position); 73 | } 74 | 75 | yield break; 76 | } 77 | 78 | [ClientRpc] 79 | void ElectrocutedClientRpc(Vector3 position) 80 | { 81 | Debug.Log("Stun received!!"); 82 | Electrocuted(position); 83 | } 84 | 85 | void Electrocuted(Vector3 position) 86 | { 87 | var stormyWeather = FindObjectOfType(true); 88 | 89 | Utilities.CreateExplosion(position, false, damage.Value, 0f, 5f, 3, CauseOfDeath.Electrocution); 90 | 91 | strikeParticle.Play(); 92 | stormyWeather.PlayThunderEffects(position, strikeAudio); 93 | } 94 | 95 | [ServerRpc] 96 | void ElectrocutedServerRpc(Vector3 position) 97 | { 98 | ElectrocutedClientRpc(position); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/RobotAI.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace LethalThings.MonoBehaviours 7 | { 8 | public class RobotAI : EnemyAI 9 | { 10 | public string dogName; 11 | private bool setRandomDogName; 12 | private int dogNameIndex = -1; 13 | public GameObject radarDot; 14 | public bool radarEnabled; 15 | public string[] dogNames; 16 | 17 | public float maxFuel = 100f; 18 | public float drainSpeed = 0.02f; 19 | public float currentFuel = 100; 20 | 21 | private void OnDisable() 22 | { 23 | if (radarEnabled) 24 | { 25 | RemoveDogFromRadar(); 26 | } 27 | } 28 | public override void DoAIInterval() 29 | { 30 | 31 | } 32 | 33 | public void SetRadarDogNameLocal(string newName) 34 | { 35 | dogName = newName; 36 | base.gameObject.GetComponentInChildren().headerText = dogName; 37 | StartOfRound.Instance.mapScreen.ChangeNameOfTargetTransform(base.transform, newName); 38 | } 39 | 40 | private void RemoveDogFromRadar() 41 | { 42 | StartOfRound.Instance.mapScreen.RemoveTargetFromRadar(base.transform); 43 | } 44 | 45 | private void AddDogToRadar() 46 | { 47 | if (!setRandomDogName) 48 | { 49 | setRandomDogName = true; 50 | int num = (dogNameIndex = ((dogNameIndex != -1) ? dogNameIndex : new System.Random(Mathf.Min(StartOfRound.Instance.randomMapSeed + (int)base.NetworkObjectId, 99999999)).Next(0, dogNames.Length))); 51 | dogName = dogNames[num]; 52 | base.gameObject.GetComponentInChildren().headerText = dogName; 53 | } 54 | string text = StartOfRound.Instance.mapScreen.AddTransformAsTargetToRadar(base.transform, dogName, isNonPlayer: true); 55 | if (!string.IsNullOrEmpty(text)) 56 | { 57 | base.gameObject.GetComponentInChildren().headerText = text; 58 | } 59 | StartOfRound.Instance.mapScreen.SyncOrderOfRadarBoostersInList(); 60 | } 61 | 62 | public void EnableRadarBooster(bool enable) 63 | { 64 | radarDot.SetActive(enable); 65 | if (enable) 66 | { 67 | AddDogToRadar(); 68 | } 69 | else 70 | { 71 | RemoveDogFromRadar(); 72 | } 73 | radarEnabled = enable; 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/RocketLauncher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using DigitalRuby.ThunderAndLightning; 6 | using GameNetcodeStuff; 7 | using LethalLib.Modules; 8 | using LethalThings.MonoBehaviours; 9 | using Unity.Netcode; 10 | using UnityEngine; 11 | 12 | namespace LethalThings 13 | { 14 | public class RocketLauncher : SaveableObject 15 | { 16 | public Light laserPointer; 17 | public Transform lightSource; 18 | 19 | public AudioSource mainAudio; 20 | 21 | public AudioClip[] activateClips; 22 | public AudioClip[] noAmmoSounds; 23 | 24 | public Transform aimDirection; 25 | 26 | public int maxAmmo = 4; 27 | [HideInInspector] 28 | private NetworkVariable currentAmmo = new NetworkVariable(4, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 29 | [HideInInspector] 30 | private NetworkVariable isLaserOn = new NetworkVariable(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner); 31 | 32 | public GameObject missilePrefab; 33 | 34 | //public float LobForce = 100f; 35 | 36 | private float timeSinceLastShot; 37 | 38 | private PlayerControllerB previousPlayerHeldBy; 39 | 40 | private Material[] ammoLampMaterials; 41 | 42 | public Animator Animator; 43 | 44 | public ParticleSystem particleSystem; 45 | 46 | public LineRenderer laserLine; 47 | 48 | private Transform laserRoot; 49 | 50 | public override void SaveObjectData() 51 | { 52 | SaveData.SaveObjectData("rocketLauncherAmmoData", currentAmmo.Value, uniqueId); 53 | } 54 | 55 | public override void LoadObjectData() 56 | { 57 | if (IsHost) 58 | { 59 | currentAmmo.Value = SaveData.LoadObjectData("rocketLauncherAmmoData", uniqueId); 60 | } 61 | } 62 | 63 | public override void OnNetworkSpawn() 64 | { 65 | base.OnNetworkSpawn(); 66 | //Plugin.logger.LogInfo("OnNetworkSpawn"); 67 | if (IsServer) 68 | { 69 | currentAmmo.Value = maxAmmo; 70 | } 71 | } 72 | 73 | public void Awake() 74 | { 75 | // get materials from mesh renderer 76 | var renderer = GetComponentInChildren(); 77 | List materials = new List(); 78 | for (int i = 1; i < renderer.materials.Length; i++) 79 | { 80 | materials.Add(renderer.materials[i]); 81 | } 82 | 83 | ammoLampMaterials = materials.ToArray(); 84 | } 85 | 86 | public override void Start() 87 | { 88 | 89 | 90 | laserRoot = laserLine.transform.parent; 91 | 92 | var renderer = GetComponentInChildren(); 93 | 94 | 95 | 96 | for (int i = 0; i < ammoLampMaterials.Length; i++) 97 | { 98 | if (i >= currentAmmo.Value) 99 | { 100 | ammoLampMaterials[i].SetColor("_BaseColor", Color.red); 101 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.red); 102 | } 103 | else 104 | { 105 | ammoLampMaterials[i].SetColor("_BaseColor", Color.green); 106 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.green); 107 | } 108 | } 109 | 110 | base.Start(); 111 | } 112 | 113 | public override void Update() 114 | { 115 | base.Update(); 116 | 117 | // update every 30 calls 118 | if (Time.frameCount % 30 == 0) 119 | { 120 | for (int i = 0; i < ammoLampMaterials.Length; i++) 121 | { 122 | if (i >= currentAmmo.Value) 123 | { 124 | ammoLampMaterials[i].SetColor("_BaseColor", Color.red); 125 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.red); 126 | } 127 | else 128 | { 129 | ammoLampMaterials[i].SetColor("_BaseColor", Color.green); 130 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.green); 131 | } 132 | } 133 | } 134 | 135 | 136 | } 137 | 138 | public override void OnDestroy() 139 | { 140 | base.OnDestroy(); 141 | } 142 | 143 | public override void ItemActivate(bool used, bool buttonDown = true) 144 | { 145 | base.ItemActivate(used, buttonDown); 146 | 147 | 148 | if (currentAmmo.Value > 0) 149 | { 150 | if (IsHost) 151 | { 152 | currentAmmo.Value--; 153 | } 154 | 155 | PlayRandomAudio(mainAudio, activateClips); 156 | Animator.Play("fire"); 157 | particleSystem.Play(); 158 | 159 | for (int i = 0; i < ammoLampMaterials.Length; i++) 160 | { 161 | if (i >= currentAmmo.Value) 162 | { 163 | ammoLampMaterials[i].SetColor("_BaseColor", Color.red); 164 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.red); 165 | } 166 | else 167 | { 168 | ammoLampMaterials[i].SetColor("_BaseColor", Color.green); 169 | ammoLampMaterials[i].SetColor("_EmissiveColor", Color.green); 170 | } 171 | } 172 | 173 | if (IsOwner) 174 | { 175 | if (IsHost) 176 | { 177 | MissileSpawner(aimDirection.position, aimDirection.rotation); 178 | } 179 | else 180 | { 181 | SpawnMissileServerRpc(aimDirection.position, aimDirection.rotation); 182 | } 183 | } 184 | } 185 | else 186 | { 187 | PlayRandomAudio(mainAudio, noAmmoSounds); 188 | } 189 | } 190 | 191 | public override void ItemInteractLeftRight(bool right) 192 | { 193 | base.ItemInteractLeftRight(right); 194 | 195 | if (!right) 196 | { 197 | if(IsOwner) 198 | { 199 | isLaserOn.Value = !isLaserOn.Value; 200 | } 201 | } 202 | } 203 | 204 | // server rpc for spawning missile 205 | [ServerRpc] 206 | private void SpawnMissileServerRpc(Vector3 aimPosition, Quaternion aimRotation) 207 | { 208 | MissileSpawner(aimPosition, aimRotation); 209 | } 210 | 211 | private void MissileSpawner(Vector3 aimPosition, Quaternion aimRotation) 212 | { 213 | // spawn missile 214 | GameObject missile = Instantiate(missilePrefab, aimPosition, aimRotation); 215 | 216 | // add force to missile 217 | // missile.GetComponent().AddForce(aimDirection.forward * LobForce); 218 | 219 | // set owner of missile 220 | missile.GetComponent().SpawnWithOwnership(OwnerClientId); 221 | } 222 | 223 | private void PlayRandomAudio(AudioSource audioSource, AudioClip[] audioClips) 224 | { 225 | if (audioClips.Length != 0) 226 | { 227 | audioSource.PlayOneShot(audioClips[UnityEngine.Random.Range(0, audioClips.Length)]); 228 | } 229 | } 230 | 231 | 232 | public override void LateUpdate() 233 | { 234 | base.LateUpdate(); 235 | 236 | // raytace laser pointer 237 | RaycastHit hit; 238 | if (Physics.Raycast(laserRoot.position, aimDirection.forward, out hit, 10f, 605030721)) 239 | { 240 | laserPointer.transform.position = hit.point; 241 | } 242 | else 243 | { 244 | var pos = laserRoot.position + (aimDirection.forward * 10f); 245 | laserPointer.transform.position = pos; 246 | } 247 | laserLine.SetPosition(0, laserRoot.position); 248 | laserLine.SetPosition(1, laserPointer.transform.position); 249 | 250 | if (isLaserOn.Value) 251 | { 252 | laserPointer.enabled = true; 253 | laserLine.enabled = true; 254 | } 255 | else 256 | { 257 | laserPointer.enabled = false; 258 | laserLine.enabled = false; 259 | } 260 | } 261 | 262 | 263 | 264 | private void OnEnable() 265 | { 266 | 267 | } 268 | 269 | 270 | 271 | private void OnDisable() 272 | { 273 | 274 | } 275 | 276 | public override void PocketItem() 277 | { 278 | base.PocketItem(); 279 | if (IsOwner) 280 | { 281 | isLaserOn.Value = false; 282 | } 283 | laserPointer.enabled = false; 284 | laserLine.enabled = false; 285 | if (playerHeldBy != null) 286 | { 287 | playerHeldBy.equippedUsableItemQE = false; 288 | } 289 | } 290 | 291 | public override void DiscardItem() 292 | { 293 | if (IsOwner) 294 | { 295 | isLaserOn.Value = false; 296 | } 297 | base.DiscardItem(); 298 | laserPointer.enabled = false; 299 | laserLine.enabled = false; 300 | if (playerHeldBy != null) 301 | { 302 | //playerHeldBy.activatingItem = false; 303 | playerHeldBy.equippedUsableItemQE = false; 304 | } 305 | } 306 | 307 | public override void EquipItem() 308 | { 309 | base.EquipItem(); 310 | if (playerHeldBy != null) 311 | { 312 | previousPlayerHeldBy = playerHeldBy; 313 | playerHeldBy.equippedUsableItemQE = true; 314 | } 315 | } 316 | 317 | } 318 | 319 | } -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/RootMarker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using UnityEngine; 5 | 6 | namespace LethalThings.MonoBehaviours 7 | { 8 | public class RootMarker : MonoBehaviour 9 | { 10 | public Transform root; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/SaveableNetworkBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode; 5 | 6 | namespace LethalThings.MonoBehaviours 7 | { 8 | public abstract class SaveableNetworkBehaviour : NetworkBehaviour 9 | { 10 | public int uniqueId = 0; 11 | 12 | public abstract void SaveObjectData(); 13 | 14 | public abstract void LoadObjectData(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/SaveableObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace LethalThings.MonoBehaviours 6 | { 7 | public abstract class SaveableObject : GrabbableObject 8 | { 9 | public int uniqueId = 0; 10 | 11 | public override void LoadItemSaveData(int saveData) 12 | { 13 | base.LoadItemSaveData(saveData); 14 | 15 | Plugin.logger.LogInfo($"Loading save data for {name} with id {saveData}"); 16 | 17 | uniqueId = saveData; 18 | } 19 | 20 | public override int GetItemDataToSave() 21 | { 22 | Plugin.logger.LogInfo($"Saving save data for {name} with id {uniqueId}"); 23 | return uniqueId; 24 | } 25 | 26 | 27 | public override void OnNetworkSpawn() 28 | { 29 | base.OnNetworkSpawn(); 30 | if (IsHost && uniqueId == 0) 31 | { 32 | uniqueId = UnityEngine.Random.Range(0, 100000000); 33 | 34 | var SaveableNetworkBehaviours = transform.GetComponentsInChildren(); 35 | 36 | foreach (var item in SaveableNetworkBehaviours) 37 | { 38 | item.uniqueId = uniqueId; 39 | } 40 | } 41 | } 42 | 43 | 44 | public abstract void SaveObjectData(); 45 | 46 | public abstract void LoadObjectData(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/SeasonalHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | public class SeasonalHandler : NetworkBehaviour 11 | { 12 | public GameObject[] crimasObjects; 13 | public AudioClip[] crimasNoisemakerSounds; 14 | public AudioClip[] crimasFarNoisemakerSounds; 15 | 16 | public void Start() 17 | { 18 | // if it is current christmas, enable all christmas objects 19 | if (DateTime.Now.Month == 12 && DateTime.Now.Day >= 20) 20 | { 21 | foreach (var crimasObject in crimasObjects) 22 | { 23 | crimasObject.SetActive(true); 24 | } 25 | 26 | var noiseMaker = GetComponent(); 27 | 28 | if (noiseMaker != null) 29 | { 30 | var noiseSfx = noiseMaker.noiseSFX.ToList(); 31 | foreach (var crimasItemSound in crimasNoisemakerSounds) 32 | { 33 | noiseSfx.Add(crimasItemSound); 34 | } 35 | noiseMaker.noiseSFX = noiseSfx.ToArray(); 36 | 37 | var noiseFarSfx = noiseMaker.noiseSFXFar.ToList(); 38 | foreach (var crimasFarItemSound in crimasFarNoisemakerSounds) 39 | { 40 | noiseFarSfx.Add(crimasFarItemSound); 41 | } 42 | noiseMaker.noiseSFXFar = noiseFarSfx.ToArray(); 43 | } 44 | } 45 | 46 | 47 | 48 | } 49 | 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/TeleporterTrap.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Unity.Netcode; 8 | using UnityEngine; 9 | using UnityEngine.SceneManagement; 10 | 11 | namespace LethalThings.MonoBehaviours 12 | { 13 | public class TeleporterTrap : NetworkBehaviour 14 | { 15 | private RaycastHit hit; 16 | public float teleportCooldownTime = 5f; 17 | public float teleporterChargeUp = 2f; 18 | [HideInInspector] 19 | private NetworkVariable teleportCooldown = new NetworkVariable(0f, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); 20 | public AudioSource teleporterAudio; 21 | public AudioClip teleporterBeamUpSFX; 22 | public AudioClip startTeleportingSFX; 23 | public AudioClip teleporterPrimeSFX; 24 | 25 | private List teleportingPlayers = new List(); 26 | private List teleportingAI = new List(); 27 | 28 | public void Update() 29 | { 30 | // if we are host, and teleport cooldown is over 0, decrease it 31 | if (IsHost && teleportCooldown.Value > 0f) 32 | { 33 | teleportCooldown.Value -= Time.deltaTime; 34 | } 35 | } 36 | 37 | private void OnTriggerEnter(Collider other) 38 | { 39 | if (teleportCooldown.Value > 0) 40 | { 41 | return; 42 | } 43 | if (other.CompareTag("Player")) 44 | { 45 | PlayerControllerB playerControllerB = other.gameObject.GetComponent(); 46 | if (!(playerControllerB != GameNetworkManager.Instance.localPlayerController) && playerControllerB != null && !playerControllerB.isPlayerDead && !teleportingPlayers.Contains(playerControllerB)) 47 | { 48 | if (RoundManager.Instance.insideAINodes.Length != 0) 49 | { 50 | teleportingPlayers.Add(playerControllerB); 51 | Vector3 position3 = RoundManager.Instance.insideAINodes[UnityEngine.Random.Range(0, RoundManager.Instance.insideAINodes.Length)].transform.position; 52 | position3 = RoundManager.Instance.GetRandomNavMeshPositionInRadiusSpherical(position3); 53 | // call teleport coroutine 54 | 55 | teleporterAudio.PlayOneShot(teleporterPrimeSFX); 56 | playerControllerB.movementAudio.PlayOneShot(teleporterPrimeSFX); 57 | //StartCoroutine(PlayTeleportAudio()); 58 | if (IsHost) 59 | { 60 | teleportCooldown.Value = teleportCooldownTime; 61 | } 62 | 63 | if (playerControllerB.deadBody != null) 64 | { 65 | StartCoroutine(TeleportPlayerBodyCoroutine((int)playerControllerB.playerClientId, position3)); 66 | return; 67 | } 68 | StartCoroutine(TeleportPlayerCoroutine((int)playerControllerB.playerClientId, position3)); 69 | } 70 | } 71 | } 72 | else if (other.CompareTag("Enemy")) 73 | { 74 | 75 | 76 | var enemyAICollision = other.gameObject.GetComponent(); 77 | if (enemyAICollision != null) 78 | { 79 | var enemyAI = enemyAICollision.mainScript; 80 | if (RoundManager.Instance.insideAINodes.Length != 0 && !teleportingAI.Contains(enemyAI)) 81 | { 82 | teleportingAI.Add(enemyAI); 83 | Vector3 position3 = RoundManager.Instance.insideAINodes[UnityEngine.Random.Range(0, RoundManager.Instance.insideAINodes.Length)].transform.position; 84 | position3 = RoundManager.Instance.GetRandomNavMeshPositionInRadiusSpherical(position3); 85 | // call teleport coroutine 86 | StartCoroutine(TeleportEnemyCoroutine(enemyAI, position3)); 87 | teleporterAudio.PlayOneShot(teleporterPrimeSFX); 88 | //StartCoroutine(PlayTeleportAudio()); 89 | if (IsHost) 90 | { 91 | teleportCooldown.Value = teleportCooldownTime; 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | private System.Collections.IEnumerator PlayTeleportAudio() 99 | { 100 | yield return new WaitForSeconds(0.2f); 101 | teleporterAudio.PlayOneShot(startTeleportingSFX); 102 | } 103 | 104 | // coroutine for teleporting 105 | private System.Collections.IEnumerator TeleportPlayerCoroutine(int playerObj, Vector3 teleportPos) 106 | { 107 | yield return new WaitForSeconds(teleporterChargeUp); 108 | Utilities.TeleportPlayer(playerObj, teleportPos); 109 | // remove player from list 110 | teleportingPlayers.Remove(StartOfRound.Instance.allPlayerScripts[playerObj]); 111 | TeleportPlayerServerRpc(playerObj, teleportPos); 112 | } 113 | 114 | private System.Collections.IEnumerator TeleportEnemyCoroutine(EnemyAI enemy, Vector3 teleportPos) 115 | { 116 | yield return new WaitForSeconds(teleporterChargeUp); 117 | Utilities.TeleportEnemy(enemy, teleportPos); 118 | // remove AI from list 119 | teleportingAI.Remove(enemy); 120 | // call server rpc with enemy object reference 121 | TeleportEnemyServerRpc(enemy.NetworkObject, teleportPos); 122 | } 123 | 124 | private System.Collections.IEnumerator TeleportPlayerBodyCoroutine(int playerObj, Vector3 teleportPos) 125 | { 126 | yield return new WaitForSeconds(teleporterChargeUp); 127 | TeleportPlayerBodyServerRpc(playerObj, teleportPos); 128 | // remove player from list 129 | teleportingPlayers.Remove(StartOfRound.Instance.allPlayerScripts[playerObj]); 130 | StartCoroutine(Utilities.TeleportPlayerBody(playerObj, teleportPos)); 131 | } 132 | 133 | 134 | [ServerRpc(RequireOwnership = false)] 135 | public void TeleportPlayerServerRpc(int playerObj, Vector3 teleportPos) 136 | { 137 | TeleportPlayerClientRpc(playerObj, teleportPos); 138 | } 139 | 140 | [ServerRpc(RequireOwnership = false)] 141 | public void TeleportEnemyServerRpc(NetworkObjectReference enemy, Vector3 teleportPos) 142 | { 143 | TeleportEnemyClientRpc(enemy, teleportPos); 144 | } 145 | 146 | [ServerRpc(RequireOwnership = false)] 147 | public void TeleportPlayerBodyServerRpc(int playerObj, Vector3 teleportPos) 148 | { 149 | TeleportPlayerBodyClientRpc(playerObj, teleportPos); 150 | } 151 | 152 | 153 | [ClientRpc] 154 | public void TeleportPlayerClientRpc(int playerObj, Vector3 teleportPos) 155 | { 156 | teleporterAudio.PlayOneShot(teleporterBeamUpSFX); 157 | StartOfRound.Instance.allPlayerScripts[playerObj].movementAudio.PlayOneShot(teleporterBeamUpSFX); 158 | Utilities.TeleportPlayer(playerObj, teleportPos); 159 | } 160 | 161 | [ClientRpc] 162 | public void TeleportEnemyClientRpc(NetworkObjectReference enemy, Vector3 teleportPos) 163 | { 164 | var enemyObj = NetworkObjectReference.Resolve(enemy); 165 | teleporterAudio.PlayOneShot(teleporterBeamUpSFX); 166 | Utilities.TeleportEnemy(enemyObj.GetComponent(), teleportPos); 167 | } 168 | 169 | [ClientRpc] 170 | public void TeleportPlayerBodyClientRpc(int playerObj, Vector3 teleportPos) 171 | { 172 | teleporterAudio.PlayOneShot(teleporterBeamUpSFX); 173 | StartOfRound.Instance.allPlayerScripts[playerObj].movementAudio.PlayOneShot(teleporterBeamUpSFX); 174 | StartCoroutine(Utilities.TeleportPlayerBody(playerObj, teleportPos)); 175 | } 176 | 177 | 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/TestBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Unity.Netcode; 5 | 6 | namespace LethalThings.MonoBehaviours 7 | { 8 | public class TestBehaviour : NetworkBehaviour 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ThrowableItem.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | public class ThrowableItem : GrabbableObject 11 | { 12 | public override void ItemActivate(bool used, bool buttonDown = true) 13 | { 14 | base.ItemActivate(used, buttonDown); 15 | if (base.IsOwner) 16 | { 17 | playerHeldBy.DiscardHeldObject(placeObject: true, null, GetItemThrowDestination()); 18 | } 19 | } 20 | 21 | public override void EquipItem() 22 | { 23 | EnableItemMeshes(enable: true); 24 | isPocketed = false; 25 | } 26 | 27 | public override void FallWithCurve() 28 | { 29 | float magnitude = (startFallingPosition - targetFloorPosition).magnitude; 30 | base.transform.rotation = Quaternion.Lerp(base.transform.rotation, Quaternion.Euler(itemProperties.restingRotation.x, base.transform.eulerAngles.y, itemProperties.restingRotation.z), 14f * Time.deltaTime / magnitude); 31 | base.transform.localPosition = Vector3.Lerp(startFallingPosition, targetFloorPosition, itemFallCurve.Evaluate(fallTime)); 32 | if (magnitude > 5f) 33 | { 34 | base.transform.localPosition = Vector3.Lerp(new Vector3(base.transform.localPosition.x, startFallingPosition.y, base.transform.localPosition.z), new Vector3(base.transform.localPosition.x, targetFloorPosition.y, base.transform.localPosition.z), itemVerticalFallCurveNoBounce.Evaluate(fallTime)); 35 | } 36 | else 37 | { 38 | base.transform.localPosition = Vector3.Lerp(new Vector3(base.transform.localPosition.x, startFallingPosition.y, base.transform.localPosition.z), new Vector3(base.transform.localPosition.x, targetFloorPosition.y, base.transform.localPosition.z), itemVerticalFallCurve.Evaluate(fallTime)); 39 | } 40 | fallTime += Mathf.Abs(Time.deltaTime * 12f / magnitude); 41 | } 42 | 43 | 44 | public override void Update() 45 | { 46 | base.Update(); 47 | } 48 | 49 | public Vector3 GetItemThrowDestination() 50 | { 51 | Vector3 position = base.transform.position; 52 | Debug.DrawRay(playerHeldBy.gameplayCamera.transform.position, playerHeldBy.gameplayCamera.transform.forward, Color.yellow, 15f); 53 | itemThrowRay = new Ray(playerHeldBy.gameplayCamera.transform.position, playerHeldBy.gameplayCamera.transform.forward); 54 | position = ((!Physics.Raycast(itemThrowRay, out itemHit, 12f, StartOfRound.Instance.collidersAndRoomMaskAndDefault)) ? itemThrowRay.GetPoint(10f) : itemThrowRay.GetPoint(itemHit.distance - 0.05f)); 55 | Debug.DrawRay(position, Vector3.down, Color.blue, 15f); 56 | 57 | // check if position is inside a collider, and position below is not 58 | if (Physics.OverlapSphere(position, 0.02f, StartOfRound.Instance.collidersAndRoomMaskAndDefault).Length > 0) 59 | { 60 | if(Physics.OverlapSphere(position + (Vector3.down * 0.05f), 0.02f, StartOfRound.Instance.collidersAndRoomMaskAndDefault).Length == 0) 61 | { 62 | // set new position 63 | position += (Vector3.down * 0.05f); 64 | } 65 | } 66 | 67 | itemThrowRay = new Ray(position, Vector3.down); 68 | if (Physics.Raycast(itemThrowRay, out itemHit, 30f, StartOfRound.Instance.collidersAndRoomMaskAndDefault)) 69 | { 70 | return itemHit.point + Vector3.up * 0.05f; 71 | } 72 | return itemThrowRay.GetPoint(30f); 73 | } 74 | 75 | public AnimationCurve itemFallCurve; 76 | 77 | public AnimationCurve itemVerticalFallCurve; 78 | 79 | public AnimationCurve itemVerticalFallCurveNoBounce; 80 | 81 | public RaycastHit itemHit; 82 | 83 | public Ray itemThrowRay; 84 | 85 | private PlayerControllerB playerThrownBy; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ThrowableNoisemaker.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.MonoBehaviours 9 | { 10 | public class ThrowableNoisemaker : NoisemakerProp 11 | { 12 | public bool throwWithRight = false; 13 | public bool beingThrown = false; 14 | 15 | public static void Init() 16 | { 17 | On.GrabbableObject.RequireCooldown += GrabbableObject_RequireCooldown; 18 | On.GrabbableObject.ItemInteractLeftRightOnClient += GrabbableObject_ItemInteractLeftRightOnClient; 19 | On.GrabbableObject.UseItemBatteries += GrabbableObject_UseItemBatteries1; 20 | } 21 | 22 | private static bool GrabbableObject_UseItemBatteries1(On.GrabbableObject.orig_UseItemBatteries orig, GrabbableObject self, bool isToggle, bool buttonDown) 23 | { 24 | if (self is ThrowableNoisemaker noisemaker) 25 | { 26 | if (noisemaker.beingThrown) 27 | { 28 | return true; 29 | } 30 | } 31 | 32 | return orig(self, isToggle, buttonDown); 33 | } 34 | 35 | 36 | private static void GrabbableObject_ItemInteractLeftRightOnClient(On.GrabbableObject.orig_ItemInteractLeftRightOnClient orig, GrabbableObject self, bool right) 37 | { 38 | if(self is ThrowableNoisemaker noisemaker) 39 | { 40 | if ((noisemaker.throwWithRight && right) || !right) 41 | { 42 | noisemaker.beingThrown = true; 43 | orig(self, right); 44 | noisemaker.beingThrown = false; 45 | } 46 | else 47 | { 48 | orig(self, right); 49 | } 50 | } 51 | else 52 | { 53 | orig(self, right); 54 | } 55 | 56 | } 57 | 58 | private static bool GrabbableObject_RequireCooldown(On.GrabbableObject.orig_RequireCooldown orig, GrabbableObject self) 59 | { 60 | if (self is ThrowableNoisemaker noisemaker) 61 | { 62 | if (noisemaker.beingThrown) 63 | { 64 | return false; 65 | } 66 | } 67 | return orig(self); 68 | } 69 | 70 | public override void ItemInteractLeftRight(bool right) 71 | { 72 | base.ItemInteractLeftRight(right); 73 | 74 | if (!IsOwner) 75 | { 76 | return; 77 | } 78 | 79 | if ((throwWithRight && right) || !right) 80 | { 81 | playerHeldBy.DiscardHeldObject(placeObject: true, null, GetItemThrowDestination()); 82 | } 83 | } 84 | 85 | public override void EquipItem() 86 | { 87 | EnableItemMeshes(enable: true); 88 | playerHeldBy.equippedUsableItemQE = true; 89 | isPocketed = false; 90 | } 91 | 92 | public override void DiscardItem() 93 | { 94 | if (playerHeldBy != null) 95 | { 96 | playerHeldBy.equippedUsableItemQE = false; 97 | } 98 | base.DiscardItem(); 99 | } 100 | 101 | public override void PocketItem() 102 | { 103 | if (base.IsOwner && playerHeldBy != null) 104 | { 105 | playerHeldBy.equippedUsableItemQE = false; 106 | } 107 | base.PocketItem(); 108 | } 109 | 110 | public override void FallWithCurve() 111 | { 112 | float magnitude = (startFallingPosition - targetFloorPosition).magnitude; 113 | base.transform.rotation = Quaternion.Lerp(base.transform.rotation, Quaternion.Euler(itemProperties.restingRotation.x, base.transform.eulerAngles.y, itemProperties.restingRotation.z), 14f * Time.deltaTime / magnitude); 114 | base.transform.localPosition = Vector3.Lerp(startFallingPosition, targetFloorPosition, itemFallCurve.Evaluate(fallTime)); 115 | if (magnitude > 5f) 116 | { 117 | base.transform.localPosition = Vector3.Lerp(new Vector3(base.transform.localPosition.x, startFallingPosition.y, base.transform.localPosition.z), new Vector3(base.transform.localPosition.x, targetFloorPosition.y, base.transform.localPosition.z), itemVerticalFallCurveNoBounce.Evaluate(fallTime)); 118 | } 119 | else 120 | { 121 | base.transform.localPosition = Vector3.Lerp(new Vector3(base.transform.localPosition.x, startFallingPosition.y, base.transform.localPosition.z), new Vector3(base.transform.localPosition.x, targetFloorPosition.y, base.transform.localPosition.z), itemVerticalFallCurve.Evaluate(fallTime)); 122 | } 123 | fallTime += Mathf.Abs(Time.deltaTime * 12f / magnitude); 124 | } 125 | 126 | 127 | public override void Update() 128 | { 129 | base.Update(); 130 | } 131 | 132 | public Vector3 GetItemThrowDestination() 133 | { 134 | Vector3 position = base.transform.position; 135 | Debug.DrawRay(playerHeldBy.gameplayCamera.transform.position, playerHeldBy.gameplayCamera.transform.forward, Color.yellow, 15f); 136 | itemThrowRay = new Ray(playerHeldBy.gameplayCamera.transform.position, playerHeldBy.gameplayCamera.transform.forward); 137 | position = ((!Physics.Raycast(itemThrowRay, out itemHit, 12f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, QueryTriggerInteraction.Ignore)) ? itemThrowRay.GetPoint(10f) : itemThrowRay.GetPoint(itemHit.distance - 0.05f)); 138 | Debug.DrawRay(position, Vector3.down, Color.blue, 15f); 139 | itemThrowRay = new Ray(position, Vector3.down); 140 | if (Physics.Raycast(itemThrowRay, out itemHit, 30f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, QueryTriggerInteraction.Ignore)) 141 | { 142 | return itemHit.point + Vector3.up * 0.05f; 143 | } 144 | return itemThrowRay.GetPoint(30f); 145 | } 146 | 147 | public AnimationCurve itemFallCurve; 148 | 149 | public AnimationCurve itemVerticalFallCurve; 150 | 151 | public AnimationCurve itemVerticalFallCurveNoBounce; 152 | 153 | public RaycastHit itemHit; 154 | 155 | public Ray itemThrowRay; 156 | 157 | private PlayerControllerB playerThrownBy; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ToyGun.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | // define unity random 9 | using Random = UnityEngine.Random; 10 | 11 | namespace LethalThings.MonoBehaviours 12 | { 13 | public class ToyGun : GrabbableObject 14 | { 15 | public bool isFiring = false; 16 | public float reloadTime = 2f; 17 | public bool wasFired = false; 18 | public AudioClip[] fireSounds; 19 | public AudioClip[] reloadSounds; 20 | public AudioSource audioSource; 21 | public AudioSource audioSourceFar; 22 | public Animator animator; 23 | 24 | public void Fire(int fireSound, int reloadSound) 25 | { 26 | if (wasFired) 27 | { 28 | return; 29 | } 30 | wasFired = true; 31 | 32 | // play fire animation 33 | animator.Play("pewpew"); 34 | 35 | isFiring = false; 36 | 37 | StartCoroutine(FireSound(fireSound)); 38 | StartCoroutine(Reload(reloadSound)); 39 | } 40 | 41 | public IEnumerator Reload(int soundIndex) 42 | { 43 | yield return new WaitForSeconds(reloadTime); 44 | wasFired = false; 45 | 46 | // play reload animation 47 | animator.Play("unpew"); 48 | 49 | // play reload sound 50 | PlayReloadSound(soundIndex); 51 | } 52 | 53 | public IEnumerator FireSound(int soundIndex) 54 | { 55 | yield return new WaitForSeconds(0.03f); 56 | PlayFireSound(soundIndex); 57 | } 58 | 59 | public void PlayFireSound(int soundIndex) 60 | { 61 | audioSource.PlayOneShot(fireSounds[soundIndex]); 62 | if (audioSourceFar != null) 63 | { 64 | audioSourceFar.PlayOneShot(fireSounds[soundIndex]); 65 | } 66 | } 67 | 68 | public void PlayReloadSound(int soundIndex) 69 | { 70 | audioSource.PlayOneShot(reloadSounds[soundIndex]); 71 | if (audioSourceFar != null) 72 | { 73 | audioSourceFar.PlayOneShot(reloadSounds[soundIndex]); 74 | } 75 | } 76 | 77 | [ServerRpc] 78 | public void FireServerRpc(int fireSound, int reloadSound) 79 | { 80 | FireClientRpc(fireSound, reloadSound); 81 | } 82 | 83 | [ClientRpc] 84 | public void FireClientRpc(int fireSound, int reloadSound) 85 | { 86 | Fire(fireSound, reloadSound); 87 | } 88 | 89 | public override void ItemActivate(bool used, bool buttonDown = true) 90 | { 91 | base.ItemActivate(used, buttonDown); 92 | 93 | if (base.IsOwner) 94 | { 95 | //Debug.Log("Player activated item to fire gun."); 96 | if (!isFiring && !wasFired) 97 | { 98 | isFiring = true; 99 | int fireSound = Random.Range(0, fireSounds.Length); 100 | int reloadSound = Random.Range(0, reloadSounds.Length); 101 | FireServerRpc(fireSound, reloadSound); 102 | } 103 | } 104 | 105 | } 106 | 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /LethalThings/MonoBehaviours/ToyHammer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using GameNetcodeStuff; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings 9 | { 10 | internal class ToyHammer : GrabbableObject 11 | { 12 | 13 | public int hammerHitForce = 1; 14 | public float hammerHitPercentage = 1; 15 | 16 | public bool reelingUp; 17 | 18 | public bool isHoldingButton; 19 | 20 | private RaycastHit rayHit; 21 | 22 | private Coroutine reelingUpCoroutine; 23 | 24 | private RaycastHit[] objectsHitByHammer; 25 | 26 | private List objectsHitByHammerList = new List(); 27 | 28 | public AudioClip reelUp; 29 | 30 | public AudioClip swing; 31 | 32 | public AudioClip[] hitSFX; 33 | 34 | public AudioSource hammerAudio; 35 | 36 | private PlayerControllerB previousPlayerHeldBy; 37 | 38 | private int hammerMask = 11012424; 39 | 40 | public override void ItemActivate(bool used, bool buttonDown = true) 41 | { 42 | if (playerHeldBy == null) 43 | { 44 | return; 45 | } 46 | //Debug.Log($"Is player pressing down button?: {buttonDown}"); 47 | isHoldingButton = buttonDown; 48 | //Debug.Log("PLAYER ACTIVATED ITEM TO HIT WITH SHOVEL. Who sent this log: " + GameNetworkManager.Instance.localPlayerController.gameObject.name); 49 | if (!reelingUp && buttonDown) 50 | { 51 | reelingUp = true; 52 | previousPlayerHeldBy = playerHeldBy; 53 | //Debug.Log($"Set previousPlayerHeldBy: {previousPlayerHeldBy}"); 54 | if (reelingUpCoroutine != null) 55 | { 56 | StopCoroutine(reelingUpCoroutine); 57 | } 58 | reelingUpCoroutine = StartCoroutine(reelUpHammer()); 59 | } 60 | } 61 | 62 | private IEnumerator reelUpHammer() 63 | { 64 | playerHeldBy.activatingItem = true; 65 | playerHeldBy.twoHanded = true; 66 | playerHeldBy.playerBodyAnimator.ResetTrigger("hammerHit"); 67 | playerHeldBy.playerBodyAnimator.SetBool("reelingUp", value: true); 68 | hammerAudio.PlayOneShot(reelUp); 69 | ReelUpSFXServerRpc(); 70 | yield return new WaitForSeconds(0.35f); 71 | yield return new WaitUntil(() => !isHoldingButton || !isHeld); 72 | SwingHammer(!isHeld); 73 | yield return new WaitForSeconds(0.13f); 74 | HitHammer(!isHeld); 75 | yield return new WaitForSeconds(0.3f); 76 | reelingUp = false; 77 | reelingUpCoroutine = null; 78 | } 79 | 80 | [ServerRpc] 81 | public void ReelUpSFXServerRpc() 82 | { 83 | ReelUpSFXClientRpc(); 84 | } 85 | 86 | [ClientRpc] 87 | public void ReelUpSFXClientRpc() 88 | { 89 | hammerAudio.PlayOneShot(reelUp); 90 | } 91 | 92 | public override void DiscardItem() 93 | { 94 | playerHeldBy.activatingItem = false; 95 | base.DiscardItem(); 96 | } 97 | 98 | public void SwingHammer(bool cancel = false) 99 | { 100 | previousPlayerHeldBy.playerBodyAnimator.SetBool("reelingUp", value: false); 101 | if (!cancel) 102 | { 103 | hammerAudio.PlayOneShot(swing); 104 | previousPlayerHeldBy.UpdateSpecialAnimationValue(specialAnimation: true, (short)previousPlayerHeldBy.transform.localEulerAngles.y, 0.4f); 105 | } 106 | } 107 | 108 | public void HitHammer(bool cancel = false) 109 | { 110 | if (previousPlayerHeldBy == null) 111 | { 112 | return; 113 | } 114 | previousPlayerHeldBy.activatingItem = false; 115 | bool flag = false; 116 | int hitSurfaceID = -1; 117 | if (!cancel) 118 | { 119 | previousPlayerHeldBy.twoHanded = false; 120 | Debug.DrawRay(previousPlayerHeldBy.gameplayCamera.transform.position + previousPlayerHeldBy.gameplayCamera.transform.right * -0.35f, previousPlayerHeldBy.gameplayCamera.transform.forward * 1.85f, Color.blue, 5f); 121 | objectsHitByHammer = Physics.SphereCastAll(previousPlayerHeldBy.gameplayCamera.transform.position + previousPlayerHeldBy.gameplayCamera.transform.right * -0.35f, 0.75f, previousPlayerHeldBy.gameplayCamera.transform.forward, 1.85f, hammerMask, QueryTriggerInteraction.Collide); 122 | objectsHitByHammerList = objectsHitByHammer.OrderBy((x) => x.distance).ToList(); 123 | Vector3 start = previousPlayerHeldBy.gameplayCamera.transform.position; 124 | for (int i = 0; i < objectsHitByHammerList.Count; i++) 125 | { 126 | IHittable component; 127 | RaycastHit hitInfo; 128 | if (objectsHitByHammerList[i].transform.gameObject.layer == 8 || objectsHitByHammerList[i].transform.gameObject.layer == 11) 129 | { 130 | start = objectsHitByHammerList[i].point + objectsHitByHammerList[i].normal * 0.01f; 131 | flag = true; 132 | string text = objectsHitByHammerList[i].collider.gameObject.tag; 133 | for (int j = 0; j < StartOfRound.Instance.footstepSurfaces.Length; j++) 134 | { 135 | if (StartOfRound.Instance.footstepSurfaces[j].surfaceTag == text) 136 | { 137 | hammerAudio.PlayOneShot(StartOfRound.Instance.footstepSurfaces[j].hitSurfaceSFX); 138 | WalkieTalkie.TransmitOneShotAudio(hammerAudio, StartOfRound.Instance.footstepSurfaces[j].hitSurfaceSFX); 139 | hitSurfaceID = j; 140 | break; 141 | } 142 | } 143 | } 144 | else if (objectsHitByHammerList[i].transform.TryGetComponent(out component) && !(objectsHitByHammerList[i].transform == previousPlayerHeldBy.transform) && (objectsHitByHammerList[i].point == Vector3.zero || !Physics.Linecast(start, objectsHitByHammerList[i].point, out hitInfo, StartOfRound.Instance.collidersAndRoomMaskAndDefault))) 145 | { 146 | flag = true; 147 | Vector3 forward = previousPlayerHeldBy.gameplayCamera.transform.forward; 148 | 149 | // 1% chance to hit player 150 | if (Random.Range(0f, 100f) < hammerHitPercentage) 151 | { 152 | component.Hit(hammerHitForce, forward, previousPlayerHeldBy, playHitSFX: true); 153 | } 154 | } 155 | } 156 | } 157 | if (flag) 158 | { 159 | var soundID = RoundManager.PlayRandomClip(hammerAudio, hitSFX); 160 | FindObjectOfType().PlayAudibleNoise(transform.position, 17f, 0.8f); 161 | playerHeldBy.playerBodyAnimator.SetTrigger("hammerHit"); 162 | HitHammerServerRpc(soundID); 163 | } 164 | } 165 | 166 | [ServerRpc] 167 | public void HitHammerServerRpc(int soundID) 168 | { 169 | HitHammerClientRpc(soundID); 170 | } 171 | 172 | [ClientRpc] 173 | public void HitHammerClientRpc(int soundID) 174 | { 175 | HitSurfaceWithHammer(soundID); 176 | } 177 | 178 | private void HitSurfaceWithHammer(int soundID) 179 | { 180 | if (!IsOwner) 181 | { 182 | hammerAudio.PlayOneShot(hitSFX[soundID]); 183 | } 184 | WalkieTalkie.TransmitOneShotAudio(hammerAudio, hitSFX[soundID]); 185 | } 186 | 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /LethalThings/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LethalThings/Patches/Debug.cs: -------------------------------------------------------------------------------- 1 | using LethalThings.MonoBehaviours; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Numerics; 5 | using System.Text; 6 | using Unity.Netcode; 7 | using UnityEngine; 8 | using UnityEngine.InputSystem; 9 | using Quaternion = UnityEngine.Quaternion; 10 | using Vector3 = UnityEngine.Vector3; 11 | 12 | namespace LethalThings.Patches 13 | { 14 | public class Debug 15 | { 16 | public static void Load() 17 | { 18 | On.StartOfRound.Update += StartOfRound_Update; 19 | On.RoundManager.Update += RoundManager_Update; 20 | On.StartOfRound.Start += StartOfRound_Start; 21 | // On.ShipBuildModeManager.Update += ShipBuildModeManager_Update; 22 | } 23 | 24 | private static void ShipBuildModeManager_Update(On.ShipBuildModeManager.orig_Update orig, ShipBuildModeManager self) 25 | { 26 | if (GameNetworkManager.Instance == null || GameNetworkManager.Instance.localPlayerController == null) 27 | { 28 | return; 29 | } 30 | self.player = GameNetworkManager.Instance.localPlayerController; 31 | if (!self.PlayerMeetsConditionsToBuild(log: false)) 32 | { 33 | self.CancelBuildMode(); 34 | } 35 | if (self.placingObject == null) 36 | { 37 | self.CancelBuildMode(); 38 | } 39 | if (self.InBuildMode) 40 | { 41 | if (self.currentCollider == null) 42 | { 43 | self.currentCollider = self.placingObject.placeObjectCollider as BoxCollider; 44 | } 45 | if (IngamePlayerSettings.Instance.playerInput.actions.FindAction("ReloadBatteries").IsPressed() || (StartOfRound.Instance.localPlayerUsingController && self.playerActions.Movement.InspectItem.IsPressed())) 46 | { 47 | self.ghostObject.eulerAngles = new Vector3(self.ghostObject.eulerAngles.x, self.ghostObject.eulerAngles.y + Time.deltaTime * 155f, self.ghostObject.eulerAngles.z); 48 | } 49 | self.playerCameraRay = new Ray(self.player.gameplayCamera.transform.position, self.player.gameplayCamera.transform.forward); 50 | if (Physics.Raycast(self.playerCameraRay, out self.rayHit, 4f, self.placementMask, QueryTriggerInteraction.Ignore)) 51 | { 52 | if (Vector3.Angle(self.rayHit.normal, Vector3.up) < 45f) 53 | { 54 | self.ghostObject.position = self.rayHit.point + Vector3.up * self.placingObject.yOffset; 55 | } 56 | else if (self.placingObject.AllowPlacementOnWalls) 57 | { 58 | self.ghostObject.position = self.OffsetObjectFromWallBasedOnDimensions(self.rayHit.point, self.rayHit); 59 | if (Physics.Raycast(self.ghostObject.position, Vector3.down, out self.rayHit, self.placingObject.yOffset, self.placementMask, QueryTriggerInteraction.Ignore)) 60 | { 61 | self.ghostObject.position += Vector3.up * self.rayHit.distance; 62 | } 63 | } 64 | else if (Physics.Raycast(self.OffsetObjectFromWallBasedOnDimensions(self.rayHit.point, self.rayHit), Vector3.down, out self.rayHit, 20f, self.placementMask, QueryTriggerInteraction.Ignore)) 65 | { 66 | self.ghostObject.position = self.rayHit.point + Vector3.up * self.placingObject.yOffset; 67 | } 68 | } 69 | else if (Physics.Raycast(self.playerCameraRay.GetPoint(4f), Vector3.down, out self.rayHit, 20f, self.placementMask, QueryTriggerInteraction.Ignore)) 70 | { 71 | self.ghostObject.position = self.rayHit.point + Vector3.up * self.placingObject.yOffset; 72 | } 73 | bool flag = Physics.CheckBox(self.ghostObject.position, self.currentCollider.size * 0.5f * 0.57f, Quaternion.Euler(self.ghostObject.eulerAngles), self.placementMaskAndBlockers, QueryTriggerInteraction.Ignore); 74 | if (!flag && self.placingObject.doCollisionPointCheck) 75 | { 76 | Vector3 vector = self.ghostObject.position + self.ghostObject.forward * self.placingObject.collisionPointCheck.z + self.ghostObject.right * self.placingObject.collisionPointCheck.x + self.ghostObject.up * self.placingObject.collisionPointCheck.y; 77 | UnityEngine.Debug.DrawRay(vector, Vector3.up * 2f, Color.blue); 78 | if (Physics.CheckSphere(vector, 1f, self.placementMaskAndBlockers, QueryTriggerInteraction.Ignore)) 79 | { 80 | flag = true; 81 | } 82 | } 83 | self.CanConfirmPosition = !flag && StartOfRound.Instance.shipInnerRoomBounds.bounds.Contains(self.ghostObject.position); 84 | if (flag) 85 | { 86 | self.ghostObjectRenderer.sharedMaterial = self.ghostObjectRed; 87 | 88 | var colliders = Physics.OverlapBox(self.ghostObject.position, self.currentCollider.size * 0.5f * 0.57f, Quaternion.Euler(self.ghostObject.eulerAngles), self.placementMaskAndBlockers, QueryTriggerInteraction.Ignore); 89 | 90 | foreach (var collider in colliders) 91 | { 92 | UnityEngine.Debug.Log($"Collider: {collider.gameObject.name}"); 93 | } 94 | } 95 | else 96 | { 97 | self.ghostObjectRenderer.sharedMaterial = self.ghostObjectGreen; 98 | } 99 | } 100 | else 101 | { 102 | self.timeSincePlacingObject += Time.deltaTime; 103 | } 104 | } 105 | 106 | 107 | private static void StartOfRound_Start(On.StartOfRound.orig_Start orig, StartOfRound self) 108 | { 109 | orig(self); 110 | 111 | if(Plugin.devMode && DevMenu.Instance == null) 112 | { 113 | var gameObject = GameObject.Instantiate(Content.devMenuPrefab); 114 | // spawn network object 115 | gameObject.GetComponent().Spawn(); 116 | } 117 | } 118 | 119 | private static void RoundManager_Update(On.RoundManager.orig_Update orig, RoundManager self) 120 | { 121 | orig(self); 122 | 123 | 124 | 125 | /*if (Keyboard.current.f2Key.wasPressedThisFrame) 126 | { 127 | var ray = Content.Prefabs["CrystalRay"]; 128 | 129 | var gameObject = GameObject.Instantiate(ray, self.playersManager.localPlayerController.gameplayCamera.transform.position, Quaternion.identity); 130 | 131 | gameObject.GetComponent().Spawn(); 132 | 133 | }*/ 134 | } 135 | 136 | static List currentCheatCode = new List(); 137 | 138 | static List devModeCode = new List() 139 | { 140 | Key.UpArrow, 141 | Key.UpArrow, 142 | Key.DownArrow, 143 | Key.DownArrow, 144 | Key.LeftArrow, 145 | Key.RightArrow, 146 | Key.LeftArrow, 147 | Key.RightArrow, 148 | Key.B, 149 | Key.A, 150 | Key.Enter 151 | }; 152 | 153 | private static void StartOfRound_Update(On.StartOfRound.orig_Update orig, StartOfRound self) 154 | { 155 | // cheat code for enabling dev menu 156 | 157 | if (self.IsHost && DevMenu.Instance == null) 158 | { 159 | foreach (var key in Keyboard.current.allKeys) 160 | { 161 | if (key.wasReleasedThisFrame) 162 | { 163 | currentCheatCode.Add(key.keyCode); 164 | 165 | // print current code 166 | /*var codeString = ""; 167 | foreach (var k in currentCheatCode) 168 | { 169 | codeString += k.ToString() + " "; 170 | 171 | }*/ 172 | 173 | //Plugin.logger.LogMessage(codeString); 174 | } 175 | } 176 | 177 | for (int i = 0; i < currentCheatCode.Count; i++) 178 | { 179 | if (currentCheatCode[i] != devModeCode[i]) 180 | { 181 | currentCheatCode.Clear(); 182 | break; 183 | } 184 | } 185 | 186 | if (currentCheatCode.Count == devModeCode.Count) 187 | { 188 | currentCheatCode.Clear(); 189 | 190 | Plugin.logger.LogMessage("Dev mode enabled, press F1 to open dev menu."); 191 | 192 | var gameObject = GameObject.Instantiate(Content.devMenuPrefab); 193 | // spawn network object 194 | gameObject.GetComponent().Spawn(); 195 | } 196 | 197 | } 198 | 199 | 200 | orig(self); 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /LethalThings/Patches/Miscellaneous.cs: -------------------------------------------------------------------------------- 1 | using BepInEx.Logging; 2 | using LethalThings.MonoBehaviours; 3 | using MonoMod.RuntimeDetour; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Reflection; 7 | using System.Text; 8 | using Unity.Netcode; 9 | using UnityEngine; 10 | 11 | namespace LethalThings.Patches 12 | { 13 | public class Miscellaneous 14 | { 15 | public static void Load() 16 | { 17 | // Allow item to have no grab animation because the game is dumb 18 | On.GameNetcodeStuff.PlayerControllerB.SetSpecialGrabAnimationBool += PlayerControllerB_SetSpecialGrabAnimationBool; 19 | 20 | On.StartOfRound.Start += StartOfRound_Start; 21 | 22 | /* 23 | On.GameNetworkManager.Start += GameNetworkManager_Start; 24 | 25 | Hook hook3 = new Hook(typeof(UnityEngine.Object).GetMethod("Instantiate", new Type[] 26 | { 27 | typeof(UnityEngine.Object), 28 | typeof(Transform), 29 | typeof(bool) 30 | }), typeof(Miscellaneous).GetMethod("InstantiateOPI")); 31 | Hook hook4 = new Hook(typeof(UnityEngine.Object).GetMethod("Instantiate", new Type[] 32 | { 33 | typeof(UnityEngine.Object), 34 | typeof(Transform) 35 | }), typeof(Miscellaneous).GetMethod("InstantiateOP")); 36 | Hook hook5 = new Hook(typeof(UnityEngine.Object).GetMethod("Instantiate", new Type[] 37 | { 38 | typeof(UnityEngine.Object) 39 | }), typeof(Miscellaneous).GetMethod("InstantiateO")); 40 | Hook hook6 = new Hook(typeof(UnityEngine.Object).GetMethod("Instantiate", new Type[] 41 | { 42 | typeof(UnityEngine.Object), 43 | typeof(Vector3), 44 | typeof(Quaternion) 45 | }), typeof(Miscellaneous).GetMethod("InstantiateOPR")); 46 | Hook hook7 = new Hook(typeof(UnityEngine.Object).GetMethod("Instantiate", new Type[] 47 | { 48 | typeof(UnityEngine.Object), 49 | typeof(Vector3), 50 | typeof(Quaternion), 51 | typeof(Transform) 52 | }), typeof(Miscellaneous).GetMethod("InstantiateOPRP")); 53 | 54 | // hook public void NetworkManager.AddNetworkPrefab(GameObject prefab) 55 | Hook hook = new Hook(typeof(NetworkManager).GetMethod("AddNetworkPrefab", new Type[] 56 | { 57 | typeof(GameObject) 58 | }), typeof(Miscellaneous).GetMethod("AddNetworkPrefab"));*/ 59 | } 60 | /* 61 | public static void AddNetworkPrefab(Action orig, NetworkManager self, GameObject prefab) 62 | { 63 | orig(self, prefab); 64 | foreach (Collider collider in prefab.GetComponentsInChildren()) 65 | { 66 | // if has root marker, skip 67 | if (collider.gameObject.GetComponent() != null) 68 | { 69 | continue; 70 | } 71 | RootMarker marker = collider.gameObject.AddComponent(); 72 | marker.root = prefab.transform; 73 | } 74 | } 75 | 76 | private static void GameNetworkManager_Start(On.GameNetworkManager.orig_Start orig, GameNetworkManager self) 77 | { 78 | orig(self); 79 | 80 | foreach(var obj in NetworkManager.Singleton.NetworkConfig.Prefabs.m_Prefabs) 81 | { 82 | var go = obj.Prefab.gameObject; 83 | foreach (Collider collider in go.GetComponentsInChildren()) 84 | { 85 | // if has root marker, skip 86 | if (collider.gameObject.GetComponent() != null) 87 | { 88 | continue; 89 | } 90 | RootMarker marker = collider.gameObject.AddComponent(); 91 | marker.root = go.transform; 92 | } 93 | } 94 | 95 | } 96 | 97 | public static UnityEngine.Object InstantiateOPI(Func orig, UnityEngine.Object original, Transform parent, bool instantiateInWorldSpace) 98 | { 99 | var obj = orig(original, parent, instantiateInWorldSpace); 100 | if (obj != null && obj is GameObject) 101 | { 102 | var go = (GameObject)obj; 103 | // find all colliders, and add root markers to them 104 | foreach (Collider collider in go.GetComponentsInChildren()) 105 | { 106 | // if has root marker, skip 107 | if (collider.gameObject.GetComponent() != null) 108 | { 109 | continue; 110 | } 111 | RootMarker marker = collider.gameObject.AddComponent(); 112 | marker.root = go.transform; 113 | } 114 | } 115 | return obj; 116 | } 117 | 118 | public static UnityEngine.Object InstantiateOP(Func orig, UnityEngine.Object original, Transform parent) 119 | { 120 | var obj = orig(original, parent); 121 | if (obj != null && obj is GameObject) 122 | { 123 | var go = (GameObject)obj; 124 | // find all colliders, and add root markers to them 125 | foreach (Collider collider in go.GetComponentsInChildren()) 126 | { 127 | // if has root marker, skip 128 | if (collider.gameObject.GetComponent() != null) 129 | { 130 | continue; 131 | } 132 | RootMarker marker = collider.gameObject.AddComponent(); 133 | marker.root = go.transform; 134 | } 135 | } 136 | return obj; 137 | 138 | } 139 | 140 | public static UnityEngine.Object InstantiateO(Func orig, UnityEngine.Object original) 141 | { 142 | var obj = orig(original); 143 | if (obj != null && obj is GameObject) 144 | { 145 | var go = (GameObject)obj; 146 | // find all colliders, and add root markers to them 147 | foreach (Collider collider in go.GetComponentsInChildren()) 148 | { 149 | // if has root marker, skip 150 | if (collider.gameObject.GetComponent() != null) 151 | { 152 | continue; 153 | } 154 | RootMarker marker = collider.gameObject.AddComponent(); 155 | marker.root = go.transform; 156 | } 157 | } 158 | return obj; 159 | 160 | } 161 | 162 | public static UnityEngine.Object InstantiateOPR(Func orig, UnityEngine.Object original, Vector3 position, Quaternion rotation) 163 | { 164 | var obj = orig(original, position, rotation); 165 | if (obj != null && obj is GameObject) 166 | { 167 | var go = (GameObject)obj; 168 | // find all colliders, and add root markers to them 169 | foreach (Collider collider in go.GetComponentsInChildren()) 170 | { 171 | // if has root marker, skip 172 | if (collider.gameObject.GetComponent() != null) 173 | { 174 | continue; 175 | } 176 | RootMarker marker = collider.gameObject.AddComponent(); 177 | marker.root = go.transform; 178 | } 179 | } 180 | return obj; 181 | 182 | } 183 | 184 | public static UnityEngine.Object InstantiateOPRP(Func orig, UnityEngine.Object original, Vector3 position, Quaternion rotation, Transform parent) 185 | { 186 | var obj = orig(original, position, rotation, parent); 187 | if (obj != null && obj is GameObject) 188 | { 189 | var go = (GameObject)obj; 190 | // find all colliders, and add root markers to them 191 | foreach (Collider collider in go.GetComponentsInChildren()) 192 | { 193 | // if has root marker, skip 194 | if (collider.gameObject.GetComponent() != null) 195 | { 196 | continue; 197 | } 198 | RootMarker marker = collider.gameObject.AddComponent(); 199 | marker.root = go.transform; 200 | } 201 | } 202 | return obj; 203 | 204 | } 205 | 206 | */ 207 | 208 | private static void StartOfRound_Start(On.StartOfRound.orig_Start orig, StartOfRound self) 209 | { 210 | orig(self); 211 | 212 | // remove other dingi, so people stop complaining about non eba dingusses 213 | 214 | if(NetworkConfig.Instance != null && NetworkConfig.Instance.disableOverlappingModContentNetVar.Value) 215 | { 216 | foreach (SelectableLevel level in self.levels) 217 | { 218 | level.spawnableScrap.RemoveAll((scrap) => scrap.spawnableItem.name == "dingus"); 219 | } 220 | 221 | self.allItemsList.itemsList.RemoveAll((item) => item.name == "dingus"); 222 | } 223 | } 224 | 225 | private static void PlayerControllerB_SetSpecialGrabAnimationBool(On.GameNetcodeStuff.PlayerControllerB.orig_SetSpecialGrabAnimationBool orig, GameNetcodeStuff.PlayerControllerB self, bool setTrue, GrabbableObject currentItem) 226 | { 227 | if (currentItem == null) 228 | { 229 | currentItem = self.currentlyGrabbingObject; 230 | } 231 | if (currentItem != null && currentItem.itemProperties.grabAnim == "none") 232 | { 233 | //no animation!!! 234 | return; 235 | } 236 | orig(self, setTrue, currentItem); 237 | } 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /LethalThings/Patches/Patches.cs: -------------------------------------------------------------------------------- 1 | using LethalLib.Modules; 2 | using LethalThings.MonoBehaviours; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Unity.Netcode; 7 | 8 | namespace LethalThings.Patches 9 | { 10 | public class Patches 11 | { 12 | public static void Load() 13 | { 14 | 15 | SaveData.Init(); 16 | PowerOutletStun.Load(); 17 | Miscellaneous.Load(); 18 | 19 | PouchyBelt.Initialize(); 20 | HandheldRadar.Load(); 21 | 22 | HackingTool.Load(); 23 | FlareController.Init(); 24 | DecalRandomizer.Init(); 25 | Dart.Init(); 26 | FatalitiesSign.Init(); 27 | GremlinEnergy.Init(); 28 | Arson.Init(); 29 | MaggieSpawner.Init(); 30 | ForcedPing.Init(); 31 | ThrowableNoisemaker.Init(); 32 | 33 | 34 | Debug.Load(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LethalThings/Patches/PowerOutletStun.cs: -------------------------------------------------------------------------------- 1 | using LethalThings.MonoBehaviours; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Unity.Netcode; 6 | using UnityEngine; 7 | 8 | namespace LethalThings.Patches 9 | { 10 | public class PowerOutletStun 11 | { 12 | public static void Load() 13 | { 14 | // Funny power socket stun 15 | 16 | On.ItemCharger.ChargeItem += ItemCharger_ChargeItem; 17 | On.ItemCharger.Update += ItemCharger_Update; 18 | On.GameNetworkManager.Start += GameNetworkManager_Start; 19 | 20 | } 21 | 22 | 23 | private static void GameNetworkManager_Start(On.GameNetworkManager.orig_Start orig, GameNetworkManager self) 24 | { 25 | orig(self); 26 | 27 | List prefabs = self?.GetComponent()?.NetworkConfig?.Prefabs?.m_Prefabs; 28 | if (prefabs == null) return; 29 | 30 | foreach (var prefabContainer in prefabs) 31 | { 32 | GameObject prefab = prefabContainer?.Prefab; 33 | 34 | // Using this to search for bugged prefabs: 35 | /* 36 | if (prefab?.name == null) 37 | { 38 | Plugin.logger.LogWarning($"Found a potentially bugged prefab! Container [{prefabContainer}] | GameObject: [{prefab}]"); 39 | } 40 | */ 41 | 42 | if (prefab?.GetComponent()?.itemProperties?.isConductiveMetal != true) continue; 43 | 44 | Plugin.logger.LogInfo($"Found conductive scrap [{prefab.name}]"); 45 | 46 | var comp = prefab.AddComponent(); 47 | } 48 | } 49 | 50 | 51 | private static void ItemCharger_Update(On.ItemCharger.orig_Update orig, ItemCharger self) 52 | { 53 | orig(self); 54 | if (self.updateInterval == 0f) 55 | { 56 | if (GameNetworkManager.Instance != null && GameNetworkManager.Instance.localPlayerController != null) 57 | { 58 | self.triggerScript.interactable = GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer != null && (GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer.itemProperties.requiresBattery || GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer.itemProperties.isConductiveMetal); 59 | return; 60 | } 61 | } 62 | } 63 | 64 | private static void ItemCharger_ChargeItem(On.ItemCharger.orig_ChargeItem orig, ItemCharger self) 65 | { 66 | if (NetworkConfig.Instance != null && NetworkConfig.Instance.enableItemChargerElectrocutionNetVar.Value) 67 | { 68 | GrabbableObject currentlyHeldObjectServer = GameNetworkManager.Instance.localPlayerController.currentlyHeldObjectServer; 69 | if (currentlyHeldObjectServer == null) 70 | { 71 | return; 72 | } 73 | if (!currentlyHeldObjectServer.itemProperties.requiresBattery) 74 | { 75 | if (currentlyHeldObjectServer.itemProperties.isConductiveMetal) 76 | { 77 | currentlyHeldObjectServer.GetComponent().Electrocute(self); 78 | } 79 | return; 80 | } 81 | } 82 | orig(self); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /LethalThings/Patches/SaveData.cs: -------------------------------------------------------------------------------- 1 | using BepInEx.Configuration; 2 | using LethalThings.MonoBehaviours; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Numerics; 7 | using System.Text; 8 | using Unity.Netcode; 9 | using UnityEngine; 10 | using static UnityEngine.Rendering.HighDefinition.CameraSettings; 11 | using Vector3 = UnityEngine.Vector3; 12 | 13 | namespace LethalLib.Modules 14 | { 15 | // This is extremely poorly coded LMAO i don't care truly 16 | public class SaveData 17 | { 18 | 19 | public static void Init() 20 | { 21 | On.GameNetworkManager.ResetSavedGameValues += GameNetworkManager_ResetSavedGameValues; 22 | On.GameNetworkManager.SaveItemsInShip += GameNetworkManager_SaveItemsInShip; 23 | On.StartOfRound.LoadShipGrabbableItems += StartOfRound_LoadShipGrabbableItems; 24 | } 25 | 26 | public static List saveKeys = new List(); 27 | 28 | private static void StartOfRound_LoadShipGrabbableItems(On.StartOfRound.orig_LoadShipGrabbableItems orig, StartOfRound self) 29 | { 30 | orig(self); 31 | 32 | SaveableObject[] saveableObjects = UnityEngine.Object.FindObjectsOfType(); 33 | SaveableNetworkBehaviour[] saveableNetworkBehaviours = UnityEngine.Object.FindObjectsOfType(); 34 | 35 | foreach (var item in saveableObjects) 36 | { 37 | item.LoadObjectData(); 38 | } 39 | 40 | foreach (var item in saveableNetworkBehaviours) 41 | { 42 | item.LoadObjectData(); 43 | } 44 | 45 | if (ES3.KeyExists("LethalLibItemSaveKeys", GameNetworkManager.Instance.currentSaveFileName)) 46 | { 47 | saveKeys = ES3.Load>("LethalLibItemSaveKeys", GameNetworkManager.Instance.currentSaveFileName); 48 | } 49 | 50 | } 51 | 52 | private static void GameNetworkManager_SaveItemsInShip(On.GameNetworkManager.orig_SaveItemsInShip orig, GameNetworkManager self) 53 | { 54 | orig(self); 55 | 56 | SaveableObject[] saveableObjects = UnityEngine.Object.FindObjectsOfType(); 57 | SaveableNetworkBehaviour[] saveableNetworkBehaviours = UnityEngine.Object.FindObjectsOfType(); 58 | 59 | foreach (var item in saveableObjects) 60 | { 61 | item.SaveObjectData(); 62 | } 63 | 64 | foreach (var item in saveableNetworkBehaviours) 65 | { 66 | item.SaveObjectData(); 67 | } 68 | 69 | ES3.Save>("LethalLibItemSaveKeys", saveKeys, GameNetworkManager.Instance.currentSaveFileName); 70 | 71 | } 72 | 73 | private static void GameNetworkManager_ResetSavedGameValues(On.GameNetworkManager.orig_ResetSavedGameValues orig, GameNetworkManager self) 74 | { 75 | orig(self); 76 | 77 | // delete save keys 78 | foreach (var key in saveKeys) 79 | { 80 | ES3.DeleteKey(key, GameNetworkManager.Instance.currentSaveFileName); 81 | } 82 | 83 | saveKeys.Clear(); 84 | } 85 | 86 | public static void SaveObjectData(string key, T data, int objectId) 87 | { 88 | List values = new List(); 89 | 90 | if (ES3.KeyExists("LethalThingsSave_" + key, GameNetworkManager.Instance.currentSaveFileName)) 91 | { 92 | values = ES3.Load>("LethalThingsSave_" + key, GameNetworkManager.Instance.currentSaveFileName); 93 | } 94 | 95 | List objectIds = new List(); 96 | if (ES3.KeyExists("LethalThingsSave_objectIds_" + key, GameNetworkManager.Instance.currentSaveFileName)) 97 | { 98 | objectIds = ES3.Load>("LethalThingsSave_objectIds_" + key, GameNetworkManager.Instance.currentSaveFileName); 99 | } 100 | 101 | values.Add(data); 102 | objectIds.Add(objectId); 103 | 104 | if (!saveKeys.Contains("LethalThingsSave_" + key)) 105 | { 106 | saveKeys.Add("LethalThingsSave_" + key); 107 | } 108 | 109 | if (!saveKeys.Contains("LethalThingsSave_objectIds_" + key)) 110 | { 111 | saveKeys.Add("LethalThingsSave_objectIds_" + key); 112 | } 113 | 114 | 115 | 116 | ES3.Save>("LethalThingsSave_" + key, values, GameNetworkManager.Instance.currentSaveFileName); 117 | ES3.Save>("LethalThingsSave_objectIds_" + key, objectIds, GameNetworkManager.Instance.currentSaveFileName); 118 | } 119 | 120 | public static T LoadObjectData(string key, int objectId) 121 | { 122 | List values = new List(); 123 | 124 | if (ES3.KeyExists("LethalThingsSave_" + key, GameNetworkManager.Instance.currentSaveFileName)) 125 | { 126 | values = ES3.Load>("LethalThingsSave_" + key, GameNetworkManager.Instance.currentSaveFileName); 127 | } 128 | 129 | List objectIds = new List(); 130 | if (ES3.KeyExists("LethalThingsSave_objectIds_" + key, GameNetworkManager.Instance.currentSaveFileName)) 131 | { 132 | objectIds = ES3.Load>("LethalThingsSave_objectIds_" + key, GameNetworkManager.Instance.currentSaveFileName); 133 | } 134 | 135 | if (!saveKeys.Contains("LethalThingsSave_" + key)) 136 | { 137 | saveKeys.Add("LethalThingsSave_" + key); 138 | } 139 | 140 | if (!saveKeys.Contains("LethalThingsSave_objectIds_" + key)) 141 | { 142 | saveKeys.Add("LethalThingsSave_objectIds_" + key); 143 | } 144 | 145 | // check if index exists 146 | if (objectIds.Contains(objectId)) 147 | { 148 | int index = objectIds.IndexOf(objectId); 149 | return values[index]; 150 | } 151 | else 152 | { 153 | return default(T); 154 | } 155 | } 156 | 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /LethalThings/Plugin.cs: -------------------------------------------------------------------------------- 1 | using BepInEx; 2 | using System.Security.Permissions; 3 | using BepInEx.Logging; 4 | using BepInEx.Configuration; 5 | using LethalThings.MonoBehaviours; 6 | using UnityEngine; 7 | using System.Reflection; 8 | using System; 9 | using static UnityEngine.Rendering.HighDefinition.HDAdditionalCameraData; 10 | 11 | [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] 12 | namespace LethalThings 13 | { 14 | [BepInPlugin(ModGUID, ModName, ModVersion)] 15 | [BepInDependency(LethalLib.Plugin.ModGUID)] 16 | [BepInDependency(LethalCompanyInputUtils.PluginInfo.PLUGIN_GUID, BepInDependency.DependencyFlags.SoftDependency)] 17 | [BepInDependency("FlipMods.ReservedItemSlotCore", BepInDependency.DependencyFlags.SoftDependency)] 18 | public class Plugin : BaseUnityPlugin 19 | { 20 | public const string ModGUID = "evaisa.lethalthings"; 21 | public const string ModName = "LethalThings"; 22 | public const string ModVersion = "0.10.7"; 23 | 24 | public static ManualLogSource logger; 25 | public static ConfigFile config; 26 | 27 | public static bool devMode = false; 28 | 29 | public static PluginInfo pluginInfo; 30 | 31 | private void Awake() 32 | { 33 | logger = Logger; 34 | config = Config; 35 | pluginInfo = Info; 36 | 37 | // check lethallib version 38 | var version = BepInEx.Bootstrap.Chainloader.PluginInfos[LethalLib.Plugin.ModGUID].Metadata.Version; 39 | 40 | 41 | // check if major version is over 0 or minor verison is over 6 42 | if (version.Major > 0 || version.Minor > 11 || (version.Minor == 11 && version.Build >= 2)) 43 | { 44 | logger.LogInfo("LethalLib version is " + version.ToString() + ", which is compatible with LethalThings 0.9.0+"); 45 | } 46 | else 47 | { 48 | logger.LogError("LethalLib version is " + version.ToString() + ", which is not compatible with LethalThings 0.9.0+"); 49 | logger.LogError("Please update LethalLib to version 0.11.2 or newer"); 50 | return; 51 | } 52 | 53 | if (BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("com.rune580.LethalCompanyInputUtils")) 54 | { 55 | var iuVersion = BepInEx.Bootstrap.Chainloader.PluginInfos["com.rune580.LethalCompanyInputUtils"].Metadata.Version; 56 | 57 | if (iuVersion.Major > 0 || iuVersion.Minor >= 7) 58 | { 59 | logger.LogInfo("[Optional dependency] LethalCompanyInputUtils version is " + iuVersion.ToString() + ", which is compatible with LethalThings 0.10.5+"); 60 | } 61 | else 62 | { 63 | logger.LogError("[Optional dependency] LethalCompanyInputUtils version is " + iuVersion.ToString() + ", which is not compatible with LethalThings 0.10.5+"); 64 | logger.LogError("Please update LethalCompanyInputUtils to version 0.4.3 or newer"); 65 | return; 66 | } 67 | } 68 | 69 | if (BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("FlipMods.ReservedItemSlotCore")) 70 | { 71 | // FlipMods-ReservedItemSlotCore-1.6.6 72 | var risVersion = BepInEx.Bootstrap.Chainloader.PluginInfos["FlipMods.ReservedItemSlotCore"].Metadata.Version; 73 | 74 | if (risVersion.Major > 1 || (risVersion.Major > 0 && ((risVersion.Minor == 6 && risVersion.Build >= 6) || risVersion.Minor > 6))) 75 | { 76 | logger.LogInfo("[Compatibility] ReservedItemSlotCore version is " + risVersion.ToString() + ", which is compatible with LethalThings 0.8.0+"); 77 | } 78 | else 79 | { 80 | logger.LogError("[Compatibility] ReservedItemSlotCore version is " + risVersion.ToString() + ", which is not compatible with LethalThings 0.8.0+"); 81 | logger.LogError("Please update ReservedItemSlotCore to version 1.6.6 or newer"); 82 | return; 83 | } 84 | } 85 | 86 | 87 | 88 | Utilities.Init(); 89 | LethalThings.NetworkConfig.Load(); 90 | Content.Init(); 91 | Patches.Patches.Load(); 92 | 93 | if (InputCompat.Enabled) 94 | InputCompat.Init(); 95 | 96 | Logger.LogInfo("LethalThings loaded successfully!!!"); 97 | 98 | } 99 | 100 | 101 | 102 | /* 103 | static bool first = true; 104 | 105 | private void RoundManager_Awake(On.RoundManager.orig_Awake orig, RoundManager self) 106 | { 107 | if (first) 108 | { 109 | var dungeon = self.dungeonFlowTypes[0]; 110 | 111 | // clone the dungeon flow 112 | var newDungeon = Instantiate(dungeon); 113 | 114 | newDungeon.name = "LethalThingsDungeon"; 115 | 116 | AudioClip audioClip = Content.MainAssets.LoadAsset("Assets/Custom/LethalThings/brap.mp3"); 117 | 118 | LethalLib.Modules.Dungeon.AddDungeon(newDungeon, 600, LethalLib.Modules.Levels.LevelTypes.All, audioClip); 119 | } 120 | orig(self); 121 | }*/ 122 | } 123 | } -------------------------------------------------------------------------------- /LethalThings/Thunderstore/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # LethalThings 0.10.7 2 | **Improvements** 3 | - Potential fix for ammo resetting upon loading save. 4 | - Thanks PlagueTR [PR #81](https://github.com/EvaisaDev/LethalThings/pull/81) 5 | 6 | # LethalThings 0.10.6 7 | **Improvements** 8 | - Better compatibility for Utility Belt, should cause less probably with some other mods probably. 9 | 10 | # LethalThings 0.10.5 11 | - Recompiled for latest version. 12 | 13 | # LethalThings 0.10.4 14 | **Bugfixes** 15 | - Maybe fixed issue with remote radar by making the code way worse. (idc) 16 | 17 | # LethalThings 0.10.3 18 | **Bugfixes** 19 | - Mod works on v50 now i think. 20 | 21 | # LethalThings 0.10.2 22 | **Bugfixes** 23 | - Unbroke the remote radar. 24 | 25 | # LethalThings 0.10.1 26 | **Bugfixes** 27 | - Maxwell can no longer explode when loading a save. 28 | - Fixed null reference error when other mods register network prefabs incorrectly or something. (Thanks DBJ) 29 | - Fixed error when dying from gremlin energy. 30 | 31 | (probably other things i forgor about) 32 | 33 | # LethalThings 0.10.0 34 | **Bugfixes** 35 | - Zapgun laser is no longer permanently active. 36 | - Radar camera is only active if any player is holding Remote Radar and said radar is turned on. 37 | 38 | # LethalThings 0.9.4 39 | **Bugfixes** 40 | - Pinger was breaking the escape menu while turned on. 41 | - Pinger ping animation was not playing. 42 | 43 | # Lethal Things 0.9.3 44 | - Updated dependency version of LethalLib to 0.11.2 45 | - If you want to LethalThings to work please update LethalLib to that version. 46 | 47 | # Lethal Things 0.9.2 48 | - Updated used NetcodePatcher version to v3.3.3 49 | - Removed unfinished content from config, accidental leak moment lmao 50 | 51 | # Lethal Things 0.9.1 52 | **Bugfixes** 53 | - Fixed crash to desktop on launch, caused by NetcodePatcher update. 54 | 55 | # Lethal Things 0.9.0 56 | **Content** 57 | - Added Shop Item: Pinger 58 | - Added Scrap: Gnarpy Plush 59 | 60 | **Systems** 61 | - Completely rewrite of Content Loader and Config system. 62 | - Config files are now synced between host and client. 63 | - Changed how utility belt adds slots for potential compatibility improvement. 64 | 65 | **Bugfixes** 66 | - Lethal Things content should now spawn on modded moons 67 | - Boomba improvements. 68 | - Power outlet stun damage config is now working. 69 | - Added null check to tracking point which should fix one of the dartboard errors. 70 | - Fixed flare desync 71 | - Rocket launcher laser turns off when pocketed. 72 | - Evil maxwell desync. 73 | - Flare gun client aim issue. 74 | - Remote radar was able to switch target while turned off. 75 | - Toy hammer was broken because of lethal company v47 update. 76 | - Darts are no longer pingable while held. 77 | - Maxwell becomes evil sometimes when loading a save :( 78 | 79 | **Changes** 80 | - Toyhammer is now a scrap item by default 81 | - Added config option to add Toyhammer to store. 82 | - Added config option to make Toyhammer spawn as scrap. 83 | - Cookie is now throwable. 84 | - Note: Batteries may spontaneously combust 85 | 86 | # Lethal Things 0.8.8 87 | - Glizzy is no longer called "Training Manual" (idk how the heck that happened because it was called glizzy before.) 88 | - Custom items / scraps no longer receive decals from spraypaint, in order to fix a transparency bug. 89 | - Added version check for Reserved Item Slots compatibility, if it is installed, please make sure you are running version 1.6.6 or newer. 90 | 91 | # Lethal Things 0.8.0 - 0.8.7 92 | **Features** 93 | - Crimas vibes!!! 94 | - Dirty stinky arsons can be showered. 95 | 96 | **Items** 97 | - Added Scrap: Gremlin Energy Drink 98 | - Added Scrap: Revolver 99 | - Added Item: Flaregun 100 | - Attracts certain enemies. 101 | - Flares are automatically pinged by nearby players. 102 | - Ammo can be bought from store. 103 | 104 | **Decor** 105 | - Added Decor: Dartboard 106 | - Usable dartboard for passing time. 107 | 108 | **Improvements** 109 | - Utility belt slot distance and positioning was improved 110 | - Rocket launcher now has a tooltip for "Fire : [LMB]" 111 | - Maxwell no longer weights 42 lbs 112 | - Removed conductiveness of various items 113 | - Improved weight of various items 114 | - Removed red tint from rocket launcher lights. 115 | - Custom items should no longer phase through the floor when ship takes off or lands. 116 | - Added version check for InputUtils, in case it is installed and the wrong version is present. 117 | 118 | **Bugfixes** 119 | - Hämis plush not longer glitches out price screen due to ä character. 120 | - Rocket launcher lights no longer break when multiple rocket launchers are present. 121 | - Rocket launcher ammo is now saved properly with the game and synced between players. 122 | - Arson no longer kills items in other player's hotbars when she munchy. 123 | - Fakewell is not synchronized between clients 124 | - Fakewell can no longer be activated multiple times. 125 | - Electrocution config setting now works. 126 | - Rocket launcher aim direction is no longer wrong when shot from clients. 127 | - Fatalities sign now shows the correct value, and is saved properly between games. 128 | - Decor items now show up in shop decor rotation and are no longer always buyable. 129 | - Fixed bug with Hacking Tool not initializing properly, caused by a change for preventing item switching. 130 | 131 | **Compatibility** 132 | - Quickswap mods not longer switch items when using hacking tool. 133 | - Utility belt should now work properly alongside the reserved item slot mods. 134 | - Added support for InputUtils, which when installed allows you to bind belt slots to hotkeys. -------------------------------------------------------------------------------- /LethalThings/Thunderstore/README.md: -------------------------------------------------------------------------------- 1 | # LethalThings 2 | **A content mod for Lethal Company that adds a ton of content!** 3 | *Features list at bottom of page!* 4 | 5 | ## Credits: 6 | - [Evaisa](https://evaisa.dev/) 7 | - Making the mod and api and everything. 8 | - Hi I'm eba. 9 | - [Bobilka](https://www.artstation.com/bobilka) 10 | - Models 11 | - Ideas 12 | - Textures 13 | - Testing 14 | - Antlers 15 | - Models 16 | - Cookie model 17 | - Testing 18 | - LocalHyena 19 | - Models 20 | - Textures 21 | - [Jek Korpen](https://twitter.com/Jek_Korpen) 22 | - Nikki (Cookie) character design. 23 | - Regretevator (Roblox) 24 | - Gnarpy origin (I think) 25 | - [horinhorin2006](https://twitter.com/horinhorin2006) 26 | - Art which was used as a reference for the gnarpy model. 27 | - [MrDrNose - EternityDev](https://mrdrnose.itch.io/) 28 | - The maxwell song, and the evil maxwell bones, originate from the game [Voices Of The Void](https://mrdrnose.itch.io/votv) (amazing game i recommend checking it out.) 29 | - [Nolla Games](https://nollagames.com/) 30 | - Toimari / Hämis characters. 31 | 32 | ## Scrap items 33 | - Plushy named Arson 34 | - May set your house on fire if you displease her. 35 | ![Arson](https://i.imgur.com/OnCGKcl.png) 36 | 37 | - Plushy named arson (Dirty) 38 | - Ew stinky 39 | ![Arson](https://i.imgur.com/Buk3lQ2.png) 40 | 41 | - Toimari plushy 42 | - Noita reference 43 | ![Toimari](https://i.imgur.com/STXtpHc.png) 44 | 45 | - Hämis plushy 46 | - Very soft. 47 | - May nibble you a little. 48 | ![Hämis](https://i.imgur.com/rM41HbK.png) 49 | 50 | - Cookie Fumo 51 | - Says strange things when you squeeze her. 52 | - (Nikki) the character by Jek Korpen 53 | ![Cookie](https://i.imgur.com/aMiji2H.png) 54 | 55 | - Maxwell 56 | - Purrs loudly. 57 | - Meows. 58 | - Plays a silly little song. 59 | - Does a silly little dance. 60 | ![Maxwell](https://i.imgur.com/nccQTQy.png) 61 | 62 | - Glizzy 63 | - Can be thrown at colleagues. 64 | ![Glizzy](https://i.imgur.com/OQUi2hq.png) 65 | 66 | - Revolver 67 | - Pew pew!! 68 | ![Revolver](https://i.imgur.com/V4YnhFe.png) 69 | 70 | - Gremlin Energy Drink 71 | - 100% lethal!! 72 | ![GremlinEnergy](https://i.imgur.com/A0lzXY0.png) 73 | 74 | - Toy Hammer 75 | - Good for bonking unruly employees. 76 | - We are not responsible for any fatalities related to this item. 77 | - Clowns are known to love this one. 78 | ![Hammer](https://i.imgur.com/UDtb5GC.png) 79 | 80 | - Gnarpy Plush 81 | - Some kind of alien critter 82 | ![GremlinEnergy](https://i.imgur.com/t8Zd7uE.png) 83 | 84 | ## Store items 85 | 86 | - Rocket Launcher 87 | - For if you want to go on the offense. 88 | - Only has 4 shots. 89 | - Highly fatal to team members. 90 | ![RocketLauncher](https://i.imgur.com/lzDTH3E.png) 91 | 92 | - Utility Belt 93 | - Additional storage for scrap. 94 | - +10 charisma. 95 | ![Belt](https://i.imgur.com/Jlt0Hmi.png) 96 | 97 | - Remote Radar 98 | - Access the ship radar system remotely. 99 | - Very limited battery life. 100 | - May piss off anyone actively watching the radar terminal. 101 | ![RemoteRadar](https://i.imgur.com/7cdQeNm.png) 102 | 103 | - Hacking Tool 104 | - Unlock gates, disable turrets and mines, from up close. 105 | - Requires basic math skills. 106 | ![HackingTool](https://cdn.discordapp.com/attachments/511206402493251586/1180890040990171186/g-3dUIk1R.png) 107 | 108 | - Flare gun 109 | - Attracts certain enemies. 110 | - Flares are automatically pinged by employees. 111 | - Ammo can be bought from the store. 112 | ![Flaregun](https://i.imgur.com/8NTZyQ3.png) 113 | 114 | - Pinger 115 | - Sends a location ping to your nearby colleagues. 116 | ![Pinger](https://i.imgur.com/C6NxvEY.png) 117 | 118 | ## Decor 119 | - Small/Large Rug 120 | - Improve your living space! 121 | ![Rugs](https://i.imgur.com/JXXXeoW.png) 122 | 123 | - Fatalities Sign 124 | - A sign which reflects the efficacy of your crew. 125 | - Automatically updates. 126 | ![FatalitiesSign](https://cdn.discordapp.com/attachments/511206402493251586/1180888999951355985/sSk78gIYS.png) 127 | 128 | - Dartboard 129 | - Usable dartboard for passing time. 130 | - Darts are included and be returned if lost. 131 | ![Dartboard](https://i.imgur.com/Gs7iiu5.png) 132 | 133 | ## Enemies 134 | - Boomba 135 | - A cute little robot. 136 | ![Boomba](https://i.imgur.com/HbKHfJU.png) 137 | 138 | ## Map Hazards 139 | - Teleporter Trap 140 | - Teleports you to a random place in the facility when you step on it. 141 | ![TeleporterTrap](https://i.imgur.com/BWPRBwW.png) 142 | 143 | ## Miscelaneous 144 | - Improved Item Charger. 145 | - Stuffing conductive items in the charger will now electrocute you. 146 | -------------------------------------------------------------------------------- /LethalThings/Thunderstore/Thunderstore.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvaisaDev/LethalThings/66b5e1137047c5aa0ba7e02d56425218f187dceb/LethalThings/Thunderstore/Thunderstore.zip -------------------------------------------------------------------------------- /LethalThings/Thunderstore/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvaisaDev/LethalThings/66b5e1137047c5aa0ba7e02d56425218f187dceb/LethalThings/Thunderstore/icon.png -------------------------------------------------------------------------------- /LethalThings/Thunderstore/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LethalThings", 3 | "author": "Evaisa", 4 | "version_number": "0.10.7", 5 | "website_url": "https://github.com/EvaisaDev/LethalThings", 6 | "description": "Adds 11 scrap, 6 store items, 1 enemy, 4 decor, 1 map hazard, and 1 game mechanic.", 7 | "dependencies": [ 8 | "BepInEx-BepInExPack-5.4.2100", 9 | "Evaisa-HookGenPatcher-0.0.5", 10 | "Evaisa-LethalLib-0.11.2" 11 | ] 12 | } -------------------------------------------------------------------------------- /LethalThings/Thunderstore/plugins/LethalThings/LethalThings.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvaisaDev/LethalThings/66b5e1137047c5aa0ba7e02d56425218f187dceb/LethalThings/Thunderstore/plugins/LethalThings/LethalThings.dll -------------------------------------------------------------------------------- /LethalThings/Thunderstore/plugins/LethalThings/lethalthings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvaisaDev/LethalThings/66b5e1137047c5aa0ba7e02d56425218f187dceb/LethalThings/Thunderstore/plugins/LethalThings/lethalthings -------------------------------------------------------------------------------- /LethalThings/Utilities.cs: -------------------------------------------------------------------------------- 1 | using GameNetcodeStuff; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using Unity.Netcode; 9 | using UnityEngine; 10 | using UnityEngine.SceneManagement; 11 | 12 | namespace LethalThings 13 | { 14 | public class Utilities 15 | { 16 | private static Dictionary _masksByLayer; 17 | public static void Init() 18 | { 19 | GenerateLayerMap(); 20 | } 21 | 22 | public static void GenerateLayerMap() 23 | { 24 | _masksByLayer = new Dictionary(); 25 | for (int i = 0; i < 32; i++) 26 | { 27 | int mask = 0; 28 | for (int j = 0; j < 32; j++) 29 | { 30 | if (!Physics.GetIgnoreLayerCollision(i, j)) 31 | { 32 | mask |= 1 << j; 33 | } 34 | } 35 | _masksByLayer.Add(i, mask); 36 | } 37 | } 38 | 39 | public static Transform TryFindRoot(Transform child) 40 | { 41 | // iterate upwards until we find a NetworkObject 42 | Transform current = child; 43 | while (current != null) 44 | { 45 | if (current.GetComponent() != null) 46 | { 47 | return current; 48 | } 49 | current = current.transform.parent; 50 | } 51 | return null; 52 | } 53 | public static int MaskForLayer(int layer) 54 | { 55 | return _masksByLayer[layer]; 56 | } 57 | 58 | public static void LoadPrefab(string name, Vector3 position) 59 | { 60 | if (Content.Prefabs.ContainsKey(name)) 61 | { 62 | Plugin.logger.LogInfo($"Loading prefab {name}"); 63 | var item = UnityEngine.Object.Instantiate(Content.Prefabs[name], position, Quaternion.identity); 64 | item.GetComponent().Spawn(); 65 | } 66 | else 67 | { 68 | Plugin.logger.LogWarning($"Prefab {name} not found!"); 69 | } 70 | } 71 | 72 | 73 | 74 | public static void TeleportPlayer(int playerObj, Vector3 teleportPos) 75 | { 76 | PlayerControllerB playerControllerB = StartOfRound.Instance.allPlayerScripts[playerObj]; 77 | // no item dropping woooo 78 | //playerControllerB.DropAllHeldItems(); 79 | if ((bool)UnityEngine.Object.FindObjectOfType()) 80 | { 81 | UnityEngine.Object.FindObjectOfType().audioPresets[2].ChangeAudioReverbForPlayer(playerControllerB); 82 | } 83 | playerControllerB.isInElevator = false; 84 | playerControllerB.isInHangarShipRoom = false; 85 | playerControllerB.isInsideFactory = true; 86 | playerControllerB.averageVelocity = 0f; 87 | playerControllerB.velocityLastFrame = Vector3.zero; 88 | StartOfRound.Instance.allPlayerScripts[playerObj].TeleportPlayer(teleportPos); 89 | StartOfRound.Instance.allPlayerScripts[playerObj].beamOutParticle.Play(); 90 | if (playerControllerB == GameNetworkManager.Instance.localPlayerController) 91 | { 92 | HUDManager.Instance.ShakeCamera(ScreenShakeType.Big); 93 | } 94 | } 95 | 96 | public static IEnumerator TeleportPlayerBody(int playerObj, Vector3 teleportPosition) 97 | { 98 | float startTime = Time.realtimeSinceStartup; 99 | yield return new WaitUntil(() => StartOfRound.Instance.allPlayerScripts[playerObj].deadBody != null || Time.realtimeSinceStartup - startTime > 2f); 100 | if (StartOfRound.Instance.inShipPhase || SceneManager.sceneCount <= 1) 101 | { 102 | yield break; 103 | } 104 | DeadBodyInfo deadBody = StartOfRound.Instance.allPlayerScripts[playerObj].deadBody; 105 | if (deadBody != null) 106 | { 107 | deadBody.attachedTo = null; 108 | deadBody.attachedLimb = null; 109 | deadBody.secondaryAttachedLimb = null; 110 | deadBody.secondaryAttachedTo = null; 111 | if (deadBody.grabBodyObject != null && deadBody.grabBodyObject.isHeld && deadBody.grabBodyObject.playerHeldBy != null) 112 | { 113 | deadBody.grabBodyObject.playerHeldBy.DropAllHeldItems(); 114 | } 115 | deadBody.isInShip = false; 116 | deadBody.parentedToShip = false; 117 | deadBody.transform.SetParent(null, worldPositionStays: true); 118 | deadBody.SetRagdollPositionSafely(teleportPosition, disableSpecialEffects: true); 119 | } 120 | } 121 | 122 | public static void TeleportEnemy(EnemyAI enemy, Vector3 teleportPos) 123 | { 124 | enemy.serverPosition = teleportPos; 125 | enemy.transform.position = teleportPos; 126 | enemy.agent.Warp(teleportPos); 127 | enemy.SyncPositionToClients(); 128 | } 129 | 130 | public static void CreateExplosion(Vector3 explosionPosition, bool spawnExplosionEffect = false, int damage = 20, float minDamageRange = 0f, float maxDamageRange = 1f, int enemyHitForce = 6, CauseOfDeath causeOfDeath = CauseOfDeath.Blast, PlayerControllerB attacker = null) 131 | { 132 | Debug.Log("Spawning explosion at pos: {explosionPosition}"); 133 | 134 | Transform holder = null; 135 | 136 | if (RoundManager.Instance != null && RoundManager.Instance.mapPropsContainer != null && RoundManager.Instance.mapPropsContainer.transform != null) 137 | { 138 | holder = RoundManager.Instance.mapPropsContainer.transform; 139 | } 140 | 141 | if (spawnExplosionEffect) 142 | { 143 | 144 | 145 | UnityEngine.Object.Instantiate(StartOfRound.Instance.explosionPrefab, explosionPosition, Quaternion.Euler(-90f, 0f, 0f), holder).SetActive(value: true); 146 | } 147 | 148 | float num = Vector3.Distance(GameNetworkManager.Instance.localPlayerController.transform.position, explosionPosition); 149 | if (num < 14f) 150 | { 151 | HUDManager.Instance.ShakeCamera(ScreenShakeType.Big); 152 | } 153 | else if (num < 25f) 154 | { 155 | HUDManager.Instance.ShakeCamera(ScreenShakeType.Small); 156 | } 157 | 158 | Collider[] array = Physics.OverlapSphere(explosionPosition, maxDamageRange, 2621448, QueryTriggerInteraction.Collide); 159 | PlayerControllerB playerControllerB = null; 160 | for (int i = 0; i < array.Length; i++) 161 | { 162 | float num2 = Vector3.Distance(explosionPosition, array[i].transform.position); 163 | if (num2 > 4f && Physics.Linecast(explosionPosition, array[i].transform.position + Vector3.up * 0.3f, 256, QueryTriggerInteraction.Ignore)) 164 | { 165 | continue; 166 | } 167 | 168 | if (array[i].gameObject.layer == 3) 169 | { 170 | playerControllerB = array[i].gameObject.GetComponent(); 171 | if (playerControllerB != null && playerControllerB.IsOwner) 172 | { 173 | // calculate damage based on distance, so if player is minDamageRange or closer, they take full damage 174 | // if player is maxDamageRange or further, they take no damage 175 | // distance is num2 176 | float damageMultiplier = 1f - Mathf.Clamp01((num2 - minDamageRange) / (maxDamageRange - minDamageRange)); 177 | 178 | playerControllerB.DamagePlayer((int)(damage * damageMultiplier), causeOfDeath: causeOfDeath); 179 | } 180 | } 181 | else if (array[i].gameObject.layer == 21) 182 | { 183 | Landmine componentInChildren = array[i].gameObject.GetComponentInChildren(); 184 | if (componentInChildren != null && !componentInChildren.hasExploded && num2 < 6f) 185 | { 186 | Debug.Log("Setting off other mine"); 187 | componentInChildren.StartCoroutine(componentInChildren.TriggerOtherMineDelayed(componentInChildren)); 188 | } 189 | } 190 | else if (array[i].gameObject.layer == 19) 191 | { 192 | EnemyAICollisionDetect componentInChildren2 = array[i].gameObject.GetComponentInChildren(); 193 | if (componentInChildren2 != null && componentInChildren2.mainScript.IsOwner && num2 < 4.5f) 194 | { 195 | componentInChildren2.mainScript.HitEnemyOnLocalClient(enemyHitForce, playerWhoHit: attacker); 196 | } 197 | } 198 | } 199 | 200 | int num3 = ~LayerMask.GetMask("Room"); 201 | num3 = ~LayerMask.GetMask("Colliders"); 202 | array = Physics.OverlapSphere(explosionPosition, 10f, num3); 203 | for (int j = 0; j < array.Length; j++) 204 | { 205 | Rigidbody component = array[j].GetComponent(); 206 | if (component != null) 207 | { 208 | component.AddExplosionForce(70f, explosionPosition, 10f); 209 | } 210 | } 211 | } 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LethalThings 2 | **A content mod for Lethal Company** 3 | *List of included content below* 4 | 5 | ## Scrap items 6 | - Plushy named Arson 7 | - May set your house on fire if you displease her. 8 | ![Arson](https://i.imgur.com/OnCGKcl.png) 9 | 10 | - Plushy named arson (Dirty) 11 | - Ew stinky 12 | ![Arson](https://i.imgur.com/Buk3lQ2.png) 13 | 14 | - Toimari plushy 15 | - Noita reference 16 | ![Toimari](https://i.imgur.com/STXtpHc.png) 17 | 18 | - Hämis plushy 19 | - Very soft. 20 | - May nibble you a little. 21 | ![Hämis](https://i.imgur.com/rM41HbK.png) 22 | 23 | - Cookie Fumo 24 | - Says strange things when you squeeze her. 25 | ![Cookie](https://i.imgur.com/aMiji2H.png) 26 | 27 | - Maxwell 28 | - Purrs loudly. 29 | - Meows. 30 | - Plays a silly little song. 31 | - Does a silly little dance. 32 | ![Maxwell](https://i.imgur.com/nccQTQy.png) 33 | 34 | ## Store items 35 | - Toy Hammer 36 | - Good for bonking unruly employees. 37 | - We are not responsible for any fatalities related to this item. 38 | - Clowns are known to love this one. 39 | ![Hammer](https://i.imgur.com/UDtb5GC.png) 40 | 41 | - Rocket Launcher 42 | - For if you want to go on the offense. 43 | - Only has 4 shots. 44 | - Highly fatal to team members. 45 | ![RocketLauncher](https://i.imgur.com/lzDTH3E.png) 46 | 47 | - Utility Belt 48 | - Additional storage for scrap. 49 | - +10 charisma. 50 | ![Belt](https://i.imgur.com/Jlt0Hmi.png) 51 | 52 | - Remote Radar 53 | - Access the ship radar system remotely. 54 | - Very limited battery life. 55 | - May piss off anyone actively watching the radar terminal. 56 | ![RemoteRadar](https://i.imgur.com/7cdQeNm.png) 57 | 58 | - Hacking Tool 59 | - Unlock gates, disable turrets and mines, from up close. 60 | - Requires basic math skills. 61 | ![HackingTool](https://cdn.discordapp.com/attachments/511206402493251586/1180890040990171186/g-3dUIk1R.png) 62 | 63 | ## Decor 64 | - Small/Large Rug 65 | - Improve your living space! 66 | ![Rugs](https://i.imgur.com/JXXXeoW.png) 67 | 68 | - Fatalities Sign 69 | - A sign which reflects the efficacity of your crew. 70 | - Automatically updates. 71 | ![FatalitiesSign](https://cdn.discordapp.com/attachments/511206402493251586/1180888999951355985/sSk78gIYS.png) 72 | 73 | ## Enemies 74 | - Boomba 75 | - A cute little robot. 76 | ![Boomba](https://i.imgur.com/HbKHfJU.png) 77 | 78 | ## Map Hazards 79 | - Teleporter Trap 80 | - Teleports you to a random place in the facility when you step on it. 81 | ![TeleporterTrap](https://i.imgur.com/BWPRBwW.png) 82 | 83 | ## Miscelaneous 84 | - Improved Item Charger. 85 | - Stuffing conductive items in the charger will now electrocute you. 86 | 87 | ## Credits: 88 | - [Bobilka](https://bsky.app/profile/bobilka.bsky.social) 89 | - Models 90 | - Ideas 91 | - Textures 92 | - Testing 93 | - Antlers 94 | - Models 95 | - Cookie 96 | - LocalHyena 97 | - Models 98 | - Textures 99 | 100 | # Latest Changes 101 | - Updated maxwell (funny) 102 | - Added audio volume config file. 103 | - Fixed Boomba map dot 104 | 105 | --------------------------------------------------------------------------------