Decompiled source of ReefLevels v0.1.0

ReefLevels.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
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("ReefLevels")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+523a001dd61578f32898283ab8d4550ef81782b9")]
[assembly: AssemblyProduct("ReefLevels")]
[assembly: AssemblyTitle("ReefLevels")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ReefLevels
{
	internal static class Display
	{
		[HarmonyPatch(typeof(LevelEffects), "SetupLevelVisualization", new Type[] { typeof(int) })]
		internal static class LevelVisualization
		{
			private static void Prefix(LevelEffects __instance, int level)
			{
				try
				{
					List<LevelSetup> levelSetups = __instance.m_levelSetups;
					if (levelSetups != null && levelSetups.Count != 0)
					{
						while (levelSetups.Count < level - 1)
						{
							levelSetups.Add(levelSetups[levelSetups.Count - 1]);
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("SetupLevelVisualization: " + ex.GetType().Name + ": " + ex.Message));
				}
			}

			private static void Postfix(LevelEffects __instance, int level)
			{
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					List<LevelSetup> levelSetups = __instance.m_levelSetups;
					if (level > 1 && levelSetups != null && levelSetups.Count >= level - 1)
					{
						float value = ReefLevelsPlugin.SizePerStar.Value;
						if (!(value <= 0f) && (!(((Component)__instance).transform.position.y >= 4500f) || ReefLevelsPlugin.SizeInDungeons.Value))
						{
							Transform transform = ((Component)__instance).transform;
							transform.localScale *= 1f + value * (float)(level - 1);
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("SetupLevelVisualization: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "ShowHud", new Type[]
		{
			typeof(Character),
			typeof(bool)
		})]
		internal static class HudShow
		{
			private static void Postfix(EnemyHud __instance, Character c)
			{
				//IL_011c: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!(hudsField.GetValue(__instance) is IDictionary dictionary) || (Object)(object)c == (Object)null)
					{
						return;
					}
					object obj = dictionary[c];
					if (obj == null)
					{
						return;
					}
					object? value = guiField.GetValue(obj);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if ((Object)(object)val == (Object)null || (Object)(object)val.transform.Find("level_4") != (Object)null)
					{
						return;
					}
					Transform val2 = val.transform.Find("level_3");
					if ((Object)(object)val2 == (Object)null || val2.childCount == 0)
					{
						return;
					}
					for (int i = 4; i <= 7; i++)
					{
						GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, val2.parent);
						((Object)val3).name = "level_" + i;
						val3.SetActive(false);
						GameObject gameObject = ((Component)val3.transform.GetChild(0)).gameObject;
						for (int j = 3; j <= i - 1; j++)
						{
							Object.Instantiate<GameObject>(gameObject, val3.transform).transform.localPosition = new Vector3(16f * (float)((j - 1) % 5) - 8f, (float)((j - 1) / 5) * -16f, 0f);
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("EnemyHud.ShowHud: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "UpdateHuds", new Type[]
		{
			typeof(Player),
			typeof(Sadle),
			typeof(float)
		})]
		internal static class HudUpdate
		{
			private static void Postfix(EnemyHud __instance)
			{
				try
				{
					if (!(hudsField.GetValue(__instance) is IDictionary dictionary))
					{
						return;
					}
					bool value = ReefLevelsPlugin.InfusionInName.Value;
					foreach (DictionaryEntry item in dictionary)
					{
						object key = item.Key;
						Character val = (Character)((key is Character) ? key : null);
						object value2 = item.Value;
						if ((Object)(object)val == (Object)null || value2 == null)
						{
							continue;
						}
						object? value3 = guiField.GetValue(value2);
						GameObject val2 = (GameObject)((value3 is GameObject) ? value3 : null);
						if ((Object)(object)val2 == (Object)null || !val2.activeSelf)
						{
							continue;
						}
						int level = val.GetLevel();
						if (level >= 4)
						{
							Transform val3 = val2.transform.Find("level_" + Mathf.Min(level, 7));
							if ((Object)(object)val3 != (Object)null && !((Component)val3).gameObject.activeSelf)
							{
								((Component)val3).gameObject.SetActive(true);
							}
						}
						if (!value)
						{
							continue;
						}
						int num = Infusion.Of(val);
						if (num == 0)
						{
							continue;
						}
						object? value4 = nameField.GetValue(value2);
						TextMeshProUGUI val4 = (TextMeshProUGUI)((value4 is TextMeshProUGUI) ? value4 : null);
						if (!((Object)(object)val4 == (Object)null))
						{
							string text = Infusion.Names[num] + "-Infused ";
							if (!((TMP_Text)val4).text.StartsWith(text, StringComparison.Ordinal))
							{
								((TMP_Text)val4).text = text + ((TMP_Text)val4).text;
							}
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("EnemyHud.UpdateHuds: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private static readonly FieldInfo hudsField = AccessTools.Field(typeof(EnemyHud), "m_huds");

		private static readonly Type hudDataType = AccessTools.Inner(typeof(EnemyHud), "HudData");

		private static readonly FieldInfo guiField = AccessTools.Field(hudDataType, "m_gui");

		private static readonly FieldInfo nameField = AccessTools.Field(hudDataType, "m_name");
	}
	internal static class Infusion
	{
		internal class ChaosTint : MonoBehaviour
		{
			private Character character;

			private float timer;

			private void Awake()
			{
				character = ((Component)this).GetComponent<Character>();
			}

			private void Update()
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				timer -= Time.deltaTime;
				if (!(timer > 0f))
				{
					timer = 5f;
					if ((Object)(object)character != (Object)null)
					{
						Tint(character, TintOf(RandomElement()));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "SetLevel", new Type[] { typeof(int) })]
		internal static class CharacterSetLevel
		{
			private static void Postfix(Character __instance)
			{
				try
				{
					if (!__instance.IsPlayer())
					{
						ApplyTint(__instance);
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("Character.SetLevel: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage", new Type[] { typeof(HitData) })]
		internal static class CharacterDamage
		{
			private static void Prefix(Character __instance, HitData hit)
			{
				try
				{
					if (hit == null || inBurst || !ReefLevelsPlugin.InfusionsEnabled.Value)
					{
						return;
					}
					Character attacker = hit.GetAttacker();
					if ((Object)(object)attacker == (Object)null || attacker.IsPlayer() || attacker.IsBoss())
					{
						return;
					}
					ZNetView val = NView(attacker);
					if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
					{
						return;
					}
					int num = Of(attacker);
					switch (num)
					{
					case 0:
						return;
					case 5:
						num = RandomElement();
						break;
					}
					float totalDamage = hit.GetTotalDamage();
					if (!(totalDamage <= 0f))
					{
						float num2 = Mathf.Min(totalDamage, __instance.GetMaxHealth() * 0.33f);
						switch (num)
						{
						case 2:
							hit.ApplyModifier(1f - num2 / totalDamage);
							hit.m_damage.m_fire += num2;
							break;
						case 3:
							hit.ApplyModifier(1f - num2 / totalDamage);
							hit.m_damage.m_frost += num2;
							break;
						case 1:
							hit.ApplyModifier(1f - num2 / totalDamage);
							hit.m_damage.m_lightning += num2;
							break;
						case 6:
							hit.ApplyModifier(1f - num2 / totalDamage);
							hit.m_damage.m_damage += totalDamage * 0.3f;
							attacker.Heal(Mathf.Min(totalDamage, attacker.GetMaxHealth() * 0.3f), true);
							break;
						case 4:
						case 5:
							break;
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("Character.Damage: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(Character), "OnDeath", new Type[] { })]
		internal static class CharacterOnDeath
		{
			private static void Prefix(Character __instance)
			{
				try
				{
					if (!ReefLevelsPlugin.InfusionsEnabled.Value || __instance.IsPlayer() || __instance.IsBoss())
					{
						return;
					}
					ZNetView val = NView(__instance);
					if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
					{
						return;
					}
					switch (Of(__instance))
					{
					case 5:
						if (!(Random.value < 0.5f))
						{
							break;
						}
						goto case 4;
					case 4:
						Burst(__instance);
						break;
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("Character.OnDeath: " + ex.GetType().Name + ": " + ex.Message));
				}
			}

			private static void Burst(Character c)
			{
				//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_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d6: Expected O, but got Unknown
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
				//IL_0102: Unknown result type (might be due to invalid IL or missing references)
				Vector3 centerPoint = c.GetCenterPoint();
				GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("vfx_blob_attack") : null);
				if ((Object)(object)val != (Object)null)
				{
					Object.Instantiate<GameObject>(val, centerPoint, Quaternion.identity);
				}
				float num = c.GetMaxHealth() / 3f;
				List<Player> allPlayers = Player.GetAllPlayers();
				if (allPlayers == null)
				{
					return;
				}
				foreach (Player item in allPlayers)
				{
					if (!((Object)(object)item == (Object)null) && !(Vector3.Distance(((Component)item).transform.position, centerPoint) > 4f))
					{
						float bodyArmor = ((Character)item).GetBodyArmor();
						float num2 = num;
						if (bodyArmor > num2 / 4f)
						{
							num2 = Mathf.Sqrt(4f * bodyArmor * num2);
						}
						if (bodyArmor < num2 / 2f)
						{
							num2 = num + bodyArmor;
						}
						HitData val2 = new HitData();
						val2.m_damage.m_poison = num2;
						val2.m_point = ((Character)item).GetCenterPoint();
						val2.m_attacker = c.GetZDOID();
						val2.m_hitType = (HitType)1;
						inBurst = true;
						try
						{
							((Character)item).Damage(val2);
						}
						finally
						{
							inBurst = false;
						}
					}
				}
			}
		}

		internal const int None = 0;

		internal const int Lightning = 1;

		internal const int Fire = 2;

		internal const int Frost = 3;

		internal const int Poison = 4;

		internal const int Chaos = 5;

		internal const int Spirit = 6;

		internal static readonly string[] Names = new string[7] { "none", "Lightning", "Fire", "Frost", "Poison", "Chaos", "Spirit" };

		internal static readonly int[] ConfigOrder = new int[6] { 2, 3, 4, 1, 6, 5 };

		private static readonly int[] Elements = new int[5] { 1, 2, 3, 4, 6 };

		private static readonly FieldRef<Character, ZNetView> nviewRef = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

		private static bool inBurst;

		internal static ZNetView NView(Character c)
		{
			if (!((Object)(object)c == (Object)null))
			{
				return nviewRef.Invoke(c);
			}
			return null;
		}

		internal static int Draw(int stars)
		{
			if (!ReefLevelsPlugin.InfusionsEnabled.Value || stars < 1)
			{
				return 0;
			}
			float num = Roll.Parse(ReefLevelsPlugin.InfusionPerStar.Value, 6)[Mathf.Clamp(stars, 0, 5)];
			float num2 = Random.value * 100f;
			float num3 = 0f;
			for (int i = 0; i < 6; i++)
			{
				num3 += ReefLevelsPlugin.InfusionChance[i].Value * num;
				if (num2 < num3)
				{
					return ConfigOrder[i];
				}
			}
			return 0;
		}

		internal static int Of(Character c)
		{
			ZNetView val = NView(c);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return 0;
			}
			ZDO zDO = val.GetZDO();
			int num = zDO.GetInt("ReefLevels.infusion", -1);
			if (num == -1)
			{
				num = zDO.GetInt("CL&LC infusion", -1);
			}
			if (num >= 0 && num <= 6)
			{
				return num;
			}
			return 0;
		}

		internal static int RandomElement()
		{
			return Elements[Random.Range(0, Elements.Length)];
		}

		internal static Color TintOf(int inf)
		{
			//IL_005b: 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_0046: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(inf switch
			{
				2 => new Color(1f, 0.1f, 0f), 
				3 => new Color(0f, 0f, 1f), 
				1 => new Color(0.8f, 0.75f, 1f), 
				6 => new Color(1f, 0f, 1f), 
				4 => new Color(0f, 1f, 0f), 
				_ => Color.white, 
			});
		}

		internal static void ApplyTint(Character c)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			int num = Of(c);
			switch (num)
			{
			case 0:
				break;
			case 5:
				if ((Object)(object)((Component)c).GetComponent<ChaosTint>() == (Object)null)
				{
					((Component)c).gameObject.AddComponent<ChaosTint>();
				}
				break;
			default:
				Tint(c, TintOf(num));
				break;
			}
		}

		internal static void Tint(Character c, Color tint)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			float value = ReefLevelsPlugin.TintBrightness.Value;
			Color val = default(Color);
			((Color)(ref val))..ctor(tint.r * value, tint.g * value, tint.b * value, 1f);
			MaterialPropertyBlock val2 = new MaterialPropertyBlock();
			Renderer[] componentsInChildren = ((Component)c).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				Material sharedMaterial = val3.sharedMaterial;
				if ((Object)(object)sharedMaterial == (Object)null)
				{
					continue;
				}
				val2.Clear();
				val3.GetPropertyBlock(val2);
				if (sharedMaterial.HasProperty("_EmissionColor"))
				{
					val2.SetColor("_EmissionColor", val);
				}
				else
				{
					if (!sharedMaterial.HasProperty("_Color"))
					{
						continue;
					}
					val2.SetColor("_Color", Color.Lerp(sharedMaterial.GetColor("_Color"), val, 0.5f));
				}
				val3.SetPropertyBlock(val2);
			}
		}
	}
	[BepInPlugin("reef.levels", "Reef Levels", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ReefLevelsPlugin : BaseUnityPlugin
	{
		public const string GUID = "reef.levels";

		public const string NAME = "Reef Levels";

		public const string VERSION = "0.1.0";

		internal const string CllcGuid = "org.bepinex.plugins.creaturelevelcontrol";

		internal static ManualLogSource Log;

		internal static ConfigEntry<int> MaxStars;

		internal static readonly ConfigEntry<string>[] StarChances = new ConfigEntry<string>[6];

		internal static ConfigEntry<float> SizePerStar;

		internal static ConfigEntry<bool> SizeInDungeons;

		internal static ConfigEntry<bool> InfusionsEnabled;

		internal static readonly ConfigEntry<float>[] InfusionChance = new ConfigEntry<float>[6];

		internal static ConfigEntry<string> InfusionPerStar;

		internal static ConfigEntry<bool> InfusionInName;

		internal static ConfigEntry<float> TintBrightness;

		internal static ConfigEntry<bool> LogRolls;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			if (Chainloader.PluginInfos.ContainsKey("org.bepinex.plugins.creaturelevelcontrol"))
			{
				Log.LogWarning((object)"Reef Levels 0.1.0: CreatureLevelControl is loaded next to us — no patch applied (its own roll and display would double ours)");
				return;
			}
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				Log.LogInfo((object)"Reef Levels 0.1.0: headless — config only, no patch");
				return;
			}
			harmony = new Harmony("reef.levels");
			harmony.PatchAll(typeof(Roll.SpawnSystemSpawn));
			harmony.PatchAll(typeof(Roll.CreatureSpawnerSpawn));
			harmony.PatchAll(typeof(Roll.SpawnAreaSpawnOne));
			harmony.PatchAll(typeof(Roll.CharacterAwake));
			harmony.PatchAll(typeof(Roll.CharacterSetLevelKeep));
			harmony.PatchAll(typeof(Infusion.CharacterSetLevel));
			harmony.PatchAll(typeof(Infusion.CharacterDamage));
			harmony.PatchAll(typeof(Infusion.CharacterOnDeath));
			harmony.PatchAll(typeof(Display.LevelVisualization));
			harmony.PatchAll(typeof(Display.HudShow));
			harmony.PatchAll(typeof(Display.HudUpdate));
			Log.LogInfo((object)"Reef Levels 0.1.0 loaded");
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static ConfigDescription Admin(string text, AcceptableValueBase range = null)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(text, range, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} });
		}

		private void BindConfig()
		{
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Expected O, but got Unknown
			MaxStars = ((BaseUnityPlugin)this).Config.Bind<int>("Levels", "Maximum stars", 2, Admin("Natural creatures never roll more stars than this (0-5). The Reef: 2 today, 5 once ReefLevels is proven.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 5)));
			string[] array = new string[6] { "10,2,0,0,0", "15,5,1,0,0", "18,8,2,0.3,0", "22,10,3,0.5,0.3", "25,12,5,1,0.5", "30,15,8,3,1" };
			for (int i = 0; i < 6; i++)
			{
				StarChances[i] = ((BaseUnityPlugin)this).Config.Bind<string>("Levels", "Chances for stars at world level " + i, array[i], Admin("Percentages for 1, 2, 3, 4 and 5 stars at world level " + i + " (= number of bosses defeated among the first six; 6 uses this row too). The rest is 0 stars."));
			}
			SizePerStar = ((BaseUnityPlugin)this).Config.Bind<float>("Levels", "Creature size increase per star", 0.1f, Admin("Creature scale grows by this fraction per star (0.10 = +10 % per star).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)));
			SizeInDungeons = ((BaseUnityPlugin)this).Config.Bind<bool>("Levels", "Increase creature size in dungeons", false, Admin("true = the size increase also applies inside dungeons (y >= 4500), where big creatures get stuck."));
			InfusionsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Infusions", "Enabled", true, Admin("Creatures with at least one star can roll an elemental infusion."));
			string[] array2 = new string[6] { "Fire", "Frost", "Poison", "Lightning", "Spirit", "Chaos" };
			float[] array3 = new float[6] { 7f, 7f, 4f, 3f, 1.75f, 1.25f };
			for (int j = 0; j < 6; j++)
			{
				InfusionChance[j] = ((BaseUnityPlugin)this).Config.Bind<float>("Infusions", "Chance for " + array2[j], array3[j], Admin("Percent chance of a " + array2[j] + " infusion, multiplied by the per-star multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			}
			InfusionPerStar = ((BaseUnityPlugin)this).Config.Bind<string>("Infusions", "Multiplier per star", "0,0.3,0.6,1,1.3,1.6", Admin("Multiplier applied to every infusion chance for 0, 1, 2, 3, 4 and 5 stars."));
			InfusionInName = ((BaseUnityPlugin)this).Config.Bind<bool>("Infusions", "Add the infusion to the name", true, "Shows 'Fire-Infused Greydwarf' in the enemy nameplate. Client-side.");
			TintBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Infusions", "Tint brightness", 0.3f, new ConfigDescription("Multiplier on the infusion tint colour applied to the creature (1 = full emission, the model reads as a flat colour — bench S030). Client-side.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 4f), Array.Empty<object>()));
			LogRolls = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log rolls", false, "Logs one line per creature rolled by this client: prefab, world level, stars, infusion. Client-side.");
		}
	}
	internal static class Roll
	{
		[HarmonyPatch(typeof(SpawnSystem), "Spawn", new Type[]
		{
			typeof(SpawnData),
			typeof(Vector3),
			typeof(bool)
		})]
		internal static class SpawnSystemSpawn
		{
			private static void Prefix()
			{
				Spawning++;
			}

			private static void Postfix()
			{
				Spawning--;
			}
		}

		[HarmonyPatch(typeof(CreatureSpawner), "Spawn", new Type[] { })]
		internal static class CreatureSpawnerSpawn
		{
			private static void Prefix()
			{
				Spawning++;
			}

			private static void Postfix()
			{
				Spawning--;
			}
		}

		[HarmonyPatch(typeof(SpawnArea), "SpawnOne", new Type[] { })]
		internal static class SpawnAreaSpawnOne
		{
			private static void Prefix()
			{
				Spawning++;
			}

			private static void Postfix()
			{
				Spawning--;
			}
		}

		[HarmonyPatch(typeof(Character), "Awake", new Type[] { })]
		internal static class CharacterAwake
		{
			private static void Postfix(Character __instance)
			{
				try
				{
					if (__instance.IsPlayer())
					{
						return;
					}
					ZNetView val = Infusion.NView(__instance);
					if (!((Object)(object)val == (Object)null) && val.IsValid())
					{
						ZDO zDO = val.GetZDO();
						if (Spawning > 0 && val.IsOwner() && !__instance.IsTamed() && !__instance.IsBoss() && zDO.GetInt("ReefLevels.rolled", -1) == -1 && zDO.GetInt("CL&LC effect", -1) == -1 && zDO.GetInt("CL&LC infusion", -1) == -1)
						{
							RollOne(__instance, zDO);
						}
						Infusion.ApplyTint(__instance);
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("Character.Awake: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(Character), "SetLevel", new Type[] { typeof(int) })]
		internal static class CharacterSetLevelKeep
		{
			private static void Prefix(Character __instance, ref int level)
			{
				try
				{
					if (Spawning <= 0 || __instance.IsPlayer())
					{
						return;
					}
					ZNetView val = Infusion.NView(__instance);
					if (!((Object)(object)val == (Object)null) && val.IsValid())
					{
						int num = val.GetZDO().GetInt("ReefLevels.level", -1);
						if (num >= 1 && level != num)
						{
							level = num;
						}
					}
				}
				catch (Exception ex)
				{
					ReefLevelsPlugin.Log.LogWarning((object)("Character.SetLevel(keep): " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		internal const string KeyRolled = "ReefLevels.rolled";

		internal const string KeyInfusion = "ReefLevels.infusion";

		internal const string KeyLevel = "ReefLevels.level";

		internal const string CllcEffect = "CL&LC effect";

		internal const string CllcInfusion = "CL&LC infusion";

		private static readonly string[] BossKeys = new string[6] { "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen" };

		internal static int Spawning;

		internal static int WorldLevel()
		{
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return 0;
			}
			int num = 0;
			string[] bossKeys = BossKeys;
			foreach (string text in bossKeys)
			{
				if (instance.GetGlobalKey(text))
				{
					num++;
				}
			}
			return num;
		}

		internal static float[] Parse(string s, int count)
		{
			float[] array = new float[count];
			string[] array2 = (s ?? "").Split(new char[1] { ',' });
			for (int i = 0; i < count && i < array2.Length; i++)
			{
				array[i] = (float.TryParse(array2[i].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) ? result : 0f);
			}
			return array;
		}

		internal static int DrawStars(int worldLevel)
		{
			float[] array = Parse(ReefLevelsPlugin.StarChances[Mathf.Clamp(worldLevel, 0, 5)].Value, 5);
			float num = Random.value * 100f;
			float num2 = 0f;
			int num3 = 0;
			for (int num4 = 5; num4 >= 1; num4--)
			{
				num2 += array[num4 - 1];
				if (num < num2)
				{
					num3 = num4;
					break;
				}
			}
			return Mathf.Clamp(num3, 0, ReefLevelsPlugin.MaxStars.Value);
		}

		internal static string PrefabName(Character c)
		{
			string name = ((Object)((Component)c).gameObject).name;
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num <= 0)
			{
				return name;
			}
			return name.Substring(0, num);
		}

		private static void RollOne(Character c, ZDO zdo)
		{
			int worldLevel = WorldLevel();
			int num = DrawStars(worldLevel);
			int num2 = Infusion.Draw(num);
			zdo.Set("ReefLevels.infusion", num2);
			zdo.Set("ReefLevels.level", num + 1);
			zdo.Set("ReefLevels.rolled", 1);
			c.SetLevel(num + 1);
			if (ReefLevelsPlugin.LogRolls.Value)
			{
				ReefLevelsPlugin.Log.LogInfo((object)("ReefLevels: " + PrefabName(c) + " wl=" + worldLevel + " stars=" + num + " infusion=" + Infusion.Names[num2]));
			}
		}
	}
}