using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MoreMerchantSlots")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+01ef0b4c091a4bc41ca5ce31a504e08f9176a069")]
[assembly: AssemblyProduct("MoreMerchantSlots")]
[assembly: AssemblyTitle("MoreMerchantSlots")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[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 MoreMerchantSlots
{
internal static class ExtraGoods
{
[HarmonyPatch(typeof(SaveManager), "GenerateMerchantGoodsAtDistance")]
private static class ApplyOnce
{
private static void Prefix(SaveManager __instance, int distance, int branch, int index)
{
HashSet<string> hashSet = Names(Merchants).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (MerchantData item in __instance.GetRunState().MerchantsAtDistance(distance, branch, index))
{
if (hashSet.Contains(((Object)item).name) && done.Add(item))
{
Append(item);
}
}
}
}
private static ConfigEntry<string> Merchants = null;
private static ConfigEntry<string> Pools = null;
private static readonly HashSet<MerchantData> done = new HashSet<MerchantData>();
public static void Init(ConfigFile config)
{
Merchants = config.Bind<string>("Goods", "Merchants", "UnitUpgradeMerchant,SpellUpgradeMerchant,SoulSavior_UpgradedUnitUpgradeMerchant,SoulSavior_UpgradedSpellUpgradeMerchant", "Asset names of the merchants to stock up, comma-separated: the Merchants of Steel and Magic and their Soul Savior upgrades by default. Takes effect on the next ring generated; the game must be restarted for a change to apply.");
Pools = config.Bind<string>("Goods", "Pools", "UnitUpgradePoolCommon,UnitUpgradePoolRare,SpellUpgradePoolCommon,SpellUpgradePoolRare", "Asset names of the upgrade pools each merchant gets one more good of, comma-separated; a merchant only gets the pools it already sells from. The Soul Savior merchants' pools carry a SoulSavior_ prefix, matched too. Same timing as Merchants.");
}
private static IEnumerable<string> Names(ConfigEntry<string> entry)
{
return from n in entry.Value.Split(',', StringSplitOptions.RemoveEmptyEntries)
select n.Trim();
}
private static IList<MerchantRewardData>? Rewards(MerchantData merchant)
{
return AccessTools.Field(typeof(MerchantData), "rewards").GetValue(merchant) as IList<MerchantRewardData>;
}
private static string? PoolName(MerchantRewardData reward)
{
RewardData rewardData = reward.RewardData;
EnhancerPoolRewardData val = (EnhancerPoolRewardData)(object)((rewardData is EnhancerPoolRewardData) ? rewardData : null);
if (val == null)
{
return null;
}
object? value = AccessTools.Field(typeof(EnhancerPoolRewardData), "relicPool").GetValue(val);
object? obj = ((value is EnhancerPool) ? value : null);
if (obj == null)
{
return null;
}
return ((Object)obj).name;
}
private static bool Draws(MerchantRewardData reward, string pool)
{
string text = PoolName(reward);
if (text != null)
{
if (!text.Equals(pool, StringComparison.OrdinalIgnoreCase))
{
return text.Equals("SoulSavior_" + pool, StringComparison.OrdinalIgnoreCase);
}
return true;
}
return false;
}
private static void Append(MerchantData merchant)
{
IList<MerchantRewardData> rewards = Rewards(merchant);
if (rewards == null)
{
Plugin.Logger.LogWarning((object)(((Object)merchant).name + ": no rewards list; left as is."));
return;
}
List<MerchantRewardData> list = (from pool in Names(Pools)
select ((IEnumerable<MerchantRewardData>)rewards).FirstOrDefault((Func<MerchantRewardData, bool>)((MerchantRewardData r) => (Object)(object)r.RequiredMutator == (Object)null && Draws(r, pool)))).OfType<MerchantRewardData>().ToList();
if (list.Count == 0)
{
Plugin.Logger.LogWarning((object)(((Object)merchant).name + ": sells from none of the pools " + Pools.Value + "; left as is."));
return;
}
foreach (MerchantRewardData item in list)
{
rewards.Add(item);
}
Plugin.Logger.LogInfo((object)string.Format("{0}: +{1} ({2} rewards).", ((Object)merchant).name, string.Join(", +", list.Select(PoolName)), rewards.Count));
}
}
internal static class GoodsLayout
{
[HarmonyPatch(typeof(MerchantScreen), "Initialize")]
private static class OnInitialize
{
private static void Postfix(MerchantScreen __instance)
{
Fit(__instance);
}
}
[HarmonyPatch(typeof(MerchantScreen), "RerollItems")]
private static class OnReroll
{
private static void Postfix(MerchantScreen __instance)
{
Fit(__instance);
}
}
private const int Columns = 3;
private const float Scale = 2f / 3f;
private const float VanillaCellWidth = 596f;
private const float VanillaBackgroundWidth = 608f;
private const float VanillaIconWidth = 176f;
private const float VanillaIconLeft = 20f;
private const float BoxGap = -12f;
private const float BoxRight = 40f;
private const float VanillaFontMin = 20f;
private const float VanillaFontMax = 32f;
private static ConfigEntry<bool> Enabled = null;
private static ConfigEntry<int> DescriptionFontSize = null;
private static ConfigEntry<int> IconWidth = null;
private static ConfigEntry<int> IconLeft = null;
private static readonly FieldRef<MerchantScreen, MerchantScreenContent> Content = AccessTools.FieldRefAccess<MerchantScreen, MerchantScreenContent>("content");
private static readonly FieldRef<MerchantScreen, List<MerchantGoodUIBase>> GoodUIs = AccessTools.FieldRefAccess<MerchantScreen, List<MerchantGoodUIBase>>("goodUIs");
private static readonly FieldRef<MerchantGoodDetailsUI, RewardDetailsUI> RewardUI = AccessTools.FieldRefAccess<MerchantGoodDetailsUI, RewardDetailsUI>("rewardUI");
private static readonly FieldRef<RewardDetailsUI, RelicInfoUI> RelicUI = AccessTools.FieldRefAccess<RewardDetailsUI, RelicInfoUI>("relicUI");
private static readonly FieldRef<RelicInfoUI, TMP_Text> DescriptionLabel = AccessTools.FieldRefAccess<RelicInfoUI, TMP_Text>("descriptionLabel");
private static MerchantScreen? current;
public static void Init(ConfigFile config)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Expected O, but got Unknown
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Expected O, but got Unknown
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Expected O, but got Unknown
Enabled = config.Bind<bool>("Layout", "FitGoods", true, "Lay the merchant screen's goods out in three narrower columns when there are more than four. Off leaves the extra goods overflowing the screen.");
DescriptionFontSize = config.Bind<int>("Layout", "DescriptionFontSize", 26, new ConfigDescription("Largest font size of a good's description on a narrowed screen (the game's is 32); a description that still doesn't fit shrinks further, down to half of it.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 32), Array.Empty<object>()));
IconWidth = config.Bind<int>("Layout", "IconWidth", 120, new ConfigDescription("Width kept for a good's icon on a narrowed screen (the game's is 176, the icon itself 104); the description box gets what is freed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(104, 176), Array.Empty<object>()));
IconLeft = config.Bind<int>("Layout", "IconLeft", 8, new ConfigDescription("Gap between a good's left edge and its icon's frame on a narrowed screen (the game's is 20); the description box moves along.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 40), Array.Empty<object>()));
config.SettingChanged += delegate(object _, SettingChangedEventArgs e)
{
if (e.ChangedSetting.Definition.Section == "Layout" && (Object)(object)current != (Object)null && ((Component)current).gameObject.activeInHierarchy)
{
Fit(current);
}
};
}
private static void Fit(MerchantScreen screen)
{
//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)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
current = screen;
MerchantScreenContent obj = GameObjectUtil.OrNull<MerchantScreenContent>(Content.Invoke(screen));
LayoutGroup obj2 = ((obj != null) ? obj.GoodsContainer : null);
GridLayoutGroup val = (GridLayoutGroup)(object)((obj2 is GridLayoutGroup) ? obj2 : null);
if ((Object)(object)val == (Object)null)
{
return;
}
List<MerchantGoodDetailsUI> list = (from g in GoodUIs.Invoke(screen).OfType<MerchantGoodDetailsUI>()
where ((MerchantGoodUIBase)g).GoodState != null
select g).ToList();
bool flag = Enabled.Value && list.Count > 4;
val.constraint = (Constraint)1;
val.constraintCount = (flag ? 3 : 2);
val.cellSize = new Vector2(flag ? 397.33334f : 596f, val.cellSize.y);
foreach (MerchantGoodDetailsUI item in list)
{
RectTransform val2 = Background((MerchantGoodUIBase)(object)item);
if ((Object)(object)val2 != (Object)null)
{
val2.sizeDelta = new Vector2(flag ? 405.33334f : 608f, val2.sizeDelta.y);
}
FitPanel(item, flag);
}
}
private static void FitPanel(MerchantGoodDetailsUI good, bool narrow)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
RelicInfoUI val = GameObjectUtil.OrNull<RelicInfoUI>(RelicUI.Invoke(GameObjectUtil.OrNull<RewardDetailsUI>(RewardUI.Invoke(good))));
if (!((Object)(object)val == (Object)null))
{
RectTransform val2 = (RectTransform)((Component)val).transform;
TMP_Text val3 = GameObjectUtil.OrNull<TMP_Text>(DescriptionLabel.Invoke(val));
TMP_Text obj = GameObjectUtil.OrNull<TMP_Text>(val3);
Transform obj2 = ((obj != null) ? obj.transform.parent : null);
RectTransform val4 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null);
Transform obj3 = GameObjectUtil.OrNull<Transform>(val.IconRoot);
Transform obj4 = ((obj3 != null) ? obj3.parent : null);
RectTransform val5 = (RectTransform)(object)((obj4 is RectTransform) ? obj4 : null);
float num = (narrow ? ((float)IconWidth.Value) : 176f);
float num2 = (narrow ? ((float)IconLeft.Value) : 20f);
val2.sizeDelta = new Vector2(narrow ? 397.33334f : 596f, val2.sizeDelta.y);
if ((Object)(object)val5 != (Object)null)
{
val5.sizeDelta = new Vector2(num, val5.sizeDelta.y);
val5.anchoredPosition = new Vector2(num2, val5.anchoredPosition.y);
}
if ((Object)(object)val4 != (Object)null)
{
val4.anchorMin = new Vector2(0f, val4.anchorMin.y);
val4.anchorMax = new Vector2(1f, val4.anchorMax.y);
val4.offsetMin = new Vector2(num2 + num + -12f, val4.offsetMin.y);
val4.offsetMax = new Vector2(-40f, val4.offsetMax.y);
}
if ((Object)(object)val3 != (Object)null)
{
val3.enableAutoSizing = true;
val3.fontSizeMax = (narrow ? ((float)DescriptionFontSize.Value) : 32f);
val3.fontSizeMin = (narrow ? ((float)DescriptionFontSize.Value / 2f) : 20f);
}
}
}
private static RectTransform? Background(MerchantGoodUIBase good)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
foreach (RectTransform item in ((Component)good).transform)
{
RectTransform val = item;
if (val.anchorMin.x == val.anchorMax.x && val.sizeDelta.x > 0f && (Object)(object)((Component)val).GetComponent<Image>() != (Object)null)
{
return val;
}
}
return null;
}
}
[BepInPlugin("SpecialCircumstances.MoreMerchantSlots", "MoreMerchantSlots", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger = new ManualLogSource("SpecialCircumstances.MoreMerchantSlots");
private const float ConfigPollSeconds = 1f;
private DateTime configWriteTime;
private float nextConfigPoll;
public void Awake()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
ExtraGoods.Init(((BaseUnityPlugin)this).Config);
GoodsLayout.Init(((BaseUnityPlugin)this).Config);
new Harmony("SpecialCircumstances.MoreMerchantSlots").PatchAll();
configWriteTime = ReadConfigWriteTime();
Logger.LogInfo((object)"Plugin SpecialCircumstances.MoreMerchantSlots is loaded!");
}
public void Update()
{
PollConfig();
}
private void PollConfig()
{
if (Time.realtimeSinceStartup < nextConfigPoll)
{
return;
}
nextConfigPoll = Time.realtimeSinceStartup + 1f;
DateTime dateTime = ReadConfigWriteTime();
if (!(dateTime == configWriteTime))
{
configWriteTime = dateTime;
try
{
((BaseUnityPlugin)this).Config.Reload();
}
catch (Exception ex)
{
Logger.LogWarning((object)("Could not reload the config file: " + ex.Message));
return;
}
configWriteTime = ReadConfigWriteTime();
Logger.LogDebug((object)"Config reloaded.");
}
}
private DateTime ReadConfigWriteTime()
{
try
{
return File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath);
}
catch (Exception ex)
{
Logger.LogDebug((object)("Could not stat the config file: " + ex.Message));
return configWriteTime;
}
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "SpecialCircumstances.MoreMerchantSlots";
public const string PLUGIN_NAME = "MoreMerchantSlots";
public const string PLUGIN_VERSION = "0.1.0";
}
}