using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Assets.Scripts.Actors.Player;
using Assets.Scripts.Game.MapGeneration;
using Assets.Scripts.Game.Spawning;
using Assets.Scripts.Inventory.Stats;
using Assets.Scripts.Inventory__Items__Pickups;
using Assets.Scripts.Inventory__Items__Pickups.Chests;
using Assets.Scripts.Inventory__Items__Pickups.GoldAndMoney;
using Assets.Scripts.Inventory__Items__Pickups.Items;
using Assets.Scripts.Inventory__Items__Pickups.Items.ItemImplementations;
using Assets.Scripts.Inventory__Items__Pickups.Progression;
using Assets.Scripts.Inventory__Items__Pickups.Stats;
using Assets.Scripts.Inventory__Items__Pickups.Weapons;
using Assets.Scripts.Managers;
using Assets.Scripts.Menu.Shop;
using Assets.Scripts.Saves___Serialization.Progression.Achievements;
using Assets.Scripts.Saves___Serialization.Progression.Stats;
using Assets.Scripts.Saves___Serialization.Progression.Unlocks;
using Assets.Scripts._Data;
using Assets.Scripts._Data.Tomes;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using IHateRNG.Patches;
using IHateRNG.Systems;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using Utility;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("IHateRNG")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.13.0")]
[assembly: AssemblyInformationalVersion("1.0.13")]
[assembly: AssemblyProduct("IHateRNG")]
[assembly: AssemblyTitle("IHateRNG")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.13.0")]
[module: UnverifiableCode]
[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;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte value)
{
NullableFlags = new byte[1] { value };
}
public NullableAttribute(byte[] value)
{
NullableFlags = value;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte value)
{
Flag = value;
}
}
}
namespace IHateRNG
{
[BepInPlugin("IHateRNG", "IHateRNG", "1.0.13")]
public class Plugin : BasePlugin
{
public const string Guid = "IHateRNG";
public const string Name = "IHateRNG";
public const string Version = "1.0.13";
internal static ManualLogSource Log = null;
internal static ConfigEntry<bool> EnableDeterministicKey = null;
internal static ConfigEntry<bool> EnableUpgradeShuffleBag = null;
internal static ConfigEntry<bool> DebugLogging = null;
private readonly Harmony harmony = new Harmony("IHateRNG");
private static readonly HashSet<string> Warnings = new HashSet<string>();
internal static bool KeyEnabled { get; private set; }
internal static bool ForceCommonMicrowaves { get; private set; }
internal static bool ForceTwoMicrowaves { get; private set; }
internal static bool ForceKindShadyGuy { get; private set; }
internal static bool ForceGreenCard { get; private set; }
internal static float KeyScalingPercent { get; private set; }
internal static float KeyBasePercent { get; private set; }
internal static float KeyStagePercent { get; private set; }
internal static bool KeyStageMultiplier { get; private set; }
internal static bool KeyScalingMultiplier { get; private set; }
public override void Load()
{
//IL_022c: Unknown result type (might be due to invalid IL or missing references)
//IL_0232: Expected O, but got Unknown
Log = ((BasePlugin)this).Log;
EnableDeterministicKey = ((BasePlugin)this).Config.Bind<bool>("main", "enable key rework", true, "");
ForceCommonMicrowaves = ((BasePlugin)this).Config.Bind<bool>("main", "force common microwaves", true, "whether the game should force one of the microwaves spawned to be of common rarity").Value;
ForceTwoMicrowaves = ((BasePlugin)this).Config.Bind<bool>("main", "force two microwaves", true, "whether the game makes at least 2 microwaves spawn").Value;
EnableUpgradeShuffleBag = ((BasePlugin)this).Config.Bind<bool>("main", "level up overhaul", true, "overhauled version prevents copies of new weapons/tomes from appearing until all have appeared in a cycle-ish manner");
ForceKindShadyGuy = ((BasePlugin)this).Config.Bind<bool>("shady guy", "force kind shady guy", true, "whether the game should forcibly convert one of spawned shady guys to be of epic rarity").Value;
ForceGreenCard = ((BasePlugin)this).Config.Bind<bool>("shady guy", "force green card", true, "whether the spawned kind shady guy has a green card as one of its inventory items 100% of the time, doesnt work with \"force kind shady guy\" disabled").Value;
KeyScalingPercent = BindPercent("key scaling decrease", 25f, float.MaxValue, "how much the reworked key should nerf the scaling formula, accepts normal numbers, type 0 to disable");
KeyBasePercent = BindPercent("key base price", 10f, 100f, "how much chest base price is lowered (compounding) per key, accepts normal numbers, type 0 to disable");
KeyStagePercent = BindPercent("key stage change", 10f, float.MaxValue, "how much % a key lowers chest price on stage change, 100% is 2x cheaper, accepts normal numbers, type 0 to disable");
KeyStageMultiplier = ((BasePlugin)this).Config.Bind<bool>("key", "key stage change mult", true, "whether the \"key stage change\" attribute gets a 2x multiplier when going into tier 3 (for balancing purposes)").Value;
KeyScalingMultiplier = ((BasePlugin)this).Config.Bind<bool>("key", "key scaling mult", true, "whether \"key scaling decrease\" gets stronger the more expensive a chest is (made for balancing purposes)").Value;
DebugLogging = ((BasePlugin)this).Config.Bind<bool>("diagnostics", "debug logging", false, "Log generation, pricing, and item selection details.");
PitySettings.Initialize(((BasePlugin)this).Config);
EnableUpgradeShuffleBag.SettingChanged += OnShuffleSettingChanged;
KeyEnabled = EnableDeterministicKey.Value;
try
{
harmony.PatchAll(typeof(Plugin).Assembly);
PitySettings.BindItems(DataManager.Instance);
if (KeyEnabled)
{
KeyStages.Subscribe();
}
if (KeyEnabled)
{
KeyStats.RefreshCurrentPlayer(enabled: true);
}
ManualLogSource log = Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(29, 4, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("IHateRNG");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.13");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded. Key=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(EnableDeterministicKey.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", shuffle bag=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(EnableUpgradeShuffleBag.Value);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
}
log.LogInfo(val);
}
catch
{
harmony.UnpatchSelf();
KeyStages.Unsubscribe();
throw;
}
}
private float BindPercent(string name, float defaultValue, float maximum, string description)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
ConfigEntry<float> val = ((BasePlugin)this).Config.Bind<float>("key", name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, maximum), Array.Empty<object>()));
if (!float.IsFinite(val.Value))
{
val.Value = defaultValue;
}
return val.Value;
}
private static void OnShuffleSettingChanged(object? sender, EventArgs args)
{
UpgradeShuffleBag.Reset("configuration changed");
}
internal static void Debug(string message)
{
if (DebugLogging.Value)
{
Log.LogInfo((object)message);
}
}
internal static void WarnOnce(string key, Exception error)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
if (Warnings.Add(key))
{
ManualLogSource log = Log;
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(2, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(key);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(error);
}
log.LogWarning(val);
}
}
public override bool Unload()
{
if (KeyEnabled)
{
KeyStats.RefreshCurrentPlayer(enabled: false);
}
KeyStages.Unsubscribe();
harmony.UnpatchSelf();
EnableUpgradeShuffleBag.SettingChanged -= OnShuffleSettingChanged;
UpgradeShuffleBag.Reset("plugin unloaded");
GuaranteedShadyGuy.Reset("plugin unloaded");
ChestItemPity.Reset();
MicrowaveGuarantee.Reset();
return true;
}
}
}
namespace IHateRNG.Systems
{
internal static class ChestItemPity
{
private static readonly Dictionary<EItemRarity, PityCounter> Counters = new Dictionary<EItemRarity, PityCounter>();
internal static void Apply(ref ItemData result)
{
//IL_000d: 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)
if (!((Object)(object)result == (Object)null) && PitySettings.TryGet(result.rarity, out var item, out var count))
{
Apply(ref result, item, count - 1);
}
}
private static void Apply(ref ItemData result, EItem targetId, int allowedMisses)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: 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_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)result == (Object)null)
{
return;
}
MyPlayer instance = MyPlayer.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
PlayerInventory inventory = instance.inventory;
obj = ((inventory != null) ? inventory.itemInventory : null);
}
ItemInventory val = (ItemInventory)obj;
if (val == null || val.GetAmount(targetId) > 0)
{
return;
}
DataManager instance2 = DataManager.Instance;
if ((Object)(object)instance2 == (Object)null)
{
return;
}
ItemData item = instance2.GetItem(targetId);
if ((Object)(object)item == (Object)null || item.rarity != result.rarity || !item.inItemPool || !MyAchievements.IsAvailable((UnlockableBase)(object)item))
{
return;
}
HashSet<ItemData> banishedItems = RunUnlockables.banishedItems;
Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
if (banishedItems == null || availableItems == null || banishedItems.Contains(item) || !availableItems.ContainsKey(result.rarity))
{
return;
}
List<ItemData> val2 = availableItems[result.rarity];
if (val2 != null && val2.Contains(item))
{
if (!Counters.TryGetValue(result.rarity, out PityCounter value))
{
Counters.Add(result.rarity, value = new PityCounter());
}
if (!value.ShouldReplace(allowedMisses, eligible: true, result.eItem == targetId))
{
Plugin.Debug($"Chest pity {result.rarity}/{targetId}: {value.Misses}/{allowedMisses} misses; vanilla {result.eItem}");
}
else
{
EItem eItem = result.eItem;
result = item;
value.Consume();
Plugin.Debug($"Chest pity {result.rarity}: replaced {eItem} with {targetId}; progress reset to 0");
}
}
}
internal static void Reset(EItemRarity rarity)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Counters.Remove(rarity);
}
internal static void Reset()
{
Counters.Clear();
Plugin.Debug("Chest pity counters reset");
}
}
internal static class ChestPricing
{
private static readonly (int Price, float Power)[] PowerPoints = new(int, float)[11]
{
(10000, 6f),
(15000, 7f),
(25000, 8f),
(40000, 9f),
(70000, 10f),
(100000, 12f),
(150000, 15f),
(200000, 20f),
(250000, 25f),
(300000, 30f),
(500000, 50f)
};
internal const string Description = "Chests: Lowers scaling by 25%, price by 10% and again on stage change";
internal static float BaseMultiplier(int keys, float percent = 10f)
{
return (float)Math.Pow(1.0 - (double)percent / 100.0, Math.Max(0, keys));
}
internal static float ScalingMultiplier(int keys, float power = 1f, float percent = 25f)
{
return (float)(1.0 / (1.0 + (double)percent / 100.0 * (double)power * (double)Math.Max(0, keys)));
}
internal static float KeyPower(int price)
{
if (price < 200)
{
return 1f;
}
if (price <= 10000)
{
return 1f + (float)price / 2000f;
}
for (int i = 1; i < PowerPoints.Length; i++)
{
(int, float) tuple = PowerPoints[i - 1];
(int, float) tuple2 = PowerPoints[i];
if (price <= tuple2.Item1)
{
return tuple.Item2 + (tuple2.Item2 - tuple.Item2) * ((float)(price - tuple.Item1) / (float)(tuple2.Item1 - tuple.Item1));
}
}
return 50f;
}
internal static float GreenCardPerCopy(int keys)
{
return (float)(10 - Math.Clamp(keys, 0, 5)) / 100f;
}
internal static float FinalPrice(float initialBase, float discountedGrowth, float chestPriceStat, float stageFactor)
{
return (initialBase + discountedGrowth) * chestPriceStat * stageFactor;
}
internal static int LinearIncrease(int count, int perChest, int over10, int over20, int over30, int over40, int over50)
{
int num = count * perChest;
if (count > 10)
{
num += (count - 10) * over10;
}
if (count > 20)
{
num += (count - 20) * over20;
}
if (count > 30)
{
num += (count - 30) * over30;
}
if (count > 40)
{
num += (count - 30) * over40;
}
if (count > 50)
{
num += (count - 30) * over50;
}
return num;
}
internal static string Describe(float scaling, float price, float stage)
{
string text = Number(scaling);
string text2 = Number(price);
string text3 = Number(stage);
if (scaling <= 0f && price <= 0f && stage <= 0f)
{
return "does nothing lmao";
}
if (scaling > 0f && price > 0f)
{
return $"Chests: Lowers scaling by {text}%, price by {text2}%" + ((stage <= 0f) ? "" : ((price == stage) ? " and again on stage change" : (" and by " + text3 + "% again on stage change")));
}
if (scaling > 0f)
{
return "Chests: Lowers scaling by " + text + "%" + ((stage > 0f) ? (" and price by " + text3 + "% on stage change") : "");
}
if (price > 0f)
{
return "Chests: Lowers price by " + text2 + "%" + ((stage <= 0f) ? "" : ((price == stage) ? " and again on stage change" : (" and by " + text3 + "% again on stage change")));
}
return "Chests: Lowers price by " + text3 + "% on stage change";
static string Number(float n)
{
return n.ToString("G", CultureInfo.InvariantCulture);
}
}
}
internal static class GuaranteedShadyGuy
{
private static bool assigned;
private static InteractableShadyGuy? selected;
private static int? stageScene;
internal static void ObserveSpawn(InteractableShadyGuy instance)
{
//IL_000e: 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)
if (Plugin.ForceKindShadyGuy)
{
Scene scene = ((Component)instance).gameObject.scene;
BeginStage(((Scene)(ref scene)).handle);
Plugin.Debug("Shady Guy spawned");
if (!assigned)
{
assigned = true;
selected = instance;
Plugin.Debug("Designated guaranteed Shady Guy");
}
}
}
internal static bool IsSelected(InteractableShadyGuy instance)
{
if (Plugin.ForceKindShadyGuy && assigned && (Object)(object)selected != (Object)null)
{
return ((Il2CppObjectBase)selected).Pointer == ((Il2CppObjectBase)instance).Pointer;
}
return false;
}
internal static void EnsureCard(InteractableShadyGuy instance)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
if (!Plugin.ForceGreenCard || !IsSelected(instance))
{
return;
}
List<ItemData> items = instance.items;
if (items == null || items.Count == 0)
{
Plugin.Debug("Guaranteed Shady Guy inventory is null or empty; left unchanged");
return;
}
for (int i = 0; i < items.Count; i++)
{
if ((Object)(object)items[i] != (Object)null && (int)items[i].eItem == 64)
{
Plugin.Debug("Green Card already present; inventory unchanged");
return;
}
}
DataManager instance2 = DataManager.Instance;
ItemData val = (((Object)(object)instance2 == (Object)null) ? null : instance2.GetItem((EItem)64));
if ((Object)(object)val == (Object)null || !ShadyOffers.IsEligible(val))
{
Plugin.Debug("Green Card unavailable, disabled, or banished; keeping Epic shop without forcing card");
return;
}
int num = Random.Range(0, items.Count);
ItemData val2 = items[num];
items[num] = val;
try
{
instance.UpdatePrices();
}
catch
{
items[num] = val2;
instance.UpdatePrices();
throw;
}
Plugin.Debug($"Replaced Shady Guy slot {num + 1} with CreditCardGreen");
}
internal static void Reset(string reason)
{
assigned = false;
selected = null;
stageScene = null;
Plugin.Debug("Shady Guy guarantee reset: " + reason);
}
internal static void BeginStage(int sceneHandle)
{
if (stageScene != sceneHandle)
{
Reset("new stage scene");
stageScene = sceneHandle;
}
}
}
internal sealed class KeyChestGrowth
{
private int lastCount;
private float lastRawGrowth;
internal float DiscountedGrowth { get; private set; }
internal int LastPrice { get; set; }
internal float LastPower { get; private set; } = 1f;
internal void Observe(int count, float rawGrowth, int keys, float scalingPercent = 25f, bool powerEnabled = true)
{
if (count < lastCount)
{
Reset();
}
if (count != lastCount)
{
LastPower = (powerEnabled ? ChestPricing.KeyPower(LastPrice) : 1f);
DiscountedGrowth += (rawGrowth - lastRawGrowth) * ChestPricing.ScalingMultiplier(keys, LastPower, scalingPercent);
lastRawGrowth = rawGrowth;
lastCount = count;
}
}
internal void Reset()
{
lastCount = 0;
lastRawGrowth = 0f;
DiscountedGrowth = 0f;
LastPrice = 0;
LastPower = 1f;
}
}
internal static class KeyGreenCard
{
internal static float PerCopy(int keys)
{
return ChestPricing.GreenCardPerCopy(keys);
}
internal static void Refresh(ItemInventory? inventory)
{
if (inventory == null)
{
return;
}
try
{
ItemBase item = inventory.GetItem((EItem)64);
if (item != null)
{
ItemCreditCardGreen obj = ((Il2CppObjectBase)item).TryCast<ItemCreditCardGreen>();
if (obj != null)
{
((ItemBase)obj).OnInitOrAmountChanged();
}
}
}
catch (Exception error)
{
Plugin.WarnOnce("Key Green Card refresh", error);
}
}
}
internal sealed class KeyStageDiscount
{
private int? lastStage;
internal double Multiplier { get; private set; } = 1.0;
internal bool BeginStage(int stage, int keys, float percent = 10f, bool tierMultiplier = true)
{
if (stage < 0 || (lastStage.HasValue && stage <= lastStage.Value))
{
return false;
}
bool hasValue = lastStage.HasValue;
bool flag = tierMultiplier && lastStage == 1 && stage == 2;
lastStage = stage;
if (!hasValue || keys <= 0)
{
return false;
}
Multiplier /= 1.0 + (double)percent / 100.0 * (flag ? 2.0 : 1.0) * (double)keys;
return true;
}
internal void Reset()
{
lastStage = null;
Multiplier = 1.0;
}
}
internal static class KeyStages
{
private static readonly KeyStageDiscount State = new KeyStageDiscount();
private static Action? preGeneration;
internal static float BaseMultiplier => (float)State.Multiplier;
internal static void Subscribe()
{
if (!((Delegate)(object)preGeneration != (Delegate)null))
{
preGeneration = DelegateSupport.ConvertDelegate<Action>((Delegate)new Action(BeforeGeneration));
MapGenerationController.A_PreGeneration = ((Il2CppObjectBase)Delegate.Combine((Delegate)(object)MapGenerationController.A_PreGeneration, (Delegate)(object)preGeneration)).Cast<Action>();
}
}
internal static void Unsubscribe()
{
if (!((Delegate)(object)preGeneration == (Delegate)null))
{
Delegate obj = Delegate.Remove((Delegate)(object)MapGenerationController.A_PreGeneration, (Delegate)(object)preGeneration);
MapGenerationController.A_PreGeneration = ((obj != null) ? ((Il2CppObjectBase)obj).Cast<Action>() : null);
preGeneration = null;
Reset();
}
}
internal static void Reset()
{
State.Reset();
KeyPricePatch.Reset();
}
private static void BeforeGeneration()
{
if (!Plugin.KeyEnabled)
{
return;
}
try
{
PlayerInventory inventory = MapController.inventory;
int? obj;
if (inventory == null)
{
obj = null;
}
else
{
ItemInventory itemInventory = inventory.itemInventory;
if (itemInventory == null)
{
obj = null;
}
else
{
ItemBase item = itemInventory.GetItem((EItem)0);
obj = ((item != null) ? new int?(item.amount) : ((int?)null));
}
}
int? num = obj;
int valueOrDefault = num.GetValueOrDefault();
int stageIndex = MapController.GetStageIndex();
bool value = State.BeginStage(stageIndex, valueOrDefault, Plugin.KeyStagePercent, Plugin.KeyStageMultiplier);
Plugin.Debug($"Key stage discount: stage={stageIndex}, keys={valueOrDefault}, applied={value}, cumulativeFinalPriceMultiplier={State.Multiplier:R}");
}
catch (Exception error)
{
Plugin.WarnOnce("Key stage discount", error);
}
}
}
internal static class KeyStats
{
internal static void Apply(ItemKey key, bool enabled)
{
//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_0032: 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_0045: Expected O, but got Unknown
if (((ItemBase)key).itemInventoryRef != null)
{
float num = (enabled ? ChestPricing.BaseMultiplier(((ItemBase)key).amount, Plugin.KeyBasePercent) : 1f);
((ItemBase)key).SetStat(new StatModifier
{
stat = (EStat)34,
modifyType = (EStatModifyType)1,
modification = num
});
Plugin.Debug($"Key count: {((ItemBase)key).amount}; ChestPriceMultiplier contribution: {num:R}");
}
}
internal static void RefreshCurrentPlayer(bool enabled)
{
//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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
MyPlayer instance = MyPlayer.Instance;
PlayerInventory val = ((instance != null) ? instance.inventory : null);
object obj;
if (val == null)
{
obj = null;
}
else
{
ItemInventory itemInventory = val.itemInventory;
if (itemInventory == null)
{
obj = null;
}
else
{
ItemBase item = itemInventory.GetItem((EItem)64);
obj = ((item != null) ? ((Il2CppObjectBase)item).TryCast<ItemCreditCardGreen>() : null);
}
}
ItemCreditCardGreen val2 = (ItemCreditCardGreen)obj;
if (val2 != null)
{
StatModifier val3 = new StatModifier
{
stat = (EStat)34,
modifyType = (EStatModifyType)2
};
float num;
if (!enabled)
{
num = 0.1f;
}
else
{
ItemBase item2 = val.itemInventory.GetItem((EItem)0);
num = KeyGreenCard.PerCopy((item2 != null) ? item2.amount : 0);
}
val3.modification = num * (float)((ItemBase)val2).amount;
((ItemBase)val2).SetStat(val3);
}
object obj2;
if (val == null)
{
obj2 = null;
}
else
{
ItemInventory itemInventory2 = val.itemInventory;
if (itemInventory2 == null)
{
obj2 = null;
}
else
{
ItemBase item3 = itemInventory2.GetItem((EItem)0);
obj2 = ((item3 != null) ? ((Il2CppObjectBase)item3).TryCast<ItemKey>() : null);
}
}
ItemKey val4 = (ItemKey)obj2;
if (val4 != null)
{
Apply(val4, enabled);
}
if (val != null)
{
PlayerStatsNew playerStats = val.playerStats;
if (playerStats != null)
{
playerStats.ForceUpdateStats();
}
}
}
}
internal static class MicrowaveDiagnostics
{
internal static bool Watching;
[Conditional("MICROWAVE_DIAGNOSTICS")]
internal static void Log(string message)
{
}
[Conditional("MICROWAVE_DIAGNOSTICS")]
internal static void Observe(string label, GameObject? go, bool components = false)
{
}
[Conditional("MICROWAVE_DIAGNOSTICS")]
internal static void Snapshot(string label, bool changesOnly = false)
{
}
}
internal static class MicrowaveGuarantee
{
private static int? stageScene;
private static int guaranteedCount;
private static InteractableMicrowave? commonMicrowave;
private static GameObject? microwavePrefab;
internal static void BeginStage(int scene)
{
if (stageScene != scene)
{
Reset();
stageScene = scene;
}
}
internal static void Reset()
{
stageScene = null;
guaranteedCount = 0;
commonMicrowave = null;
microwavePrefab = null;
}
internal static bool IsCommonTarget(InteractableMicrowave instance)
{
if (Plugin.ForceCommonMicrowaves && (Object)(object)commonMicrowave != (Object)null)
{
return ((Il2CppObjectBase)commonMicrowave).Pointer == ((Il2CppObjectBase)instance).Pointer;
}
return false;
}
internal static void ObserveStart(InteractableMicrowave instance)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
Scene scene = ((Component)instance).gameObject.scene;
BeginStage(((Scene)(ref scene)).handle);
if (Plugin.ForceCommonMicrowaves && (Object)(object)commonMicrowave == (Object)null)
{
commonMicrowave = instance;
}
}
internal static void CapturePrefab(RandomMapObject entry, int scene)
{
BeginStage(scene);
if (Object.op_Implicit((Object)(object)microwavePrefab) || entry == null || entry.prefabs == null)
{
return;
}
foreach (GameObject item in (Il2CppArrayBase<GameObject>)(object)entry.prefabs)
{
if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.GetComponentInChildren<InteractableMicrowave>()))
{
microwavePrefab = item;
Plugin.Debug($"Cached Microwave prefab from RandomObjectSpawner: {((Object)item).name}, scene {scene}");
break;
}
}
}
internal static HashSet<int> GetStageRootIds(int scene)
{
//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_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: 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_0051: Unknown result type (might be due to invalid IL or missing references)
HashSet<int> hashSet = new HashSet<int>();
foreach (InteractableMicrowave item in Resources.FindObjectsOfTypeAll<InteractableMicrowave>())
{
if (!Object.op_Implicit((Object)(object)item))
{
continue;
}
GameObject gameObject = ((Component)item).gameObject;
Scene scene2 = gameObject.scene;
if (!((Scene)(ref scene2)).IsValid())
{
continue;
}
scene2 = gameObject.scene;
if (((Scene)(ref scene2)).isLoaded)
{
scene2 = gameObject.scene;
if (((Scene)(ref scene2)).handle == scene)
{
hashSet.Add(((Object)((Component)((Component)item).transform.root).gameObject).GetInstanceID());
}
}
}
return hashSet;
}
internal static bool SpawnShrines(SpawnInteractables spawner)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_027c: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0189: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
//IL_033d: Unknown result type (might be due to invalid IL or missing references)
//IL_0343: Unknown result type (might be due to invalid IL or missing references)
//IL_0352: Unknown result type (might be due to invalid IL or missing references)
//IL_036d: Unknown result type (might be due to invalid IL or missing references)
//IL_0372: Unknown result type (might be due to invalid IL or missing references)
//IL_0374: Unknown result type (might be due to invalid IL or missing references)
//IL_0376: Unknown result type (might be due to invalid IL or missing references)
//IL_020d: Unknown result type (might be due to invalid IL or missing references)
//IL_0212: Unknown result type (might be due to invalid IL or missing references)
//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
//IL_047a: Unknown result type (might be due to invalid IL or missing references)
//IL_047c: Unknown result type (might be due to invalid IL or missing references)
//IL_048d: Unknown result type (might be due to invalid IL or missing references)
//IL_0492: Unknown result type (might be due to invalid IL or missing references)
//IL_04ac: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.ForceTwoMicrowaves)
{
return true;
}
MicrowaveDiagnostics.Watching = true;
Scene scene = ((Component)spawner).gameObject.scene;
BeginStage(((Scene)(ref scene)).handle);
MapData currentMap = MapController.currentMap;
if ((Object)(object)currentMap == (Object)null || currentMap.shrines == null || (Object)(object)GameManager.Instance == (Object)null || (Object)(object)spawner.chest == (Object)null)
{
return true;
}
scene = ((Component)spawner).gameObject.scene;
HashSet<int> stageRootIds = GetStageRootIds(((Scene)(ref scene)).handle);
int num = Math.Max(0, 2 - stageRootIds.Count);
Plugin.Debug($"Microwave minimum: existing={stageRootIds.Count} roots=[{string.Join(",", stageRootIds)}] needed={num}");
if (num == 0)
{
return true;
}
if (!Object.op_Implicit((Object)(object)microwavePrefab))
{
StageData currentStage = MapController.currentStage;
if (((currentStage != null) ? currentStage.randomMapObjects : null) != null)
{
foreach (RandomMapObject item in (Il2CppArrayBase<RandomMapObject>)(object)MapController.currentStage.randomMapObjects)
{
scene = ((Component)spawner).gameObject.scene;
CapturePrefab(item, ((Scene)(ref scene)).handle);
}
}
}
if (!Object.op_Implicit((Object)(object)microwavePrefab) && currentMap.randomObjectsOverride != null)
{
foreach (RandomMapObject item2 in (Il2CppArrayBase<RandomMapObject>)(object)currentMap.randomObjectsOverride)
{
scene = ((Component)spawner).gameObject.scene;
CapturePrefab(item2, ((Scene)(ref scene)).handle);
}
}
if (!Object.op_Implicit((Object)(object)microwavePrefab) && currentMap.stages != null)
{
foreach (StageData item3 in (Il2CppArrayBase<StageData>)(object)currentMap.stages)
{
if (((item3 != null) ? item3.randomMapObjects : null) == null)
{
continue;
}
foreach (RandomMapObject item4 in (Il2CppArrayBase<RandomMapObject>)(object)item3.randomMapObjects)
{
scene = ((Component)spawner).gameObject.scene;
CapturePrefab(item4, ((Scene)(ref scene)).handle);
}
if (Object.op_Implicit((Object)(object)microwavePrefab))
{
break;
}
}
}
List<GameObject> list = new List<GameObject>();
foreach (GameObject item5 in (Il2CppArrayBase<GameObject>)(object)currentMap.shrines)
{
if (!(MyStats.GetStat(((object)(EMyStat)22/*cast due to .constrained prefix*/).ToString()) <= 2f) || !Object.op_Implicit((Object)(object)item5.GetComponentInChildren<InteractableShrineCursed>()))
{
list.Add(item5);
}
}
Plugin.Debug($"Eligible shrine prefabs: {list.Count}");
if (!Object.op_Implicit((Object)(object)microwavePrefab))
{
Plugin.WarnOnce("Microwave guarantee unavailable; using vanilla shrines", new InvalidOperationException("No Microwave prefab found in the stage RandomObjectSpawner inputs or StageData.randomMapObjects"));
return true;
}
int num2 = (int)(14f * currentMap.numShrinesMultiplier);
if (list.Count == 0)
{
return true;
}
int num3 = 0;
int num4 = 0;
try
{
Vector3 val = default(Vector3);
for (int i = 0; i < num2; i++)
{
Vector3 objectSpawnPosition = SpawnPositions.GetObjectSpawnPosition(spawner.worldCenter, spawner.worldArea, 0.5f, LayerMask.op_Implicit(GameManager.Instance.whatIsGroundAndObjects), ref val, 50, true, true, false, 44f, 0f);
if (objectSpawnPosition == SpawnPositions.INVALID_POS)
{
continue;
}
bool flag = num4 < num;
GameObject val2 = list[MyRandom.random.Next(0, list.Count)];
GameObject val3 = Object.Instantiate<GameObject>((GameObject)(flag ? ((object)microwavePrefab) : ((object)val2)), objectSpawnPosition, spawner.chest.transform.rotation);
if ((Object)(object)val3 == (Object)null)
{
continue;
}
num3++;
if (flag)
{
InteractableMicrowave componentInChildren = val3.GetComponentInChildren<InteractableMicrowave>();
if ((Object)(object)componentInChildren == (Object)null)
{
throw new InvalidOperationException("Spawned Microwave prefab has no Microwave component");
}
if (guaranteedCount == 0 && (Object)(object)commonMicrowave == (Object)null)
{
commonMicrowave = componentInChildren;
}
guaranteedCount++;
num4++;
Plugin.Debug($"Guaranteed Microwave {guaranteedCount} instantiated at shrine slot {num3}");
}
val3.transform.rotation = Quaternion.LookRotation(val);
Vector3 forward = val3.transform.forward;
float num5 = Random.Range(0f, 360f);
val3.transform.Rotate(forward, num5, (Space)0);
}
Plugin.Debug($"Successful shrine placements: {num3}; guaranteed Microwaves this stage: {guaranteedCount}");
if (num4 < num)
{
Plugin.Debug("Microwave guarantee shortfall: insufficient valid shrine placements; no extra objects spawned");
}
}
catch (Exception error)
{
Plugin.WarnOnce("Microwave shrine generation failed after allocation began", error);
}
return false;
}
}
internal sealed class PityCounter
{
internal int Misses { get; private set; }
internal bool ShouldReplace(int allowedMisses, bool eligible, bool naturalTarget)
{
if (!eligible || naturalTarget)
{
return false;
}
if (Misses >= allowedMisses)
{
return true;
}
Misses++;
return false;
}
internal void Consume()
{
Misses = 0;
}
}
internal static class PitySettings
{
private const string ItemDescription = "what pity item to roll if enough of the same rarity drops didnt give said item";
private const string CounterDescription = "how many drops of that rarity until the pity item is forced, put 0 to disable";
private static readonly (EItemRarity Rarity, EItem Item, int Count)[] Defaults = new(EItemRarity, EItem, int)[4]
{
((EItemRarity)0, (EItem)0, 8),
((EItemRarity)1, (EItem)32, 7),
((EItemRarity)2, (EItem)64, 5),
((EItemRarity)3, (EItem)41, 3)
};
private static readonly Dictionary<EItemRarity, ConfigEntry<int>> Counts = new Dictionary<EItemRarity, ConfigEntry<int>>();
private static readonly Dictionary<EItemRarity, ConfigEntry<string>> Items = new Dictionary<EItemRarity, ConfigEntry<string>>();
private static ConfigFile? config;
internal unsafe static void Initialize(ConfigFile file)
{
//IL_0032: 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_0043: 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)
//IL_0085: Expected O, but got Unknown
config = file;
Counts.Clear();
Items.Clear();
(EItemRarity, EItem, int)[] defaults = Defaults;
for (int i = 0; i < defaults.Length; i++)
{
(EItemRarity, EItem, int) tuple = defaults[i];
Dictionary<EItemRarity, ConfigEntry<int>> counts = Counts;
EItemRarity item = tuple.Item1;
var (val, _, _) = tuple;
counts.Add(item, file.Bind<int>("pity counters", ((object)(*(EItemRarity*)(&val))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant() + " pity counter", tuple.Item3, new ConfigDescription("how many drops of that rarity until the pity item is forced, put 0 to disable", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>())));
}
}
internal unsafe static void BindItems(DataManager database)
{
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Expected O, but got Unknown
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
if (config == null || (Object)(object)database == (Object)null || database.unsortedItems == null)
{
return;
}
(EItemRarity, EItem, int)[] defaults = Defaults;
for (int i = 0; i < defaults.Length; i++)
{
(EItemRarity Rarity, EItem Item, int Count) rule = defaults[i];
if (Items.ContainsKey(rule.Rarity))
{
continue;
}
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
Enumerator<ItemData> enumerator = database.unsortedItems.GetEnumerator();
while (enumerator.MoveNext())
{
ItemData current = enumerator.Current;
if ((Object)(object)current != (Object)null && current.rarity == rule.Rarity)
{
hashSet.Add(((object)current.eItem/*cast due to .constrained prefix*/).ToString());
}
}
EItem item = rule.Item;
if (!hashSet.Contains(((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString()))
{
Plugin.WarnOnce($"Pity item catalog incomplete for {rule.Rarity}", new InvalidOperationException("Default item missing; leaving this rarity's pity inactive until the database is ready."));
continue;
}
string[] array = new string[1];
item = rule.Item;
array[0] = ((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString();
string[] array2 = array.Concat(hashSet.Where(delegate(string s)
{
//IL_0007: 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)
EItem item3 = rule.Item;
return s != ((object)(*(EItem*)(&item3))/*cast due to .constrained prefix*/).ToString();
}).OrderBy<string, string>((string s) => s, StringComparer.Ordinal)).ToArray();
ConfigFile? obj = config;
EItemRarity item2 = rule.Rarity;
string text = ((object)(*(EItemRarity*)(&item2))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant() + " pity item";
item = rule.Item;
ConfigEntry<string> val = obj.Bind<string>("pity items", text, ((object)(*(EItem*)(&item))/*cast due to .constrained prefix*/).ToString(), new ConfigDescription("what pity item to roll if enough of the same rarity drops didnt give said item", (AcceptableValueBase)(object)new AcceptableValueList<string>(array2), Array.Empty<object>()));
EItemRarity rarity = rule.Rarity;
val.SettingChanged += delegate
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
ChestItemPity.Reset(rarity);
};
Items.Add(rarity, val);
Plugin.Debug($"Pity config {rarity}: {array2.Length} item choices, target={val.Value}, counter={Counts[rarity].Value}");
}
}
internal static bool TryGet(EItemRarity rarity, out EItem item, out int count)
{
//IL_000b: 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_003c: Unknown result type (might be due to invalid IL or missing references)
item = (EItem)0;
count = 0;
if (!Counts.TryGetValue(rarity, out ConfigEntry<int> value) || value.Value <= 0)
{
return false;
}
if (!Items.ContainsKey(rarity))
{
BindItems(DataManager.Instance);
}
if (!Items.TryGetValue(rarity, out ConfigEntry<string> value2) || !Enum.TryParse<EItem>(value2.Value, out item))
{
return false;
}
count = value.Value;
return true;
}
}
internal static class ShadyOffers
{
internal static bool IsEligible(ItemData item)
{
//IL_0038: 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_0054: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)item == (Object)null || !item.inItemPool || !MyAchievements.IsAvailable((UnlockableBase)(object)item))
{
return false;
}
Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
HashSet<ItemData> banishedItems = RunUnlockables.banishedItems;
if (availableItems != null && banishedItems != null && !banishedItems.Contains(item) && availableItems.ContainsKey(item.rarity) && availableItems[item.rarity] != null)
{
return availableItems[item.rarity].Contains(item);
}
return false;
}
internal static void FillMissing(List<ItemData> items)
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
if (items == null || items.Count >= 3)
{
return;
}
HashSet<EItem> hashSet = new HashSet<EItem>();
Enumerator<ItemData> enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
{
ItemData current = enumerator.Current;
if ((Object)(object)current != (Object)null)
{
hashSet.Add(current.eItem);
}
}
Dictionary<EItemRarity, List<ItemData>> availableItems = RunUnlockables.availableItems;
if (availableItems == null)
{
return;
}
EItemRarity[] array = (EItemRarity[])(object)new EItemRarity[2]
{
(EItemRarity)2,
(EItemRarity)3
};
foreach (EItemRarity val in array)
{
if (!availableItems.ContainsKey(val) || availableItems[val] == null)
{
continue;
}
List<ItemData> list = new List<ItemData>();
enumerator = availableItems[val].GetEnumerator();
while (enumerator.MoveNext())
{
ItemData current2 = enumerator.Current;
if (IsEligible(current2) && hashSet.Add(current2.eItem))
{
list.Add(current2);
}
}
while (items.Count < 3 && list.Count > 0)
{
int index = Random.Range(0, list.Count);
items.Add(list[index]);
list.RemoveAt(index);
}
if (items.Count >= 3)
{
break;
}
}
Plugin.Debug($"Guaranteed Epic Shady Guy offers after eligible-pool fallback: {items.Count}/3");
}
}
internal sealed class ShuffleCycle<T> where T : notnull
{
private readonly IReadOnlyList<T> eligible;
private readonly HashSet<T> eligibleSet;
private readonly HashSet<T> screen = new HashSet<T>();
internal HashSet<T> Seen { get; }
internal int Resets { get; private set; }
internal ShuffleCycle(IEnumerable<T> seen, IReadOnlyList<T> eligible)
{
Seen = new HashSet<T>(seen);
this.eligible = eligible;
eligibleSet = new HashSet<T>(eligible);
if (eligibleSet.Count != eligible.Count)
{
throw new ArgumentException("Duplicate eligible IDs.");
}
}
internal T Draw(T preferred, Func<int, int> randomIndex)
{
if (!eligibleSet.Contains(preferred))
{
throw new InvalidOperationException($"Vanilla offered {preferred}, absent from the verified eligible pool.");
}
if (eligibleSet.IsSubsetOf(Seen))
{
Seen.Clear();
Resets++;
}
T val;
if (!Seen.Contains(preferred) && !screen.Contains(preferred))
{
val = preferred;
}
else
{
List<T> list = new List<T>();
for (int i = 0; i < eligible.Count; i++)
{
if (!Seen.Contains(eligible[i]) && !screen.Contains(eligible[i]))
{
list.Add(eligible[i]);
}
}
if (list.Count == 0)
{
throw new InvalidOperationException("Insufficient unique eligible entries for this screen.");
}
val = list[randomIndex(list.Count)];
}
Seen.Add(val);
screen.Add(val);
return val;
}
}
internal static class UpgradeShuffleBag
{
internal sealed record OfferPlan(List<IUpgradable> Offers, ShuffleCycle<EWeapon> Weapons, ShuffleCycle<ETome> Tomes, int Revision);
private static HashSet<EWeapon> seenWeapons = new HashSet<EWeapon>();
private static HashSet<ETome> seenTomes = new HashSet<ETome>();
private static IntPtr inventoryPointer;
private static int revision;
private static readonly Random Random = new Random();
internal static void Reset(string reason)
{
seenWeapons.Clear();
seenTomes.Clear();
inventoryPointer = IntPtr.Zero;
revision++;
Plugin.Debug("Reset weapon and tome shuffle bags: " + reason);
}
internal static void ObserveInventory(PlayerInventory inventory)
{
if (!(inventoryPointer == ((Il2CppObjectBase)inventory).Pointer))
{
Reset("new run inventory");
inventoryPointer = ((Il2CppObjectBase)inventory).Pointer;
}
}
internal static void CleanupInventory(PlayerInventory inventory)
{
if (inventoryPointer == ((Il2CppObjectBase)inventory).Pointer)
{
Reset("run inventory cleaned up");
}
}
internal static OfferPlan? Plan(List<IUpgradable> original)
{
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
//IL_020e: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
MyPlayer instance = MyPlayer.Instance;
if ((Object)(object)instance == (Object)null || instance.inventory == null || (Object)(object)DataManager.Instance == (Object)null)
{
return null;
}
PlayerInventory inventory = instance.inventory;
ObserveInventory(inventory);
WeaponInventory weaponInventory = inventory.weaponInventory;
if (((weaponInventory != null) ? weaponInventory.weapons : null) != null)
{
TomeInventory tomeInventory = inventory.tomeInventory;
if (((tomeInventory != null) ? tomeInventory.tomeLevels : null) != null)
{
List<WeaponData> availableWeapons = UnlockUtility.GetAvailableWeapons();
HashSet<TomeData> availableTomes = UnlockUtility.GetAvailableTomes();
List<WeaponData> allWeapons = DataManager.Instance.GetAllWeapons();
List<TomeData> allTomes = DataManager.Instance.GetAllTomes();
Dictionary<EWeapon, IUpgradable> dictionary = new Dictionary<EWeapon, IUpgradable>();
Dictionary<ETome, IUpgradable> dictionary2 = new Dictionary<ETome, IUpgradable>();
for (int i = 0; i < allWeapons.Count; i++)
{
WeaponData val = allWeapons[i];
if (!((Object)(object)val == (Object)null) && availableWeapons.Contains(val) && !Owns(inventory, val))
{
IUpgradable val2 = ((Il2CppObjectBase)val).Cast<IUpgradable>();
if (val2.GetLevel() < val2.GetMaxLevel() && InventoryUtility.CanUnlockItem(val2))
{
dictionary.TryAdd(val.eWeapon, val2);
}
}
}
for (int j = 0; j < allTomes.Count; j++)
{
TomeData val3 = allTomes[j];
if (!((Object)(object)val3 == (Object)null) && availableTomes.Contains(val3) && !Owns(inventory, val3))
{
IUpgradable val4 = ((Il2CppObjectBase)val3).Cast<IUpgradable>();
if (val4.GetLevel() < val4.GetMaxLevel() && InventoryUtility.CanUnlockItem(val4))
{
dictionary2.TryAdd(val3.eTome, val4);
}
}
}
ShuffleCycle<EWeapon> shuffleCycle = new ShuffleCycle<EWeapon>(seenWeapons, new List<EWeapon>(dictionary.Keys));
ShuffleCycle<ETome> shuffleCycle2 = new ShuffleCycle<ETome>(seenTomes, new List<ETome>(dictionary2.Keys));
List<IUpgradable> val5 = new List<IUpgradable>();
for (int k = 0; k < original.Count; k++)
{
IUpgradable val6 = original[k];
WeaponData val7 = ((val6 != null) ? ((Il2CppObjectBase)val6).TryCast<WeaponData>() : null);
TomeData val8 = ((val6 != null) ? ((Il2CppObjectBase)val6).TryCast<TomeData>() : null);
if ((Object)(object)val7 != (Object)null && !Owns(inventory, val7))
{
val5.Add(dictionary[shuffleCycle.Draw(val7.eWeapon, Random.Next)]);
}
else if ((Object)(object)val8 != (Object)null && !Owns(inventory, val8))
{
val5.Add(dictionary2[shuffleCycle2.Draw(val8.eTome, Random.Next)]);
}
else
{
val5.Add(val6);
}
}
Plugin.Debug($"Eligible unowned pool: {dictionary.Count} weapons, {dictionary2.Count} tomes.");
return new OfferPlan(val5, shuffleCycle, shuffleCycle2, revision);
}
}
return null;
}
internal static void CommitDisplayed(OfferPlan plan, UpgradePicker picker)
{
if (plan.Revision != revision || !Plugin.EnableUpgradeShuffleBag.Value)
{
return;
}
Il2CppReferenceArray<UpgradeButton> buttons = picker.buttons;
if (buttons == null || picker.numUpgrades != plan.Offers.Count || ((Il2CppArrayBase<UpgradeButton>)(object)buttons).Length < plan.Offers.Count)
{
throw new InvalidOperationException("Displayed offer count differs from plan; cycle not consumed.");
}
int num = 0;
while (num < plan.Offers.Count)
{
UpgradeButton val = ((Il2CppArrayBase<UpgradeButton>)(object)buttons)[num];
if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeSelf && !val.isItem)
{
IUpgradable upgradable = val.upgradable;
IntPtr? intPtr = ((upgradable != null) ? new IntPtr?(((Il2CppObjectBase)upgradable).Pointer) : ((IntPtr?)null));
IUpgradable obj = plan.Offers[num];
if (!(intPtr != ((obj != null) ? new IntPtr?(((Il2CppObjectBase)obj).Pointer) : ((IntPtr?)null))))
{
num++;
continue;
}
}
throw new InvalidOperationException("Displayed offer differs from plan; cycle not consumed.");
}
seenWeapons = plan.Weapons.Seen;
seenTomes = plan.Tomes.Seen;
revision++;
if (plan.Weapons.Resets > 0)
{
Plugin.Debug($"Reset weapon shuffle bag ({plan.Weapons.Resets} cycle boundaries).");
}
if (plan.Tomes.Resets > 0)
{
Plugin.Debug($"Reset tome shuffle bag ({plan.Tomes.Resets} cycle boundaries).");
}
LogOffers(plan.Offers, "displayed / unowned entries marked seen");
}
internal static bool Owns(PlayerInventory inventory, WeaponData weapon)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
return inventory.weaponInventory.weapons.ContainsKey(weapon.eWeapon);
}
internal static bool Owns(PlayerInventory inventory, TomeData tome)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return inventory.tomeInventory.HasTome(tome.eTome);
}
internal static void LogOffers(List<IUpgradable> offers, string phase)
{
//IL_00e1: 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)
if (!Plugin.DebugLogging.Value)
{
return;
}
MyPlayer instance = MyPlayer.Instance;
PlayerInventory val = ((instance != null) ? instance.inventory : null);
for (int i = 0; i < offers.Count; i++)
{
IUpgradable val2 = offers[i];
if (val2 == null)
{
Plugin.Debug($"{phase}: offer {i} is null");
continue;
}
WeaponData val3 = ((Il2CppObjectBase)val2).TryCast<WeaponData>();
TomeData val4 = ((Il2CppObjectBase)val2).TryCast<TomeData>();
string value = (((Object)(object)val3 != (Object)null) ? $"weapon {val3.eWeapon}" : (((Object)(object)val4 != (Object)null) ? $"tome {val4.eTome}" : "other"));
string value2 = ((val == null) ? "unknown" : ((!((Object)(object)val3 != (Object)null)) ? ((!((Object)(object)val4 != (Object)null)) ? "not tracked" : (Owns(val, val4) ? "owned" : "unowned")) : (Owns(val, val3) ? "owned" : "unowned")));
Plugin.Debug($"{phase}: {((Il2CppObjectBase)val2).Cast<Object>().GetIl2CppType().FullName}; {value}; level {val2.GetLevel()}/{val2.GetMaxLevel()}; [{value2}]");
}
}
}
}
namespace IHateRNG.Patches
{
[HarmonyPatch(typeof(ItemUtility), "GetRandomChestItem")]
internal static class ChestItemPityPatch
{
[HarmonyPostfix]
private static void Postfix(ref ItemData __result)
{
try
{
ChestItemPity.Apply(ref __result);
}
catch (Exception error)
{
Plugin.WarnOnce("Chest item pity failed", error);
}
}
}
[HarmonyPatch(typeof(RunUnlockables), "OnNewRunStarted")]
internal static class ChestPityNewRunPatch
{
[HarmonyPrefix]
private static void Prefix()
{
ChestItemPity.Reset();
}
}
[HarmonyPatch(typeof(PlayerInventory), "Cleanup")]
internal static class ChestPityCleanupPatch
{
[HarmonyPrefix]
private static void Prefix()
{
ChestItemPity.Reset();
}
}
[HarmonyPatch(typeof(InteractableChest), "OnChestWindowClose")]
internal static class KeyChancePatch
{
internal sealed record SavedChance(ItemKey Key, float Chance);
[HarmonyPrefix]
private static void Prefix(out SavedChance? __state)
{
__state = null;
if (Plugin.KeyEnabled)
{
MyPlayer instance = MyPlayer.Instance;
object obj;
if (instance == null)
{
obj = null;
}
else
{
PlayerInventory inventory = instance.inventory;
obj = ((inventory != null) ? inventory.itemInventory : null);
}
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
ItemBase item = ((ItemInventory)obj).GetItem((EItem)0);
obj2 = ((item != null) ? ((Il2CppObjectBase)item).TryCast<ItemKey>() : null);
}
ItemKey val = (ItemKey)obj2;
if (val != null)
{
__state = new SavedChance(val, val.currentChance);
val.currentChance = 0f;
Plugin.Debug("Suppressed Key free-chest chance during chest settlement.");
}
}
}
[HarmonyFinalizer]
private static void Finalizer(SavedChance? __state)
{
if (__state != null)
{
__state.Key.currentChance = __state.Chance;
}
}
}
[HarmonyPatch(typeof(ItemKey), "GetDescription")]
internal static class KeyDescriptionPatch
{
[HarmonyPrefix]
private static bool Prefix(ref string __result)
{
if (!Plugin.KeyEnabled)
{
return true;
}
__result = ChestPricing.Describe(Plugin.KeyScalingPercent, Plugin.KeyBasePercent, Plugin.KeyStagePercent);
return false;
}
}
[HarmonyPatch(typeof(ItemCreditCardGreen), "OnInitOrAmountChanged")]
internal static class KeyGreenCardStatPatch
{
[HarmonyPrefix]
private static void Prefix(ItemCreditCardGreen __instance, out float? __state)
{
__state = null;
if (Plugin.KeyEnabled && ((ItemBase)__instance).itemInventoryRef != null)
{
__state = __instance.chestPriceIncreasePerAmount;
ItemBase item = ((ItemBase)__instance).itemInventoryRef.GetItem((EItem)0);
int keys = ((item != null) ? item.amount : 0);
__instance.chestPriceIncreasePerAmount = KeyGreenCard.PerCopy(keys);
}
}
[HarmonyFinalizer]
private static void Finalizer(ItemCreditCardGreen __instance, float? __state)
{
if (__state.HasValue)
{
__instance.chestPriceIncreasePerAmount = __state.Value;
}
}
}
[HarmonyPatch(typeof(ItemInventory), "AddItem", new Type[] { typeof(EItem) })]
internal static class KeyGreenCardAddedPatch
{
[HarmonyPostfix]
private static void Postfix(ItemInventory __instance, EItem __0)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.KeyEnabled && (int)__0 == 0)
{
KeyGreenCard.Refresh(__instance);
}
}
}
[HarmonyPatch(typeof(ItemInventory), "RemoveItem")]
internal static class KeyGreenCardRemovedPatch
{
[HarmonyPostfix]
private static void Postfix(ItemInventory __instance, EItem __0)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.KeyEnabled && (int)__0 == 0)
{
KeyGreenCard.Refresh(__instance);
}
}
}
[HarmonyPatch(typeof(MoneyUtility), "GetChestPrice")]
internal static class KeyPricePatch
{
private static readonly KeyChestGrowth Growth = new KeyChestGrowth();
internal static void Reset()
{
Growth.Reset();
}
[HarmonyPrefix]
private static bool Prefix(ref int __result)
{
if (!Plugin.KeyEnabled)
{
return true;
}
try
{
MyPlayer instance = MyPlayer.Instance;
int? obj;
if (instance == null)
{
obj = null;
}
else
{
PlayerInventory inventory = instance.inventory;
if (inventory == null)
{
obj = null;
}
else
{
ItemInventory itemInventory = inventory.itemInventory;
if (itemInventory == null)
{
obj = null;
}
else
{
ItemBase item = itemInventory.GetItem((EItem)0);
obj = ((item != null) ? new int?(item.amount) : ((int?)null));
}
}
}
int? num = obj;
int valueOrDefault = num.GetValueOrDefault();
__result = CalculatePrice(valueOrDefault);
return false;
}
catch (Exception error)
{
Plugin.WarnOnce("Key split chest pricing", error);
return true;
}
}
internal static int CalculatePrice(int keys)
{
int chestsPurchased = MoneyUtility.chestsPurchased;
float num = Mathf.Pow(MoneyUtility.chestPriceIncrease, (float)chestsPurchased);
int num2 = ChestPricing.LinearIncrease(chestsPurchased, MoneyUtility.priceIncreasePerChest, MoneyUtility.priceIncreasePerChestOver10, MoneyUtility.priceIncreasePerChestOver20, MoneyUtility.priceIncreasePerChestOver30, MoneyUtility.priceIncreasePerChestOver40, MoneyUtility.priceIncreasePerChestOver50);
float num3 = MoneyUtility.chestBasePrice;
float rawGrowth = num3 * (num - 1f) + (float)num2;
Growth.Observe(chestsPurchased, rawGrowth, keys, Plugin.KeyScalingPercent, Plugin.KeyScalingMultiplier);
int num4 = Mathf.RoundToInt(ChestPricing.FinalPrice(chestPriceStat: PlayerStats.GetStat((EStat)34), initialBase: num3, discountedGrowth: Growth.DiscountedGrowth, stageFactor: KeyStages.BaseMultiplier));
Growth.LastPrice = num4;
return num4;
}
}
[HarmonyPatch(typeof(InteractableChest), "OnChestWindowClose")]
internal static class KeyChestPriceCapturePatch
{
[HarmonyPrefix]
private static void Prefix()
{
if (Plugin.KeyEnabled)
{
MoneyUtility.GetChestPrice();
}
}
[HarmonyPostfix]
private static void Postfix()
{
Prefix();
}
}
[HarmonyPatch(typeof(MoneyUtility), "IncreaseChestPrice")]
internal static class KeyPriceIncreaseCapturePatch
{
[HarmonyPrefix]
private static void Prefix()
{
if (Plugin.KeyEnabled)
{
MoneyUtility.GetChestPrice();
}
}
[HarmonyPostfix]
private static void Postfix()
{
Prefix();
}
}
[HarmonyPatch(typeof(MapController), "StartNewMap")]
internal static class KeyStageRunPatch
{
[HarmonyPrefix]
private static void Prefix()
{
KeyStages.Reset();
}
}
[HarmonyPatch(typeof(MapController), "RestartRun")]
internal static class KeyStageRestartPatch
{
[HarmonyPrefix]
private static void Prefix()
{
KeyStages.Reset();
}
}
[HarmonyPatch(typeof(ItemKey), "OnInitOrAmountChanged")]
internal static class KeyStatPatch
{
[HarmonyPostfix]
private static void Postfix(ItemKey __instance)
{
if (Plugin.KeyEnabled)
{
KeyStats.Apply(__instance, enabled: true);
}
}
}
[HarmonyPatch(typeof(RandomObjectPlacer), "RandomObjectSpawner")]
internal static class MicrowavePrefabCapturePatch
{
[HarmonyPrefix]
private static void Prefix(RandomObjectPlacer __instance, RandomMapObject __0)
{
//IL_0007: 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)
try
{
Scene scene = ((Component)__instance).gameObject.scene;
MicrowaveGuarantee.CapturePrefab(__0, ((Scene)(ref scene)).handle);
}
catch (Exception error)
{
Plugin.WarnOnce("Microwave prefab capture failed", error);
}
}
}
[HarmonyPatch(typeof(SpawnInteractables), "SpawnShrines")]
internal static class MicrowaveSpawnPatch
{
[HarmonyPrefix]
private static bool Prefix(SpawnInteractables __instance)
{
try
{
return MicrowaveGuarantee.SpawnShrines(__instance);
}
catch (Exception error)
{
Plugin.WarnOnce("Microwave guarantee preparation failed; using vanilla shrines", error);
return true;
}
}
}
[HarmonyPatch(typeof(InteractableMicrowave), "Start")]
internal static class MicrowaveStartPatch
{
[ThreadStatic]
internal static bool ForceCommon;
[HarmonyPrefix]
private static void Prefix(InteractableMicrowave __instance, out bool __state)
{
__state = ForceCommon;
MicrowaveGuarantee.ObserveStart(__instance);
ForceCommon = MicrowaveGuarantee.IsCommonTarget(__instance);
}
[HarmonyFinalizer]
private static void Finalizer(bool __state)
{
ForceCommon = __state;
}
}
[HarmonyPatch(typeof(Rarity), "GetShadyGuyRarity")]
internal static class MicrowaveRarityPatch
{
[HarmonyPostfix]
private static void Postfix(ref EItemRarity __result)
{
if (MicrowaveStartPatch.ForceCommon)
{
__result = (EItemRarity)0;
Plugin.Debug("First guaranteed Microwave initialized as Common; vanilla applies material and 3 uses");
}
}
}
[HarmonyPatch(typeof(MoneyUtility), "OnNewStage")]
internal static class MicrowaveStagePatch
{
[HarmonyPrefix]
private static void Prefix()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
MicrowaveGuarantee.BeginStage(((Scene)(ref activeScene)).handle);
}
}
[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
internal static class MicrowaveRunPatch
{
[HarmonyPrefix]
private static void Prefix()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
MicrowaveGuarantee.BeginStage(((Scene)(ref activeScene)).handle);
}
}
[HarmonyPatch(typeof(DataManager), "Load")]
internal static class PityConfigPatch
{
[HarmonyPostfix]
private static void Postfix(DataManager __instance)
{
try
{
PitySettings.BindItems(__instance);
}
catch (Exception error)
{
Plugin.WarnOnce("Pity configuration catalog failed", error);
}
}
}
[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
internal static class NewRunPatch
{
[HarmonyPostfix]
private static void Postfix()
{
UpgradeShuffleBag.Reset("new run started");
}
}
[HarmonyPatch(typeof(MapController), "GetPlayerInventory")]
internal static class InventoryInitializedPatch
{
[HarmonyPostfix]
private static void Postfix(PlayerInventory __result)
{
if (__result != null)
{
UpgradeShuffleBag.ObserveInventory(__result);
}
}
}
[HarmonyPatch(typeof(PlayerInventory), "Cleanup")]
internal static class InventoryCleanupPatch
{
[HarmonyPrefix]
private static void Prefix(PlayerInventory __instance)
{
UpgradeShuffleBag.CleanupInventory(__instance);
}
}
[HarmonyPatch(typeof(InteractableShadyGuy), "Start")]
internal static class ShadyGuyStartPatch
{
[ThreadStatic]
internal static InteractableShadyGuy? Starting;
[HarmonyPrefix]
private static void Prefix(InteractableShadyGuy __instance, out InteractableShadyGuy? __state)
{
__state = Starting;
Starting = __instance;
GuaranteedShadyGuy.ObserveSpawn(__instance);
}
[HarmonyFinalizer]
private static void Finalizer(InteractableShadyGuy? __state)
{
Starting = __state;
}
}
[HarmonyPatch(typeof(Rarity), "GetShadyGuyRarity")]
internal static class ShadyGuyRarityPatch
{
[HarmonyPostfix]
private static void Postfix(ref EItemRarity __result)
{
InteractableShadyGuy starting = ShadyGuyStartPatch.Starting;
if (!((Object)(object)starting == (Object)null) && GuaranteedShadyGuy.IsSelected(starting))
{
__result = (EItemRarity)2;
Plugin.Debug("Forced Shady Guy rarity to Epic");
}
}
}
[HarmonyPatch(typeof(InteractableShadyGuy), "FindItems")]
internal static class ShadyGuyItemsPatch
{
[ThreadStatic]
internal static InteractableShadyGuy? Generating;
[HarmonyPrefix]
private static void Prefix(InteractableShadyGuy __instance, out InteractableShadyGuy? __state)
{
__state = Generating;
Generating = __instance;
}
[HarmonyFinalizer]
private static void Finalizer(InteractableShadyGuy? __state)
{
Generating = __state;
}
[HarmonyPostfix]
private static void Postfix(InteractableShadyGuy __instance)
{
try
{
GuaranteedShadyGuy.EnsureCard(__instance);
}
catch (Exception error)
{
Plugin.WarnOnce("Shady Guy guarantee failed", error);
}
}
}
[HarmonyPatch(typeof(InventoryUtility), "GetRandomItemsShadyGuy")]
internal static class ShadyGuyShortInventoryPatch
{
[HarmonyPostfix]
private static void Postfix(List<ItemData> __result)
{
InteractableShadyGuy val = ShadyGuyItemsPatch.Generating ?? ShadyGuyStartPatch.Starting;
if ((Object)(object)val == (Object)null || !GuaranteedShadyGuy.IsSelected(val))
{
return;
}
try
{
ShadyOffers.FillMissing(__result);
}
catch (Exception error)
{
Plugin.WarnOnce("Shady Guy missing offer repair", error);
}
}
}
[HarmonyPatch(typeof(MoneyUtility), "OnNewStage")]
internal static class ShadyGuyNewStagePatch
{
[HarmonyPrefix]
private static void Prefix()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
GuaranteedShadyGuy.BeginStage(((Scene)(ref activeScene)).handle);
}
}
[HarmonyPatch(typeof(MoneyUtility), "OnNewRun")]
internal static class ShadyGuyNewRunPatch
{
[HarmonyPrefix]
private static void Prefix()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
GuaranteedShadyGuy.BeginStage(((Scene)(ref activeScene)).handle);
}
}
[HarmonyPatch(typeof(InventoryUtility), "GetRandomUpgrades")]
internal static class UpgradeOfferPatch
{
[HarmonyPostfix]
private static void Postfix(ref List<IUpgradable> __result)
{
if (__result == null)
{
return;
}
try
{
UpgradeShuffleBag.LogOffers(__result, "vanilla generated");
}
catch (Exception error)
{
Plugin.WarnOnce("Offer diagnostics failed", error);
}
OfferDisplayPatch.Frame current = OfferDisplayPatch.Current;
if (!Plugin.EnableUpgradeShuffleBag.Value || current == null)
{
return;
}
current.Plan = null;
try
{
UpgradeShuffleBag.OfferPlan offerPlan = UpgradeShuffleBag.Plan(__result);
if (!(offerPlan == null))
{
current.Plan = offerPlan;
__result = offerPlan.Offers;
}
}
catch (Exception error2)
{
Plugin.WarnOnce("Shuffle planning failed; preserving vanilla offers", error2);
}
}
}
[HarmonyPatch(typeof(UpgradePicker), "ShuffleUpgrades")]
internal static class OfferDisplayPatch
{
internal sealed class Frame
{
internal Frame? Parent;
internal UpgradeShuffleBag.OfferPlan? Plan;
}
[ThreadStatic]
internal static Frame? Current;
[HarmonyPrefix]
private static void Prefix(out Frame __state)
{
__state = new Frame
{
Parent = Current
};
Current = __state;
}
[HarmonyPostfix]
private static void Postfix(UpgradePicker __instance, Frame __state)
{
if (__state.Plan == null)
{
return;
}
try
{
UpgradeShuffleBag.CommitDisplayed(__state.Plan, __instance);
}
catch (Exception error)
{
Plugin.WarnOnce("Offer display verification failed", error);
}
}
[HarmonyFinalizer]
private static void Finalizer(Frame? __state)
{
Current = __state?.Parent;
}
}
}