Decompiled source of MoreRelics v1.0.0

MoreRelics.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SuperFantasyKingdom;
using SuperFantasyKingdom.Buildings;
using SuperFantasyKingdom.Clickable;
using SuperFantasyKingdom.Spawner;
using SuperFantasyKingdom.Spells;
using SuperFantasyKingdom.Tavern;
using SuperFantasyKingdom.UI;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("MoreRelics")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f98f1699223006a870c71b5365fcb9d67bf33b8d")]
[assembly: AssemblyProduct("More Relics")]
[assembly: AssemblyTitle("MoreRelics")]
[assembly: AssemblyVersion("1.0.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 MoreRelics
{
	internal sealed class Cornucopia : RelicEntry
	{
		private const int MinPerDay = 1;

		private const int MaxPerDay = 2;

		private const int SeedSalt = 4123;

		private static readonly ResourceType[] Gathered;

		private static readonly RelicDef Definition;

		public override RelicDef Def => Definition;

		public override void OnMorning(int day)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			Random random = new Random((((Object)(object)GameManager.Instance != (Object)null) ? GameManager.Instance.GetSeed() : 0) * 7 + 4123 + day);
			BuildingCastle val = (((Object)(object)CityManager.Instance != (Object)null) ? CityManager.Instance.GetCastle() : null);
			int num = random.Next(1, 3);
			for (int i = 0; i < num; i++)
			{
				ResourceType val2 = Gathered[random.Next(Gathered.Length)];
				if ((Object)(object)val == (Object)null || (Object)(object)DroppedShardSpawner.Instance == (Object)null)
				{
					ResourceManager.Instance.AddResource(val2, 1);
				}
				else
				{
					DroppedShardSpawner.Instance.Spawn(((BuildingCity)val).GetPosition(), 1, val2, false);
				}
			}
		}

		static Cornucopia()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			ResourceType[] array = new ResourceType[7];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Gathered = (ResourceType[])(object)array;
			Definition = new RelicDef
			{
				id = "ownly_Cornucopia",
				cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
				rarity = (Rarity)2,
				cost = 8,
				title = "Cornucopia",
				description = "1-2 random resources every morning."
			};
		}
	}
	internal sealed class Grimoire : RelicEntry
	{
		private static readonly RelicDef Definition = new RelicDef
		{
			id = "ownly_Grimoire",
			cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
			rarity = (Rarity)3,
			cost = 9,
			title = "Grimoire",
			description = "A new spell no longer replaces the old one. Click the second slot to switch."
		};

		public override RelicDef Def => Definition;

		public override void OnAcquired()
		{
			Preview.Refresh();
		}

		public override void OnMorning(int day)
		{
			Preview.Refresh();
		}

		internal static bool Active()
		{
			return Registry.Find(Definition.id)?.Held() ?? false;
		}

		internal static void Swap()
		{
			//IL_002a: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			SpellManager instance = SpellManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			bool flag = instance.IsOnBattlefield();
			SpellBase val = (flag ? instance.GetCombatSpell() : instance.GetCitySpell());
			SpellType val2 = Reserve.Get(flag);
			if (!((Object)(object)val == (Object)null) && (int)val2 != 0 && val2 != val.GetSpellType() && !((Object)(object)instance.GetSpell(val2) == (Object)null))
			{
				instance.Cancel(false);
				Reserve.Set(flag, val.GetSpellType());
				if (flag)
				{
					instance.SetCombatSpell(val2);
				}
				else
				{
					instance.SetCitySpell(val2);
				}
				Traverse.Create(typeof(SpellManager)).Field("OnSwitch").GetValue<Action<bool>>()?.Invoke(flag);
				Preview.Refresh();
			}
		}
	}
	internal static class Preview
	{
		private const float Scale = 0.62f;

		private const float OffsetX = 0f;

		private const float OffsetY = -0.85f;

		private static readonly Color Dimmed = new Color(1f, 1f, 1f, 0.8f);

		private static Image s_Image;

		private static Sprite s_Unknown;

		internal static bool Hovering;

		internal static void Build(Image icon)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			Hovering = false;
			RectTransform rectTransform = ((Graphic)icon).rectTransform;
			GameObject val = new GameObject("GrimoireReserve", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(((Transform)rectTransform).parent, false);
			Vector2 sizeDelta = rectTransform.sizeDelta;
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = rectTransform.anchorMin;
			component.anchorMax = rectTransform.anchorMax;
			component.pivot = rectTransform.pivot;
			((Transform)component).localScale = Vector3.one;
			component.sizeDelta = sizeDelta * 0.62f;
			component.anchoredPosition = rectTransform.anchoredPosition + new Vector2(sizeDelta.x * 0f, sizeDelta.y * -0.85f);
			s_Image = val.AddComponent<Image>();
			((Graphic)s_Image).material = ((Graphic)icon).material;
			s_Image.preserveAspect = true;
			((Graphic)s_Image).raycastTarget = true;
			EventTrigger trigger = val.AddComponent<EventTrigger>();
			Hover(trigger, (EventTriggerType)0, over: true);
			Hover(trigger, (EventTriggerType)1, over: false);
			Refresh();
		}

		internal static void Refresh()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			if ((Object)(object)s_Image == (Object)null)
			{
				return;
			}
			bool flag = Grimoire.Active();
			((Component)s_Image).gameObject.SetActive(flag);
			if (flag)
			{
				SpellManager instance = SpellManager.Instance;
				SpellType val = (SpellType)(((Object)(object)instance != (Object)null) ? ((int)Reserve.Get(instance.IsOnBattlefield())) : 0);
				SpellBase val2 = (((Object)(object)instance != (Object)null && (int)val != 0) ? instance.GetSpell(val) : null);
				if ((Object)(object)val2 != (Object)null)
				{
					s_Image.sprite = val2.GetIcon();
					((Graphic)s_Image).color = Color.white;
				}
				else
				{
					s_Image.sprite = Unknown();
					((Graphic)s_Image).color = Dimmed;
				}
			}
		}

		private static void Hover(EventTrigger trigger, EventTriggerType type, bool over)
		{
			//IL_000d: 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)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			Entry val = new Entry
			{
				eventID = type
			};
			((UnityEvent<BaseEventData>)(object)val.callback).AddListener((UnityAction<BaseEventData>)delegate
			{
				Hovering = over;
			});
			trigger.triggers.Add(val);
		}

		private static Sprite Unknown()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s_Unknown != (Object)null)
			{
				return s_Unknown;
			}
			Stream manifestResourceStream = typeof(Plugin).Assembly.GetManifestResourceStream("MoreRelics.Icons.SlotUnknown.png");
			if (manifestResourceStream == null)
			{
				return null;
			}
			byte[] array = new byte[manifestResourceStream.Length];
			manifestResourceStream.Read(array, 0, array.Length);
			manifestResourceStream.Dispose();
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)"could not decode SlotUnknown.png");
				}
				return null;
			}
			((Texture)val).filterMode = (FilterMode)0;
			((Object)val).hideFlags = (HideFlags)61;
			s_Unknown = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width);
			((Object)s_Unknown).hideFlags = (HideFlags)61;
			return s_Unknown;
		}
	}
	internal static class Reserve
	{
		private static SpellType s_City;

		private static SpellType s_Combat;

		private static string s_Key;

		private static int s_Seed;

		private static int CurrentSeed()
		{
			if (!((Object)(object)GameManager.Instance != (Object)null))
			{
				return 0;
			}
			return GameManager.Instance.GetSeed();
		}

		public static SpellType Get(bool combat)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Load();
			if (!combat)
			{
				return s_City;
			}
			return s_Combat;
		}

		public static void Set(bool combat, SpellType spell)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Load();
			if (combat)
			{
				s_Combat = spell;
			}
			else
			{
				s_City = spell;
			}
			Write();
		}

		public static void Clear()
		{
			//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)
			Load();
			s_City = (SpellType)0;
			s_Combat = (SpellType)0;
			Write();
		}

		private static string Key()
		{
			//IL_0019: 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)
			string obj = (((Object)(object)RaceManager.Instance != (Object)null) ? ((object)RaceManager.Instance.GetRace()/*cast due to .constrained prefix*/).ToString() : "None");
			string text = (((Object)(object)SettingsManager.Instance != (Object)null) ? SettingsManager.Instance.GetProfile().ToString() : "0");
			bool flag = (Object)(object)MainManager.Instance != (Object)null && MainManager.Instance.IsChallenge();
			return obj + "_" + text + (flag ? "_challenge" : "");
		}

		private static string Path()
		{
			return System.IO.Path.Combine(Paths.ConfigPath, "MoreRelics", s_Key + ".txt");
		}

		private static void Load()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: 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)
			string text = Key();
			int num = CurrentSeed();
			if (text == s_Key && (num == 0 || num == s_Seed))
			{
				return;
			}
			s_Key = text;
			s_Seed = num;
			s_City = (SpellType)0;
			s_Combat = (SpellType)0;
			int result = 0;
			try
			{
				string path = Path();
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllLines(path);
				foreach (string text2 in array)
				{
					int num2 = text2.IndexOf('=');
					if (num2 <= 0)
					{
						continue;
					}
					string text3 = text2.Substring(num2 + 1).Trim();
					if (text2.StartsWith("seed"))
					{
						int.TryParse(text3, out result);
					}
					else if (Enum.IsDefined(typeof(SpellType), text3))
					{
						SpellType val = (SpellType)Enum.Parse(typeof(SpellType), text3);
						if (text2.StartsWith("city"))
						{
							s_City = val;
						}
						else if (text2.StartsWith("combat"))
						{
							s_Combat = val;
						}
					}
				}
				if (num != 0 && result != num)
				{
					s_City = (SpellType)0;
					s_Combat = (SpellType)0;
					Write();
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire could not read its spells: " + ex));
				}
			}
		}

		private static void Write()
		{
			try
			{
				string path = Path();
				Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
				File.WriteAllText(path, "city=" + ((object)Unsafe.As<SpellType, SpellType>(ref s_City)/*cast due to .constrained prefix*/).ToString() + "\ncombat=" + ((object)Unsafe.As<SpellType, SpellType>(ref s_Combat)/*cast due to .constrained prefix*/).ToString() + "\nseed=" + CurrentSeed() + "\n");
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire could not write its spells: " + ex));
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Patch_GrimoireKeep
	{
		[HarmonyPatch(typeof(SpellManager), "SetCitySpell", new Type[] { typeof(SpellBase) })]
		[HarmonyPrefix]
		private static void City(SpellManager __instance, SpellBase spell)
		{
			Keep(__instance.GetCitySpell(), spell, combat: false);
		}

		[HarmonyPatch(typeof(SpellManager), "SetCombatSpell", new Type[] { typeof(SpellBase) })]
		[HarmonyPrefix]
		private static void Combat(SpellManager __instance, SpellBase spell)
		{
			Keep(__instance.GetCombatSpell(), spell, combat: true);
		}

		private static void Keep(SpellBase outgoing, SpellBase incoming, bool combat)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)outgoing == (Object)null) && !((Object)(object)incoming == (Object)null) && !((Object)(object)outgoing == (Object)(object)incoming) && Grimoire.Active())
				{
					SpellType val = Reserve.Get(combat);
					if ((int)val == 0 || val == incoming.GetSpellType())
					{
						Reserve.Set(combat, outgoing.GetSpellType());
						Preview.Refresh();
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire failed to keep the old spell: " + ex));
				}
			}
		}
	}
	[HarmonyPatch(typeof(SpellManager), "SetDefaultSpells")]
	internal static class Patch_GrimoireReset
	{
		private static void Postfix()
		{
			try
			{
				Reserve.Clear();
				Preview.Refresh();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire failed to clear its spells: " + ex));
				}
			}
		}
	}
	[HarmonyPatch(typeof(UISpells), "Awake")]
	internal static class Patch_GrimoireSlot
	{
		private static void Postfix(UISpells __instance)
		{
			try
			{
				Image value = Traverse.Create((object)__instance).Field("icon").GetValue<Image>();
				if (!((Object)(object)value == (Object)null))
				{
					Preview.Build(value);
					SpellManager.OnSwitch -= OnSwitch;
					SpellManager.OnSwitch += OnSwitch;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire could not build its slot: " + ex));
				}
			}
		}

		private static void OnSwitch(bool combat)
		{
			Preview.Refresh();
		}
	}
	[HarmonyPatch(typeof(GameInputManager), "GameClick")]
	internal static class Patch_GrimoireClick
	{
		private static bool Prefix(CallbackContext context)
		{
			try
			{
				if (!((CallbackContext)(ref context)).performed || !Preview.Hovering || !Grimoire.Active())
				{
					return true;
				}
				Grimoire.Swap();
				return false;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("grimoire failed on click: " + ex));
				}
				return true;
			}
		}
	}
	internal sealed class MasterKey : RelicEntry
	{
		private const string Id = "ownly_MasterKey";

		private const int FaithPerMorning = 2;

		private static readonly RelicDef Definition = new RelicDef
		{
			id = "ownly_MasterKey",
			cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
			rarity = (Rarity)1,
			cost = 6,
			title = "Master Key",
			description = "Relics ignore all their requirements.\n" + 2 + "<sprite name=ResourceFaith> every morning."
		};

		public override RelicDef Def => Definition;

		public override void OnMorning(int day)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)TaxManager.Instance != (Object)null)
			{
				TaxManager.Instance.AddToStatistics((ResourceType)13, 2);
			}
			BuildingCity val = null;
			if ((Object)(object)CityManager.Instance != (Object)null)
			{
				val = (BuildingCity)(object)CityManager.Instance.GetChurch();
				if ((Object)(object)val == (Object)null)
				{
					val = (BuildingCity)(object)CityManager.Instance.GetCastle();
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)DroppedShardSpawner.Instance == (Object)null)
			{
				ResourceManager.Instance.AddResource((ResourceType)13, 2);
				return;
			}
			for (int i = 0; i < 2; i++)
			{
				DroppedShardSpawner.Instance.Spawn(val.GetPosition(), 1, (ResourceType)13, false);
			}
		}

		internal static bool Active()
		{
			return Registry.Find("ownly_MasterKey")?.Held() ?? false;
		}
	}
	[HarmonyPatch(typeof(Relic), "GetRequiredBuilding")]
	internal static class Patch_RelicBuilding
	{
		private static void Postfix(ref BuildingType __result)
		{
			try
			{
				if (MasterKey.Active())
				{
					__result = (BuildingType)666;
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(DropBossChest), "PreparePool")]
	internal static class Patch_BossChestPool
	{
		private static void Postfix(DropBossChest __instance)
		{
			try
			{
				if (!MasterKey.Active())
				{
					return;
				}
				List<string> value = Traverse.Create((object)__instance).Field("RelicPool").GetValue<List<string>>();
				if (value == null)
				{
					return;
				}
				foreach (KeyValuePair<string, Unit> allUnit in AddressablesManager.Instance.GetAllUnits())
				{
					List<string> list = (((Object)(object)allUnit.Value != (Object)null) ? ((UnitBase)allUnit.Value).GetRelatedRelics() : null);
					if (list == null)
					{
						continue;
					}
					foreach (string item in list)
					{
						if (RelicManager.Instance.IsUnlocked(item) && !RelicManager.Instance.HasRelic(item) && !value.Contains(item))
						{
							value.Add(item);
						}
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Relic), "GetRequiredKingdomLevel")]
	internal static class Patch_RelicLevel
	{
		private static void Postfix(ref int __result)
		{
			try
			{
				if (MasterKey.Active())
				{
					__result = 0;
				}
			}
			catch
			{
			}
		}
	}
	internal sealed class Millstone : RelicEntry
	{
		internal const float ExtraDuration = 0.1f;

		private static readonly RelicDef Definition = new RelicDef
		{
			id = "ownly_Millstone",
			cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
			rarity = (Rarity)2,
			cost = 10,
			title = "Millstone",
			description = "<sprite name=ResourceWheat> to <sprite name=ResourceBread> in Bakery."
		};

		public override RelicDef Def => Definition;

		public override bool Available => !Chainloader.PluginInfos.ContainsKey("ownly.bakeryuseswheat");

		public override void OnAcquired()
		{
			Convert();
		}

		public override void OnMorning(int day)
		{
			Convert();
		}

		internal static bool Rewrite(BuildingResource building)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00c4: Invalid comparison between Unknown and I4
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((Building)building).GetBuildingType() != 18)
			{
				return false;
			}
			bool result = false;
			BuildingCrafting val = (BuildingCrafting)(object)((building is BuildingCrafting) ? building : null);
			if (val != null)
			{
				List<CraftingRecipe> craftingRecipes = ((BuildingCity)val).GetCraftingRecipes(false);
				if (craftingRecipes != null)
				{
					for (int i = 0; i < craftingRecipes.Count; i++)
					{
						ResourceAmount[] ingredients = craftingRecipes[i].ingredients;
						if (ingredients == null)
						{
							continue;
						}
						for (int j = 0; j < ingredients.Length; j++)
						{
							if ((int)ingredients[j].type == 8)
							{
								ingredients[j].type = (ResourceType)7;
								result = true;
							}
						}
					}
				}
			}
			ResourceStorage storage = ((Building)building).GetStorage();
			if ((Object)(object)storage == (Object)null)
			{
				return result;
			}
			List<ResourceAmount> value = Traverse.Create((object)storage).Field("storage").GetValue<List<ResourceAmount>>();
			if (value == null)
			{
				return result;
			}
			for (int k = 0; k < value.Count; k++)
			{
				if ((int)value[k].type == 8)
				{
					value[k] = new ResourceAmount((ResourceType)7, value[k].amount);
					result = true;
				}
			}
			return result;
		}

		private void Convert()
		{
			if ((Object)(object)CityManager.Instance == (Object)null)
			{
				return;
			}
			BuildingCity building = CityManager.Instance.GetBuilding((BuildingType)18);
			BuildingCrafting val = (BuildingCrafting)(object)((building is BuildingCrafting) ? building : null);
			if (val == null)
			{
				return;
			}
			ResourceStorage storage = ((Building)val).GetStorage();
			int num = (((Object)(object)storage != (Object)null) ? storage.GetStorageSpace((ResourceType)8) : 0);
			if (Rewrite((BuildingResource)(object)val))
			{
				val.SelectRecipe(Traverse.Create((object)val).Field("m_SelectedRecipe").GetValue<int>());
				if ((Object)(object)storage != (Object)null)
				{
					storage.SetStorageSpace((ResourceType)7, num);
					storage.SetStorageSpace((ResourceType)8, 0);
				}
				float timer = ((Building)val).GetTimer();
				((Building)val).SetTimer(timer * 1.1f);
			}
		}
	}
	[HarmonyPatch(typeof(BuildingResource), "Init")]
	internal static class Patch_Millstone
	{
		private static void Prefix(BuildingResource __instance, out bool __state)
		{
			__state = false;
			try
			{
				RelicEntry relicEntry = Registry.Find("ownly_Millstone");
				if (relicEntry != null && relicEntry.Held())
				{
					__state = Millstone.Rewrite(__instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("millstone failed on building init: " + ex));
				}
			}
		}

		private static void Postfix(BuildingResource __instance, bool __state)
		{
			if (!__state)
			{
				return;
			}
			try
			{
				float timer = ((Building)__instance).GetTimer();
				((Building)__instance).SetTimer(timer * 1.1f);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("millstone failed on building init: " + ex));
				}
			}
		}
	}
	internal sealed class Phalanx : RelicEntry
	{
		private const string Id = "ownly_Phalanx";

		private const int Lanes = 10;

		private const int MaxRank = 5;

		private const int LastFieldSpot = 45;

		private static readonly RelicDef Definition = new RelicDef
		{
			id = "ownly_Phalanx",
			cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
			rarity = (Rarity)3,
			cost = 12,
			title = "Phalanx",
			description = "Only the first unit of each column can be hurt.",
			bossOnly = true
		};

		public override RelicDef Def => Definition;

		internal static bool Covered(Entity entity)
		{
			UnitBase val = (UnitBase)(object)((entity is UnitBase) ? entity : null);
			if ((Object)(object)val == (Object)null || (Object)(object)GridManager.Instance == (Object)null)
			{
				return false;
			}
			int gridPosition = val.GetGridPosition();
			if (gridPosition < 1 || gridPosition > 45)
			{
				return false;
			}
			int num = gridPosition % 10;
			int num2 = gridPosition / 10;
			if (num < 1 || num > 5)
			{
				return false;
			}
			for (int i = num + 1; i <= 5; i++)
			{
				UnitBase unitByGridPosition = GridManager.Instance.GetUnitByGridPosition(num2 * 10 + i);
				if ((Object)(object)unitByGridPosition != (Object)null && !unitByGridPosition.IsDead() && !unitByGridPosition.IsAway())
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(UnitHealth), "ReceiveDamage", new Type[]
	{
		typeof(Damage),
		typeof(bool),
		typeof(bool)
	})]
	internal static class Patch_Phalanx
	{
		private static bool Prefix(UnitHealth __instance, ref float __result)
		{
			try
			{
				RelicEntry relicEntry = Registry.Find("ownly_Phalanx");
				if (relicEntry == null || !relicEntry.Held() || !Phalanx.Covered(((Health)__instance).GetEntity()))
				{
					return true;
				}
				__result = 0f;
				return false;
			}
			catch
			{
				return true;
			}
		}
	}
	[BepInPlugin("ownly.morerelics", "More Relics", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID).PatchAll();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("PatchAll THREW, later patches did not apply: " + ex));
			}
		}
	}
	internal static class Registry
	{
		public static readonly RelicEntry[] Entries = new RelicEntry[6]
		{
			new Cornucopia(),
			new Millstone(),
			new MasterKey(),
			new Phalanx(),
			new SousChef(),
			new Grimoire()
		};

		public static RelicEntry Find(string identifier)
		{
			RelicEntry[] entries = Entries;
			foreach (RelicEntry relicEntry in entries)
			{
				if (relicEntry.Def.id == identifier && relicEntry.Available)
				{
					return relicEntry;
				}
			}
			return null;
		}
	}
	internal sealed class RelicDef
	{
		public string id;

		public string[] cloneFrom;

		public Rarity rarity;

		public int cost;

		public string title;

		public string description;

		public int requiredKingdomLevel;

		public bool bossOnly;
	}
	internal abstract class RelicEntry
	{
		public abstract RelicDef Def { get; }

		public virtual bool Available => true;

		public virtual void OnMorning(int day)
		{
		}

		public virtual void OnAcquired()
		{
		}

		public bool Held()
		{
			if ((Object)(object)RelicManager.Instance != (Object)null)
			{
				return RelicManager.Instance.HasRelic(Def.id);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(AddressablesManager), "IsLoaded")]
	internal static class Patch_Register
	{
		private static bool s_Done;

		private static void Postfix(AddressablesManager __instance, bool __result)
		{
			if (!__result || s_Done)
			{
				return;
			}
			s_Done = true;
			try
			{
				Register(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("relic registration failed: " + ex));
				}
			}
		}

		private static void Register(AddressablesManager addressables)
		{
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Expected O, but got Unknown
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Expected O, but got Unknown
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Relic> allRelics = addressables.GetAllRelics();
			List<string> allRelicIdentifiers = addressables.GetAllRelicIdentifiers();
			RelicEntry[] entries = Registry.Entries;
			foreach (RelicEntry relicEntry in entries)
			{
				RelicDef def = relicEntry.Def;
				if (!relicEntry.Available)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("skipping " + def.id + ", another mod already covers it"));
					}
				}
				else
				{
					if (allRelics.ContainsKey(def.id))
					{
						continue;
					}
					Relic val = Donor(allRelics, def);
					if ((Object)(object)val == (Object)null)
					{
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogError((object)("no donor prefab for " + def.id));
						}
						continue;
					}
					Relic val2 = Object.Instantiate<Relic>(val);
					Object.DontDestroyOnLoad((Object)(object)((Component)val2).gameObject);
					((Component)val2).gameObject.SetActive(false);
					((Object)val2).name = def.id;
					Traverse val3 = Traverse.Create((object)val2);
					val3.Field("identifier").SetValue((object)def.id);
					val3.Field("rarity").SetValue((object)def.rarity);
					val3.Field("cost").SetValue((object)def.cost);
					val3.Field("generic").SetValue((object)false);
					val3.Field("racial").SetValue((object)false);
					val3.Field("unlockedByDefault").SetValue((object)true);
					val3.Field("triggerOnLoad").SetValue((object)false);
					val3.Field("triggerLater").SetValue((object)false);
					val3.Field("requiredKingdomLevel").SetValue((object)def.requiredKingdomLevel);
					val3.Field("upgrade").SetValue((object)null);
					val3.Field("soldAtCartographer1").SetValue((object)(!def.bossOnly));
					val3.Field("soldAtCartographer2").SetValue((object)(!def.bossOnly));
					val3.Field("soldAtCartographer3").SetValue((object)(!def.bossOnly));
					val3.Field("soldAtCartographer4").SetValue((object)(!def.bossOnly));
					val3.Field("requiredBuilding").SetValue((object)(BuildingType)666);
					val3.Field("relatedUnit").SetValue((object)"");
					val3.Field("kingdom").SetValue((object)(Races)11);
					val3.Field("keywords").SetValue((object)new EffectKeywordType[0]);
					val3.Field("attack").SetValue((object)new Attack());
					val3.Field("cooldown").SetValue((object)1E+09f);
					Sprite icon = ((Item)val).GetIcon();
					Stream manifestResourceStream = typeof(Plugin).Assembly.GetManifestResourceStream("MoreRelics.Icons." + relicEntry.GetType().Name + ".png");
					if (manifestResourceStream != null)
					{
						byte[] array = new byte[manifestResourceStream.Length];
						manifestResourceStream.Read(array, 0, array.Length);
						manifestResourceStream.Dispose();
						Texture2D val4 = new Texture2D(2, 2, (TextureFormat)4, false);
						if (ImageConversion.LoadImage(val4, array))
						{
							((Texture)val4).filterMode = (FilterMode)0;
							((Object)val4).hideFlags = (HideFlags)61;
							float num;
							if (!((Object)(object)icon != (Object)null))
							{
								num = 100f;
							}
							else
							{
								float pixelsPerUnit = icon.pixelsPerUnit;
								float num2 = ((Texture)val4).width;
								Rect rect = icon.rect;
								num = pixelsPerUnit * (num2 / ((Rect)(ref rect)).width);
							}
							float num3 = num;
							Sprite val5 = Sprite.Create(val4, new Rect(0f, 0f, (float)((Texture)val4).width, (float)((Texture)val4).height), new Vector2(0.5f, 0.5f), num3);
							((Object)val5).hideFlags = (HideFlags)61;
							val3.Field("icon").SetValue((object)val5);
							Image component = ((Component)val2).GetComponent<Image>();
							if ((Object)(object)component != (Object)null)
							{
								component.sprite = val5;
							}
						}
						else
						{
							ManualLogSource log3 = Plugin.Log;
							if (log3 != null)
							{
								log3.LogError((object)("could not decode the icon png for " + def.id));
							}
						}
					}
					allRelics[def.id] = val2;
					if (!allRelicIdentifiers.Contains(def.id))
					{
						allRelicIdentifiers.Add(def.id);
					}
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)("registered " + def.id + " cloned from " + ((Object)val).name));
					}
				}
			}
		}

		private static Relic Donor(Dictionary<string, Relic> relics, RelicDef def)
		{
			string[] cloneFrom = def.cloneFrom;
			foreach (string key in cloneFrom)
			{
				if (relics.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
				{
					return value;
				}
			}
			foreach (KeyValuePair<string, Relic> relic in relics)
			{
				if ((Object)(object)relic.Value != (Object)null && Registry.Find(relic.Key) == null)
				{
					return relic.Value;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(RelicManager), "SpawnRelic", new Type[] { typeof(Relic) })]
	internal static class Patch_SpawnActive
	{
		private static void Postfix(Relic __result)
		{
			if ((Object)(object)__result != (Object)null && Registry.Find(((Item)__result).GetIdentifier()) != null)
			{
				((Component)__result).gameObject.SetActive(true);
			}
		}
	}
	[HarmonyPatch(typeof(RelicManager), "IsUnlocked")]
	internal static class Patch_IsUnlocked
	{
		private static void Postfix(string relic, ref bool __result)
		{
			__result = __result || Registry.Find(relic) != null;
		}
	}
	[HarmonyPatch(typeof(RaceDataManager), "GetStartingRelic")]
	internal static class Patch_StartingRelic
	{
		private static void Postfix(ref string __result)
		{
			if (!string.IsNullOrEmpty(__result) && (Object)(object)AddressablesManager.Instance != (Object)null && (Object)(object)AddressablesManager.Instance.GetRelic(__result) == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("starting relic " + __result + " does not exist, dropping it"));
				}
				__result = "";
			}
		}
	}
	internal static class BossOnly
	{
		public static void Stamp()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			if ((Object)(object)RaceManager.Instance == (Object)null || (Object)(object)AddressablesManager.Instance == (Object)null)
			{
				return;
			}
			Races race = RaceManager.Instance.GetRace();
			RelicEntry[] entries = Registry.Entries;
			foreach (RelicEntry relicEntry in entries)
			{
				if (relicEntry.Def.bossOnly && relicEntry.Available)
				{
					Relic relic = AddressablesManager.Instance.GetRelic(relicEntry.Def.id);
					if ((Object)(object)relic != (Object)null)
					{
						Traverse.Create((object)relic).Field("kingdom").SetValue((object)race);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(DropBossChest), "PreparePool")]
	internal static class Patch_BossPoolStamp
	{
		private static void Prefix()
		{
			try
			{
				BossOnly.Stamp();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("boss pool stamp failed: " + ex));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Item), "GetTitle")]
	internal static class Patch_Title
	{
		private static void Postfix(Item __instance, ref string __result)
		{
			RelicEntry relicEntry = Registry.Find(__instance.GetIdentifier());
			if (relicEntry != null)
			{
				__result = relicEntry.Def.title;
			}
		}
	}
	[HarmonyPatch(typeof(Item), "GetDescription")]
	internal static class Patch_Description
	{
		private static void Postfix(Item __instance, ref string __result)
		{
			RelicEntry relicEntry = Registry.Find(__instance.GetIdentifier());
			if (relicEntry != null)
			{
				__result = relicEntry.Def.description;
			}
		}
	}
	[HarmonyPatch(typeof(RelicManager), "Awake")]
	internal static class Patch_Hook
	{
		private static int s_LastDay = -1;

		private static void Postfix()
		{
			s_LastDay = -1;
			try
			{
				BossOnly.Stamp();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("boss only stamp failed: " + ex));
				}
			}
			DaytimeManager.BeforeMorningStart -= Morning;
			DaytimeManager.BeforeMorningStart += Morning;
			RelicManager.OnRelicFound -= Found;
			RelicManager.OnRelicFound += Found;
		}

		private static void Found(Relic relic)
		{
			RelicEntry relicEntry = (((Object)(object)relic != (Object)null) ? Registry.Find(((Item)relic).GetIdentifier()) : null);
			if (relicEntry == null)
			{
				return;
			}
			try
			{
				relicEntry.OnAcquired();
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)(relicEntry.Def.id + " failed on pickup: " + ex));
				}
			}
		}

		private static void Morning(int day)
		{
			if (day == s_LastDay)
			{
				return;
			}
			s_LastDay = day;
			RelicEntry[] entries = Registry.Entries;
			foreach (RelicEntry relicEntry in entries)
			{
				try
				{
					if (relicEntry.Held())
					{
						relicEntry.OnMorning(day);
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogError((object)(relicEntry.Def.id + " failed on morning: " + ex));
					}
				}
			}
		}
	}
	internal sealed class SousChef : RelicEntry
	{
		internal const int ExtraMeat = 1;

		private static readonly RelicDef Definition = new RelicDef
		{
			id = "ownly_SousChef",
			cloneFrom = new string[4] { "GreenHouse", "BetterBerries", "Fruitarian", "SpawnTrees" },
			rarity = (Rarity)2,
			cost = 8,
			title = "Sous Chef",
			description = "The cook prepares one more meat per night."
		};

		public override RelicDef Def => Definition;

		internal static bool HeldInTavern()
		{
			GameData val = (((Object)(object)TavernSaveManager.Instance != (Object)null) ? TavernSaveManager.Instance.GetGameData() : null);
			if (val != null && val.relics != null)
			{
				return val.relics.Contains(Definition.id);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(TavernSaveManager), "GetMeatToCook")]
	internal static class Patch_SousChef
	{
		private static void Postfix(ref int __result)
		{
			try
			{
				if (SousChef.HeldInTavern())
				{
					__result++;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("sous chef failed on meat to cook: " + ex));
				}
			}
		}
	}
}