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