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>()?.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(); 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(); ((Graphic)s_Image).material = ((Graphic)icon).material; s_Image.preserveAspect = true; ((Graphic)s_Image).raycastTarget = true; EventTrigger trigger = val.AddComponent(); 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)(object)val.callback).AddListener((UnityAction)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(ref s_City)/*cast due to .constrained prefix*/).ToString() + "\ncombat=" + ((object)Unsafe.As(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(); 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 + " 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 value = Traverse.Create((object)__instance).Field("RelicPool").GetValue>(); if (value == null) { return; } foreach (KeyValuePair allUnit in AddressablesManager.Instance.GetAllUnits()) { List 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 = " to 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 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 value = Traverse.Create((object)storage).Field("storage").GetValue>(); 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()); 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 allRelics = addressables.GetAllRelics(); List 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(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(); 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 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 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)); } } } } }