using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NightTerrors")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d5123f41927d720c0452d1c2014ee6686a47d44b")] [assembly: AssemblyProduct("NightTerrors")] [assembly: AssemblyTitle("NightTerrors")] [assembly: AssemblyVersion("1.0.0.0")] namespace NightTerrors; public static class NightTerrorsEvent { public static bool IsActive; public static Scenario CurrentScenario; public static Vector3 ChosenDestination; public static HashSet AlivePeers = new HashSet(); public static void Begin() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) if (IsActive) { return; } CurrentScenario = ScenarioSelector.Choose(NightTerrorsPlugin.CfgScenarioWeights.Value); ChosenDestination = FindRandomPosition(); if (ChosenDestination == Vector3.zero) { NightTerrorsPlugin.Log.LogWarning((object)"NightTerrors: could not find a valid teleport position — aborting."); return; } AlivePeers.Clear(); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_uid != 0L) { AlivePeers.Add(peer.m_uid); } } if (AlivePeers.Count == 0) { NightTerrorsPlugin.Log.LogWarning((object)"NightTerrors: no valid peers — aborting."); return; } IsActive = true; NightTerrorsPlugin.Log.LogInfo((object)$"NightTerrors: event starting — scenario={CurrentScenario}, peers={AlivePeers.Count}, dest={ChosenDestination}"); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_SaveInventory", Array.Empty()); ((MonoBehaviour)NightTerrorsPlugin.Instance).StartCoroutine(EventSequence()); } private static IEnumerator EventSequence() { yield return (object)new WaitForSeconds(1.5f); string[] array = ((CurrentScenario == Scenario.DifferentEquipment) ? ScenarioSelector.PickKit() : new string[0]); ZPackage val = new ZPackage(); val.Write((int)CurrentScenario); val.Write(NightTerrorsPlugin.CfgFriendlyFire.Value); val.Write(NightTerrorsPlugin.CfgMonsterCount.Value); val.Write(array.Length); string[] array2 = array; foreach (string text in array2) { val.Write(text); } Announce("YOU HAVE BEEN TAKEN", (MessageType)2); ApplyRandomWeather(); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_EventStart", new object[1] { val }); foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_uid != 0L) { TeleportPeer(peer, ChosenDestination); } } if (NightTerrorsPlugin.CfgSpawnMonsters.Value) { SpawnMonsters(ChosenDestination, NightTerrorsPlugin.CfgMonsterCount.Value); } yield return (object)new WaitForSeconds((float)NightTerrorsPlugin.CfgEventDuration.Value); if (IsActive) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: time limit reached — ending event."); End(); } } public static void OnPlayerDied(long peerUID) { if (IsActive) { AlivePeers.Remove(peerUID); NightTerrorsPlugin.Log.LogInfo((object)$"NightTerrors: {AlivePeers.Count} players still alive."); HashSet connected = new HashSet(from p in ZNet.instance.GetPeers() select p.m_uid); AlivePeers.RemoveWhere((long uid) => !connected.Contains(uid)); if (AlivePeers.Count == 0) { End(); } } } public static void End() { if (!IsActive) { return; } IsActive = false; NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: ending event."); Announce("The darkness claims you.", (MessageType)2); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_SetWeather", new object[1] { "" }); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_RestoreInventory", Array.Empty()); foreach (long alivePeer in AlivePeers) { NightTerrorsPlugin.Log.LogInfo((object)$"NightTerrors: killing survivor {alivePeer}."); ZRoutedRpc.instance.InvokeRoutedRPC(alivePeer, "NightTerrors_KillSurvivor", Array.Empty()); } ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_EventEnd", Array.Empty()); AlivePeers.Clear(); } private static void TeleportPeer(ZNetPeer peer, Vector3 pos) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) ZRoutedRpc.instance.InvokeRoutedRPC(peer.m_uid, "RPC_TeleportPlayer", new object[3] { pos, Quaternion.identity, true }); } private static Vector3 FindRandomPosition() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) float waterLevel = ZoneSystem.instance.m_waterLevel; for (int i = 0; i < 100; i++) { float num = Random.Range(-10000f, 10000f); float num2 = Random.Range(-10000f, 10000f); float height = WorldGenerator.instance.GetHeight(num, num2); if (height > waterLevel - 20f) { return new Vector3(num, Mathf.Max(height, waterLevel) + 1f, num2); } } NightTerrorsPlugin.Log.LogError((object)"NightTerrors: FindRandomPosition failed after 100 attempts."); return Vector3.zero; } private static void SpawnMonsters(Vector3 pos, int count) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) string[] monstersForBiome = GetMonstersForBiome(pos); for (int i = 0; i < count; i++) { int stableHashCode = StringExtensionMethods.GetStableHashCode(monstersForBiome[Random.Range(0, monstersForBiome.Length)]); Vector3 val = pos + new Vector3(Random.Range(-8f, 8f), 0f, Random.Range(-8f, 8f)); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "SpawnObject", new object[3] { val, Quaternion.identity, stableHashCode }); } } private static string[] GetMonstersForBiome(Vector3 pos) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Invalid comparison between Unknown and I4 //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Invalid comparison between Unknown and I4 //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Invalid comparison between Unknown and I4 Biome biome = WorldGenerator.instance.GetBiome(pos.x, pos.z, 0.02f, false); if (!(WorldGenerator.instance.GetHeight(pos.x, pos.z) < ZoneSystem.instance.m_waterLevel)) { if ((int)biome != 1) { if ((int)biome != 8) { if ((int)biome != 2) { if ((int)biome != 4) { if ((int)biome != 16) { if ((int)biome != 512) { if ((int)biome != 32) { return new string[2] { "Greydwarf", "Troll" }; } return new string[2] { "Charred_Warrior", "Morgen" }; } return new string[2] { "Seeker", "Tick" }; } return new string[2] { "Fuling", "Deathsquito" }; } return new string[2] { "Drake", "Fenring" }; } return new string[3] { "Draugr", "Blob", "Wraith" }; } return new string[2] { "Troll", "Greydwarf_Elite" }; } return new string[2] { "Greydwarf", "Neck" }; } return new string[1] { "Serpent" }; } private static void ApplyRandomWeather() { string value = NightTerrorsPlugin.CfgWeatherPool.Value; if (!string.IsNullOrWhiteSpace(value)) { string[] array = value.Split(','); string text = array[Random.Range(0, array.Length)].Trim(); NightTerrorsPlugin.Log.LogInfo((object)("NightTerrors: forcing weather '" + text + "'.")); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NightTerrors_SetWeather", new object[1] { text }); } } private static void Announce(string text, MessageType type) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected I4, but got Unknown if (!string.IsNullOrWhiteSpace(text) && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ShowMessage", new object[2] { (int)type, text }); } } } [HarmonyPatch(typeof(EnvMan), "SkipToMorning")] internal static class Patch_SkipToMorning { private static void Prefix() { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !NightTerrorsEvent.IsActive) { int value = NightTerrorsPlugin.CfgTriggerChance.Value; if (value > 0 && Random.Range(0, value) == 0) { NightTerrorsEvent.Begin(); } } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class Patch_Player_OnDeath { private static void Postfix(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && NightTerrorsClient.IsEventActive) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: local player died during event."); ZRoutedRpc.instance.InvokeRoutedRPC("NightTerrors_PlayerDied", Array.Empty()); } } } [HarmonyPatch(typeof(Skills), "OnDeath")] internal static class Patch_Skills_OnDeath { private static bool Prefix() { if (NightTerrorsClient.IsEventActive) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: skill loss suppressed."); return false; } return true; } } [HarmonyPatch(typeof(Player), "CreateTombStone")] internal static class Patch_CreateTombStone { private static bool Prefix() { if (NightTerrorsClient.IsEventActive) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: tombstone suppressed."); return false; } return true; } } [HarmonyPatch(typeof(EnvMan), "OnMorning")] internal static class Patch_EnvMan_OnMorning { private static bool Prefix() { return !NightTerrorsClient.SuppressMorning; } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Patch_Player_OnSpawned { private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (NightTerrorsClient.PendingRestore) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: applying deferred inventory restore on spawn."); NightTerrorsClient.ApplyRestore(); } if (NightTerrorsClient.SuppressMorning) { NightTerrorsClient.SuppressMorning = false; if ((Object)(object)EnvMan.instance != (Object)null) { ((Character)__instance).Message((MessageType)2, $"Day {EnvMan.instance.GetDay()}", 0, (Sprite)null); } } } } [HarmonyPatch(typeof(Player), "Message")] internal static class Patch_Player_Message { private static bool Prefix(string msg) { if (!NightTerrorsClient.IsEventStarting && !NightTerrorsClient.IsEventActive) { return true; } if (msg == "$msg_goodmorning") { return false; } return true; } } [HarmonyPatch(typeof(SleepText), "ShowDreamText")] internal static class Patch_SleepText_ShowDreamText { private static bool Prefix() { if (NightTerrorsClient.IsEventStarting || NightTerrorsClient.IsEventActive) { return false; } return true; } } [HarmonyPatch(typeof(Player), "AddKnownItem")] internal static class Patch_AddKnownItem { private static bool Prefix() { if (NightTerrorsClient.IsEventActive || NightTerrorsClient.IsEventStarting) { return false; } return true; } } [HarmonyPatch(typeof(Player), "AddKnownBiome")] internal static class Patch_AddKnownBiome { private static bool Prefix() { if (NightTerrorsClient.IsEventActive || NightTerrorsClient.IsEventStarting) { return false; } return true; } } [HarmonyPatch(typeof(Character), "Damage")] internal static class Patch_FriendlyFire { private static void Prefix(HitData hit, Character __instance) { if (NightTerrorsClient.IsEventActive && NightTerrorsPlugin.CfgFriendlyFire.Value && __instance.IsPlayer()) { Character attacker = hit.GetAttacker(); if (!((Object)(object)attacker == (Object)null) && attacker.IsPlayer()) { hit.m_ignorePVP = true; } } } } [BepInPlugin("nightterrors", "NightTerrors", "1.0.3")] public class NightTerrorsPlugin : BaseUnityPlugin { public const string PluginGUID = "nightterrors"; public const string PluginName = "NightTerrors"; public const string PluginVersion = "1.0.3"; internal static ManualLogSource Log; internal static NightTerrorsPlugin Instance; private Harmony _harmony; internal static ConfigEntry CfgTriggerChance; internal static ConfigEntry CfgFriendlyFire; internal static ConfigEntry CfgSpawnMonsters; internal static ConfigEntry CfgMonsterCount; internal static ConfigEntry CfgScenarioWeights; internal static ConfigEntry CfgWeatherPool; internal static ConfigEntry CfgEventDuration; private void Awake() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; CfgTriggerChance = ((BaseUnityPlugin)this).Config.Bind("General", "TriggerChance", 20, "1-in-N chance of the event triggering each time everyone sleeps."); CfgFriendlyFire = ((BaseUnityPlugin)this).Config.Bind("General", "FriendlyFire", false, "Allow players to damage each other during the event."); CfgSpawnMonsters = ((BaseUnityPlugin)this).Config.Bind("General", "SpawnMonsters", true, "Spawn monsters at the teleport location."); CfgMonsterCount = ((BaseUnityPlugin)this).Config.Bind("General", "MonsterCount", 3, "Number of monsters to spawn."); CfgScenarioWeights = ((BaseUnityPlugin)this).Config.Bind("General", "ScenarioWeights", "1,1,1", "Comma-separated weights for: KeepGear, GoNaked, DifferentEquipment."); CfgEventDuration = ((BaseUnityPlugin)this).Config.Bind("General", "EventDuration", 120, "Maximum event duration in seconds. Survivors have their inventory restored and the event ends."); CfgWeatherPool = ((BaseUnityPlugin)this).Config.Bind("Weather", "WeatherPool", "ThunderStorm,Ashrain,Snow,Twilight_Snow,DeepForest_Mist,SwampRain,Mistlands_darkening", "Comma-separated list of environment names to pick from randomly. Set to empty string to disable weather effects."); _harmony = new Harmony("nightterrors"); _harmony.PatchAll(); Log.LogInfo((object)"NightTerrors v1.0.3 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class NightTerrorsClient { public static bool IsEventActive; public static bool IsEventStarting; public static bool SuppressMorning; public static byte[] SavedInventory; public static bool PendingRestore; public static Scenario CurrentScenario; public static void ApplyRestore() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && SavedInventory != null) { ((Humanoid)localPlayer).UnequipAllItems(); ((Humanoid)localPlayer).GetInventory().Load(new ZPackage(SavedInventory)); SavedInventory = null; PendingRestore = false; NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: inventory restored."); } } } internal static class RpcHandler { [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static class Patch_ZRoutedRpc_Awake { private static void Postfix() { ZRoutedRpc.instance.Register("NightTerrors_SaveInventory", (Action)SaveInventory); ZRoutedRpc.instance.Register("NightTerrors_EventStart", (Action)EventStart); ZRoutedRpc.instance.Register("NightTerrors_RestoreInventory", (Action)RestoreInventory); ZRoutedRpc.instance.Register("NightTerrors_EventEnd", (Action)EventEnd); ZRoutedRpc.instance.Register("NightTerrors_PlayerDied", (Action)PlayerDied); ZRoutedRpc.instance.Register("NightTerrors_KillSurvivor", (Action)KillSurvivor); ZRoutedRpc.instance.Register("NightTerrors_SetWeather", (Action)SetWeather); } } private static void SaveInventory(long sender) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { NightTerrorsClient.IsEventStarting = true; NightTerrorsClient.SuppressMorning = true; ZPackage val = new ZPackage(); ((Humanoid)localPlayer).GetInventory().Save(val); NightTerrorsClient.SavedInventory = val.GetArray(); NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: inventory saved."); } } private static void EventStart(long sender, ZPackage pkg) { int currentScenario = pkg.ReadInt(); pkg.ReadBool(); pkg.ReadInt(); int num = pkg.ReadInt(); string[] array = new string[num]; for (int i = 0; i < num; i++) { array[i] = pkg.ReadString(); } NightTerrorsClient.IsEventActive = true; NightTerrorsClient.CurrentScenario = (Scenario)currentScenario; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } switch (NightTerrorsClient.CurrentScenario) { case Scenario.GoNaked: ((Humanoid)localPlayer).UnequipAllItems(); ((Humanoid)localPlayer).GetInventory().RemoveAll(); NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: stripped for GoNaked."); break; case Scenario.DifferentEquipment: { ((Humanoid)localPlayer).UnequipAllItems(); ((Humanoid)localPlayer).GetInventory().RemoveAll(); string[] array2 = array; foreach (string text in array2) { ItemData val = ((Humanoid)localPlayer).GetInventory().AddItem(text, 1, 1, 0, 0L, "", false); if (val != null) { ((Humanoid)localPlayer).EquipItem(val, false); } else { NightTerrorsPlugin.Log.LogWarning((object)("NightTerrors: unknown kit item '" + text + "'")); } } NightTerrorsPlugin.Log.LogInfo((object)("NightTerrors: equipped kit [" + string.Join(", ", array) + "].")); break; } } } private static void RestoreInventory(long sender) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { NightTerrorsClient.PendingRestore = true; NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: restore deferred (player dead/null)."); } else { NightTerrorsClient.ApplyRestore(); } } private static void EventEnd(long sender) { NightTerrorsClient.IsEventActive = false; NightTerrorsClient.IsEventStarting = false; NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: event ended on client."); } private static void SetWeather(long sender, string envName) { if (!((Object)(object)EnvMan.instance == (Object)null)) { EnvMan.instance.SetForceEnvironment(envName); NightTerrorsPlugin.Log.LogInfo((object)("NightTerrors: weather set to '" + envName + "'.")); } } private static void PlayerDied(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { NightTerrorsPlugin.Log.LogInfo((object)$"NightTerrors: peer {sender} died."); NightTerrorsEvent.OnPlayerDied(sender); } } private static void KillSurvivor(long sender) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && NightTerrorsClient.IsEventActive) { NightTerrorsPlugin.Log.LogInfo((object)"NightTerrors: time limit — killing survivor."); HitData val = new HitData(); val.m_damage.m_blunt = 99999f; val.m_point = ((Component)localPlayer).transform.position; ((Character)localPlayer).Damage(val); } } } public enum Scenario { KeepGear, GoNaked, DifferentEquipment } public static class ScenarioSelector { public static readonly string[][] Kits = new string[5][] { new string[2] { "Club", "ShieldWood" }, new string[1] { "Torch" }, new string[1] { "FishingRod" }, new string[1] { "Hammer" }, new string[2] { "SwordBlackmetal", "ShieldBlackmetal" } }; public static Scenario Choose(string weightsConfig) { string[] array = weightsConfig.Split(','); int[] array2 = new int[4]; for (int i = 0; i < array2.Length; i++) { if (i < array.Length && int.TryParse(array[i].Trim(), out var result)) { array2[i] = Mathf.Max(0, result); } else { array2[i] = 1; } } int num = 0; int[] array3 = array2; foreach (int num2 in array3) { num += num2; } if (num <= 0) { return Scenario.KeepGear; } int num3 = Random.Range(0, num); int num4 = 0; for (int k = 0; k < array2.Length; k++) { num4 += array2[k]; if (num3 < num4) { return (Scenario)k; } } return Scenario.KeepGear; } public static string[] PickKit() { return Kits[Random.Range(0, Kits.Length)]; } }