Decompiled source of ArtifactOfTheNight v0.2.0

plugins/MuckArtifactNight.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("MuckArtifactNight")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Risk of Rain 2 artifacts for Muck nights: Kin and Swarms. Host-only.")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+b3815082b9868be7615596cfa6cd60a86ecd2179")]
[assembly: AssemblyProduct("Artifact of the Night")]
[assembly: AssemblyTitle("MuckArtifactNight")]
[assembly: InternalsVisibleTo("MuckArtifactNight.Tests")]
[assembly: AssemblyVersion("0.2.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace MuckArtifactNight
{
	internal static class Announcement
	{
		public const int ChatMaxLength = 120;

		public static string Text(Artifact a, string kinMobName, int swarmsCount, float swarmsHealth)
		{
			return Line("Tonight: ", a, kinMobName, swarmsCount, swarmsHealth);
		}

		public static string Dusk(Artifact a, string kinMobName, int swarmsCount, float swarmsHealth)
		{
			return Line("Night falls: ", a, kinMobName, swarmsCount, swarmsHealth);
		}

		private static string Line(string lead, Artifact a, string kinMobName, int swarmsCount, float swarmsHealth)
		{
			switch (a)
			{
			case Artifact.Kin:
				if (string.IsNullOrEmpty(kinMobName))
				{
					return "<color=orange>" + lead + "Artifact of Kin.<color=white> Only one kind of monster will spawn.";
				}
				return "<color=orange>" + lead + "Artifact of Kin.<color=white> Only " + kinMobName + " will spawn.";
			case Artifact.Swarms:
			{
				int num = (int)Math.Round(swarmsHealth * 100f, MidpointRounding.AwayFromZero);
				return $"<color=orange>{lead}Artifact of Swarms.<color=white> {swarmsCount}x the monsters at {num}% health.";
			}
			default:
				return null;
			}
		}
	}
	public enum Artifact
	{
		None,
		Kin,
		Swarms
	}
	internal static class ArtifactLobbyLink
	{
		public static bool Register(string id, string name, string description, ConfigEntry<bool> enabled)
		{
			try
			{
				if (!Chainloader.PluginInfos.TryGetValue("evan.muck.artifactlobby", out var value) || (Object)(object)value.Instance == (Object)null)
				{
					return false;
				}
				object obj = (((object)value.Instance).GetType().Assembly.GetType("MuckArtifactLobby.ArtifactRegistry")?.GetMethod("Register", new Type[4]
				{
					typeof(string),
					typeof(string),
					typeof(string),
					typeof(ConfigEntry<bool>)
				}))?.Invoke(null, new object[4] { id, name, description, enabled });
				return obj is bool && (bool)obj;
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	internal readonly struct RollSettings
	{
		public readonly bool Enabled;

		public readonly float Chance;

		public readonly int FirstDay;

		public readonly bool SkipBossNights;

		public readonly bool KinEnabled;

		public readonly float KinWeight;

		public readonly bool SwarmsEnabled;

		public readonly float SwarmsWeight;

		public readonly Artifact Force;

		public RollSettings(bool enabled, float chance, int firstDay, bool skipBossNights, bool kinEnabled, float kinWeight, bool swarmsEnabled, float swarmsWeight, Artifact force)
		{
			Enabled = enabled;
			Chance = chance;
			FirstDay = firstDay;
			SkipBossNights = skipBossNights;
			KinEnabled = kinEnabled;
			KinWeight = kinWeight;
			SwarmsEnabled = swarmsEnabled;
			SwarmsWeight = swarmsWeight;
			Force = force;
		}
	}
	internal static class ArtifactRoll
	{
		public static Artifact Pick(RollSettings s, int day, bool bossNight, bool survival, float chanceRoll, float pickRoll)
		{
			if (!s.Enabled || !survival)
			{
				return Artifact.None;
			}
			if (day < s.FirstDay)
			{
				return Artifact.None;
			}
			if (bossNight && s.SkipBossNights)
			{
				return Artifact.None;
			}
			float num = ((s.KinEnabled && s.KinWeight > 0f) ? s.KinWeight : 0f);
			float num2 = ((s.SwarmsEnabled && s.SwarmsWeight > 0f) ? s.SwarmsWeight : 0f);
			if (s.Force == Artifact.Kin)
			{
				if (!(num > 0f))
				{
					return Artifact.None;
				}
				return Artifact.Kin;
			}
			if (s.Force == Artifact.Swarms)
			{
				if (!(num2 > 0f))
				{
					return Artifact.None;
				}
				return Artifact.Swarms;
			}
			if (!(num + num2 > 0f))
			{
				return Artifact.None;
			}
			if (!(s.Chance > 0f))
			{
				return Artifact.None;
			}
			if (!(s.Chance >= 1f) && !(chanceRoll < s.Chance))
			{
				return Artifact.None;
			}
			if (num <= 0f)
			{
				return Artifact.Swarms;
			}
			if (num2 <= 0f)
			{
				return Artifact.Kin;
			}
			if (!(pickRoll * (num + num2) < num))
			{
				return Artifact.Swarms;
			}
			return Artifact.Kin;
		}
	}
	[HarmonyPatch]
	internal static class CheckMobSpawnsPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(GameLoop), "CheckMobSpawns", Type.EmptyTypes, (Type[])null);
		}

		private static void Prefix()
		{
			NightHost.InDirector = true;
		}

		private static Exception Finalizer(Exception __exception)
		{
			NightHost.InDirector = false;
			return __exception;
		}
	}
	[HarmonyPatch]
	internal static class FindMobCapPatch
	{
		private static MethodBase TargetMethod()
		{
			return NightHost.FindMobCap = AccessTools.DeclaredMethod(typeof(GameLoop), "FindMobCap", Type.EmptyTypes, (Type[])null);
		}

		private static void Postfix()
		{
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (NightHost.ScaleSwarmsCap && NightHost.State.Tonight == Artifact.Swarms)
				{
					GameLoop.currentMobCap = SwarmRules.ScaleCap(GameLoop.currentMobCap, NightPlugin.Cfg.SwarmsCapMultiplier.Value);
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: Swarms cap scale failed. {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class GameLoopSpawnMobPatch
	{
		private static MethodBase TargetMethod()
		{
			return NightHost.GameLoopSpawnMob = AccessTools.DeclaredMethod(typeof(GameLoop), "SpawnMob", new Type[6]
			{
				typeof(MobType),
				typeof(Vector3),
				typeof(float),
				typeof(float),
				typeof(BossType),
				typeof(bool)
			}, (Type[])null);
		}

		private static void Postfix(GameLoop __instance, int __result, MobType __0, Vector3 __1)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (!NightHost.InDirector || NightHost.SpawningExtra || __result == -1 || NightHost.State.Tonight != Artifact.Swarms || __1 == Vector3.zero)
				{
					return;
				}
				int num = SwarmRules.ExtraSpawns(NightPlugin.Cfg.SwarmsCountMultiplier.Value);
				NightHost.SpawningExtra = true;
				try
				{
					RaycastHit val = default(RaycastHit);
					for (int i = 0; i < num; i++)
					{
						if (Physics.Raycast(__1 + new Vector3(1.5f * (float)(i + 1), 0f, 0f) + Vector3.up * 20f, Vector3.down, ref val, 5000f, LayerMask.op_Implicit(__instance.whatIsSpawnable)))
						{
							NightHost.GameLoopSpawnMob.Invoke(__instance, new object[6]
							{
								__0,
								((RaycastHit)(ref val)).point,
								1f,
								1f,
								(object)(BossType)0,
								false
							});
						}
					}
				}
				finally
				{
					NightHost.SpawningExtra = false;
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: extra Swarms spawn failed. {arg}");
			}
		}
	}
	internal sealed class KinLock<T> where T : class
	{
		public T Locked { get; private set; }

		public bool TryLock(Func<T> roll, Func<T, bool> eligible, int maxTries)
		{
			Locked = null;
			for (int i = 0; i < maxTries; i++)
			{
				T val = roll();
				if (val != null && eligible(val))
				{
					Locked = val;
					return true;
				}
			}
			return false;
		}

		public T Apply(T vanillaPick, bool shrine)
		{
			if (!(Locked == null || shrine))
			{
				return Locked;
			}
			return vanillaPick;
		}

		public void Clear()
		{
			Locked = null;
		}
	}
	internal static class KinRules
	{
		public static bool IsEligible(bool boss, bool neutral, string name, bool dontCountTag)
		{
			if (!boss && !neutral && !dontCountTag)
			{
				return name != "Woodman";
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class NewDayPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(GameLoop), "NewDay", new Type[1] { typeof(int) }, (Type[])null);
		}

		private static void Prefix()
		{
			if (LocalClient.serverOwner)
			{
				NightHost.ScaleSwarmsCap = false;
			}
		}

		private static void Postfix(GameLoop __instance, int __0)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (__instance.currentDay != __0 || !NightHost.State.TryBeginDay(__instance, __0))
				{
					return;
				}
				NightHost.Kin.Clear();
				GameSettings gameSettings = GameManager.gameSettings;
				if (gameSettings == null)
				{
					return;
				}
				bool survival = (int)gameSettings.gameMode == 0;
				bool flag = NightCalendar.IsBossNight(__0, gameSettings.BossDay(), survival);
				Artifact artifact = ArtifactRoll.Pick(NightPlugin.Cfg.RollSettings(NightHooks.KinAvailable, NightHooks.SwarmsAvailable), __0, flag, survival, Random.value, Random.value);
				if (artifact == Artifact.Kin && !NightHost.Kin.TryLock(() => __instance.SelectMobToSpawn(false), (MobType t) => (Object)(object)t != (Object)null && KinRules.IsEligible(t.boss, (int)t.behaviour == 0, t.name, (Object)(object)t.mobPrefab != (Object)null && t.mobPrefab.CompareTag("DontCount")), NightPlugin.Cfg.KinMaxRerolls.Value))
				{
					artifact = Artifact.None;
					NightPlugin.Log.LogWarning((object)"Artifact of the Night: Kin found no eligible mob. This night has no artifact.");
				}
				NightHost.State.Set(artifact);
				if (artifact == Artifact.Swarms)
				{
					NightHost.ScaleSwarmsCap = true;
					if (NightHost.FindMobCap != null)
					{
						NightHost.FindMobCap.Invoke(__instance, null);
					}
					else
					{
						GameLoop.currentMobCap = SwarmRules.ScaleCap(GameLoop.currentMobCap, NightPlugin.Cfg.SwarmsCapMultiplier.Value);
					}
				}
				Say(Announcement.Text(artifact, ((Object)(object)NightHost.Kin.Locked != (Object)null) ? NightHost.Kin.Locked.name : null, NightPlugin.Cfg.SwarmsCountMultiplier.Value, NightPlugin.Cfg.SwarmsHealthFactor.Value));
				if (NightPlugin.Cfg.VerboseLogging.Value)
				{
					string text = (((Object)(object)NightHost.Kin.Locked != (Object)null) ? NightHost.Kin.Locked.name : "");
					NightPlugin.Log.LogInfo((object)$"Artifact of the Night: day={__0} boss={flag} artifact={artifact} kin={text} cap={GameLoop.currentMobCap}");
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: NewDay failed. {arg}");
			}
		}

		internal static void Say(string msg)
		{
			if (msg != null)
			{
				NightPlugin.Log.LogInfo((object)msg);
				if (NightPlugin.Cfg.AnnounceInChat.Value)
				{
					ServerSend.SendChatMessage(-1, "", msg);
				}
				if (NightPlugin.Cfg.HostLocalEcho.Value && (Object)(object)ChatBox.Instance != (Object)null)
				{
					ChatBox.Instance.AppendMessage(-1, msg, "");
				}
			}
		}
	}
	internal static class NightCalendar
	{
		public static bool IsBossNight(int day, int bossDay, bool survival)
		{
			if (survival && bossDay > 0 && day != 0)
			{
				return day % bossDay == 0;
			}
			return false;
		}
	}
	internal sealed class NightConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<float> Chance;

		public readonly ConfigEntry<int> FirstDay;

		public readonly ConfigEntry<bool> SkipBossNights;

		public readonly ConfigEntry<bool> KinEnabled;

		public readonly ConfigEntry<float> KinWeight;

		public readonly ConfigEntry<int> KinMaxRerolls;

		public readonly ConfigEntry<bool> SwarmsEnabled;

		public readonly ConfigEntry<float> SwarmsWeight;

		public readonly ConfigEntry<int> SwarmsCountMultiplier;

		public readonly ConfigEntry<float> SwarmsHealthFactor;

		public readonly ConfigEntry<float> SwarmsCapMultiplier;

		public readonly ConfigEntry<bool> AnnounceInChat;

		public readonly ConfigEntry<bool> HostLocalEcho;

		public readonly ConfigEntry<Artifact> ForceArtifact;

		public readonly ConfigEntry<bool> VerboseLogging;

		public NightConfig(ConfigFile cfg)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("Artifact", "Enabled", false, "Turn the artifact on. Artifacts are opt-in, as in Risk of Rain 2. Off leaves every night vanilla, ForceArtifact included. Only the host's config is read.");
			Chance = cfg.Bind<float>("Night", "Chance", 0.35f, new ConfigDescription("Chance (0-1) that a Survival night rolls an artifact. Not from the game. Only the host's config is read.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			FirstDay = cfg.Bind<int>("Night", "FirstDay", 1, new ConfigDescription("First day that can roll. 1 leaves day 0 vanilla. Not from the game.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			SkipBossNights = cfg.Bind<bool>("Night", "SkipBossNights", true, "Skip nights where the game would spawn a boss (day % BossDay == 0). Not from the game.");
			KinEnabled = cfg.Bind<bool>("Kin", "Enabled", true, "Allow Artifact of Kin to be rolled.");
			KinWeight = cfg.Bind<float>("Kin", "Weight", 1f, new ConfigDescription("Relative weight against Swarms. Not from the game. 0 disables Kin.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			KinMaxRerolls = cfg.Bind<int>("Kin", "MaxRerolls", 8, new ConfigDescription("How many vanilla SelectMobToSpawn rolls to try before giving up on Kin. Not from the game.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 32), Array.Empty<object>()));
			SwarmsEnabled = cfg.Bind<bool>("Swarms", "Enabled", true, "Allow Artifact of Swarms to be rolled.");
			SwarmsWeight = cfg.Bind<float>("Swarms", "Weight", 1f, new ConfigDescription("Relative weight against Kin. Not from the game. 0 disables Swarms.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			SwarmsCountMultiplier = cfg.Bind<int>("Swarms", "CountMultiplier", 2, new ConfigDescription("Director spawns are repeated this many times. 2 matches Risk of Rain 2 (spawns doubled).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
			SwarmsHealthFactor = cfg.Bind<float>("Swarms", "HealthFactor", 0.5f, new ConfigDescription("Scales bossMultiplier on director mobs, which changes max HP only. 0.5 matches Risk of Rain 2 (health halved). Buff size, loot, and ranged damage stay on multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			SwarmsCapMultiplier = cfg.Bind<float>("Swarms", "CapMultiplier", 2f, new ConfigDescription("Scales the night's mob cap. Not from the game. The default matches CountMultiplier. The two are independent: a higher count with this left at 2 lets one tick spawn past the cap. Clamped to the vanilla cap of 999.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f), Array.Empty<object>()));
			AnnounceInChat = cfg.Bind<bool>("Announce", "Chat", true, "Send the night's artifact line through the vanilla chat packet.");
			HostLocalEcho = cfg.Bind<bool>("Announce", "HostLocalEcho", false, "Also append the line on the host's own chat box. Fallback if the host does not receive its own chat broadcast.");
			ForceArtifact = cfg.Bind<Artifact>("Debug", "ForceArtifact", Artifact.None, "Skips the chance roll. Still respects [Artifact] Enabled, FirstDay, boss nights, and whether that artifact is enabled. None rolls normally.");
			VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Log the day, boss flag, artifact, Kin mob, and cap after each roll.");
		}

		public RollSettings RollSettings(bool kinAvailable, bool swarmsAvailable)
		{
			return new RollSettings(Enabled.Value, Chance.Value, FirstDay.Value, SkipBossNights.Value, KinEnabled.Value && kinAvailable, KinWeight.Value, SwarmsEnabled.Value && swarmsAvailable, SwarmsWeight.Value, ForceArtifact.Value);
		}
	}
	internal static class NightHooks
	{
		internal static bool CoreApplied;

		internal static bool KinAvailable;

		internal static bool SwarmsAvailable;

		internal static void Apply(Harmony h)
		{
			try
			{
				CoreApplied = TryGroup(h, "core", typeof(NewDayPatch));
				if (!CoreApplied)
				{
					NightPlugin.Log.LogError((object)"Artifact of the Night: mod disabled.");
					return;
				}
				KinAvailable = TryGroup(h, "Kin", typeof(SelectMobPatch));
				SwarmsAvailable = TryGroup(h, "Swarms", typeof(CheckMobSpawnsPatch), typeof(GameLoopSpawnMobPatch), typeof(ServerSpawnNewMobPatch), typeof(FindMobCapPatch));
				bool flag = TryGroup(h, "dusk", typeof(StartNightPatch));
				NightPlugin.Log.LogInfo((object)("Hooks: core=" + (CoreApplied ? "ok" : "FAILED") + " Kin=" + (KinAvailable ? "ok" : "FAILED") + " Swarms=" + (SwarmsAvailable ? "ok" : "FAILED") + " dusk=" + (flag ? "ok" : "FAILED")));
			}
			catch (Exception arg)
			{
				CoreApplied = false;
				KinAvailable = false;
				SwarmsAvailable = false;
				NightPlugin.Log.LogError((object)$"Artifact of the Night: hook install failed and the mod is disabled. {arg}");
			}
		}

		private static bool TryGroup(Harmony h, string name, params Type[] patchClasses)
		{
			List<MethodBase> list = new List<MethodBase>();
			try
			{
				foreach (Type type in patchClasses)
				{
					MethodInfo methodInfo = AccessTools.Method(type, "TargetMethod", (Type[])null, (Type[])null);
					if (methodInfo == null)
					{
						throw new MissingMethodException(type.Name + ": TargetMethod not found");
					}
					MethodBase methodBase = (MethodBase)methodInfo.Invoke(null, null);
					if (methodBase == null)
					{
						throw new MissingMethodException(type.Name + ": target not found");
					}
					list.Add(methodBase);
					List<MethodInfo> list2 = h.CreateClassProcessor(type).Patch();
					if (list2 == null || list2.Count == 0)
					{
						throw new InvalidOperationException(type.Name + ": no patches were applied");
					}
				}
				return true;
			}
			catch (Exception arg)
			{
				foreach (MethodBase item in list)
				{
					h.Unpatch(item, (HarmonyPatchType)0, h.Id);
				}
				NightPlugin.Log.LogError((object)$"Artifact of the Night: {name} hooks failed and were removed. {arg}");
				return false;
			}
		}
	}
	internal static class NightHost
	{
		public static readonly NightState State = new NightState();

		public static readonly KinLock<MobType> Kin = new KinLock<MobType>();

		public static bool InDirector;

		public static bool SpawningExtra;

		public static bool ScaleSwarmsCap;

		public static MethodBase GameLoopSpawnMob;

		public static MethodBase FindMobCap;
	}
	[BepInPlugin("evan.muck.artifactofthenight", "Artifact of the Night", "0.2.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class NightPlugin : BaseUnityPlugin
	{
		public const string Guid = "evan.muck.artifactofthenight";

		public const string Name = "Artifact of the Night";

		public const string Version = "0.2.0";

		internal static ManualLogSource Log;

		internal static NightConfig Cfg;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new NightConfig(((BaseUnityPlugin)this).Config);
			NightHooks.Apply(new Harmony("evan.muck.artifactofthenight"));
			if (NightHooks.CoreApplied)
			{
				Log.LogInfo((object)"Artifact of the Night 0.2.0 loaded. Only the host needs this mod; clients' configs are ignored.");
				if (ArtifactLobbyLink.Register("evan.muck.artifactofthenight", "Night", "Some nights roll Kin or Swarms. Host only.", Cfg.Enabled))
				{
					Log.LogInfo((object)"Artifact of the Night: registered with Artifact Lobby; the lobby host's pick sets [Artifact] Enabled.");
				}
			}
			if (!Cfg.Enabled.Value)
			{
				Log.LogInfo((object)"Artifact of the Night is off. Set [Artifact] Enabled = true to turn it on.");
			}
		}
	}
	internal sealed class NightState
	{
		private object _owner;

		public Artifact Tonight { get; private set; }

		public int Day { get; private set; } = -1;

		public bool TryBeginDay(object owner, int day)
		{
			if (owner != _owner)
			{
				_owner = owner;
				Day = -1;
				Tonight = Artifact.None;
			}
			if (day <= Day)
			{
				return false;
			}
			Day = day;
			Tonight = Artifact.None;
			return true;
		}

		public void Set(Artifact a)
		{
			Tonight = a;
		}

		public bool IsFor(object owner, int day)
		{
			if (owner == _owner)
			{
				return day == Day;
			}
			return false;
		}

		public void Reset()
		{
			_owner = null;
			Day = -1;
			Tonight = Artifact.None;
		}
	}
	[HarmonyPatch]
	internal static class SelectMobPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(GameLoop), "SelectMobToSpawn", new Type[1] { typeof(bool) }, (Type[])null);
		}

		private static void Postfix(bool __0, ref MobType __result)
		{
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (NightHost.State.Tonight == Artifact.Kin)
				{
					__result = NightHost.Kin.Apply(__result, __0);
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: SelectMob failed. {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class ServerSpawnNewMobPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(MobSpawner), "ServerSpawnNewMob", new Type[7]
			{
				typeof(int),
				typeof(int),
				typeof(Vector3),
				typeof(float),
				typeof(float),
				typeof(BossType),
				typeof(int)
			}, (Type[])null);
		}

		private static void Prefix(ref float __4)
		{
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (NightHost.InDirector && NightHost.State.Tonight == Artifact.Swarms)
				{
					__4 = SwarmRules.ScaleMultiplier(__4, NightPlugin.Cfg.SwarmsHealthFactor.Value);
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: Swarms health scale failed. {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class StartNightPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(GameLoop), "StartNight", Type.EmptyTypes, (Type[])null);
		}

		private static void Postfix(GameLoop __instance)
		{
			if (!LocalClient.serverOwner)
			{
				return;
			}
			try
			{
				if (NightHost.State.IsFor(__instance, __instance.currentDay))
				{
					NewDayPatch.Say(Announcement.Dusk(NightHost.State.Tonight, ((Object)(object)NightHost.Kin.Locked != (Object)null) ? NightHost.Kin.Locked.name : null, NightPlugin.Cfg.SwarmsCountMultiplier.Value, NightPlugin.Cfg.SwarmsHealthFactor.Value));
				}
			}
			catch (Exception arg)
			{
				NightPlugin.Log.LogError((object)$"Artifact of the Night: dusk line failed. {arg}");
			}
		}
	}
	internal static class SwarmRules
	{
		public const int VanillaMaxMobCap = 999;

		public const float ExtraOffsetMeters = 1.5f;

		public static float ScaleMultiplier(float multiplier, float healthFactor)
		{
			if (healthFactor > 0f)
			{
				return multiplier * healthFactor;
			}
			return multiplier;
		}

		public static int ExtraSpawns(int countMultiplier)
		{
			if (countMultiplier <= 1)
			{
				return 0;
			}
			return countMultiplier - 1;
		}

		public static int ScaleCap(int cap, float capMultiplier)
		{
			if (!(capMultiplier > 0f) || cap <= 0)
			{
				return cap;
			}
			double num = Math.Round((double)cap * (double)capMultiplier, MidpointRounding.AwayFromZero);
			if (!(num >= 999.0))
			{
				return (int)num;
			}
			return 999;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "MuckArtifactNight";

		public const string PLUGIN_NAME = "Artifact of the Night";

		public const string PLUGIN_VERSION = "0.2.0";
	}
}