Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MorkhallaProgressionScaling v0.1.1
plugins/MorkhallaProgressionScaling.Core.dll
Decompiled 4 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; [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("MorkhallaProgressionScaling.Core")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+3ad057b0fa4691d6870c25aec36bef61999d2ac7")] [assembly: AssemblyProduct("MorkhallaProgressionScaling.Core")] [assembly: AssemblyTitle("MorkhallaProgressionScaling.Core")] [assembly: AssemblyVersion("1.0.0.0")] namespace MorkhallaScaling.Core; public static class Progression { public const string ClearCountKey = "mps_morkhallaclears"; public const int DeepNorthBiomeBit = 64; public static bool IsDeepNorth(int biomeMask) { return biomeMask == 64; } public static int ScaleCount(int baseCount, float multiplier) { if (baseCount <= 0 || multiplier <= 1f) { return baseCount; } return Math.Max(baseCount, (int)Math.Round((float)baseCount * multiplier, MidpointRounding.AwayFromZero)); } public static float ScaleInterval(float baseInterval, float multiplier) { if (baseInterval <= 0f || multiplier <= 1f) { return baseInterval; } return baseInterval / multiplier; } public static int RandomRound(float value, double roll) { if (value <= 0f) { return 0; } int num = (int)Math.Floor(value); return num + ((roll < (double)(value - (float)num)) ? 1 : 0); } public static int TakeShare(ref float carry, int baseCount, float multiplier) { if (baseCount <= 0 || multiplier <= 1f) { return 0; } carry += (float)baseCount * (multiplier - 1f); int num = (int)Math.Floor(carry + 0.0001f); carry -= num; return num; } public static bool IsCountedEvent(string eventName, string filter) { if (string.IsNullOrWhiteSpace(filter)) { return true; } string[] array = filter.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { if (string.Equals(array[i].Trim(), eventName, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static int GammeltrollCount(float perStep, int steps) { if (perStep <= 0f || steps <= 0) { return 0; } return (int)Math.Round(perStep * (float)steps, MidpointRounding.AwayFromZero); } public static int ParseClearCount(string value) { if (string.IsNullOrEmpty(value) || !int.TryParse(value.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return 0; } return Math.Max(0, result); } public static string ClearCountKeyLine(int clears) { return "mps_morkhallaclears " + Math.Max(0, clears).ToString(CultureInfo.InvariantCulture); } } public sealed class ScalingSettings { public static readonly ScalingSettings Default = new ScalingSettings(enabled: true, 3, 0.5f, 5f, "Moose"); private const int FieldCount = 5; public const int MaxStepsLimit = 20; public const float MaxSpawnIncreasePerStep = 5f; public const float MaxStarChancePerStep = 50f; private readonly HashSet<string> excluded; public bool Enabled { get; } public int MaxSteps { get; } public float SpawnIncreasePerStep { get; } public float StarChancePerStep { get; } public string ExcludedCreatures { get; } public ScalingSettings(bool enabled, int maxSteps, float spawnIncreasePerStep, float starChancePerStep, string excludedCreatures) { Enabled = enabled; MaxSteps = Math.Min(20, Math.Max(0, maxSteps)); SpawnIncreasePerStep = Clamp(spawnIncreasePerStep, 5f); StarChancePerStep = Clamp(starChancePerStep, 50f); excluded = new HashSet<string>(from n in (excludedCreatures ?? "").Split(',', ';') select n.Trim() into n where n.Length > 0 select n, StringComparer.OrdinalIgnoreCase); ExcludedCreatures = string.Join(",", excluded.OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase)); } public bool IsExcluded(string prefabName) { if (prefabName != null) { return excluded.Contains(prefabName); } return false; } public int CapSteps(int steps) { return Math.Min(Math.Max(0, steps), MaxSteps); } public float SpawnMultiplier(int steps) { if (!Enabled) { return 1f; } return 1f + SpawnIncreasePerStep * (float)CapSteps(steps); } public float StarChance(float vanillaChance, int steps) { int num = CapSteps(steps); if (!Enabled || num == 0 || StarChancePerStep <= 0f) { return vanillaChance; } return Math.Min(100f, vanillaChance + StarChancePerStep * (float)num); } public string Encode() { return string.Join(";", Enabled ? "1" : "0", MaxSteps.ToString(CultureInfo.InvariantCulture), F(SpawnIncreasePerStep), F(StarChancePerStep), ExcludedCreatures); } public static bool TryDecode(string text, out ScalingSettings settings) { settings = null; if (string.IsNullOrEmpty(text)) { return false; } string[] array = text.Split(new char[1] { ';' }); if (array.Length != 5 || (array[0] != "0" && array[0] != "1") || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !TryParseFloat(array[2], out var value) || !TryParseFloat(array[3], out var value2)) { return false; } settings = new ScalingSettings(array[0] == "1", result, value, value2, array[4]); return true; } private static bool TryParseFloat(string text, out float value) { if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value) && !float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static float Clamp(float value, float max) { if (!float.IsNaN(value) && !(value < 0f)) { return Math.Min(max, value); } return 0f; } private static string F(float value) { return value.ToString("R", CultureInfo.InvariantCulture); } }
plugins/MorkhallaProgressionScaling.dll
Decompiled 4 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MorkhallaScaling.Core; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("jonasd")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+3ad057b0fa4691d6870c25aec36bef61999d2ac7")] [assembly: AssemblyProduct("Morkhalla Progression Scaling")] [assembly: AssemblyTitle("MorkhallaProgressionScaling")] [assembly: AssemblyVersion("0.1.1.0")] namespace MorkhallaScaling { internal static class Gammeltrolls { private const string NameToken = "$enemy_trollfrost"; private const string FallbackPrefabName = "TrollFrost"; private const float WaterLevel = 30f; private const float MinHeightAboveWater = 1f; private const float MaxSlopeDegrees = 30f; private const float MinDistanceBetween = 6f; private const float GroundOffset = 0.5f; private const int AttemptsPerTroll = 50; private static GameObject cachedPrefab; public static void PlaceAround(Vector3 center, int steps) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) int num = Progression.GammeltrollCount(Plugin.GammeltrollsPerStep.Value, steps); if (num <= 0 || !SettingsSync.Current.Enabled) { return; } GameObject val = FindPrefab(); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"No Gammeltroll prefab found (looked for a creature named $enemy_trollfrost). Set [3 - Gammeltrolls] PrefabName in the config."); return; } float num2 = Mathf.Max(0f, Plugin.GammeltrollMinDistance.Value); float maxDistance = Mathf.Max(num2 + 1f, Plugin.GammeltrollMaxDistance.Value); List<Vector3> list = new List<Vector3>(); for (int i = 0; i < num; i++) { if (!TryFindSpot(center, num2, maxDistance, list, out var spot)) { Plugin.Log.LogWarning((object)$"Found no dry, flat ground for Gammeltroll {i + 1} of {num} near {center}."); continue; } list.Add(spot); CreateSaved(val, spot + Vector3.up * 0.5f); } Plugin.Log.LogInfo((object)$"Placed {list.Count} {((Object)val).name} near the invasion at {center}."); } private static void CreateSaved(GameObject prefab, Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) ZNetView.StartGhostInit(); try { Object.Destroy((Object)(object)Object.Instantiate<GameObject>(prefab, position, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f))); } finally { ZNetView.FinishGhostInit(); } } private static bool TryFindSpot(Vector3 center, float minDistance, float maxDistance, List<Vector3> placed, out Vector3 spot) { //IL_0012: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Cos((float)Math.PI / 6f); Vector3 val2 = default(Vector3); for (int i = 0; i < 50; i++) { Vector2 insideUnitCircle = Random.insideUnitCircle; Vector2 normalized = ((Vector2)(ref insideUnitCircle)).normalized; if (!(normalized == Vector2.zero)) { Vector2 val = normalized * Random.Range(minDistance, maxDistance); ((Vector3)(ref val2))..ctor(center.x + val.x, 0f, center.z + val.y); val2.y = WorldGenerator.instance.GetHeight(val2.x, val2.z); if (!(val2.y < 31f) && !(WorldGenerator.instance.GetNormal(val2.x, val2.z, 1f).y < num) && !IsTooClose(val2, placed)) { spot = val2; return true; } } } spot = Vector3.zero; return false; } private static bool IsTooClose(Vector3 candidate, List<Vector3> placed) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) foreach (Vector3 item in placed) { if (Utils.DistanceXZ(candidate, item) < 6f) { return true; } } return false; } private static GameObject FindPrefab() { string text = Plugin.GammeltrollPrefab.Value?.Trim(); if (!string.IsNullOrEmpty(text)) { return ZNetScene.instance.GetPrefab(text); } if ((Object)(object)cachedPrefab != (Object)null) { return cachedPrefab; } foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs) { Character val = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<Character>() : null); if ((Object)(object)val != (Object)null && val.m_name == "$enemy_trollfrost") { cachedPrefab = prefab2; Plugin.Detail("Gammeltroll prefab: " + ((Object)prefab2).name); return cachedPrefab; } } GameObject prefab = ZNetScene.instance.GetPrefab("TrollFrost"); if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<Character>() != (Object)null) { cachedPrefab = prefab; Plugin.Log.LogInfo((object)"Gammeltroll found by prefab name TrollFrost, not by $enemy_trollfrost."); } return cachedPrefab; } } internal static class Places { private static readonly HashSet<Vector2s> MorkhallaZones = new HashSet<Vector2s>(); private static readonly Dictionary<Vector2s, float> Carry = new Dictionary<Vector2s, float>(); public static void Reset() { MorkhallaZones.Clear(); Carry.Clear(); } public static int TakeShare(Vector3 position, int baseCount, float multiplier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(position); Carry.TryGetValue(zone, out var value); int result = Progression.TakeShare(ref value, baseCount, multiplier); Carry[zone] = value; return result; } public static bool IsInMorkhalla(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!Character.InInterior(position)) { return false; } Vector2s zone = ZoneSystem.GetZone(position); if (MorkhallaZones.Contains(zone)) { return true; } DungeonGenerator[] array = Object.FindObjectsByType<DungeonGenerator>((FindObjectsSortMode)0); foreach (DungeonGenerator val in array) { if (ZoneSystem.GetZone(((Component)val).transform.position) == zone && (val.m_themes & 0x20000) != 0) { MorkhallaZones.Add(zone); return true; } } return false; } } [BepInPlugin("com.jonasd.valheim.morkhallaprogressionscaling", "Morkhalla Progression Scaling", "0.1.1")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.jonasd.valheim.morkhallaprogressionscaling"; public const string PluginName = "Morkhalla Progression Scaling"; public const string PluginVersion = "0.1.1"; internal static ManualLogSource Log; internal static ConfigEntry<bool> LogDetails; internal static ConfigEntry<string> CountedEvents; internal static ConfigEntry<float> GammeltrollsPerStep; internal static ConfigEntry<string> GammeltrollPrefab; internal static ConfigEntry<float> GammeltrollMinDistance; internal static ConfigEntry<float> GammeltrollMaxDistance; private ConfigEntry<bool> enabledSetting; private ConfigEntry<int> maxSteps; private ConfigEntry<float> spawnIncreasePerStep; private ConfigEntry<float> starChancePerStep; private ConfigEntry<string> excludedCreatures; private Harmony harmony; private static readonly HashSet<string> LoggedOnce = new HashSet<string>(); private void Awake() { //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ScalingSettings val = ScalingSettings.Default; maxSteps = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Steps", "MaxSteps", val.MaxSteps, "A step is one cleared Morkhalla (counted when its ice starts a Jotunn invasion). Progression stops at this many steps; 3 = the three Morkhallas vanilla needs."); spawnIncreasePerStep = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Steps", "SpawnIncreasePerStep", val.SpawnIncreasePerStep, "Added per step to Deep North spawning, as a fraction of vanilla: 0.5 = +50% per step, so 3 steps = 2.5x. Applies to how often creatures spawn, how many may be around at once, group size, Morkhalla creatures and Jotunn invasion creatures. 0 turns spawn scaling off."); starChancePerStep = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Steps", "StarChancePerStep", val.StarChancePerStep, "Percentage points added per step to the star chance of Deep North creatures that can have stars (vanilla is about 10%, so 5 per step = 25% at 3 steps). Creatures without stars never get any. 0 turns this off."); GammeltrollsPerStep = ((BaseUnityPlugin)this).Config.Bind<float>("1 - Steps", "GammeltrollsPerStep", 1f, "Gammeltrolls placed once near each new Jotunn invasion: this many per step, counting the step that started it (1 = first invasion 1, second 2, third 3). They never respawn. 0 turns this off. Server only."); enabledSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - General", "Enabled", val.Enabled, "Scale the Deep North with the number of cleared Morkhallas. Raid events are never changed. On a server, the server's settings (except those marked server only) apply to every player."); excludedCreatures = ((BaseUnityPlugin)this).Config.Bind<string>("2 - General", "ExcludedCreatures", val.ExcludedCreatures, "Creatures (prefab names, comma separated) that are never scaled, e.g. Moose,Barka. Only hostile creatures are scaled anyway; seals, fish and meteors always stay vanilla."); CountedEvents = ((BaseUnityPlugin)this).Config.Bind<string>("2 - General", "CountedEvents", "", "Which started events count as a step, comma separated. Empty = every event started by breaking ice (in Valheim 1.0.20 that is only the Jotunn invasion, internal name jotun_invasion). Server only."); LogDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - General", "LogDetails", false, "Write what the mod scales and spawns to the BepInEx log. For testing."); GammeltrollMinDistance = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Gammeltrolls", "MinDistance", 15f, "Closest a Gammeltroll is placed to the invasion's centre (the ice), in metres. Server only."); GammeltrollMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Gammeltrolls", "MaxDistance", 30f, "Farthest a Gammeltroll is placed from the invasion's centre, in metres. Server only."); GammeltrollPrefab = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Gammeltrolls", "PrefabName", "", "Leave empty to find the Gammeltroll by its in-game name (prefab TrollFrost). Set a prefab name here only if that fails (the log says so). Server only."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { SettingsSync.OnLocalSettingsChanged(ReadLocalSettings()); }; SettingsSync.Initialize(ReadLocalSettings()); harmony = new Harmony("com.jonasd.valheim.morkhallaprogressionscaling"); harmony.PatchAll(); } private ScalingSettings ReadLocalSettings() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown return new ScalingSettings(enabledSetting.Value, maxSteps.Value, spawnIncreasePerStep.Value, starChancePerStep.Value, excludedCreatures.Value); } internal static void Detail(string message) { if (LogDetails != null && LogDetails.Value) { Log.LogInfo((object)message); } } internal static void DetailOnce(string message) { if (LogDetails != null && LogDetails.Value && LoggedOnce.Add(message)) { Log.LogInfo((object)message); } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } internal static class SettingsSync { [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNetAwakePatch { private static void Postfix(ZNet __instance) { fromServer = null; Places.Reset(); ZRoutedRpc.instance.Register<string>("MPS_Settings", (Action<long, string>)OnSettings); if (__instance.IsServer()) { ZRoutedRpc instance = ZRoutedRpc.instance; instance.m_onNewPeer = (Action<long>)Delegate.Combine(instance.m_onNewPeer, new Action<long>(SendTo)); } } } private const string SettingsRpc = "MPS_Settings"; private static ScalingSettings local = ScalingSettings.Default; private static ScalingSettings fromServer; public static ScalingSettings Current => fromServer ?? local; public static void Initialize(ScalingSettings settings) { local = settings; } public static void OnLocalSettingsChanged(ScalingSettings settings) { local = settings; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZRoutedRpc.instance != null) { SendTo(0L); } } private static void SendTo(long peer) { ZRoutedRpc.instance.InvokeRoutedRPC(peer, "MPS_Settings", new object[1] { local.Encode() }); } private static void OnSettings(long sender, string encoded) { ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) ? ZNet.instance.GetServerPeer() : null); if (val != null && sender == val.m_uid) { ScalingSettings val2 = default(ScalingSettings); if (ScalingSettings.TryDecode(encoded, ref val2)) { fromServer = val2; Plugin.Detail("Using the server's settings: " + encoded); } else { Plugin.Log.LogWarning((object)("Ignoring unreadable settings from the server: " + encoded)); } } } } internal static class Steps { public static int Count { get { string text = default(string); if ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.GetGlobalKey("mps_morkhallaclears", ref text)) { return 0; } return SettingsSync.Current.CapSteps(Progression.ParseClearCount(text)); } } public static float SpawnMultiplier => SettingsSync.Current.SpawnMultiplier(Count); public static int Increment() { int count = Count; int num = SettingsSync.Current.CapSteps(count + 1); if (num != count) { ZoneSystem.instance.SetGlobalKey(Progression.ClearCountKeyLine(num)); } return num; } } } namespace MorkhallaScaling.Patches { [HarmonyPatch(typeof(CreatureSpawner), "Spawn")] internal static class DungeonSpawnPatch { private const float ExtraRadius = 1.5f; private static readonly FieldRef<CreatureSpawner, ZNetView> NView = AccessTools.FieldRefAccess<CreatureSpawner, ZNetView>("m_nview"); private static void Prefix(CreatureSpawner __instance, out bool __state) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 ZNetView obj = NView.Invoke(__instance); ZDO val = ((obj != null) ? obj.GetZDO() : null); ZDOConnection val2 = ((val != null) ? val.GetConnection() : null); __state = val != null && (val2 == null || (int)val2.m_type != 3); } private static void Postfix(CreatureSpawner __instance, ZNetView __result, bool __state) { //IL_0037: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) if (!__state || (Object)(object)__result == (Object)null || (Object)(object)((Component)__result).GetComponent<MonsterAI>() == (Object)null || SettingsSync.Current.IsExcluded(((Object)__instance.m_creaturePrefab).name) || !Places.IsInMorkhalla(((Component)__instance).transform.position)) { return; } float spawnMultiplier = Steps.SpawnMultiplier; int num = Places.TakeShare(((Component)__instance).transform.position, 1, spawnMultiplier); if (num <= 0) { return; } Character component = ((Component)__result).GetComponent<Character>(); int num2 = ((!((Object)(object)component != (Object)null)) ? 1 : component.GetLevel()); float y = default(float); for (int i = 0; i < num; i++) { Vector2 val = Random.insideUnitCircle * 1.5f; Vector3 val2 = ((Component)__result).transform.position + new Vector3(val.x, 0f, val.y); if (ZoneSystem.instance.FindFloor(val2, ref y)) { val2.y = y; } GameObject val3 = Object.Instantiate<GameObject>(__instance.m_creaturePrefab, val2, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); if (num2 > 1) { Character component2 = val3.GetComponent<Character>(); if (component2 != null) { component2.SetLevel(num2); } } } Plugin.Detail($"Morkhalla spawner {((Object)__instance.m_creaturePrefab).name}: +{num} ({spawnMultiplier:0.##}x)"); } } [HarmonyPatch(typeof(PersistentEventSystem), "RPC_RequestStartEvent")] internal static class InvasionStartPatch { private static void Prefix(PersistentEventSystem __instance, out int __state) { __state = __instance.m_activePersistentEvents.list.Count; } private static void Postfix(PersistentEventSystem __instance, int sourceEventId, int __state) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) List<ActivePersistentEvent> list = __instance.m_activePersistentEvents.list; if (ZNet.instance.IsServer() && list.Count > __state) { ActivePersistentEvent val = list[list.Count - 1]; PersistentEvent eventInfo = __instance.GetEventInfo(sourceEventId); if (!Progression.IsCountedEvent(eventInfo.internalName, Plugin.CountedEvents.Value)) { Plugin.Detail("Event " + eventInfo.internalName + " is not in CountedEvents; not a Morkhalla clear."); return; } int num = Steps.Increment(); Plugin.Log.LogInfo((object)$"Morkhalla cleared ({eventInfo.internalName} started). Step {num} of {SettingsSync.Current.MaxSteps}."); Gammeltrolls.PlaceAround(val.position, num); } } } [HarmonyPatch(typeof(PersistentEventSystem), "Start")] internal static class PersistentEventListPatch { private static void Postfix(PersistentEventSystem __instance) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) foreach (PersistentEvent possibleEvent in __instance.m_possibleEvents) { bool flag = Progression.IsCountedEvent(possibleEvent.internalName, Plugin.CountedEvents.Value); Plugin.Log.LogInfo((object)$"Persistent event '{possibleEvent.internalName}' (biomes {possibleEvent.biomes}) counts as a Morkhalla clear: {flag}"); } } } [HarmonyPatch(typeof(SpawnArea), "SpawnOne")] internal static class SpawnAreaPatch { private sealed class Share { public float Multiplier; public int BaseMaxNear; public int ExtraNear; } private struct Saved { public bool Changed; public int MaxNear; public int MaxTotal; } private static readonly ConditionalWeakTable<SpawnArea, Share> Shares = new ConditionalWeakTable<SpawnArea, Share>(); private static void Prefix(SpawnArea __instance, out Saved __state) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) __state = default(Saved); float num = ((Places.IsInMorkhalla(((Component)__instance).transform.position) || IsInInvasion(__instance)) ? Steps.SpawnMultiplier : 1f); if (!(num <= 1f)) { Share orCreateValue = Shares.GetOrCreateValue(__instance); if (orCreateValue.Multiplier != num || orCreateValue.BaseMaxNear != __instance.m_maxNear) { orCreateValue.Multiplier = num; orCreateValue.BaseMaxNear = __instance.m_maxNear; orCreateValue.ExtraNear = Places.TakeShare(((Component)__instance).transform.position, __instance.m_maxNear, num); Plugin.Detail($"Spawn area at {((Component)__instance).transform.position}: max nearby {__instance.m_maxNear} -> {__instance.m_maxNear + orCreateValue.ExtraNear} ({num:0.##}x)"); } __state = new Saved { Changed = true, MaxNear = __instance.m_maxNear, MaxTotal = __instance.m_maxTotal }; __instance.m_maxNear += orCreateValue.ExtraNear; __instance.m_maxTotal = Progression.ScaleCount(__state.MaxTotal, num); } } private static Exception Finalizer(SpawnArea __instance, Saved __state, Exception __exception) { if (__state.Changed) { __instance.m_maxNear = __state.MaxNear; __instance.m_maxTotal = __state.MaxTotal; } return __exception; } private static bool IsInInvasion(SpawnArea area) { //IL_0006: 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_001e: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)area).transform.position; if ((Object)(object)PersistentEventSystem.instance != (Object)null) { return PersistentEventSystem.instance.GetActiveEvent(position) != null; } return false; } } [HarmonyPatch(typeof(SpawnSystem), "UpdateSpawnList")] internal static class SpawnSystemPatch { private readonly struct Saved { public readonly SpawnData Data; public readonly float Interval; public readonly int MaxSpawned; public readonly int GroupSizeMin; public readonly int GroupSizeMax; public Saved(SpawnData data) { Data = data; Interval = data.m_spawnInterval; MaxSpawned = data.m_maxSpawned; GroupSizeMin = data.m_groupSizeMin; GroupSizeMax = data.m_groupSizeMax; } public void Restore() { Data.m_spawnInterval = Interval; Data.m_maxSpawned = MaxSpawned; Data.m_groupSizeMin = GroupSizeMin; Data.m_groupSizeMax = GroupSizeMax; } } private static readonly List<Saved> Changed = new List<Saved>(); private static readonly Dictionary<GameObject, bool> HostilePrefabs = new Dictionary<GameObject, bool>(); private static void Prefix(List<SpawnData> spawners, bool eventSpawners) { Changed.Clear(); ScalingSettings current = SettingsSync.Current; float spawnMultiplier = Steps.SpawnMultiplier; if (spawnMultiplier <= 1f || spawners == null || eventSpawners) { return; } foreach (SpawnData spawner in spawners) { ScaleEntry(spawner, current, spawnMultiplier); } } private static Exception Finalizer(Exception __exception) { foreach (Saved item in Changed) { item.Restore(); } Changed.Clear(); return __exception; } private static void ScaleEntry(SpawnData data, ScalingSettings settings, float multiplier) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected I4, but got Unknown if (IsHostile(data.m_prefab) && !settings.IsExcluded(((Object)data.m_prefab).name) && (!string.IsNullOrEmpty(data.m_requiredPersistentEvent) || Progression.IsDeepNorth((int)data.m_biome))) { Saved item = new Saved(data); Changed.Add(item); data.m_spawnInterval = Progression.ScaleInterval(item.Interval, multiplier); data.m_maxSpawned = Progression.ScaleCount(item.MaxSpawned, multiplier); data.m_groupSizeMin = Progression.ScaleCount(item.GroupSizeMin, multiplier); data.m_groupSizeMax = Math.Max(data.m_groupSizeMin, Progression.ScaleCount(item.GroupSizeMax, multiplier)); if (Plugin.LogDetails.Value) { Plugin.DetailOnce("Scaled " + Name(data) + " (" + ((data.m_requiredPersistentEvent.Length > 0) ? "invasion" : "world") + "): " + $"interval {item.Interval}->{data.m_spawnInterval}, max {item.MaxSpawned}->{data.m_maxSpawned}, " + $"group {item.GroupSizeMin}-{item.GroupSizeMax} -> {data.m_groupSizeMin}-{data.m_groupSizeMax}"); } } } private static bool IsHostile(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return false; } if (!HostilePrefabs.TryGetValue(prefab, out var value)) { value = (Object)(object)prefab.GetComponent<MonsterAI>() != (Object)null; HostilePrefabs[prefab] = value; } return value; } private static string Name(SpawnData data) { if (!((Object)(object)data.m_prefab != (Object)null)) { return data.m_name; } return ((Object)data.m_prefab).name; } } internal static class StarChance { private static int spawningHostile; internal static bool SpawningHostile => spawningHostile > 0; internal static bool Enter(GameObject prefab) { if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent<MonsterAI>() == (Object)null || SettingsSync.Current.IsExcluded(((Object)prefab).name)) { return false; } spawningHostile++; return true; } internal static void Leave(bool entered) { if (entered && spawningHostile > 0) { spawningHostile--; } } internal static float Apply(float chance, Vector3 position) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected I4, but got Unknown if (WorldGenerator.instance == null || !Progression.IsDeepNorth((int)WorldGenerator.instance.GetBiome(position))) { return chance; } return SettingsSync.Current.StarChance(chance, Steps.Count); } } [HarmonyPatch(typeof(SpawnSystem), "Spawn")] internal static class WorldSpawnStarContext { private static void Prefix(SpawnData critter, out bool __state) { __state = StarChance.Enter(critter.m_prefab); } private static Exception Finalizer(bool __state, Exception __exception) { StarChance.Leave(__state); return __exception; } } [HarmonyPatch(typeof(CreatureSpawner), "Spawn")] internal static class CreatureSpawnerStarContext { private static void Prefix(CreatureSpawner __instance, out bool __state) { __state = StarChance.Enter(__instance.m_creaturePrefab); } private static Exception Finalizer(bool __state, Exception __exception) { StarChance.Leave(__state); return __exception; } } [HarmonyPatch(typeof(SpawnSystem), "GetLevelUpChance", new Type[] { typeof(Vector3), typeof(float) })] internal static class LevelUpChancePatch { private static void Postfix(Vector3 position, ref float __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (StarChance.SpawningHostile) { __result = StarChance.Apply(__result, position); } } } [HarmonyPatch(typeof(SpawnArea), "GetLevelUpChance")] internal static class SpawnAreaLevelUpChancePatch { private static void Postfix(SpawnArea __instance, ref float __result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) __result = StarChance.Apply(__result, ((Component)__instance).transform.position); } } }