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";
}
}