Decompiled source of ArmsRace v1.0.0

Arms Race.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.Items;
using PerfectRandom.Sulfur.Core.UI;
using PerfectRandom.Sulfur.Core.UI.Inventory;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("RandomWeaponPerLevel")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RandomWeaponPerLevel")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("2c8445fc-70f2-4406-be3e-d54a3e8b4737")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace RandomWeaponPerLevel;

public enum PreferredWeaponSlotMode
{
	Weapon0,
	Weapon1,
	Random,
	FirstAvailable
}
public sealed class RandomWeaponMarker : MonoBehaviour
{
	public int generationId;

	public int levelSignature;

	public string reason;

	public string weaponName;
}
[BepInPlugin("kumo.sulfur.random_weapon_per_level", "Random Weapon Per Level", "0.4.1")]
public sealed class Plugin : BaseUnityPlugin
{
	private sealed class WeightedAttachmentCandidate
	{
		public ItemDefinition Item;

		public float Weight;

		public WeightedAttachmentCandidate(ItemDefinition item, float weight)
		{
			Item = item;
			Weight = weight;
		}
	}

	[CompilerGenerated]
	private sealed class <AutoGiveForLevelSignature>d__78 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public int signature;

		public string reason;

		public Plugin <>4__this;

		private float <delay>5__1;

		private int <currentSignature>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <AutoGiveForLevelSignature>d__78(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>4__this.autoGiveRoutineRunning = true;
				<delay>5__1 = Mathf.Max(0f, <>4__this.autoGiveDelayAfterLevelStart.Value);
				if (<delay>5__1 > 0f)
				{
					<>2__current = (object)new WaitForSeconds(<delay>5__1);
					<>1__state = 1;
					return true;
				}
				goto IL_008c;
			case 1:
				<>1__state = -1;
				goto IL_008c;
			case 2:
				{
					<>1__state = -1;
					<>4__this.autoGiveRoutineRunning = false;
					return false;
				}
				IL_008c:
				if (!<>4__this.enableMod.Value || !<>4__this.randomizeOnLevelStart.Value)
				{
					<>4__this.autoGivenLevelSignatures.Remove(signature);
					<>4__this.autoGiveRoutineRunning = false;
					return false;
				}
				if (!<>4__this.IsInPlayableLevel())
				{
					<>4__this.autoGivenLevelSignatures.Remove(signature);
					<>4__this.sawLoadingOrLevelTransition = true;
					<>4__this.autoGiveRoutineRunning = false;
					return false;
				}
				<currentSignature>5__2 = <>4__this.GetCachedLevelSignature();
				if (<currentSignature>5__2 != signature)
				{
					<>4__this.autoGivenLevelSignatures.Remove(signature);
					<>4__this.sawLoadingOrLevelTransition = true;
					<>4__this.autoGiveRoutineRunning = false;
					return false;
				}
				<>2__current = <>4__this.GiveRandomWeaponRoutine(reason + " " + signature, signature);
				<>1__state = 2;
				return true;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <GiveRandomWeaponRoutine>d__82 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public string reason;

		public int levelSignature;

		public Plugin <>4__this;

		private ItemGrid <backpack>5__1;

		private WeaponSO <weapon>5__2;

		private InventorySlot <targetSlot>5__3;

		private HashSet<InventoryItem> <beforeItems>5__4;

		private int <waitFrames>5__5;

		private InventoryItem <createdItem>5__6;

		private int <removed>5__7;

		private Exception <ex>5__8;

		private int <i>5__9;

		private int <appliedOilCount>5__10;

		private int <appliedScrollCount>5__11;

		private int <appliedAttachmentCount>5__12;

		private string <itemInfo>5__13;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <GiveRandomWeaponRoutine>d__82(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<backpack>5__1 = null;
			<weapon>5__2 = null;
			<beforeItems>5__4 = null;
			<createdItem>5__6 = null;
			<ex>5__8 = null;
			<itemInfo>5__13 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: 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_0152: Invalid comparison between Unknown and I4
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<backpack>5__1 = <>4__this.GetPlayerBackpackGrid();
				if ((Object)(object)<backpack>5__1 == (Object)null)
				{
					((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: PlayerBackpackGrid is null.");
					return false;
				}
				<weapon>5__2 = <>4__this.PickRandomWeapon();
				if ((Object)(object)<weapon>5__2 == (Object)null)
				{
					((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: no valid WeaponSO found.");
					return false;
				}
				if (<>4__this.cleanupOldGeneratedWeapons.Value)
				{
					<removed>5__7 = <>4__this.CleanupOldGeneratedWeapons(null);
					if (<removed>5__7 > 0 && <>4__this.logActions.Value)
					{
						((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Removed old generated weapons before generating a new one: " + <removed>5__7));
					}
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				goto IL_0139;
			case 1:
				<>1__state = -1;
				goto IL_0139;
			case 2:
				<>1__state = -1;
				if (!<>4__this.IsWeaponSlotEmpty(<targetSlot>5__3))
				{
					((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Could not give random weapon: target slot is still occupied: " + ((object)(InventorySlot)(ref <targetSlot>5__3)).ToString()));
					return false;
				}
				<beforeItems>5__4 = <>4__this.CapturePlayerInventoryItems();
				try
				{
					StaticInstance<UIManager>.Instance.InventoryUI.SpawnItemInSlot((ItemDefinition)(object)<weapon>5__2, <targetSlot>5__3, (InventoryData)null);
					if (<>4__this.announcePickup.Value && (Object)(object)<backpack>5__1 != (Object)null)
					{
						try
						{
							<backpack>5__1.PlayPickupNote((ItemDefinition)(object)<weapon>5__2, (int?)null);
						}
						catch
						{
						}
					}
				}
				catch (Exception ex)
				{
					<ex>5__8 = ex;
					((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)("Failed to spawn random weapon " + GetWeaponName(<weapon>5__2) + " into " + ((object)(InventorySlot)(ref <targetSlot>5__3)).ToString() + ": " + <ex>5__8.Message));
					return false;
				}
				<waitFrames>5__5 = Mathf.Clamp(<>4__this.postCreateWaitFrames.Value, 1, 60);
				<i>5__9 = 0;
				break;
			case 3:
				{
					<>1__state = -1;
					<i>5__9++;
					break;
				}
				IL_0139:
				<targetSlot>5__3 = <>4__this.PrepareTargetWeaponSlot();
				if ((int)<targetSlot>5__3 == 9)
				{
					((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"Could not give random weapon: no usable Weapon0/Weapon1 slot. Backpack may be full.");
					return false;
				}
				<>2__current = null;
				<>1__state = 2;
				return true;
			}
			if (<i>5__9 < <waitFrames>5__5)
			{
				<>2__current = null;
				<>1__state = 3;
				return true;
			}
			<createdItem>5__6 = <>4__this.FindNewInventoryItem(<beforeItems>5__4, <weapon>5__2);
			if ((Object)(object)<createdItem>5__6 == (Object)null)
			{
				<createdItem>5__6 = <>4__this.GetItemInWeaponSlot(<targetSlot>5__3);
			}
			if ((Object)(object)<createdItem>5__6 != (Object)null)
			{
				<>4__this.MarkGeneratedWeapon(<createdItem>5__6, reason, levelSignature);
				if (<>4__this.forceSelectGeneratedWeapon.Value)
				{
					<>4__this.TrySelectWeaponSlot(<targetSlot>5__3);
				}
				<appliedOilCount>5__10 = <>4__this.ApplyRandomOilsIfNeeded(<createdItem>5__6);
				<appliedScrollCount>5__11 = <>4__this.ApplyRandomScrollsIfNeeded(<createdItem>5__6);
				<>4__this.GrantMinimumRankForAppliedEnchantments(<createdItem>5__6, <appliedOilCount>5__10 + <appliedScrollCount>5__11);
				<>4__this.TrySyncInstancedWeapon(<createdItem>5__6);
				<appliedAttachmentCount>5__12 = <>4__this.ApplyRandomAttachmentsIfNeeded(<createdItem>5__6);
				<>4__this.TrySyncInstancedWeapon(<createdItem>5__6);
				<>4__this.NormalizeDurabilityIfNeeded(<createdItem>5__6);
				<>4__this.FixDurabilityIfNeeded(<createdItem>5__6);
				<>4__this.TrySyncInstancedWeapon(<createdItem>5__6);
				if (<>4__this.forceSelectGeneratedWeapon.Value)
				{
					<>4__this.TrySelectWeaponSlot(<targetSlot>5__3);
				}
				if (<>4__this.cleanupOldGeneratedWeapons.Value)
				{
					<>4__this.CleanupOldGeneratedWeapons(<createdItem>5__6);
				}
			}
			if (<>4__this.logActions.Value)
			{
				<itemInfo>5__13 = (((Object)(object)<createdItem>5__6 != (Object)null) ? <>4__this.BuildCreatedItemInfo(<createdItem>5__6) : "created item not found after SpawnItemInSlot");
				((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Generated random weapon by " + reason + " into " + ((object)(InventorySlot)(ref <targetSlot>5__3)).ToString() + ": " + GetWeaponName(<weapon>5__2) + " (" + <itemInfo>5__13 + ")"));
				<itemInfo>5__13 = null;
			}
			return false;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	internal static ManualLogSource Log;

	internal static Plugin Instance;

	private Harmony harmony;

	private ConfigEntry<bool> enableMod;

	private ConfigEntry<bool> randomizeOnLevelStart;

	private ConfigEntry<bool> debugKeyEnabled;

	private ConfigEntry<Key> debugKey;

	private int lastTransitionCleanupFrame = -1;

	private ConfigEntry<PreferredWeaponSlotMode> preferredWeaponSlot;

	private ConfigEntry<bool> forceSelectGeneratedWeapon;

	private ConfigEntry<bool> cleanupOldGeneratedWeapons;

	private ConfigEntry<bool> destroyGeneratedWeaponsOnDrop;

	private ConfigEntry<bool> cleanupGeneratedWeaponsBeforeLevelTransition;

	private ConfigEntry<bool> gunsOnly;

	private ConfigEntry<bool> excludeStartsEmpty;

	private ConfigEntry<bool> requireWeaponPrefab;

	private ConfigEntry<bool> requireAmmoMagazine;

	private ConfigEntry<bool> requireUsableByPlayer;

	private ConfigEntry<bool> enableRandomOils;

	private ConfigEntry<int> minOilCount;

	private ConfigEntry<int> maxOilCount;

	private ConfigEntry<bool> respectEnchantmentSlots;

	private ConfigEntry<bool> grantRankForAppliedOils;

	private ConfigEntry<bool> enableRandomScrolls;

	private ConfigEntry<float> scrollChance;

	private ConfigEntry<int> minScrollCount;

	private ConfigEntry<int> maxScrollCount;

	private ConfigEntry<bool> enableRandomWeaponOnKill;

	private ConfigEntry<float> randomWeaponOnKillCooldown;

	private ConfigEntry<bool> killRewardRequiresPlayableLevel;

	private ConfigEntry<bool> killRewardRequireExperienceOnKill;

	private ConfigEntry<bool> logKillRewardChecks;

	private float nextKillRewardAllowedTime;

	private readonly HashSet<int> rewardedKillUnitIds = new HashSet<int>();

	private ConfigEntry<bool> enableRandomAttachments;

	private ConfigEntry<float> attachmentChance;

	private ConfigEntry<int> minAttachmentCount;

	private ConfigEntry<int> maxAttachmentCount;

	private ConfigEntry<float> minimumDurabilityNormalized;

	private ConfigEntry<bool> fixLowDurability;

	private ConfigEntry<bool> announcePickup;

	private ConfigEntry<bool> logActions;

	private ConfigEntry<bool> logWeaponPool;

	private ConfigEntry<float> autoGiveDelayAfterLevelStart;

	private ConfigEntry<int> postCreateWaitFrames;

	private ConfigEntry<float> sceneSignatureCheckInterval;

	private readonly List<WeaponSO> cachedWeaponPool = new List<WeaponSO>();

	private readonly HashSet<int> autoGivenLevelSignatures = new HashSet<int>();

	private bool sawLoadingOrLevelTransition;

	private bool autoGiveRoutineRunning;

	private int currentLevelSignature;

	private int cachedLevelSignature;

	private float nextSignatureCheckTime;

	private int generationCounter;

	internal int CleanupGeneratedWeaponsForTransition(string reason)
	{
		if (!ShouldCleanupBeforeLevelTransition())
		{
			return 0;
		}
		if (lastTransitionCleanupFrame == Time.frameCount)
		{
			return 0;
		}
		lastTransitionCleanupFrame = Time.frameCount;
		int num = CleanupOldGeneratedWeapons(null);
		if (num > 0)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogInfo((object)("Removed generated weapon(s) before transition: " + num + " (" + reason + ")"));
			}
		}
		else if (logActions != null && logActions.Value)
		{
			ManualLogSource log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)("Transition cleanup checked, no generated weapon found. (" + reason + ")"));
			}
		}
		return num;
	}

	private void Awake()
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Expected O, but got Unknown
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Expected O, but got Unknown
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Expected O, but got Unknown
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f5: Expected O, but got Unknown
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Expected O, but got Unknown
		//IL_04be: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c8: Expected O, but got Unknown
		//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fa: Expected O, but got Unknown
		//IL_0522: Unknown result type (might be due to invalid IL or missing references)
		//IL_052c: Expected O, but got Unknown
		//IL_0581: Unknown result type (might be due to invalid IL or missing references)
		//IL_058b: Expected O, but got Unknown
		//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_05bd: Expected O, but got Unknown
		//IL_05e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ef: Expected O, but got Unknown
		//IL_0644: Unknown result type (might be due to invalid IL or missing references)
		//IL_064e: Expected O, but got Unknown
		//IL_066b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0675: Expected O, but got Unknown
		//IL_071a: Unknown result type (might be due to invalid IL or missing references)
		//IL_071f: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		Instance = this;
		enableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Enable this mod.");
		randomizeOnLevelStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RandomizeOnLevelStart", true, "Give one random weapon when entering a non-safe-zone level.");
		enableRandomWeaponOnKill = ((BaseUnityPlugin)this).Config.Bind<bool>("Kill Reward", "EnableRandomWeaponOnKill", true, "If true, killing an eligible enemy grants one generated random weapon.");
		randomWeaponOnKillCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Kill Reward", "RandomWeaponOnKillCooldown", 1f, new ConfigDescription("Cooldown in seconds for random weapon rewards from enemy kills.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>()));
		killRewardRequiresPlayableLevel = ((BaseUnityPlugin)this).Config.Bind<bool>("Kill Reward", "KillRewardRequiresPlayableLevel", true, "If true, kill rewards only trigger in playable non-safe-zone levels.");
		killRewardRequireExperienceOnKill = ((BaseUnityPlugin)this).Config.Bind<bool>("Kill Reward", "KillRewardRequireExperienceOnKill", true, "If true, only units with ExperienceOnKill > 0 can trigger a random weapon reward. This avoids most props and non-enemy objects.");
		logKillRewardChecks = ((BaseUnityPlugin)this).Config.Bind<bool>("Kill Reward", "LogKillRewardChecks", false, "Log detailed kill reward checks. Keep false for normal gameplay.");
		nextKillRewardAllowedTime = 0f;
		announcePickup = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnnouncePickup", true, "Show pickup notification when a random weapon is generated.");
		preferredWeaponSlot = ((BaseUnityPlugin)this).Config.Bind<PreferredWeaponSlotMode>("General", "PreferredWeaponSlot", PreferredWeaponSlotMode.FirstAvailable, "Which weapon slot should receive the generated weapon.");
		forceSelectGeneratedWeapon = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceSelectGeneratedWeapon", true, "Force-select the generated weapon after it is equipped.");
		cleanupOldGeneratedWeapons = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CleanupOldGeneratedWeapons", true, "Remove older runtime-tagged weapons generated by this mod before generating a new one.");
		cleanupGeneratedWeaponsBeforeLevelTransition = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "CleanupGeneratedWeaponsBeforeLevelTransition", true, "Remove runtime-tagged generated weapons before GameManager.SwitchLevel runs. This prevents generated weapons from entering cross-level equipment data.");
		destroyGeneratedWeaponsOnDrop = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "DestroyGeneratedWeaponsOnDrop", true, "Destroy runtime-tagged generated weapons when the player tries to drop them. This prevents tag loss through ground pickup data.");
		autoGiveDelayAfterLevelStart = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "AutoGiveDelayAfterLevelStart", 2f, "Delay before giving the level-start random weapon after entering a playable level.");
		postCreateWaitFrames = ((BaseUnityPlugin)this).Config.Bind<int>("Timing", "PostCreateWaitFrames", 8, new ConfigDescription("Frames to wait after SpawnItemInSlot before searching for the created InventoryItem.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60), Array.Empty<object>()));
		sceneSignatureCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Timing", "SceneSignatureCheckInterval", 0.5f, new ConfigDescription("How often the mod checks the current level signature.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
		debugKeyEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugKeyEnabled", false, "Enable debug key spawning.");
		debugKey = ((BaseUnityPlugin)this).Config.Bind<Key>("Debug", "DebugKey", (Key)25, "Press this key to generate one random debug weapon. This can be used repeatedly.");
		logActions = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogActions", true, "Log generated weapon information.");
		logWeaponPool = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogWeaponPool", false, "Log every weapon in the random pool. Keep false unless debugging.");
		gunsOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Pool", "GunsOnly", true, "Exclude melee and throwable weapons.");
		excludeStartsEmpty = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Pool", "ExcludeStartsEmpty", true, "Exclude weapons marked as startsEmpty.");
		requireWeaponPrefab = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Pool", "RequireWeaponPrefab", true, "Only include weapons with a prefab. Recommended.");
		requireAmmoMagazine = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Pool", "RequireAmmoMagazine", true, "Only include weapons with iAmmoMax > 0.");
		requireUsableByPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Pool", "RequireUsableByPlayer", true, "Only include WeaponSO.usableByPlayer weapons.");
		enableRandomOils = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Upgrades", "EnableRandomOils", true, "Add random oil enchantments to generated weapons.");
		minOilCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MinOilCount", 1, new ConfigDescription("Minimum random oil enchantments added to generated weapons.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
		maxOilCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MaxOilCount", 5, new ConfigDescription("Maximum random oil enchantments added to generated weapons.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
		respectEnchantmentSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Upgrades", "RespectEnchantmentSlots", false, "If true, only add oils/scrolls when the weapon has free enchantment slots. If false, this mod can create chaos guns regardless of rank.");
		grantRankForAppliedOils = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Upgrades", "GrantRankForAppliedOils", true, "If true, generated weapons gain enough XP to match the total applied enchantment count.");
		enableRandomScrolls = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Upgrades", "EnableRandomScrolls", true, "Add random scroll enchantments to generated weapons.");
		scrollChance = ((BaseUnityPlugin)this).Config.Bind<float>("Random Upgrades", "ScrollChance", 0.5f, new ConfigDescription("Chance for a generated weapon to receive scroll enchantments. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		minScrollCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MinScrollCount", 1, new ConfigDescription("Minimum scroll enchantments if scroll generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
		maxScrollCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MaxScrollCount", 2, new ConfigDescription("Maximum scroll enchantments if scroll generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 5), Array.Empty<object>()));
		enableRandomAttachments = ((BaseUnityPlugin)this).Config.Bind<bool>("Random Upgrades", "EnableRandomAttachments", true, "Add random compatible attachments to generated weapons.");
		attachmentChance = ((BaseUnityPlugin)this).Config.Bind<float>("Random Upgrades", "AttachmentChance", 0.6f, new ConfigDescription("Chance for a generated weapon to receive attachments. 0 = never, 1 = always.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		minAttachmentCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MinAttachmentCount", 1, new ConfigDescription("Minimum attachments if attachment generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
		maxAttachmentCount = ((BaseUnityPlugin)this).Config.Bind<int>("Random Upgrades", "MaxAttachmentCount", 2, new ConfigDescription("Maximum attachments if attachment generation succeeds.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 4), Array.Empty<object>()));
		fixLowDurability = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "FixLowDurability", true, "Raise generated weapon durability to MinimumDurabilityNormalized if it is lower.");
		minimumDurabilityNormalized = ((BaseUnityPlugin)this).Config.Bind<float>("Safety", "MinimumDurabilityNormalized", 0.5f, new ConfigDescription("Minimum durability for generated weapons. 0.5 = at least 50%.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		SceneManager.sceneLoaded += OnSceneLoaded;
		harmony = new Harmony("kumo.sulfur.random_weapon_per_level");
		TryPatchHarmony();
		sawLoadingOrLevelTransition = true;
		currentLevelSignature = 0;
		cachedLevelSignature = 0;
		nextSignatureCheckTime = 0f;
		generationCounter = 0;
		ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
		string[] obj = new string[10]
		{
			"Random Weapon Per Level 0.4.2 loaded. EnableMod=",
			enableMod.Value.ToString(),
			", RandomizeOnLevelStart=",
			randomizeOnLevelStart.Value.ToString(),
			", DebugKeyEnabled=",
			debugKeyEnabled.Value.ToString(),
			", DebugKey=",
			null,
			null,
			null
		};
		Key value = debugKey.Value;
		obj[7] = ((object)(Key)(ref value)).ToString();
		obj[8] = ", PreferredWeaponSlot=";
		obj[9] = preferredWeaponSlot.Value.ToString();
		logger.LogInfo((object)string.Concat(obj));
	}

	private void OnDestroy()
	{
		SceneManager.sceneLoaded -= OnSceneLoaded;
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		sawLoadingOrLevelTransition = true;
		currentLevelSignature = 0;
		cachedLevelSignature = 0;
		nextSignatureCheckTime = 0f;
		rewardedKillUnitIds.Clear();
		if (logActions != null && logActions.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name + ". Auto-give transition armed."));
		}
	}

	private void TryPatchHarmony()
	{
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(InventoryItem), "DropFromPlayer", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(GeneratedWeaponDropFromPlayerHook), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo != null && methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched InventoryItem.DropFromPlayer.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not patch InventoryItem.DropFromPlayer.");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch InventoryItem.DropFromPlayer: " + ex.Message));
		}
		TryPatchLevelTransitionMethods();
		TryPatchNextLevelTrigger();
		TryPatchAmuletHelper();
		TryPatchUnitDie();
	}

	private void TryPatchUnitDie()
	{
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Expected O, but got Unknown
		try
		{
			Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.Units.Unit");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find Unit type for kill reward patch.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(UnitDieRandomWeaponRewardHook), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find UnitDieRandomWeaponRewardHook.Prefix.");
				return;
			}
			int num = 0;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2 == null) && !(methodInfo2.Name != "Die"))
				{
					try
					{
						harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched Unit.Die for random weapon on kill. Params=" + methodInfo2.GetParameters().Length));
					}
					catch (Exception ex)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch Unit.Die overload: " + ex.Message));
					}
				}
			}
			if (num == 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"No Unit.Die method was patched.");
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch Unit.Die for kill reward: " + ex2.Message));
		}
	}

	internal void TryRewardRandomWeaponOnEnemyDeath(object unit)
	{
		if (enableRandomWeaponOnKill == null || !enableRandomWeaponOnKill.Value || unit == null || (killRewardRequiresPlayableLevel.Value && !IsInPlayableLevel()))
		{
			return;
		}
		if (Time.unscaledTime < nextKillRewardAllowedTime)
		{
			if (logKillRewardChecks.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Kill reward skipped by cooldown.");
			}
		}
		else
		{
			if (!ShouldRewardForDeadUnit(unit))
			{
				return;
			}
			int stableRuntimeUnitId = GetStableRuntimeUnitId(unit);
			if (stableRuntimeUnitId == 0)
			{
				return;
			}
			if (!rewardedKillUnitIds.Add(stableRuntimeUnitId))
			{
				if (logKillRewardChecks.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: unit already rewarded. id=" + stableRuntimeUnitId));
				}
				return;
			}
			nextKillRewardAllowedTime = Time.unscaledTime + Mathf.Max(0f, randomWeaponOnKillCooldown.Value);
			if (logActions.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Kill reward triggered. Generating random weapon.");
			}
			((MonoBehaviour)this).StartCoroutine(GiveRandomWeaponRoutine("enemy kill reward", currentLevelSignature));
		}
	}

	private bool ShouldRewardForDeadUnit(object unit)
	{
		if (unit == null)
		{
			return false;
		}
		Component val = (Component)((unit is Component) ? unit : null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		if ((Object)(object)val.gameObject == (Object)null)
		{
			return false;
		}
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				if ((Object)(object)instance.PlayerObject != (Object)null && (Object)(object)val.gameObject == (Object)(object)instance.PlayerObject)
				{
					return false;
				}
				if ((Object)(object)instance.PlayerUnit != (Object)null && unit == instance.PlayerUnit)
				{
					return false;
				}
			}
		}
		catch
		{
		}
		if (killRewardRequireExperienceOnKill.Value)
		{
			if (!TryReadFloatMember(unit, "ExperienceOnKill", out var value))
			{
				if (logKillRewardChecks.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: could not read ExperienceOnKill from " + ((Object)val.gameObject).name));
				}
				return false;
			}
			if (value <= 0f)
			{
				if (logKillRewardChecks.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Kill reward skipped: ExperienceOnKill <= 0 for " + ((Object)val.gameObject).name));
				}
				return false;
			}
		}
		return true;
	}

	private bool TryReadFloatMember(object target, string memberName, out float value)
	{
		value = 0f;
		if (target == null)
		{
			return false;
		}
		Type type = target.GetType();
		try
		{
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				object value2 = property.GetValue(target, null);
				if (TryConvertToFloat(value2, out value))
				{
					return true;
				}
			}
		}
		catch
		{
		}
		try
		{
			FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object value3 = field.GetValue(target);
				if (TryConvertToFloat(value3, out value))
				{
					return true;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private bool TryConvertToFloat(object raw, out float value)
	{
		value = 0f;
		if (raw == null)
		{
			return false;
		}
		try
		{
			if (raw is float)
			{
				value = (float)raw;
				return true;
			}
			if (raw is int)
			{
				value = (int)raw;
				return true;
			}
			if (raw is double)
			{
				value = (float)(double)raw;
				return true;
			}
			value = Convert.ToSingle(raw);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private int GetStableRuntimeUnitId(object unit)
	{
		if (unit == null)
		{
			return 0;
		}
		try
		{
			Component val = (Component)((unit is Component) ? unit : null);
			if ((Object)(object)val != (Object)null)
			{
				return ((Object)val).GetInstanceID();
			}
		}
		catch
		{
		}
		try
		{
			return unit.GetHashCode();
		}
		catch
		{
			return 0;
		}
	}

	private void TryPatchAmuletHelper()
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		try
		{
			Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Gameplay.Items.AmuletHelper");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletHelper type.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "DoneChanneling", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletHelper.DoneChanneling.");
				return;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(AmuletTeleportCleanupHook), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find AmuletTeleportCleanupHook.Prefix.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched AmuletHelper.DoneChanneling.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch AmuletHelper.DoneChanneling: " + ex.Message));
		}
	}

	private void TryPatchNextLevelTrigger()
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		try
		{
			Type type = AccessTools.TypeByName("PerfectRandom.Sulfur.Core.LevelGeneration.NextLevelTrigger");
			if (type == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTrigger type.");
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(type, "MakeTransition", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTrigger.MakeTransition.");
				return;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(NextLevelTriggerCleanupHook), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo2 == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find NextLevelTriggerCleanupHook.Prefix.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched NextLevelTrigger.MakeTransition.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch NextLevelTrigger.MakeTransition: " + ex.Message));
		}
	}

	private void TryPatchLevelTransitionMethods()
	{
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(LevelTransitionCleanupHook), "Prefix", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find LevelTransitionCleanupHook.Prefix.");
				return;
			}
			int num = 0;
			HashSet<MethodBase> hashSet = new HashSet<MethodBase>();
			MethodInfo[] methods = typeof(GameManager).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2 == null) && IsLikelyLevelTransitionMethod(methodInfo2) && !hashSet.Contains(methodInfo2))
				{
					try
					{
						harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						hashSet.Add(methodInfo2);
						num++;
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched level transition method: GameManager." + methodInfo2.Name + "(" + methodInfo2.GetParameters().Length + " params)"));
					}
					catch (Exception ex)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch GameManager." + methodInfo2.Name + ": " + ex.Message));
					}
				}
			}
			if (num == 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"No likely GameManager level transition methods were patched.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Level transition cleanup patched methods: " + num));
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to patch level transition cleanup: " + ex2.Message));
		}
	}

	private bool IsLikelyLevelTransitionMethod(MethodInfo method)
	{
		string name = method.Name;
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		switch (name)
		{
		case "GoToLevel":
			return true;
		case "GoToChurchHub":
			return true;
		case "GoToCarHub":
			return true;
		case "CompleteLevel":
			return true;
		case "SwitchLevel":
			return true;
		case "GoToNextLevel":
			return true;
		case "GoToPreviousLevel":
			return true;
		case "ReturnToChurch":
			return true;
		case "ReturnToChurchHub":
			return true;
		case "ReturnToHub":
			return true;
		case "LeaveLevel":
			return true;
		case "ExitLevel":
			return true;
		default:
			if (name.Contains("GoTo") && name.Contains("Level"))
			{
				return true;
			}
			if (name.Contains("Switch") && name.Contains("Level"))
			{
				return true;
			}
			if (name.Contains("Load") && name.Contains("Level"))
			{
				return true;
			}
			if (name.Contains("Next") && name.Contains("Level"))
			{
				return true;
			}
			if (name.Contains("Return") && (name.Contains("Church") || name.Contains("Hub")))
			{
				return true;
			}
			return false;
		}
	}

	private void Update()
	{
		if (enableMod.Value)
		{
			HandleDebugKey();
			HandleLevelSignatureAutoGive();
		}
	}

	internal bool ShouldCleanupBeforeLevelTransition()
	{
		return cleanupGeneratedWeaponsBeforeLevelTransition != null && cleanupGeneratedWeaponsBeforeLevelTransition.Value;
	}

	internal bool ShouldDestroyGeneratedWeaponsOnDrop()
	{
		return destroyGeneratedWeaponsOnDrop != null && destroyGeneratedWeaponsOnDrop.Value;
	}

	internal static bool IsGeneratedWeapon(InventoryItem item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return false;
		}
		try
		{
			return (Object)(object)((Component)item).GetComponent<RandomWeaponMarker>() != (Object)null;
		}
		catch
		{
			return false;
		}
	}

	internal static void RemoveGeneratedWeaponSafely(InventoryItem item, string reason)
	{
		if ((Object)(object)item == (Object)null)
		{
			return;
		}
		try
		{
			item.GetRemovedByExternalFactor(reason);
		}
		catch (Exception ex)
		{
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogWarning((object)("Failed to remove generated weapon: " + ex.Message));
			}
		}
	}

	private void HandleDebugKey()
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Invalid comparison between Unknown and I4
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		if (!debugKeyEnabled.Value)
		{
			return;
		}
		Keyboard current = Keyboard.current;
		if (current == null)
		{
			return;
		}
		Key value = debugKey.Value;
		if ((int)value == 0)
		{
			return;
		}
		try
		{
			if (((ButtonControl)current[value]).wasPressedThisFrame)
			{
				((MonoBehaviour)this).StartCoroutine(GiveRandomWeaponRoutine("debug key " + ((object)(Key)(ref value)).ToString(), 0));
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to read debug key " + ((object)(Key)(ref value)).ToString() + ": " + ex.Message));
		}
	}

	private void HandleLevelSignatureAutoGive()
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Invalid comparison between Unknown and I4
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Invalid comparison between Unknown and I4
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Invalid comparison between Unknown and I4
		if (!randomizeOnLevelStart.Value)
		{
			return;
		}
		GameManager instance;
		try
		{
			instance = StaticInstance<GameManager>.Instance;
		}
		catch
		{
			return;
		}
		if ((Object)(object)instance == (Object)null)
		{
			return;
		}
		if (instance.InSafeZone)
		{
			ResetAutoGiveMemoryForSafeZone();
		}
		else if ((int)instance.gameState == 1 || (int)instance.gameState == 0)
		{
			sawLoadingOrLevelTransition = true;
			currentLevelSignature = 0;
			cachedLevelSignature = 0;
			nextSignatureCheckTime = 0f;
		}
		else
		{
			if ((int)instance.gameState != 3 || !IsInPlayableLevel())
			{
				return;
			}
			int num = GetCachedLevelSignature();
			if (num != 0)
			{
				if (currentLevelSignature == 0)
				{
					currentLevelSignature = num;
				}
				bool flag = sawLoadingOrLevelTransition && currentLevelSignature != num;
				bool flag2 = sawLoadingOrLevelTransition && currentLevelSignature == num;
				if (flag || flag2)
				{
					currentLevelSignature = num;
					sawLoadingOrLevelTransition = false;
					TryStartAutoGiveForSignature(num, "level signature");
				}
			}
		}
	}

	private void ResetAutoGiveMemoryForSafeZone()
	{
		sawLoadingOrLevelTransition = true;
		currentLevelSignature = 0;
		cachedLevelSignature = 0;
		nextSignatureCheckTime = 0f;
		rewardedKillUnitIds.Clear();
		nextKillRewardAllowedTime = 0f;
		autoGivenLevelSignatures.Clear();
	}

	private void TryStartAutoGiveForSignature(int signature, string reason)
	{
		if (signature != 0 && !autoGiveRoutineRunning && !autoGivenLevelSignatures.Contains(signature))
		{
			autoGivenLevelSignatures.Add(signature);
			((MonoBehaviour)this).StartCoroutine(AutoGiveForLevelSignature(signature, reason));
		}
	}

	[IteratorStateMachine(typeof(<AutoGiveForLevelSignature>d__78))]
	private IEnumerator AutoGiveForLevelSignature(int signature, string reason)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <AutoGiveForLevelSignature>d__78(0)
		{
			<>4__this = this,
			signature = signature,
			reason = reason
		};
	}

	private bool IsInPlayableLevel()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Invalid comparison between Unknown and I4
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if ((int)instance.gameState != 3)
			{
				return false;
			}
			if (instance.InSafeZone)
			{
				return false;
			}
			if ((Object)(object)instance.PlayerUnit == (Object)null)
			{
				return false;
			}
			if ((Object)(object)StaticInstance<UIManager>.Instance == (Object)null)
			{
				return false;
			}
			if ((Object)(object)StaticInstance<UIManager>.Instance.PlayerBackpackGrid == (Object)null)
			{
				return false;
			}
			if ((Object)(object)StaticInstance<UIManager>.Instance.InventoryUI == (Object)null)
			{
				return false;
			}
			return true;
		}
		catch
		{
			return false;
		}
	}

	private int GetCachedLevelSignature()
	{
		float num = Mathf.Clamp(sceneSignatureCheckInterval.Value, 0.1f, 5f);
		if (cachedLevelSignature != 0 && Time.unscaledTime < nextSignatureCheckTime)
		{
			return cachedLevelSignature;
		}
		cachedLevelSignature = ComputeLevelSignature();
		nextSignatureCheckTime = Time.unscaledTime + num;
		return cachedLevelSignature;
	}

	private int ComputeLevelSignature()
	{
		//IL_0043: 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)
		try
		{
			int num = 17;
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				num = num * 31 + instance.InSafeZone.GetHashCode();
			}
			num = num * 31 + SceneManager.sceneCount;
			for (int i = 0; i < SceneManager.sceneCount; i++)
			{
				Scene sceneAt = SceneManager.GetSceneAt(i);
				if (!((Scene)(ref sceneAt)).IsValid() || !((Scene)(ref sceneAt)).isLoaded)
				{
					continue;
				}
				num = num * 31 + ((Scene)(ref sceneAt)).name.GetHashCode();
				GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects();
				num = num * 31 + rootGameObjects.Length;
				foreach (GameObject val in rootGameObjects)
				{
					if (!((Object)(object)val == (Object)null))
					{
						num = num * 31 + ((Object)val).name.GetHashCode();
						num = num * 31 + val.activeSelf.GetHashCode();
					}
				}
			}
			return num;
		}
		catch
		{
			return 0;
		}
	}

	[IteratorStateMachine(typeof(<GiveRandomWeaponRoutine>d__82))]
	private IEnumerator GiveRandomWeaponRoutine(string reason, int levelSignature)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <GiveRandomWeaponRoutine>d__82(0)
		{
			<>4__this = this,
			reason = reason,
			levelSignature = levelSignature
		};
	}

	private InventorySlot PrepareTargetWeaponSlot()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: 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_0027: 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_004c: Unknown result type (might be due to invalid IL or missing references)
		List<InventorySlot> preferredWeaponSlotOrder = GetPreferredWeaponSlotOrder();
		foreach (InventorySlot item in preferredWeaponSlotOrder)
		{
			if (TryPrepareWeaponSlot(item))
			{
				return item;
			}
		}
		return (InventorySlot)9;
	}

	private List<InventorySlot> GetPreferredWeaponSlotOrder()
	{
		List<InventorySlot> list = new List<InventorySlot>();
		switch (preferredWeaponSlot.Value)
		{
		case PreferredWeaponSlotMode.Weapon0:
			list.Add((InventorySlot)4);
			list.Add((InventorySlot)5);
			return list;
		case PreferredWeaponSlotMode.Weapon1:
			list.Add((InventorySlot)5);
			list.Add((InventorySlot)4);
			return list;
		case PreferredWeaponSlotMode.Random:
			if (Random.value < 0.5f)
			{
				list.Add((InventorySlot)4);
				list.Add((InventorySlot)5);
			}
			else
			{
				list.Add((InventorySlot)5);
				list.Add((InventorySlot)4);
			}
			return list;
		default:
			list.Add((InventorySlot)4);
			list.Add((InventorySlot)5);
			return list;
		}
	}

	private bool TryPrepareWeaponSlot(InventorySlot slot)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		PaperdollSlot paperdollSlot = GetPaperdollSlot(slot);
		if ((Object)(object)paperdollSlot == (Object)null)
		{
			return false;
		}
		InventoryItem itemInSlot = paperdollSlot.itemInSlot;
		if ((Object)(object)itemInSlot == (Object)null)
		{
			return true;
		}
		if ((Object)(object)((Component)itemInSlot).GetComponent<RandomWeaponMarker>() != (Object)null)
		{
			try
			{
				itemInSlot.GetRemovedByExternalFactor("Random Weapon Per Level replacing generated weapon");
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to remove old generated weapon from " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex.Message));
				return false;
			}
		}
		if (!CanMoveItemToBackpack(itemInSlot))
		{
			if (logActions.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Cannot move existing weapon to backpack, skipping slot " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + itemInSlot.itemDefinition.displayName));
			}
			return false;
		}
		try
		{
			itemInSlot.TryMoveToPlayerInventory();
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to move existing weapon to backpack from " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex2.Message));
			return false;
		}
		return true;
	}

	private bool IsWeaponSlotEmpty(InventorySlot slot)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		InventoryItem itemInWeaponSlot = GetItemInWeaponSlot(slot);
		return (Object)(object)itemInWeaponSlot == (Object)null;
	}

	private InventoryItem GetItemInWeaponSlot(InventorySlot slot)
	{
		//IL_0003: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			PaperdollSlot paperdollSlot = GetPaperdollSlot(slot);
			if ((Object)(object)paperdollSlot != (Object)null)
			{
				return paperdollSlot.itemInSlot;
			}
		}
		catch
		{
		}
		try
		{
			EquipmentManager equipmentManager = GetEquipmentManager();
			if ((Object)(object)equipmentManager != (Object)null && equipmentManager.EquippedItems.ContainsKey(slot))
			{
				return equipmentManager.EquippedItems[slot];
			}
		}
		catch
		{
		}
		return null;
	}

	private PaperdollSlot GetPaperdollSlot(InventorySlot slot)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			UIManager instance = StaticInstance<UIManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if ((Object)(object)instance.Paperdoll == (Object)null)
			{
				return null;
			}
			return instance.Paperdoll.GetSlot(slot);
		}
		catch
		{
			return null;
		}
	}

	private bool CanMoveItemToBackpack(InventoryItem item)
	{
		//IL_002e: 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)
		//IL_0035: 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_003d: 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_007d: 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)
		if ((Object)(object)item == (Object)null)
		{
			return false;
		}
		try
		{
			ItemGrid playerBackpackGrid = GetPlayerBackpackGrid();
			if ((Object)(object)playerBackpackGrid == (Object)null)
			{
				return false;
			}
			Vector2Int inventorySize = item.InventorySize;
			Vector2Int possibleSpace = playerBackpackGrid.GetPossibleSpace(inventorySize, false, true);
			if (((Vector2Int)(ref possibleSpace)).x >= 0 && ((Vector2Int)(ref possibleSpace)).y >= 0)
			{
				return true;
			}
			Vector2Int val = default(Vector2Int);
			((Vector2Int)(ref val))..ctor(((Vector2Int)(ref inventorySize)).y, ((Vector2Int)(ref inventorySize)).x);
			Vector2Int possibleSpace2 = playerBackpackGrid.GetPossibleSpace(val, false, true);
			return ((Vector2Int)(ref possibleSpace2)).x >= 0 && ((Vector2Int)(ref possibleSpace2)).y >= 0;
		}
		catch
		{
			return false;
		}
	}

	private void MarkGeneratedWeapon(InventoryItem item, string reason, int levelSignature)
	{
		if (!((Object)(object)item == (Object)null))
		{
			RandomWeaponMarker randomWeaponMarker = ((Component)item).GetComponent<RandomWeaponMarker>();
			if ((Object)(object)randomWeaponMarker == (Object)null)
			{
				randomWeaponMarker = ((Component)item).gameObject.AddComponent<RandomWeaponMarker>();
			}
			generationCounter++;
			randomWeaponMarker.generationId = generationCounter;
			randomWeaponMarker.levelSignature = levelSignature;
			randomWeaponMarker.reason = reason;
			randomWeaponMarker.weaponName = (((Object)(object)item.itemDefinition != (Object)null) ? item.itemDefinition.displayName : "Unknown");
		}
	}

	internal int CleanupOldGeneratedWeapons(InventoryItem keepItem)
	{
		int num = 0;
		try
		{
			RandomWeaponMarker[] array = Resources.FindObjectsOfTypeAll<RandomWeaponMarker>();
			RandomWeaponMarker[] array2 = array;
			foreach (RandomWeaponMarker randomWeaponMarker in array2)
			{
				if ((Object)(object)randomWeaponMarker == (Object)null)
				{
					continue;
				}
				InventoryItem component = ((Component)randomWeaponMarker).GetComponent<InventoryItem>();
				if (!((Object)(object)component == (Object)null) && (!((Object)(object)keepItem != (Object)null) || !((Object)(object)component == (Object)(object)keepItem)))
				{
					try
					{
						component.GetRemovedByExternalFactor("Random Weapon Per Level cleanup");
						num++;
					}
					catch (Exception ex)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to remove generated weapon: " + ex.Message));
					}
				}
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to cleanup generated weapons: " + ex2.Message));
		}
		return num;
	}

	private void TrySelectWeaponSlot(InventorySlot slot)
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			EquipmentManager equipmentManager = GetEquipmentManager();
			if (!((Object)(object)equipmentManager == (Object)null))
			{
				equipmentManager.ChangeWeapon(slot, true);
			}
		}
		catch (Exception ex)
		{
			if (logActions.Value)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select generated weapon slot " + ((object)(InventorySlot)(ref slot)).ToString() + ": " + ex.Message));
			}
		}
	}

	private ItemGrid GetPlayerBackpackGrid()
	{
		try
		{
			UIManager instance = StaticInstance<UIManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			return instance.PlayerBackpackGrid;
		}
		catch
		{
			return null;
		}
	}

	private HashSet<InventoryItem> CapturePlayerInventoryItems()
	{
		HashSet<InventoryItem> hashSet = new HashSet<InventoryItem>();
		try
		{
			ItemGrid playerBackpackGrid = GetPlayerBackpackGrid();
			if ((Object)(object)playerBackpackGrid != (Object)null)
			{
				foreach (InventoryItem item in playerBackpackGrid.AllItems())
				{
					if ((Object)(object)item != (Object)null)
					{
						hashSet.Add(item);
					}
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to capture backpack items: " + ex.Message));
		}
		try
		{
			EquipmentManager equipmentManager = GetEquipmentManager();
			if ((Object)(object)equipmentManager != (Object)null)
			{
				foreach (InventoryItem value in equipmentManager.EquippedItems.Values)
				{
					if ((Object)(object)value != (Object)null)
					{
						hashSet.Add(value);
					}
				}
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to capture equipped items: " + ex2.Message));
		}
		return hashSet;
	}

	private List<InventoryItem> GetAllPlayerItemsSnapshot()
	{
		HashSet<InventoryItem> collection = CapturePlayerInventoryItems();
		return new List<InventoryItem>(collection);
	}

	private InventoryItem FindNewInventoryItem(HashSet<InventoryItem> beforeItems, WeaponSO weapon)
	{
		if ((Object)(object)weapon == (Object)null)
		{
			return null;
		}
		List<InventoryItem> allPlayerItemsSnapshot = GetAllPlayerItemsSnapshot();
		foreach (InventoryItem item in allPlayerItemsSnapshot)
		{
			if ((Object)(object)item == (Object)null || (beforeItems != null && beforeItems.Contains(item)) || !((Object)(object)item.itemDefinition == (Object)(object)weapon))
			{
				continue;
			}
			return item;
		}
		return null;
	}

	private EquipmentManager GetEquipmentManager()
	{
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if ((Object)(object)instance.EquipmentManager != (Object)null)
			{
				return instance.EquipmentManager;
			}
			if ((Object)(object)instance.PlayerScript != (Object)null)
			{
				return instance.PlayerScript.equipmentManager;
			}
			return null;
		}
		catch
		{
			return null;
		}
	}

	private int ApplyRandomOilsIfNeeded(InventoryItem item)
	{
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
		if (!enableRandomOils.Value)
		{
			return 0;
		}
		if ((Object)(object)item == (Object)null)
		{
			return 0;
		}
		ItemDefinition itemDefinition = item.itemDefinition;
		WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null);
		if ((Object)(object)val == (Object)null)
		{
			return 0;
		}
		if (!val.TypeIsEnchantable)
		{
			return 0;
		}
		int num = Mathf.Clamp(minOilCount.Value, 1, 5);
		int max = Mathf.Clamp(maxOilCount.Value, num, 5);
		int num2 = PickWeightedOilCount(num, max);
		LootTable oilLootTable = GetOilLootTable();
		if ((Object)(object)oilLootTable == (Object)null || oilLootTable.entries == null || oilLootTable.entries.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random oils: oil loot table is empty.");
			return 0;
		}
		HashSet<ItemId> hashSet = new HashSet<ItemId>();
		int num3 = 0;
		int num4 = 0;
		int num5 = num2 * 30;
		while (num3 < num2 && num4 < num5)
		{
			num4++;
			ItemDefinition val2 = null;
			try
			{
				val2 = oilLootTable.SelectOneItem();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select random oil: " + ex.Message));
				break;
			}
			if ((Object)(object)val2 == (Object)null || !((EnchantmentId)(ref val2.appliesEnchantment)).IsValid || hashSet.Contains(val2.id) || IsEnchantmentAlreadyApplied(item, val2) || (respectEnchantmentSlots.Value && !item.IsEnchantmentCompatible(val2)))
			{
				continue;
			}
			try
			{
				item.AddEnchantment(val2, false);
				hashSet.Add(val2.id);
				num3++;
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random oil to " + item.itemDefinition.displayName + ": " + val2.displayName));
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random oil " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex2.Message));
			}
		}
		return num3;
	}

	private int PickWeightedOilCount(int min, int max)
	{
		min = Mathf.Clamp(min, 1, 5);
		max = Mathf.Clamp(max, min, 5);
		float num = 0f;
		for (int i = min; i <= max; i++)
		{
			num += GetOilCountWeight(i);
		}
		if (num <= 0f)
		{
			return Random.Range(min, max + 1);
		}
		float num2 = Random.value * num;
		float num3 = 0f;
		for (int j = min; j <= max; j++)
		{
			num3 += GetOilCountWeight(j);
			if (num2 <= num3)
			{
				return j;
			}
		}
		return max;
	}

	private float GetOilCountWeight(int count)
	{
		return count switch
		{
			1 => 5f, 
			2 => 4f, 
			3 => 3.5f, 
			4 => 3f, 
			5 => 2.5f, 
			_ => 1f, 
		};
	}

	private int ApplyRandomScrollsIfNeeded(InventoryItem item)
	{
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		if (!enableRandomScrolls.Value)
		{
			return 0;
		}
		if ((Object)(object)item == (Object)null)
		{
			return 0;
		}
		ItemDefinition itemDefinition = item.itemDefinition;
		WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null);
		if ((Object)(object)val == (Object)null)
		{
			return 0;
		}
		if (!val.TypeIsEnchantable)
		{
			return 0;
		}
		float num = Mathf.Clamp01(scrollChance.Value);
		if (Random.value > num)
		{
			if (logActions.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Random scroll roll skipped for " + item.itemDefinition.displayName + "."));
			}
			return 0;
		}
		LootTable scrollLootTable = GetScrollLootTable();
		if ((Object)(object)scrollLootTable == (Object)null || scrollLootTable.entries == null || scrollLootTable.entries.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random scrolls: scroll loot table is empty.");
			return 0;
		}
		int num2 = Mathf.Clamp(minScrollCount.Value, 1, 5);
		int num3 = Mathf.Clamp(maxScrollCount.Value, num2, 5);
		int num4 = Random.Range(num2, num3 + 1);
		HashSet<ItemId> hashSet = new HashSet<ItemId>();
		int num5 = 0;
		int num6 = 0;
		int num7 = num4 * 30;
		while (num5 < num4 && num6 < num7)
		{
			num6++;
			ItemDefinition val2 = null;
			try
			{
				val2 = scrollLootTable.SelectOneItem();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to select random scroll: " + ex.Message));
				break;
			}
			if ((Object)(object)val2 == (Object)null || !((EnchantmentId)(ref val2.appliesEnchantment)).IsValid || hashSet.Contains(val2.id) || IsEnchantmentAlreadyApplied(item, val2) || (respectEnchantmentSlots.Value && !item.IsEnchantmentCompatible(val2)))
			{
				continue;
			}
			try
			{
				item.AddEnchantment(val2, false);
				hashSet.Add(val2.id);
				num5++;
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random scroll to " + item.itemDefinition.displayName + ": " + val2.displayName));
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random scroll " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex2.Message));
			}
		}
		return num5;
	}

	private bool IsEnchantmentAlreadyApplied(InventoryItem item, ItemDefinition enchantmentItem)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)item == (Object)null || (Object)(object)enchantmentItem == (Object)null)
		{
			return false;
		}
		if (!((EnchantmentId)(ref enchantmentItem.appliesEnchantment)).IsValid)
		{
			return false;
		}
		try
		{
			EnchantmentDefinition asset = AssetAccess.GetAsset(enchantmentItem.appliesEnchantment);
			if ((Object)(object)asset == (Object)null)
			{
				return false;
			}
			return item.enchantments != null && item.enchantments.Contains(asset);
		}
		catch
		{
			return false;
		}
	}

	private int ApplyRandomAttachmentsIfNeeded(InventoryItem item)
	{
		//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		if (!enableRandomAttachments.Value)
		{
			return 0;
		}
		if ((Object)(object)item == (Object)null)
		{
			return 0;
		}
		ItemDefinition itemDefinition = item.itemDefinition;
		WeaponSO val = (WeaponSO)(object)((itemDefinition is WeaponSO) ? itemDefinition : null);
		if ((Object)(object)val == (Object)null)
		{
			return 0;
		}
		float num = Mathf.Clamp01(attachmentChance.Value);
		if (Random.value > num)
		{
			if (logActions.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Random attachment roll skipped for " + item.itemDefinition.displayName + "."));
			}
			return 0;
		}
		LootTable attachmentLootTable = GetAttachmentLootTable();
		if ((Object)(object)attachmentLootTable == (Object)null || attachmentLootTable.entries == null || attachmentLootTable.entries.Count == 0)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not apply random attachments: attachment loot table is empty.");
			return 0;
		}
		int num2 = Mathf.Clamp(minAttachmentCount.Value, 1, 4);
		int num3 = Mathf.Clamp(maxAttachmentCount.Value, num2, 4);
		int num4 = Random.Range(num2, num3 + 1);
		HashSet<ItemId> hashSet = new HashSet<ItemId>();
		int num5 = 0;
		while (num5 < num4)
		{
			List<WeightedAttachmentCandidate> list = BuildCompatibleAttachmentCandidates(item, attachmentLootTable, hashSet);
			if (list.Count == 0)
			{
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("No more compatible attachments for " + item.itemDefinition.displayName + ". Applied " + num5 + "/" + num4 + "."));
				}
				break;
			}
			ItemDefinition val2 = PickWeightedAttachment(list);
			if ((Object)(object)val2 == (Object)null)
			{
				break;
			}
			try
			{
				item.AddAttachment(val2, false);
				hashSet.Add(val2.id);
				num5++;
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied random attachment to " + item.itemDefinition.displayName + ": " + val2.displayName));
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply random attachment " + val2.displayName + " to " + item.itemDefinition.displayName + ": " + ex.Message));
				hashSet.Add(val2.id);
			}
		}
		return num5;
	}

	private List<WeightedAttachmentCandidate> BuildCompatibleAttachmentCandidates(InventoryItem item, LootTable attachmentTable, HashSet<ItemId> usedAttachmentIds)
	{
		//IL_013a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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_0072: 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)
		List<WeightedAttachmentCandidate> list = new List<WeightedAttachmentCandidate>();
		if ((Object)(object)item == (Object)null)
		{
			return list;
		}
		if ((Object)(object)attachmentTable == (Object)null || attachmentTable.entries == null)
		{
			return list;
		}
		foreach (LootEntry entry in attachmentTable.entries)
		{
			ItemDefinition lootItem = entry.lootItem;
			if ((Object)(object)lootItem == (Object)null || entry.lootWeight <= 0f || (usedAttachmentIds != null && usedAttachmentIds.Contains(lootItem.id)))
			{
				continue;
			}
			bool flag = false;
			try
			{
				flag = item.IsAttachmentCompatible(lootItem);
			}
			catch (Exception ex)
			{
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Attachment compatibility check failed for " + lootItem.displayName + " on " + item.itemDefinition.displayName + ": " + ex.Message));
				}
				flag = false;
			}
			if (flag)
			{
				list.Add(new WeightedAttachmentCandidate(lootItem, entry.lootWeight));
			}
		}
		return list;
	}

	private ItemDefinition PickWeightedAttachment(List<WeightedAttachmentCandidate> candidates)
	{
		if (candidates == null || candidates.Count == 0)
		{
			return null;
		}
		float num = 0f;
		for (int i = 0; i < candidates.Count; i++)
		{
			num += Mathf.Max(0f, candidates[i].Weight);
		}
		if (num <= 0f)
		{
			int index = Random.Range(0, candidates.Count);
			return candidates[index].Item;
		}
		float num2 = Random.value * num;
		float num3 = 0f;
		for (int j = 0; j < candidates.Count; j++)
		{
			num3 += Mathf.Max(0f, candidates[j].Weight);
			if (num2 <= num3)
			{
				return candidates[j].Item;
			}
		}
		return candidates[candidates.Count - 1].Item;
	}

	private void GrantMinimumRankForAppliedEnchantments(InventoryItem item, int appliedEnchantmentCount)
	{
		if (!grantRankForAppliedOils.Value || (Object)(object)item == (Object)null || appliedEnchantmentCount <= 0)
		{
			return;
		}
		int num = Mathf.Clamp(appliedEnchantmentCount, 0, 5);
		if (num <= 0)
		{
			return;
		}
		try
		{
			float experience = item.GetExperience();
			float minimumExperienceForRank = GetMinimumExperienceForRank(num);
			if (!(experience >= minimumExperienceForRank))
			{
				item.AddExperience(minimumExperienceForRank - experience);
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Raised rank for " + item.itemDefinition.displayName + " to match applied enchantments. Target rank: " + num));
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to raise weapon rank for applied enchantments: " + ex.Message));
		}
	}

	private float GetMinimumExperienceForRank(int rank)
	{
		return rank switch
		{
			1 => 50f, 
			2 => 125f, 
			3 => 312.5f, 
			4 => 781.25f, 
			5 => 1953.125f, 
			_ => 0f, 
		};
	}

	private LootTable GetOilLootTable()
	{
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null)
			{
				return null;
			}
			return instance.Settings.LootSettings.enchantmentOilLootTable;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get oil loot table: " + ex.Message));
			return null;
		}
	}

	private LootTable GetScrollLootTable()
	{
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null)
			{
				return null;
			}
			return instance.Settings.LootSettings.enchantmentLootTable;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get scroll loot table: " + ex.Message));
			return null;
		}
	}

	private LootTable GetAttachmentLootTable()
	{
		try
		{
			GameManager instance = StaticInstance<GameManager>.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.Settings == (Object)null || (Object)(object)instance.Settings.LootSettings == (Object)null)
			{
				return null;
			}
			return instance.Settings.LootSettings.attachmentLootTable;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to get attachment loot table: " + ex.Message));
			return null;
		}
	}

	private void NormalizeDurabilityIfNeeded(InventoryItem item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return;
		}
		try
		{
			if (!item.HasDurability)
			{
				return;
			}
			int durabilityMax = item.DurabilityMax;
			int durabilityCurrent = item.DurabilityCurrent;
			if (durabilityCurrent > durabilityMax)
			{
				item.ModifyDurability((float)(durabilityMax - durabilityCurrent));
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Clamped durability for " + item.itemDefinition.displayName + " to max durability: " + durabilityMax));
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to normalize durability: " + ex.Message));
		}
	}

	private void FixDurabilityIfNeeded(InventoryItem item)
	{
		if (!fixLowDurability.Value || (Object)(object)item == (Object)null)
		{
			return;
		}
		try
		{
			if (!item.HasDurability)
			{
				return;
			}
			float num = Mathf.Clamp01(minimumDurabilityNormalized.Value);
			if (item.DurabilityNormalized >= num)
			{
				return;
			}
			int durabilityMax = item.DurabilityMax;
			int num2 = Mathf.CeilToInt((float)durabilityMax * num);
			int num3 = num2 - item.DurabilityCurrent;
			if (num3 > 0)
			{
				item.ModifyDurability((float)num3);
				if (logActions.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Raised durability for " + item.itemDefinition.displayName + " to at least " + Mathf.RoundToInt(num * 100f) + "%"));
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to fix generated weapon durability: " + ex.Message));
		}
	}

	private void TrySyncInstancedWeapon(InventoryItem item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return;
		}
		try
		{
			item.SyncWithInstancedVersion();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to sync generated weapon instance: " + ex.Message));
		}
	}

	private WeaponSO PickRandomWeapon()
	{
		EnsureWeaponPool();
		if (cachedWeaponPool.Count == 0)
		{
			return null;
		}
		int index = Random.Range(0, cachedWeaponPool.Count);
		return cachedWeaponPool[index];
	}

	private void EnsureWeaponPool()
	{
		if (cachedWeaponPool.Count <= 0)
		{
			RefreshWeaponPool();
		}
	}

	private void RefreshWeaponPool()
	{
		cachedWeaponPool.Clear();
		WeaponSO[] array;
		try
		{
			array = Resources.FindObjectsOfTypeAll<WeaponSO>();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to find WeaponSO assets: " + ex.Message));
			return;
		}
		WeaponSO[] array2 = array;
		foreach (WeaponSO val in array2)
		{
			if (IsValidWeaponForRandomPool(val) && !cachedWeaponPool.Contains(val))
			{
				cachedWeaponPool.Add(val);
			}
		}
		cachedWeaponPool.Sort((WeaponSO a, WeaponSO b) => string.Compare(GetWeaponName(a), GetWeaponName(b), StringComparison.OrdinalIgnoreCase));
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Random weapon pool loaded. Valid weapons: " + cachedWeaponPool.Count));
		if (!logWeaponPool.Value)
		{
			return;
		}
		foreach (WeaponSO item in cachedWeaponPool)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Random pool weapon: " + GetWeaponName(item)));
		}
	}

	private bool IsValidWeaponForRandomPool(WeaponSO weapon)
	{
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Invalid comparison between Unknown and I4
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Invalid comparison between Unknown and I4
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)weapon == (Object)null)
		{
			return false;
		}
		if (requireUsableByPlayer.Value && !weapon.usableByPlayer)
		{
			return false;
		}
		if (gunsOnly.Value)
		{
			if (weapon.IsMelee)
			{
				return false;
			}
			if (weapon.IsThrowable)
			{
				return false;
			}
		}
		if (excludeStartsEmpty.Value && weapon.startsEmpty)
		{
			return false;
		}
		if (requireAmmoMagazine.Value && weapon.iAmmoMax <= 0)
		{
			return false;
		}
		if (requireWeaponPrefab.Value && (Object)(object)((ItemDefinition)weapon).prefab == (Object)null)
		{
			return false;
		}
		if ((int)((ItemDefinition)weapon).slotType != 7)
		{
			return false;
		}
		if ((int)weapon.caliber == 0)
		{
			return false;
		}
		if ((int)weapon.projectileType == 0 && !((Object)(object)weapon.customProjectile != (Object)null))
		{
			return false;
		}
		if (string.IsNullOrWhiteSpace(((ItemDefinition)weapon).displayName))
		{
			return false;
		}
		return true;
	}

	private string BuildCreatedItemInfo(InventoryItem item)
	{
		if ((Object)(object)item == (Object)null)
		{
			return "null";
		}
		int num = 0;
		try
		{
			num = ((item.enchantments != null) ? item.enchantments.Count : 0);
		}
		catch
		{
			num = -1;
		}
		int num2 = 0;
		try
		{
			num2 = ((item.attachments != null) ? item.attachments.Count : 0);
		}
		catch
		{
			num2 = -1;
		}
		string text = "rank=";
		try
		{
			text += item.GetRankLevel();
		}
		catch
		{
			text += "unknown";
		}
		string text2 = "durability=";
		try
		{
			text2 = ((!item.HasDurability) ? (text2 + "none") : (text2 + item.DurabilityCurrent + "/" + item.DurabilityMax));
		}
		catch
		{
			text2 += "unknown";
		}
		string text3 = "marker=";
		try
		{
			RandomWeaponMarker component = ((Component)item).GetComponent<RandomWeaponMarker>();
			text3 += (((Object)(object)component != (Object)null) ? component.generationId.ToString() : "none");
		}
		catch
		{
			text3 += "unknown";
		}
		return "created item found, enchantments=" + num + ", attachments=" + num2 + ", " + text + ", " + text2 + ", " + text3;
	}

	private static string GetWeaponName(WeaponSO weapon)
	{
		if ((Object)(object)weapon == (Object)null)
		{
			return "null";
		}
		if (!string.IsNullOrWhiteSpace(((ItemDefinition)weapon).displayName))
		{
			return ((ItemDefinition)weapon).displayName;
		}
		return ((Object)weapon).name;
	}
}
internal static class AmuletTeleportCleanupHook
{
	public static void Prefix()
	{
		try
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				Plugin.Instance.CleanupGeneratedWeaponsForTransition("AmuletHelper.DoneChanneling");
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Failed to cleanup generated weapons in AmuletHelper.DoneChanneling: " + ex.Message));
			}
		}
	}
}
internal static class NextLevelTriggerCleanupHook
{
	public static void Prefix()
	{
		try
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				Plugin.Instance.CleanupGeneratedWeaponsForTransition("NextLevelTrigger.MakeTransition");
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Failed to cleanup generated weapons in NextLevelTrigger.MakeTransition: " + ex.Message));
			}
		}
	}
}
internal static class GeneratedWeaponDropFromPlayerHook
{
	public static bool Prefix(InventoryItem __instance)
	{
		if ((Object)(object)Plugin.Instance == (Object)null)
		{
			return true;
		}
		if (!Plugin.Instance.ShouldDestroyGeneratedWeaponsOnDrop())
		{
			return true;
		}
		if (!Plugin.IsGeneratedWeapon(__instance))
		{
			return true;
		}
		Plugin.RemoveGeneratedWeaponSafely(__instance, "Random Weapon Per Level: generated weapon dropped");
		return false;
	}
}
internal static class UnitDieRandomWeaponRewardHook
{
	public static void Prefix(object __instance)
	{
		try
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				Plugin.Instance.TryRewardRandomWeaponOnEnemyDeath(__instance);
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Failed to process random weapon kill reward: " + ex.Message));
			}
		}
	}
}
internal static class LevelTransitionCleanupHook
{
	public static void Prefix(MethodBase __originalMethod)
	{
		try
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				string reason = ((__originalMethod != null) ? (__originalMethod.DeclaringType.Name + "." + __originalMethod.Name) : "unknown transition method");
				Plugin.Instance.CleanupGeneratedWeaponsForTransition(reason);
			}
		}
		catch (Exception ex)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Failed to cleanup generated weapons before transition: " + ex.Message));
			}
		}
	}
}